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/fib_test.h>
17 #include <vnet/fib/ip6_fib.h>
18 #include <vnet/fib/ip4_fib.h>
19 #include <vnet/fib/mpls_fib.h>
20 #include <vnet/adj/adj.h>
21 #include <vnet/dpo/load_balance.h>
22 #include <vnet/dpo/load_balance_map.h>
23 #include <vnet/dpo/mpls_label_dpo.h>
24 #include <vnet/dpo/lookup_dpo.h>
25 #include <vnet/dpo/drop_dpo.h>
26 #include <vnet/dpo/receive_dpo.h>
27 #include <vnet/dpo/ip_null_dpo.h>
28 #include <vnet/bfd/bfd_main.h>
29 #include <vnet/dpo/interface_rx_dpo.h>
30 #include <vnet/dpo/replicate_dpo.h>
31 #include <vnet/dpo/l2_bridge_dpo.h>
32 #include <vnet/dpo/mpls_disposition.h>
34 #include <vnet/mpls/mpls.h>
36 #include <vnet/fib/fib_test.h>
37 #include <vnet/fib/fib_path_list.h>
38 #include <vnet/fib/fib_entry_src.h>
39 #include <vnet/fib/fib_walk.h>
40 #include <vnet/fib/fib_node_list.h>
41 #include <vnet/fib/fib_urpf_list.h>
44 * Add debugs for passing tests
46 static int fib_test_do_debug;
48 #define FIB_TEST_I(_cond, _comment, _args...) \
50 int _evald = (_cond); \
52 fformat(stderr, "FAIL:%d: " _comment "\n", \
55 if (fib_test_do_debug) \
56 fformat(stderr, "PASS:%d: " _comment "\n", \
61 #define FIB_TEST(_cond, _comment, _args...) \
63 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
65 ASSERT(!("FAIL: " _comment)); \
70 * A 'i'm not fussed is this is not efficient' store of test data
72 typedef struct test_main_t_ {
76 u32 hw_if_indicies[4];
80 vnet_hw_interface_t * hw[4];
83 static test_main_t test_main;
85 /* fake ethernet device class, distinct from "fake-ethX" */
86 static u8 * format_test_interface_name (u8 * s, va_list * args)
88 u32 dev_instance = va_arg (*args, u32);
89 return format (s, "test-eth%d", dev_instance);
92 static uword dummy_interface_tx (vlib_main_t * vm,
93 vlib_node_runtime_t * node,
96 clib_warning ("you shouldn't be here, leaking buffers...");
97 return frame->n_vectors;
100 static clib_error_t *
101 test_interface_admin_up_down (vnet_main_t * vnm,
105 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
106 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
107 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
111 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
112 .name = "Test interface",
113 .format_device_name = format_test_interface_name,
114 .tx_function = dummy_interface_tx,
115 .admin_up_down_function = test_interface_admin_up_down,
118 static u8 *hw_address;
121 fib_test_mk_intf (u32 ninterfaces)
123 clib_error_t * error = NULL;
124 test_main_t *tm = &test_main;
128 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
133 vec_add1(hw_address, byte);
136 for (i = 0; i < ninterfaces; i++)
140 error = ethernet_register_interface(vnet_get_main(),
141 test_interface_device_class.index,
144 &tm->hw_if_indicies[i],
145 /* flag change */ 0);
147 FIB_TEST((NULL == error), "ADD interface %d", i);
149 error = vnet_hw_interface_set_flags(vnet_get_main(),
150 tm->hw_if_indicies[i],
151 VNET_HW_INTERFACE_FLAG_LINK_UP);
152 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
153 tm->hw_if_indicies[i]);
154 vec_validate (ip4_main.fib_index_by_sw_if_index,
155 tm->hw[i]->sw_if_index);
156 vec_validate (ip6_main.fib_index_by_sw_if_index,
157 tm->hw[i]->sw_if_index);
158 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
159 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
161 error = vnet_sw_interface_set_flags(vnet_get_main(),
162 tm->hw[i]->sw_if_index,
163 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
164 FIB_TEST((NULL == error), "UP interface %d", i);
167 * re-eval after the inevitable realloc
169 for (i = 0; i < ninterfaces; i++)
171 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
172 tm->hw_if_indicies[i]);
178 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
180 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
181 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
182 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
183 fib_table_lookup(fib_index, (_via_prefix))); \
184 FIB_TEST(!dpo_cmp(_via_dpo, \
185 load_balance_get_bucket(_rec_dpo->dpoi_index, \
187 "%U is recursive via %U", \
188 format_fib_prefix, (_rec_prefix), \
189 format_fib_prefix, _via_prefix); \
192 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
194 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
195 fib_table_lookup_exact_match(fib_index, (_prefix))); \
196 const dpo_id_t *_dpo1 = \
197 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
198 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
199 format_dpo_type, _dpo1->dpoi_type); \
200 FIB_TEST((_ai == _dpo1->dpoi_index), \
201 "%U bucket %d resolves via %U", \
202 format_fib_prefix, (_prefix), \
204 format_dpo_id, _dpo1, 0); \
207 #define FIB_TEST_RPF(_cond, _comment, _args...) \
209 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
215 fib_test_urpf_is_equal (fib_node_index_t fei,
216 fib_forward_chain_type_t fct,
219 dpo_id_t dpo = DPO_INVALID;
220 fib_urpf_list_t *urpf;
227 fib_entry_contribute_forwarding(fei, fct, &dpo);
228 ui = load_balance_get_urpf(dpo.dpoi_index);
230 urpf = fib_urpf_list_get(ui);
232 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
233 "RPF:%U len %d == %d",
234 format_fib_urpf_list, ui,
235 num, vec_len(urpf->furpf_itfs));
236 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
237 "RPF:%U check-size %d == %d",
238 format_fib_urpf_list, ui,
239 num, vec_len(urpf->furpf_itfs));
241 for (ii = 0; ii < num; ii++)
243 adj_index_t ai = va_arg(ap, adj_index_t);
245 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
246 "RPF:%d item:%d - %d == %d",
247 ui, ii, ai, urpf->furpf_itfs[ii]);
248 FIB_TEST_RPF(fib_urpf_check(ui, ai),
261 fib_test_build_rewrite (u8 *eth_addr)
265 vec_validate(rewrite, 13);
267 memcpy(rewrite, eth_addr, 6);
268 memcpy(rewrite+6, eth_addr, 6);
273 #define FIB_TEST_LB(_cond, _comment, _args...) \
275 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
281 fib_test_validate_rep_v (const replicate_t *rep,
285 const fib_test_rep_bucket_t *exp;
289 FIB_TEST_LB((n_buckets == rep->rep_n_buckets),
290 "n_buckets = %d", rep->rep_n_buckets);
292 for (bucket = 0; bucket < n_buckets; bucket++)
294 exp = va_arg(*ap, fib_test_rep_bucket_t*);
296 dpo = replicate_get_bucket_i(rep, bucket);
300 case FT_REP_LABEL_O_ADJ:
302 const mpls_label_dpo_t *mld;
304 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
305 "bucket %d stacks on %U",
307 format_dpo_type, dpo->dpoi_type);
309 mld = mpls_label_dpo_get(dpo->dpoi_index);
310 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
312 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
313 exp->label_o_adj.label),
314 "bucket %d stacks on label %d",
316 exp->label_o_adj.label);
318 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
319 exp->label_o_adj.eos),
320 "bucket %d stacks on label %d %U",
322 exp->label_o_adj.label,
323 format_mpls_eos_bit, exp->label_o_adj.eos);
325 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
326 "bucket %d label stacks on %U",
328 format_dpo_type, mld->mld_dpo.dpoi_type);
330 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
331 "bucket %d label stacks on adj %d",
333 exp->label_o_adj.adj);
337 FIB_TEST_LB((DPO_INTERFACE_RX == dpo->dpoi_type),
338 "bucket %d stacks on %U",
340 format_dpo_type, dpo->dpoi_type);
342 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
343 "bucket %d stacks on adj %d",
347 case FT_REP_DISP_MFIB_LOOKUP:
357 fib_test_validate_lb_v (const load_balance_t *lb,
364 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
366 for (bucket = 0; bucket < n_buckets; bucket++)
368 const fib_test_lb_bucket_t *exp;
370 exp = va_arg(*ap, fib_test_lb_bucket_t*);
371 dpo = load_balance_get_bucket_i(lb, bucket);
375 case FT_LB_LABEL_STACK_O_ADJ:
377 const mpls_label_dpo_t *mld;
381 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
382 "bucket %d stacks on %U",
384 format_dpo_type, dpo->dpoi_type);
386 mld = mpls_label_dpo_get(dpo->dpoi_index);
388 FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
392 for (ii = 0; ii < mld->mld_n_labels; ii++)
394 hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
395 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
396 exp->label_stack_o_adj.label_stack[ii]),
397 "bucket %d stacks on label %d",
399 exp->label_stack_o_adj.label_stack[ii]);
401 if (ii == mld->mld_n_labels-1)
403 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
404 exp->label_o_adj.eos),
405 "bucket %d stacks on label %d %U!=%U",
407 exp->label_stack_o_adj.label_stack[ii],
408 format_mpls_eos_bit, exp->label_o_adj.eos,
409 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
413 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
414 "bucket %d stacks on label %d %U",
416 exp->label_stack_o_adj.label_stack[ii],
417 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
421 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
422 "bucket %d label stacks on %U",
424 format_dpo_type, mld->mld_dpo.dpoi_type);
426 FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
427 "bucket %d label stacks on adj %d",
429 exp->label_stack_o_adj.adj);
432 case FT_LB_LABEL_O_ADJ:
434 const mpls_label_dpo_t *mld;
436 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
437 "bucket %d stacks on %U",
439 format_dpo_type, dpo->dpoi_type);
441 mld = mpls_label_dpo_get(dpo->dpoi_index);
442 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
444 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
445 exp->label_o_adj.label),
446 "bucket %d stacks on label %d",
448 exp->label_o_adj.label);
450 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
451 exp->label_o_adj.eos),
452 "bucket %d stacks on label %d %U",
454 exp->label_o_adj.label,
455 format_mpls_eos_bit, exp->label_o_adj.eos);
457 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
458 "bucket %d label stacks on %U",
460 format_dpo_type, mld->mld_dpo.dpoi_type);
462 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
463 "bucket %d label stacks on adj %d",
465 exp->label_o_adj.adj);
468 case FT_LB_LABEL_O_LB:
470 const mpls_label_dpo_t *mld;
473 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
474 "bucket %d stacks on %U",
476 format_dpo_type, dpo->dpoi_type);
478 mld = mpls_label_dpo_get(dpo->dpoi_index);
479 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
481 FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
483 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
484 exp->label_o_lb.label),
485 "bucket %d stacks on label %d",
487 exp->label_o_lb.label);
489 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
490 exp->label_o_lb.eos),
491 "bucket %d stacks on label %d %U",
493 exp->label_o_lb.label,
494 format_mpls_eos_bit, exp->label_o_lb.eos);
496 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
497 "bucket %d label stacks on %U",
499 format_dpo_type, mld->mld_dpo.dpoi_type);
501 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
502 "bucket %d label stacks on LB %d",
508 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
509 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
510 "bucket %d stacks on %U",
512 format_dpo_type, dpo->dpoi_type);
513 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
514 "bucket %d stacks on adj %d",
518 case FT_LB_MPLS_DISP_O_ADJ:
520 const mpls_disp_dpo_t *mdd;
522 FIB_TEST_I((DPO_MPLS_DISPOSITION == dpo->dpoi_type),
523 "bucket %d stacks on %U",
525 format_dpo_type, dpo->dpoi_type);
527 mdd = mpls_disp_dpo_get(dpo->dpoi_index);
531 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
532 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
533 "bucket %d stacks on %U",
535 format_dpo_type, dpo->dpoi_type);
536 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
537 "bucket %d stacks on adj %d",
543 FIB_TEST_I((DPO_INTERFACE_RX == dpo->dpoi_type),
544 "bucket %d stacks on %U",
546 format_dpo_type, dpo->dpoi_type);
547 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
548 "bucket %d stacks on adj %d",
553 FIB_TEST_I((DPO_L2_BRIDGE == dpo->dpoi_type),
554 "bucket %d stacks on %U",
556 format_dpo_type, dpo->dpoi_type);
557 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
558 "bucket %d stacks on adj %d",
563 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
564 "bucket %d stacks on %U",
566 format_dpo_type, dpo->dpoi_type);
567 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
568 "bucket %d stacks on lb %d not %d",
573 case FT_LB_BIER_TABLE:
574 FIB_TEST_LB((DPO_BIER_TABLE == dpo->dpoi_type),
575 "bucket %d stacks on %U",
577 format_dpo_type, dpo->dpoi_type);
578 FIB_TEST_LB((exp->bier.table == dpo->dpoi_index),
579 "bucket %d stacks on lb %d",
583 case FT_LB_BIER_FMASK:
584 FIB_TEST_LB((DPO_BIER_FMASK == dpo->dpoi_type),
585 "bucket %d stacks on %U",
587 format_dpo_type, dpo->dpoi_type);
588 FIB_TEST_LB((exp->bier.fmask == dpo->dpoi_index),
589 "bucket %d stacks on lb %d",
594 FIB_TEST_LB((DPO_DROP == dpo->dpoi_type),
595 "bucket %d stacks on %U",
597 format_dpo_type, dpo->dpoi_type);
605 fib_test_validate_lb (const dpo_id_t *dpo,
609 const load_balance_t *lb;
613 va_start(ap, n_buckets);
615 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo->dpoi_type),
617 format_dpo_type, dpo->dpoi_type);
618 lb = load_balance_get(dpo->dpoi_index);
620 res = fib_test_validate_lb_v(lb, n_buckets, &ap);
628 fib_test_validate_entry (fib_node_index_t fei,
629 fib_forward_chain_type_t fct,
633 dpo_id_t dpo = DPO_INVALID;
640 va_start(ap, n_buckets);
642 fib_entry_get_prefix(fei, &pfx);
643 fib_index = fib_entry_get_fib_index(fei);
644 fib_entry_contribute_forwarding(fei, fct, &dpo);
646 if (DPO_REPLICATE == dpo.dpoi_type)
648 const replicate_t *rep;
650 rep = replicate_get(dpo.dpoi_index);
651 res = fib_test_validate_rep_v(rep, n_buckets, &ap);
655 const load_balance_t *lb;
657 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
659 format_dpo_type, dpo.dpoi_type);
661 lb = load_balance_get(dpo.dpoi_index);
662 res = fib_test_validate_lb_v(lb, n_buckets, &ap);
665 * ensure that the LB contributed by the entry is the
666 * same as the LB in the forwarding tables
668 if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
670 switch (pfx.fp_proto)
672 case FIB_PROTOCOL_IP4:
673 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
675 case FIB_PROTOCOL_IP6:
676 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
678 case FIB_PROTOCOL_MPLS:
680 mpls_unicast_header_t hdr = {
681 .label_exp_s_ttl = 0,
684 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
685 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
686 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
688 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
694 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
695 "Contributed LB = FW LB: %U\n %U",
696 format_load_balance, fw_lbi, 0,
697 format_load_balance, dpo.dpoi_index, 0);
712 * In the default table check for the presence and correct forwarding
713 * of the special entries
715 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
716 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
717 const ip_adjacency_t *adj;
718 const load_balance_t *lb;
725 ip46_address_t nh_10_10_10_1 = {
726 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
729 ip46_address_t nh_10_10_10_2 = {
730 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
733 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
734 pool_elts(load_balance_map_pool));
738 /* record the nubmer of load-balances in use before we start */
739 lb_count = pool_elts(load_balance_pool);
741 /* Find or create FIB table 11 */
742 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11,
745 for (ii = 0; ii < 4; ii++)
747 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
750 fib_prefix_t pfx_0_0_0_0_s_0 = {
752 .fp_proto = FIB_PROTOCOL_IP4,
762 .fp_proto = FIB_PROTOCOL_IP4,
770 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
772 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
773 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
774 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
775 "Default route is DROP");
778 fei = fib_table_lookup(fib_index, &pfx);
779 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
780 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
781 "all 0s route is DROP");
783 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
785 fei = fib_table_lookup(fib_index, &pfx);
786 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
787 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
788 "all 1s route is DROP");
790 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
792 fei = fib_table_lookup(fib_index, &pfx);
793 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
794 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
795 "all-mcast route is DROP");
797 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
799 fei = fib_table_lookup(fib_index, &pfx);
800 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
801 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
802 "class-e route is DROP");
805 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
806 * all of which are special sourced and so none of which share path-lists.
807 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
808 * table, and 4 path-lists in the v6 MFIB table
812 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
813 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
814 fib_path_list_pool_size());
815 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
816 fib_entry_pool_size());
819 * add interface routes.
820 * validate presence of /24 attached and /32 recieve.
821 * test for the presence of the receive address in the glean and local adj
823 fib_prefix_t local_pfx = {
825 .fp_proto = FIB_PROTOCOL_IP4,
828 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
833 fib_table_entry_update_one_path(fib_index, &local_pfx,
834 FIB_SOURCE_INTERFACE,
835 (FIB_ENTRY_FLAG_CONNECTED |
836 FIB_ENTRY_FLAG_ATTACHED),
839 tm->hw[0]->sw_if_index,
840 ~0, // invalid fib index
843 FIB_ROUTE_PATH_FLAG_NONE);
844 fei = fib_table_lookup(fib_index, &local_pfx);
845 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
846 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
847 fib_entry_get_flags(fei)),
848 "Flags set on attached interface");
850 ai = fib_entry_get_adj(fei);
851 FIB_TEST((FIB_NODE_INDEX_INVALID != ai),
852 "attached interface route adj present %d", ai);
854 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
855 "attached interface adj is glean");
856 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
857 &adj->sub_type.glean.receive_addr)),
858 "attached interface adj is receive ok");
860 local_pfx.fp_len = 32;
861 fib_table_entry_update_one_path(fib_index, &local_pfx,
862 FIB_SOURCE_INTERFACE,
863 (FIB_ENTRY_FLAG_CONNECTED |
864 FIB_ENTRY_FLAG_LOCAL),
867 tm->hw[0]->sw_if_index,
868 ~0, // invalid fib index
871 FIB_ROUTE_PATH_FLAG_NONE);
872 fei = fib_table_lookup(fib_index, &local_pfx);
873 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
874 fib_entry_get_flags(fei)),
875 "Flags set on local interface");
877 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
879 dpo = fib_entry_contribute_ip_forwarding(fei);
880 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
881 "RPF list for local length 0");
882 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
883 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
884 "local interface adj is local");
885 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
887 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
889 "local interface adj is receive ok");
891 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
893 FIB_SOURCE_INTERFACE)),
894 "2 Interface Source'd prefixes");
897 * +2 interface routes +2 non-shared path-lists
899 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
900 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
901 fib_path_list_pool_size());
902 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
903 fib_entry_pool_size());
906 * Modify the default route to be via an adj not yet known.
907 * this sources the defalut route with the API source, which is
908 * a higher preference to the DEFAULT_ROUTE source
910 pfx.fp_addr.ip4.as_u32 = 0;
912 fib_table_entry_path_add(fib_index, &pfx,
917 tm->hw[0]->sw_if_index,
918 ~0, // invalid fib index
921 FIB_ROUTE_PATH_FLAG_NONE);
922 fei = fib_table_lookup(fib_index, &pfx);
923 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
924 "Flags set on API route");
926 FIB_TEST((fei == dfrt), "default route same index");
927 ai = fib_entry_get_adj(fei);
928 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
930 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
931 "adj is incomplete");
932 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
933 "adj nbr next-hop ok");
934 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
937 "1 API Source'd prefixes");
940 * find the adj in the shared db
942 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
945 tm->hw[0]->sw_if_index);
946 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
947 adj_unlock(locked_ai);
950 * +1 shared path-list
952 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
953 fib_path_list_db_size());
954 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
955 fib_path_list_pool_size());
956 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
957 fib_entry_pool_size());
960 * remove the API source from the default route. We expected
961 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
963 pfx.fp_addr.ip4.as_u32 = 0;
965 fib_table_entry_path_remove(fib_index, &pfx,
969 tm->hw[0]->sw_if_index,
970 ~0, // non-recursive path, so no FIB index
972 FIB_ROUTE_PATH_FLAG_NONE);
974 fei = fib_table_lookup(fib_index, &pfx);
976 FIB_TEST((fei == dfrt), "default route same index");
977 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
978 "Default route is DROP");
981 * -1 shared-path-list
983 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
984 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
985 fib_path_list_pool_size());
986 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
987 fib_entry_pool_size());
990 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
992 fib_prefix_t pfx_10_10_10_1_s_32 = {
994 .fp_proto = FIB_PROTOCOL_IP4,
997 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
1000 fib_prefix_t pfx_10_10_10_2_s_32 = {
1002 .fp_proto = FIB_PROTOCOL_IP4,
1005 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
1008 fib_prefix_t pfx_11_11_11_11_s_32 = {
1010 .fp_proto = FIB_PROTOCOL_IP4,
1013 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
1017 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
1020 ip46_address_t nh_12_12_12_12 = {
1021 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
1023 adj_index_t ai_12_12_12_12;
1026 * Add a route via an incomplete ADJ. then complete the ADJ
1027 * Expect the route LB is updated to use complete adj type.
1029 fei = fib_table_entry_update_one_path(fib_index,
1030 &pfx_11_11_11_11_s_32,
1032 FIB_ENTRY_FLAG_ATTACHED,
1034 &pfx_10_10_10_1_s_32.fp_addr,
1035 tm->hw[0]->sw_if_index,
1036 ~0, // invalid fib index
1039 FIB_ROUTE_PATH_FLAG_NONE);
1041 dpo = fib_entry_contribute_ip_forwarding(fei);
1042 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1043 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1044 "11.11.11.11/32 via incomplete adj");
1046 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1048 &pfx_10_10_10_1_s_32.fp_addr,
1049 tm->hw[0]->sw_if_index);
1050 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1051 adj = adj_get(ai_01);
1052 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1053 "adj is incomplete");
1054 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1055 &adj->sub_type.nbr.next_hop)),
1056 "adj nbr next-hop ok");
1058 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1059 fib_test_build_rewrite(eth_addr));
1060 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1062 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1063 &adj->sub_type.nbr.next_hop)),
1064 "adj nbr next-hop ok");
1065 ai = fib_entry_get_adj(fei);
1066 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1068 dpo = fib_entry_contribute_ip_forwarding(fei);
1069 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1070 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1071 "11.11.11.11/32 via complete adj");
1072 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1073 tm->hw[0]->sw_if_index),
1074 "RPF list for adj-fib contains adj");
1076 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1079 tm->hw[1]->sw_if_index);
1080 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1081 adj = adj_get(ai_12_12_12_12);
1082 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1083 "adj is incomplete");
1084 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1085 &adj->sub_type.nbr.next_hop)),
1086 "adj nbr next-hop ok");
1087 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1088 fib_test_build_rewrite(eth_addr));
1089 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1095 fei = fib_table_entry_path_add(fib_index,
1096 &pfx_10_10_10_1_s_32,
1098 FIB_ENTRY_FLAG_ATTACHED,
1100 &pfx_10_10_10_1_s_32.fp_addr,
1101 tm->hw[0]->sw_if_index,
1102 ~0, // invalid fib index
1105 FIB_ROUTE_PATH_FLAG_NONE);
1106 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1107 "Flags set on adj-fib");
1108 ai = fib_entry_get_adj(fei);
1109 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
1111 fib_table_entry_path_remove(fib_index,
1112 &pfx_11_11_11_11_s_32,
1115 &pfx_10_10_10_1_s_32.fp_addr,
1116 tm->hw[0]->sw_if_index,
1117 ~0, // invalid fib index
1119 FIB_ROUTE_PATH_FLAG_NONE);
1123 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1125 &pfx_10_10_10_2_s_32.fp_addr,
1126 tm->hw[0]->sw_if_index);
1127 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1128 adj = adj_get(ai_02);
1129 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1130 "adj is incomplete");
1131 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1132 &adj->sub_type.nbr.next_hop)),
1133 "adj nbr next-hop ok");
1135 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1136 fib_test_build_rewrite(eth_addr));
1137 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1139 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1140 &adj->sub_type.nbr.next_hop)),
1141 "adj nbr next-hop ok");
1142 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1144 fib_table_entry_path_add(fib_index,
1145 &pfx_10_10_10_2_s_32,
1147 FIB_ENTRY_FLAG_ATTACHED,
1149 &pfx_10_10_10_2_s_32.fp_addr,
1150 tm->hw[0]->sw_if_index,
1151 ~0, // invalid fib index
1154 FIB_ROUTE_PATH_FLAG_NONE);
1156 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1157 ai = fib_entry_get_adj(fei);
1158 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1161 * +2 adj-fibs, and their non-shared path-lists
1163 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1164 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1165 fib_path_list_pool_size());
1166 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1167 fib_entry_pool_size());
1170 * Add 2 routes via the first ADJ. ensure path-list sharing
1172 fib_prefix_t pfx_1_1_1_1_s_32 = {
1174 .fp_proto = FIB_PROTOCOL_IP4,
1177 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1181 fib_table_entry_path_add(fib_index,
1184 FIB_ENTRY_FLAG_NONE,
1187 tm->hw[0]->sw_if_index,
1188 ~0, // invalid fib index
1191 FIB_ROUTE_PATH_FLAG_NONE);
1192 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1193 ai = fib_entry_get_adj(fei);
1194 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1197 * +1 entry and a shared path-list
1199 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1200 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1201 fib_path_list_pool_size());
1202 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1203 fib_entry_pool_size());
1206 fib_prefix_t pfx_1_1_2_0_s_24 = {
1208 .fp_proto = FIB_PROTOCOL_IP4,
1210 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1214 fib_table_entry_path_add(fib_index,
1217 FIB_ENTRY_FLAG_NONE,
1220 tm->hw[0]->sw_if_index,
1221 ~0, // invalid fib index
1224 FIB_ROUTE_PATH_FLAG_NONE);
1225 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1226 ai = fib_entry_get_adj(fei);
1227 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1232 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1233 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1234 fib_path_list_pool_size());
1235 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1236 fib_entry_pool_size());
1239 * modify 1.1.2.0/24 to use multipath.
1241 fib_table_entry_path_add(fib_index,
1244 FIB_ENTRY_FLAG_NONE,
1247 tm->hw[0]->sw_if_index,
1248 ~0, // invalid fib index
1251 FIB_ROUTE_PATH_FLAG_NONE);
1252 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1253 dpo = fib_entry_contribute_ip_forwarding(fei);
1254 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1255 1, tm->hw[0]->sw_if_index),
1256 "RPF list for 1.1.2.0/24 contains both adjs");
1258 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1259 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1260 FIB_TEST((ai_01 == dpo1->dpoi_index),
1261 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1262 ai_01, dpo1->dpoi_index);
1264 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1265 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1266 FIB_TEST((ai_02 == dpo1->dpoi_index),
1267 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1270 * +1 shared-pathlist
1272 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1273 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1274 fib_path_list_pool_size());
1275 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1276 fib_entry_pool_size());
1281 fib_table_entry_path_remove(fib_index,
1286 tm->hw[0]->sw_if_index,
1289 FIB_ROUTE_PATH_FLAG_NONE);
1290 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1291 dpo = fib_entry_contribute_ip_forwarding(fei);
1292 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1293 1, tm->hw[0]->sw_if_index),
1294 "RPF list for 1.1.2.0/24 contains one adj");
1296 ai = fib_entry_get_adj(fei);
1297 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1300 * +1 shared-pathlist
1302 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1303 fib_path_list_db_size());
1304 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1305 fib_path_list_pool_size());
1306 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1307 fib_entry_pool_size());
1310 * Add 2 recursive routes:
1311 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1312 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1314 fib_prefix_t bgp_100_pfx = {
1316 .fp_proto = FIB_PROTOCOL_IP4,
1318 /* 100.100.100.100/32 */
1319 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1323 ip46_address_t nh_1_1_1_1 = {
1324 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1327 fei = fib_table_entry_path_add(fib_index,
1330 FIB_ENTRY_FLAG_NONE,
1333 ~0, // no index provided.
1334 fib_index, // nexthop in same fib as route
1337 FIB_ROUTE_PATH_FLAG_NONE);
1339 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1340 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1341 tm->hw[0]->sw_if_index),
1342 "RPF list for adj-fib contains adj");
1345 * +1 entry and +1 shared-path-list
1347 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1348 fib_path_list_db_size());
1349 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1350 fib_path_list_pool_size());
1351 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1352 fib_entry_pool_size());
1354 fib_prefix_t bgp_101_pfx = {
1356 .fp_proto = FIB_PROTOCOL_IP4,
1358 /* 100.100.100.101/32 */
1359 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1363 fib_table_entry_path_add(fib_index,
1366 FIB_ENTRY_FLAG_NONE,
1369 ~0, // no index provided.
1370 fib_index, // nexthop in same fib as route
1373 FIB_ROUTE_PATH_FLAG_NONE);
1375 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1376 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1377 tm->hw[0]->sw_if_index),
1378 "RPF list for adj-fib contains adj");
1381 * +1 entry, but the recursive path-list is shared.
1383 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1384 fib_path_list_db_size());
1385 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1386 fib_path_list_pool_size());
1387 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1388 fib_entry_pool_size());
1391 * An special route; one where the user (me) provides the
1392 * adjacency through which the route will resovle by setting the flags
1394 fib_prefix_t ex_pfx = {
1396 .fp_proto = FIB_PROTOCOL_IP4,
1399 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1403 fib_table_entry_special_add(fib_index,
1406 FIB_ENTRY_FLAG_LOCAL);
1407 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1408 dpo = fib_entry_contribute_ip_forwarding(fei);
1409 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1410 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1411 "local interface adj is local");
1413 fib_table_entry_special_remove(fib_index,
1415 FIB_SOURCE_SPECIAL);
1416 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1417 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1418 "Exclusive reoute removed");
1421 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1422 * adjacency through which the route will resovle
1424 dpo_id_t ex_dpo = DPO_INVALID;
1426 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1429 LOOKUP_INPUT_DST_ADDR,
1430 LOOKUP_TABLE_FROM_CONFIG,
1433 fib_table_entry_special_dpo_add(fib_index,
1436 FIB_ENTRY_FLAG_EXCLUSIVE,
1438 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1439 dpo = fib_entry_contribute_ip_forwarding(fei);
1440 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1441 "exclusive remote uses lookup DPO");
1444 * update the exclusive to use a different DPO
1446 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1447 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1449 fib_table_entry_special_dpo_update(fib_index,
1452 FIB_ENTRY_FLAG_EXCLUSIVE,
1454 dpo = fib_entry_contribute_ip_forwarding(fei);
1455 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1456 "exclusive remote uses now uses NULL DPO");
1458 fib_table_entry_special_remove(fib_index,
1460 FIB_SOURCE_SPECIAL);
1461 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1462 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1463 "Exclusive reoute removed");
1467 * Add a recursive route:
1468 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1470 fib_prefix_t bgp_200_pfx = {
1472 .fp_proto = FIB_PROTOCOL_IP4,
1474 /* 200.200.200.200/32 */
1475 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1479 fib_prefix_t pfx_1_1_1_2_s_32 = {
1481 .fp_proto = FIB_PROTOCOL_IP4,
1483 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1487 fei = fib_table_entry_path_add(fib_index,
1490 FIB_ENTRY_FLAG_NONE,
1492 &pfx_1_1_1_2_s_32.fp_addr,
1493 ~0, // no index provided.
1494 fib_index, // nexthop in same fib as route
1497 FIB_ROUTE_PATH_FLAG_NONE);
1499 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1500 "Recursive via unresolved is drop");
1503 * the adj should be recursive via drop, since the route resolves via
1504 * the default route, which is itself a DROP
1506 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1507 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1508 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1509 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1510 "RPF list for 1.1.1.2/32 contains 0 adjs");
1513 * +2 entry and +1 shared-path-list
1515 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1516 fib_path_list_db_size());
1517 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1518 fib_path_list_pool_size());
1519 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1520 fib_entry_pool_size());
1523 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1524 * The paths are sort by NH first. in this case the the path with greater
1525 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1527 fib_prefix_t pfx_1_2_3_4_s_32 = {
1529 .fp_proto = FIB_PROTOCOL_IP4,
1531 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1534 fib_table_entry_path_add(fib_index,
1537 FIB_ENTRY_FLAG_NONE,
1540 tm->hw[0]->sw_if_index,
1544 FIB_ROUTE_PATH_FLAG_NONE);
1545 fei = fib_table_entry_path_add(fib_index,
1548 FIB_ENTRY_FLAG_NONE,
1551 tm->hw[1]->sw_if_index,
1555 FIB_ROUTE_PATH_FLAG_NONE);
1557 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1558 dpo = fib_entry_contribute_ip_forwarding(fei);
1559 lb = load_balance_get(dpo->dpoi_index);
1560 FIB_TEST((lb->lb_n_buckets == 4),
1561 "1.2.3.4/32 LB has %d bucket",
1564 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1565 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1566 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1567 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1569 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1570 tm->hw[0]->sw_if_index,
1571 tm->hw[1]->sw_if_index),
1572 "RPF list for 1.2.3.4/32 contains both adjs");
1576 * Unequal Cost load-balance. 4:1 ratio.
1577 * fits in a 16 bucket LB with ratio 13:3
1579 fib_prefix_t pfx_1_2_3_5_s_32 = {
1581 .fp_proto = FIB_PROTOCOL_IP4,
1583 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1586 fib_table_entry_path_add(fib_index,
1589 FIB_ENTRY_FLAG_NONE,
1592 tm->hw[1]->sw_if_index,
1596 FIB_ROUTE_PATH_FLAG_NONE);
1597 fei = fib_table_entry_path_add(fib_index,
1600 FIB_ENTRY_FLAG_NONE,
1603 tm->hw[0]->sw_if_index,
1607 FIB_ROUTE_PATH_FLAG_NONE);
1609 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1610 dpo = fib_entry_contribute_ip_forwarding(fei);
1611 lb = load_balance_get(dpo->dpoi_index);
1612 FIB_TEST((lb->lb_n_buckets == 16),
1613 "1.2.3.5/32 LB has %d bucket",
1616 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1617 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1618 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1619 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1620 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1621 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1622 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1623 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1624 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1625 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1626 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1627 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1628 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1629 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1630 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1631 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1633 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1634 tm->hw[0]->sw_if_index,
1635 tm->hw[1]->sw_if_index),
1636 "RPF list for 1.2.3.4/32 contains both adjs");
1639 * Test UCMP with a large weight skew - this produces load-balance objects with large
1640 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1641 * laso testing the LB in placce modify code when number of buckets is large.
1643 fib_prefix_t pfx_6_6_6_6_s_32 = {
1645 .fp_proto = FIB_PROTOCOL_IP4,
1648 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1651 fib_test_lb_bucket_t ip_o_10_10_10_1 = {
1657 fib_test_lb_bucket_t ip_o_10_10_10_2 = {
1663 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1666 .adj = ai_12_12_12_12,
1669 fib_table_entry_update_one_path(fib_index,
1672 FIB_ENTRY_FLAG_NONE,
1675 tm->hw[0]->sw_if_index,
1676 ~0, // invalid fib index
1679 FIB_ROUTE_PATH_FLAG_NONE);
1681 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1682 FIB_TEST(fib_test_validate_entry(fei,
1683 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1686 "6.6.6.6/32 via 10.10.10.1");
1688 fib_table_entry_path_add(fib_index,
1691 FIB_ENTRY_FLAG_NONE,
1694 tm->hw[0]->sw_if_index,
1695 ~0, // invalid fib index
1698 FIB_ROUTE_PATH_FLAG_NONE);
1700 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1701 FIB_TEST(fib_test_validate_entry(fei,
1702 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1768 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1770 fib_table_entry_path_add(fib_index,
1773 FIB_ENTRY_FLAG_NONE,
1776 tm->hw[1]->sw_if_index,
1777 ~0, // invalid fib index
1780 FIB_ROUTE_PATH_FLAG_NONE);
1782 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1783 FIB_TEST(fib_test_validate_entry(fei,
1784 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1851 &ip_6_6_6_6_o_12_12_12_12,
1852 &ip_6_6_6_6_o_12_12_12_12,
1853 &ip_6_6_6_6_o_12_12_12_12,
1854 &ip_6_6_6_6_o_12_12_12_12,
1855 &ip_6_6_6_6_o_12_12_12_12,
1856 &ip_6_6_6_6_o_12_12_12_12,
1857 &ip_6_6_6_6_o_12_12_12_12,
1858 &ip_6_6_6_6_o_12_12_12_12,
1859 &ip_6_6_6_6_o_12_12_12_12,
1860 &ip_6_6_6_6_o_12_12_12_12,
1861 &ip_6_6_6_6_o_12_12_12_12,
1862 &ip_6_6_6_6_o_12_12_12_12,
1863 &ip_6_6_6_6_o_12_12_12_12,
1864 &ip_6_6_6_6_o_12_12_12_12,
1865 &ip_6_6_6_6_o_12_12_12_12,
1866 &ip_6_6_6_6_o_12_12_12_12,
1867 &ip_6_6_6_6_o_12_12_12_12,
1868 &ip_6_6_6_6_o_12_12_12_12,
1869 &ip_6_6_6_6_o_12_12_12_12,
1870 &ip_6_6_6_6_o_12_12_12_12,
1871 &ip_6_6_6_6_o_12_12_12_12,
1872 &ip_6_6_6_6_o_12_12_12_12,
1873 &ip_6_6_6_6_o_12_12_12_12,
1874 &ip_6_6_6_6_o_12_12_12_12,
1875 &ip_6_6_6_6_o_12_12_12_12,
1876 &ip_6_6_6_6_o_12_12_12_12,
1877 &ip_6_6_6_6_o_12_12_12_12,
1878 &ip_6_6_6_6_o_12_12_12_12,
1879 &ip_6_6_6_6_o_12_12_12_12,
1880 &ip_6_6_6_6_o_12_12_12_12,
1881 &ip_6_6_6_6_o_12_12_12_12,
1882 &ip_6_6_6_6_o_12_12_12_12,
1883 &ip_6_6_6_6_o_12_12_12_12,
1884 &ip_6_6_6_6_o_12_12_12_12,
1885 &ip_6_6_6_6_o_12_12_12_12,
1886 &ip_6_6_6_6_o_12_12_12_12,
1887 &ip_6_6_6_6_o_12_12_12_12,
1888 &ip_6_6_6_6_o_12_12_12_12,
1889 &ip_6_6_6_6_o_12_12_12_12,
1890 &ip_6_6_6_6_o_12_12_12_12,
1891 &ip_6_6_6_6_o_12_12_12_12,
1892 &ip_6_6_6_6_o_12_12_12_12,
1893 &ip_6_6_6_6_o_12_12_12_12,
1894 &ip_6_6_6_6_o_12_12_12_12,
1895 &ip_6_6_6_6_o_12_12_12_12,
1896 &ip_6_6_6_6_o_12_12_12_12,
1897 &ip_6_6_6_6_o_12_12_12_12,
1898 &ip_6_6_6_6_o_12_12_12_12,
1899 &ip_6_6_6_6_o_12_12_12_12,
1900 &ip_6_6_6_6_o_12_12_12_12,
1901 &ip_6_6_6_6_o_12_12_12_12,
1902 &ip_6_6_6_6_o_12_12_12_12,
1903 &ip_6_6_6_6_o_12_12_12_12,
1904 &ip_6_6_6_6_o_12_12_12_12,
1905 &ip_6_6_6_6_o_12_12_12_12,
1906 &ip_6_6_6_6_o_12_12_12_12,
1907 &ip_6_6_6_6_o_12_12_12_12,
1908 &ip_6_6_6_6_o_12_12_12_12,
1909 &ip_6_6_6_6_o_12_12_12_12,
1910 &ip_6_6_6_6_o_12_12_12_12,
1911 &ip_6_6_6_6_o_12_12_12_12,
1912 &ip_6_6_6_6_o_12_12_12_12,
1913 &ip_6_6_6_6_o_12_12_12_12),
1914 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1916 fib_table_entry_path_remove(fib_index,
1921 tm->hw[1]->sw_if_index,
1922 ~0, // invalid fib index
1924 FIB_ROUTE_PATH_FLAG_NONE);
1926 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1927 FIB_TEST(fib_test_validate_entry(fei,
1928 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1994 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1996 fib_table_entry_path_remove(fib_index,
2001 tm->hw[0]->sw_if_index,
2002 ~0, // invalid fib index
2004 FIB_ROUTE_PATH_FLAG_NONE);
2006 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2007 FIB_TEST(fib_test_validate_entry(fei,
2008 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2011 "6.6.6.6/32 via 10.10.10.1");
2013 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
2016 * A recursive via the two unequal cost entries
2018 fib_prefix_t bgp_44_s_32 = {
2020 .fp_proto = FIB_PROTOCOL_IP4,
2022 /* 200.200.200.201/32 */
2023 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2026 fei = fib_table_entry_path_add(fib_index,
2029 FIB_ENTRY_FLAG_NONE,
2031 &pfx_1_2_3_4_s_32.fp_addr,
2036 FIB_ROUTE_PATH_FLAG_NONE);
2037 fei = fib_table_entry_path_add(fib_index,
2040 FIB_ENTRY_FLAG_NONE,
2042 &pfx_1_2_3_5_s_32.fp_addr,
2047 FIB_ROUTE_PATH_FLAG_NONE);
2049 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2050 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2051 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2052 tm->hw[0]->sw_if_index,
2053 tm->hw[1]->sw_if_index),
2054 "RPF list for 1.2.3.4/32 contains both adjs");
2057 * test the uRPF check functions
2059 dpo_id_t dpo_44 = DPO_INVALID;
2062 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2063 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2065 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2066 "uRPF check for 68.68.68.68/32 on %d OK",
2067 tm->hw[0]->sw_if_index);
2068 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2069 "uRPF check for 68.68.68.68/32 on %d OK",
2070 tm->hw[1]->sw_if_index);
2071 FIB_TEST(!fib_urpf_check(urpfi, 99),
2072 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2076 fib_table_entry_delete(fib_index,
2079 fib_table_entry_delete(fib_index,
2082 fib_table_entry_delete(fib_index,
2087 * Add a recursive route:
2088 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2090 fib_prefix_t bgp_201_pfx = {
2092 .fp_proto = FIB_PROTOCOL_IP4,
2094 /* 200.200.200.201/32 */
2095 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2099 fib_prefix_t pfx_1_1_1_200_s_32 = {
2101 .fp_proto = FIB_PROTOCOL_IP4,
2103 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2107 fei = fib_table_entry_path_add(fib_index,
2110 FIB_ENTRY_FLAG_NONE,
2112 &pfx_1_1_1_200_s_32.fp_addr,
2113 ~0, // no index provided.
2114 fib_index, // nexthop in same fib as route
2117 FIB_ROUTE_PATH_FLAG_NONE);
2119 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2120 "Recursive via unresolved is drop");
2122 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2123 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2124 "Flags set on RR via non-attached");
2125 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2126 "RPF list for BGP route empty");
2129 * +2 entry (BGP & RR) and +1 shared-path-list
2131 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2132 fib_path_list_db_size());
2133 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2134 fib_path_list_pool_size());
2135 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2136 fib_entry_pool_size());
2139 * insert a route that covers the missing 1.1.1.2/32. we epxect
2140 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2142 fib_prefix_t pfx_1_1_1_0_s_24 = {
2144 .fp_proto = FIB_PROTOCOL_IP4,
2147 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2151 fib_table_entry_path_add(fib_index,
2154 FIB_ENTRY_FLAG_NONE,
2157 tm->hw[0]->sw_if_index,
2158 ~0, // invalid fib index
2161 FIB_ROUTE_PATH_FLAG_NONE);
2162 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2163 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2164 ai = fib_entry_get_adj(fei);
2165 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2166 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2167 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2168 ai = fib_entry_get_adj(fei);
2169 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2170 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2171 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2172 ai = fib_entry_get_adj(fei);
2173 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2176 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2178 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2179 fib_path_list_db_size());
2180 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2181 fib_path_list_pool_size());
2182 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2183 fib_entry_pool_size());
2186 * the recursive adj for 200.200.200.200 should be updated.
2188 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2189 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2190 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2191 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2192 tm->hw[0]->sw_if_index),
2193 "RPF list for BGP route has itf index 0");
2196 * insert a more specific route than 1.1.1.0/24 that also covers the
2197 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2198 * 200.200.200.200 to resolve through it.
2200 fib_prefix_t pfx_1_1_1_0_s_28 = {
2202 .fp_proto = FIB_PROTOCOL_IP4,
2205 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2209 fib_table_entry_path_add(fib_index,
2212 FIB_ENTRY_FLAG_NONE,
2215 tm->hw[0]->sw_if_index,
2216 ~0, // invalid fib index
2219 FIB_ROUTE_PATH_FLAG_NONE);
2220 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2221 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2222 ai = fib_entry_get_adj(fei);
2223 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2226 * +1 entry. +1 shared path-list
2228 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2229 fib_path_list_db_size());
2230 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2231 fib_path_list_pool_size());
2232 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2233 fib_entry_pool_size());
2236 * the recursive adj for 200.200.200.200 should be updated.
2237 * 200.200.200.201 remains unchanged.
2239 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2240 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2243 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2245 fib_table_entry_path_remove(fib_index,
2250 tm->hw[0]->sw_if_index,
2253 FIB_ROUTE_PATH_FLAG_NONE);
2254 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2255 FIB_NODE_INDEX_INVALID),
2256 "1.1.1.0/28 removed");
2257 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2258 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2259 "1.1.1.0/28 lookup via /24");
2260 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2261 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2264 * -1 entry. -1 shared path-list
2266 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2267 fib_path_list_db_size());
2268 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2269 fib_path_list_pool_size());
2270 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2271 fib_entry_pool_size());
2274 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2276 fib_table_entry_path_remove(fib_index,
2281 tm->hw[0]->sw_if_index,
2284 FIB_ROUTE_PATH_FLAG_NONE);
2285 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2286 FIB_NODE_INDEX_INVALID),
2287 "1.1.1.0/24 removed");
2289 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2290 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2291 "1.1.1.2/32 route is DROP");
2292 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2293 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2294 "1.1.1.200/32 route is DROP");
2296 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2297 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2299 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2300 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2306 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2307 fib_path_list_db_size());
2308 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2309 fib_path_list_pool_size());
2310 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2311 fib_entry_pool_size());
2314 * insert the missing 1.1.1.2/32
2316 fei = fib_table_entry_path_add(fib_index,
2319 FIB_ENTRY_FLAG_NONE,
2322 tm->hw[0]->sw_if_index,
2323 ~0, // invalid fib index
2326 FIB_ROUTE_PATH_FLAG_NONE);
2327 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2328 ai = fib_entry_get_adj(fei);
2329 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2331 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2332 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2334 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2337 * no change. 1.1.1.2/32 was already there RR sourced.
2339 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2340 fib_path_list_db_size());
2341 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2342 fib_path_list_pool_size());
2343 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2344 fib_entry_pool_size());
2347 * give 201 a resolved path.
2348 * it now has the unresolved 1.1.1.200 and the resolved 1.1.1.2,
2349 * only the latter contributes forwarding.
2351 fei = fib_table_entry_path_add(fib_index,
2354 FIB_ENTRY_FLAG_NONE,
2356 &pfx_1_1_1_2_s_32.fp_addr,
2361 FIB_ROUTE_PATH_FLAG_NONE);
2362 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_2_s_32, 0);
2363 fib_table_entry_path_remove(fib_index,
2367 &pfx_1_1_1_2_s_32.fp_addr,
2371 FIB_ROUTE_PATH_FLAG_NONE);
2374 * remove 200.200.200.201/32 which does not have a valid via FIB
2376 fib_table_entry_path_remove(fib_index,
2380 &pfx_1_1_1_200_s_32.fp_addr,
2381 ~0, // no index provided.
2384 FIB_ROUTE_PATH_FLAG_NONE);
2387 * -2 entries (BGP and RR). -1 shared path-list;
2389 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2390 FIB_NODE_INDEX_INVALID),
2391 "200.200.200.201/32 removed");
2392 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2393 FIB_NODE_INDEX_INVALID),
2394 "1.1.1.200/32 removed");
2396 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2397 fib_path_list_db_size());
2398 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2399 fib_path_list_pool_size());
2400 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2401 fib_entry_pool_size());
2404 * remove 200.200.200.200/32 which does have a valid via FIB
2406 fib_table_entry_path_remove(fib_index,
2410 &pfx_1_1_1_2_s_32.fp_addr,
2411 ~0, // no index provided.
2414 FIB_ROUTE_PATH_FLAG_NONE);
2416 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2417 FIB_NODE_INDEX_INVALID),
2418 "200.200.200.200/32 removed");
2419 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2420 FIB_NODE_INDEX_INVALID),
2421 "1.1.1.2/32 still present");
2424 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2426 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2427 fib_path_list_db_size());
2428 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2429 fib_path_list_pool_size());
2430 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2431 fib_entry_pool_size());
2434 * A recursive prefix that has a 2 path load-balance.
2435 * It also shares a next-hop with other BGP prefixes and hence
2436 * test the ref counting of RR sourced prefixes and 2 level LB.
2438 const fib_prefix_t bgp_102 = {
2440 .fp_proto = FIB_PROTOCOL_IP4,
2442 /* 100.100.100.101/32 */
2443 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2446 fib_table_entry_path_add(fib_index,
2449 FIB_ENTRY_FLAG_NONE,
2451 &pfx_1_1_1_1_s_32.fp_addr,
2452 ~0, // no index provided.
2453 fib_index, // same as route
2456 FIB_ROUTE_PATH_FLAG_NONE);
2457 fib_table_entry_path_add(fib_index,
2460 FIB_ENTRY_FLAG_NONE,
2462 &pfx_1_1_1_2_s_32.fp_addr,
2463 ~0, // no index provided.
2464 fib_index, // same as route's FIB
2467 FIB_ROUTE_PATH_FLAG_NONE);
2468 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2469 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2470 dpo = fib_entry_contribute_ip_forwarding(fei);
2472 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2473 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2474 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2475 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2477 lb = load_balance_get(dpo->dpoi_index);
2478 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2479 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2480 "First via 10.10.10.1");
2481 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2482 "Second via 10.10.10.1");
2484 fib_table_entry_path_remove(fib_index,
2488 &pfx_1_1_1_1_s_32.fp_addr,
2489 ~0, // no index provided.
2490 fib_index, // same as route's FIB
2492 FIB_ROUTE_PATH_FLAG_NONE);
2493 fib_table_entry_path_remove(fib_index,
2497 &pfx_1_1_1_2_s_32.fp_addr,
2498 ~0, // no index provided.
2499 fib_index, // same as route's FIB
2501 FIB_ROUTE_PATH_FLAG_NONE);
2502 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2503 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2506 * remove the remaining recursives
2508 fib_table_entry_path_remove(fib_index,
2512 &pfx_1_1_1_1_s_32.fp_addr,
2513 ~0, // no index provided.
2514 fib_index, // same as route's FIB
2516 FIB_ROUTE_PATH_FLAG_NONE);
2517 fib_table_entry_path_remove(fib_index,
2521 &pfx_1_1_1_1_s_32.fp_addr,
2522 ~0, // no index provided.
2523 fib_index, // same as route's FIB
2525 FIB_ROUTE_PATH_FLAG_NONE);
2526 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2527 FIB_NODE_INDEX_INVALID),
2528 "100.100.100.100/32 removed");
2529 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2530 FIB_NODE_INDEX_INVALID),
2531 "100.100.100.101/32 removed");
2534 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2536 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2537 fib_path_list_db_size());
2538 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2539 fib_path_list_pool_size());
2540 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2541 fib_entry_pool_size());
2544 * Add a recursive route via a connected cover, using an adj-fib that does exist
2546 fib_table_entry_path_add(fib_index,
2549 FIB_ENTRY_FLAG_NONE,
2552 ~0, // no index provided.
2553 fib_index, // Same as route's FIB
2556 FIB_ROUTE_PATH_FLAG_NONE);
2559 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2561 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2562 fib_path_list_db_size());
2563 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2564 fib_path_list_pool_size());
2565 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2566 fib_entry_pool_size());
2568 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2569 dpo = fib_entry_contribute_ip_forwarding(fei);
2571 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2572 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2574 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2575 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2577 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2578 "Flags set on RR via existing attached");
2581 * Add a recursive route via a connected cover, using and adj-fib that does
2584 ip46_address_t nh_10_10_10_3 = {
2585 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2587 fib_prefix_t pfx_10_10_10_3 = {
2589 .fp_proto = FIB_PROTOCOL_IP4,
2590 .fp_addr = nh_10_10_10_3,
2593 fib_table_entry_path_add(fib_index,
2596 FIB_ENTRY_FLAG_NONE,
2599 ~0, // no index provided.
2603 FIB_ROUTE_PATH_FLAG_NONE);
2606 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2607 * one unshared non-recursive via 10.10.10.3
2609 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2610 fib_path_list_db_size());
2611 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2612 fib_path_list_pool_size());
2613 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2614 fib_entry_pool_size());
2616 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2619 tm->hw[0]->sw_if_index);
2621 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2622 dpo = fib_entry_contribute_ip_forwarding(fei);
2623 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2624 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2626 ai = fib_entry_get_adj(fei);
2627 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2628 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2629 fib_entry_get_flags(fei)),
2630 "Flags set on RR via non-existing attached");
2632 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2633 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2638 * remove the recursives
2640 fib_table_entry_path_remove(fib_index,
2645 ~0, // no index provided.
2646 fib_index, // same as route's FIB
2648 FIB_ROUTE_PATH_FLAG_NONE);
2649 fib_table_entry_path_remove(fib_index,
2654 ~0, // no index provided.
2655 fib_index, // same as route's FIB
2657 FIB_ROUTE_PATH_FLAG_NONE);
2659 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2660 FIB_NODE_INDEX_INVALID),
2661 "200.200.200.201/32 removed");
2662 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2663 FIB_NODE_INDEX_INVALID),
2664 "200.200.200.200/32 removed");
2665 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2666 FIB_NODE_INDEX_INVALID),
2667 "10.10.10.3/32 removed");
2670 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2671 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2673 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2674 fib_path_list_db_size());
2675 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2676 fib_path_list_pool_size());
2677 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2678 fib_entry_pool_size());
2683 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2685 fib_prefix_t pfx_5_5_5_5_s_32 = {
2687 .fp_proto = FIB_PROTOCOL_IP4,
2689 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2692 fib_prefix_t pfx_5_5_5_6_s_32 = {
2694 .fp_proto = FIB_PROTOCOL_IP4,
2696 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2699 fib_prefix_t pfx_5_5_5_7_s_32 = {
2701 .fp_proto = FIB_PROTOCOL_IP4,
2703 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2707 fib_table_entry_path_add(fib_index,
2710 FIB_ENTRY_FLAG_NONE,
2712 &pfx_5_5_5_6_s_32.fp_addr,
2713 ~0, // no index provided.
2717 FIB_ROUTE_PATH_FLAG_NONE);
2718 fib_table_entry_path_add(fib_index,
2721 FIB_ENTRY_FLAG_NONE,
2723 &pfx_5_5_5_7_s_32.fp_addr,
2724 ~0, // no index provided.
2728 FIB_ROUTE_PATH_FLAG_NONE);
2729 fib_table_entry_path_add(fib_index,
2732 FIB_ENTRY_FLAG_NONE,
2734 &pfx_5_5_5_5_s_32.fp_addr,
2735 ~0, // no index provided.
2739 FIB_ROUTE_PATH_FLAG_NONE);
2741 * +3 entries, +3 shared path-list
2743 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2744 fib_path_list_db_size());
2745 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2746 fib_path_list_pool_size());
2747 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2748 fib_entry_pool_size());
2751 * All the entries have only looped paths, so they are all drop
2753 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2754 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2755 "LB for 5.5.5.7/32 is via adj for DROP");
2756 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2757 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2758 "LB for 5.5.5.5/32 is via adj for DROP");
2759 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2760 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2761 "LB for 5.5.5.6/32 is via adj for DROP");
2764 * provide 5.5.5.6/32 with alternate path.
2765 * this will allow only 5.5.5.6/32 to forward with this path, the others
2766 * are still drop since the loop is still present.
2768 fib_table_entry_path_add(fib_index,
2771 FIB_ENTRY_FLAG_NONE,
2774 tm->hw[0]->sw_if_index,
2778 FIB_ROUTE_PATH_FLAG_NONE);
2780 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2781 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2783 lb = load_balance_get(dpo1->dpoi_index);
2784 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2786 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2787 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2788 FIB_TEST((ai_01 == dpo2->dpoi_index),
2789 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2791 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2792 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2793 "LB for 5.5.5.7/32 is via adj for DROP");
2794 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2795 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2796 "LB for 5.5.5.5/32 is via adj for DROP");
2799 * remove the alternate path for 5.5.5.6/32
2802 fib_table_entry_path_remove(fib_index,
2807 tm->hw[0]->sw_if_index,
2810 FIB_ROUTE_PATH_FLAG_NONE);
2812 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2813 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2814 "LB for 5.5.5.7/32 is via adj for DROP");
2815 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2816 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2817 "LB for 5.5.5.5/32 is via adj for DROP");
2818 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2819 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2820 "LB for 5.5.5.6/32 is via adj for DROP");
2823 * break the loop by giving 5.5.5.5/32 a new set of paths
2824 * expect all to forward via this new path.
2826 fib_table_entry_update_one_path(fib_index,
2829 FIB_ENTRY_FLAG_NONE,
2832 tm->hw[0]->sw_if_index,
2833 ~0, // invalid fib index
2836 FIB_ROUTE_PATH_FLAG_NONE);
2838 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2839 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2840 lb = load_balance_get(dpo1->dpoi_index);
2841 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2843 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2844 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2845 FIB_TEST((ai_01 == dpo2->dpoi_index),
2846 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2848 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2849 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2851 lb = load_balance_get(dpo2->dpoi_index);
2852 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2853 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2854 "5.5.5.5.7 via 5.5.5.5");
2856 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2857 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2859 lb = load_balance_get(dpo1->dpoi_index);
2860 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2861 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2862 "5.5.5.5.6 via 5.5.5.7");
2865 * revert back to the loop. so we can remove the prefixes with
2868 fib_table_entry_update_one_path(fib_index,
2871 FIB_ENTRY_FLAG_NONE,
2873 &pfx_5_5_5_6_s_32.fp_addr,
2874 ~0, // no index provided.
2878 FIB_ROUTE_PATH_FLAG_NONE);
2880 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2881 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2882 "LB for 5.5.5.7/32 is via adj for DROP");
2883 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2884 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2885 "LB for 5.5.5.5/32 is via adj for DROP");
2886 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2887 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2888 "LB for 5.5.5.6/32 is via adj for DROP");
2891 * remove all the 5.5.5.x/32 prefixes
2893 fib_table_entry_path_remove(fib_index,
2897 &pfx_5_5_5_6_s_32.fp_addr,
2898 ~0, // no index provided.
2899 fib_index, // same as route's FIB
2901 FIB_ROUTE_PATH_FLAG_NONE);
2902 fib_table_entry_path_remove(fib_index,
2906 &pfx_5_5_5_7_s_32.fp_addr,
2907 ~0, // no index provided.
2908 fib_index, // same as route's FIB
2910 FIB_ROUTE_PATH_FLAG_NONE);
2911 fib_table_entry_path_remove(fib_index,
2915 &pfx_5_5_5_5_s_32.fp_addr,
2916 ~0, // no index provided.
2917 fib_index, // same as route's FIB
2919 FIB_ROUTE_PATH_FLAG_NONE);
2920 fib_table_entry_path_remove(fib_index,
2925 ~0, // no index provided.
2926 fib_index, // same as route's FIB
2928 FIB_ROUTE_PATH_FLAG_NONE);
2931 * -3 entries, -3 shared path-list
2933 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2934 fib_path_list_db_size());
2935 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2936 fib_path_list_pool_size());
2937 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2938 fib_entry_pool_size());
2941 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2943 fib_table_entry_path_add(fib_index,
2946 FIB_ENTRY_FLAG_NONE,
2948 &pfx_5_5_5_6_s_32.fp_addr,
2949 ~0, // no index provided.
2953 FIB_ROUTE_PATH_FLAG_NONE);
2954 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2955 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2956 "1-level 5.5.5.6/32 loop is via adj for DROP");
2958 fib_table_entry_path_remove(fib_index,
2962 &pfx_5_5_5_6_s_32.fp_addr,
2963 ~0, // no index provided.
2964 fib_index, // same as route's FIB
2966 FIB_ROUTE_PATH_FLAG_NONE);
2967 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2968 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2969 "1-level 5.5.5.6/32 loop is removed");
2972 * A recursive route whose next-hop is covered by the prefix.
2973 * This would mean the via-fib, which inherits forwarding from its
2974 * cover, thus picks up forwarding from the prfix, which is via the
2975 * via-fib, and we have a loop.
2977 fib_prefix_t pfx_23_23_23_0_s_24 = {
2979 .fp_proto = FIB_PROTOCOL_IP4,
2981 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2984 fib_prefix_t pfx_23_23_23_23_s_32 = {
2986 .fp_proto = FIB_PROTOCOL_IP4,
2988 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2991 fei = fib_table_entry_path_add(fib_index,
2992 &pfx_23_23_23_0_s_24,
2994 FIB_ENTRY_FLAG_NONE,
2996 &pfx_23_23_23_23_s_32.fp_addr,
3001 FIB_ROUTE_PATH_FLAG_NONE);
3002 dpo = fib_entry_contribute_ip_forwarding(fei);
3003 FIB_TEST(load_balance_is_drop(dpo),
3004 "23.23.23.0/24 via covered is DROP");
3005 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3008 * add-remove test. no change.
3010 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3011 fib_path_list_db_size());
3012 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3013 fib_path_list_pool_size());
3014 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3015 fib_entry_pool_size());
3018 * Make the default route recursive via a unknown next-hop. Thus the
3019 * next hop's cover would be the default route
3021 fei = fib_table_entry_path_add(fib_index,
3024 FIB_ENTRY_FLAG_NONE,
3026 &pfx_23_23_23_23_s_32.fp_addr,
3031 FIB_ROUTE_PATH_FLAG_NONE);
3032 dpo = fib_entry_contribute_ip_forwarding(fei);
3033 FIB_TEST(load_balance_is_drop(dpo),
3034 "0.0.0.0.0/0 via is DROP");
3035 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3036 "no resolving interface for looped 0.0.0.0/0");
3038 fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
3039 dpo = fib_entry_contribute_ip_forwarding(fei);
3040 FIB_TEST(load_balance_is_drop(dpo),
3041 "23.23.23.23/32 via is DROP");
3042 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3043 "no resolving interface for looped 23.23.23.23/32");
3045 fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
3048 * A recursive route with recursion constraints.
3049 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
3051 fib_table_entry_path_add(fib_index,
3054 FIB_ENTRY_FLAG_NONE,
3061 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3063 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3064 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3066 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3067 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3069 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3070 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3073 * save the load-balance. we expect it to be inplace modified
3075 lb = load_balance_get(dpo1->dpoi_index);
3078 * add a covering prefix for the via fib that would otherwise serve
3079 * as the resolving route when the host is removed
3081 fib_table_entry_path_add(fib_index,
3084 FIB_ENTRY_FLAG_NONE,
3087 tm->hw[0]->sw_if_index,
3088 ~0, // invalid fib index
3091 FIB_ROUTE_PATH_FLAG_NONE);
3092 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3093 ai = fib_entry_get_adj(fei);
3094 FIB_TEST((ai == ai_01),
3095 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3098 * remove the host via FIB - expect the BGP prefix to be drop
3100 fib_table_entry_path_remove(fib_index,
3105 tm->hw[0]->sw_if_index,
3106 ~0, // invalid fib index
3108 FIB_ROUTE_PATH_FLAG_NONE);
3110 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3111 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3114 * add the via-entry host reoute back. expect to resolve again
3116 fib_table_entry_path_add(fib_index,
3119 FIB_ENTRY_FLAG_NONE,
3122 tm->hw[0]->sw_if_index,
3123 ~0, // invalid fib index
3126 FIB_ROUTE_PATH_FLAG_NONE);
3127 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3128 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3131 * add another path for the recursive. it will then have 2.
3133 fib_prefix_t pfx_1_1_1_3_s_32 = {
3135 .fp_proto = FIB_PROTOCOL_IP4,
3137 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3140 fib_table_entry_path_add(fib_index,
3143 FIB_ENTRY_FLAG_NONE,
3146 tm->hw[0]->sw_if_index,
3147 ~0, // invalid fib index
3150 FIB_ROUTE_PATH_FLAG_NONE);
3152 fib_table_entry_path_add(fib_index,
3155 FIB_ENTRY_FLAG_NONE,
3157 &pfx_1_1_1_3_s_32.fp_addr,
3162 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3165 * add a bunch load more entries using this path combo so that we get
3166 * an LB-map created.
3169 fib_prefix_t bgp_78s[N_P];
3170 for (ii = 0; ii < N_P; ii++)
3172 bgp_78s[ii].fp_len = 32;
3173 bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3174 bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3177 fib_table_entry_path_add(fib_index,
3180 FIB_ENTRY_FLAG_NONE,
3182 &pfx_1_1_1_3_s_32.fp_addr,
3187 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3188 fib_table_entry_path_add(fib_index,
3191 FIB_ENTRY_FLAG_NONE,
3198 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3201 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3202 dpo = fib_entry_contribute_ip_forwarding(fei);
3204 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3205 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3206 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3207 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3208 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3209 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3210 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3211 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3214 * expect the lb-map used by the recursive's load-balance is using both buckets
3216 load_balance_map_t *lbm;
3219 lb = load_balance_get(dpo->dpoi_index);
3221 load_balance_map_lock(lbmi);
3222 lbm = load_balance_map_get(lbmi);
3224 FIB_TEST(lbm->lbm_buckets[0] == 0,
3225 "LB maps's bucket 0 is %d",
3226 lbm->lbm_buckets[0]);
3227 FIB_TEST(lbm->lbm_buckets[1] == 1,
3228 "LB maps's bucket 1 is %d",
3229 lbm->lbm_buckets[1]);
3232 * withdraw one of the /32 via-entrys.
3233 * that ECMP path will be unresolved and forwarding should continue on the
3234 * other available path. this is an iBGP PIC edge failover.
3235 * Test the forwarding changes without re-fetching the adj from the
3236 * recursive entry. this ensures its the same one that is updated; i.e. an
3239 fib_table_entry_path_remove(fib_index,
3244 tm->hw[0]->sw_if_index,
3245 ~0, // invalid fib index
3247 FIB_ROUTE_PATH_FLAG_NONE);
3249 /* suspend so the update walk kicks int */
3250 vlib_process_suspend(vlib_get_main(), 1e-5);
3252 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3253 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3254 "post PIC 200.200.200.200/32 was inplace modified");
3256 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3257 "post PIC adj for 200.200.200.200/32 is recursive"
3258 " via adj for 1.1.1.3");
3261 * the LB maps that was locked above should have been modified to remove
3262 * the path that was down, and thus its bucket points to a path that is
3265 FIB_TEST(lbm->lbm_buckets[0] == 1,
3266 "LB maps's bucket 0 is %d",
3267 lbm->lbm_buckets[0]);
3268 FIB_TEST(lbm->lbm_buckets[1] == 1,
3269 "LB maps's bucket 1 is %d",
3270 lbm->lbm_buckets[1]);
3272 load_balance_map_unlock(lbmi);
3275 * add it back. again
3277 fib_table_entry_path_add(fib_index,
3280 FIB_ENTRY_FLAG_NONE,
3283 tm->hw[0]->sw_if_index,
3284 ~0, // invalid fib index
3287 FIB_ROUTE_PATH_FLAG_NONE);
3289 /* suspend so the update walk kicks in */
3290 vlib_process_suspend(vlib_get_main(), 1e-5);
3292 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3293 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3294 "via adj for 1.1.1.1");
3295 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3296 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3297 "via adj for 1.1.1.3");
3299 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3300 dpo = fib_entry_contribute_ip_forwarding(fei);
3301 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3302 "post PIC 200.200.200.200/32 was inplace modified");
3305 * add a 3rd path. this makes the LB 16 buckets.
3307 fib_table_entry_path_add(fib_index,
3310 FIB_ENTRY_FLAG_NONE,
3312 &pfx_1_1_1_2_s_32.fp_addr,
3317 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3318 for (ii = 0; ii < N_P; ii++)
3320 fib_table_entry_path_add(fib_index,
3323 FIB_ENTRY_FLAG_NONE,
3325 &pfx_1_1_1_2_s_32.fp_addr,
3330 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3333 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3334 dpo = fib_entry_contribute_ip_forwarding(fei);
3335 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3336 "200.200.200.200/32 was inplace modified for 3rd path");
3337 FIB_TEST(16 == lb->lb_n_buckets,
3338 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3341 load_balance_map_lock(lbmi);
3342 lbm = load_balance_map_get(lbmi);
3344 for (ii = 0; ii < 16; ii++)
3346 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3347 "LB Map for 200.200.200.200/32 at %d is %d",
3348 ii, lbm->lbm_buckets[ii]);
3352 * trigger PIC by removing the first via-entry
3353 * the first 6 buckets of the map should map to the next 6
3355 fib_table_entry_path_remove(fib_index,
3360 tm->hw[0]->sw_if_index,
3363 FIB_ROUTE_PATH_FLAG_NONE);
3364 /* suspend so the update walk kicks int */
3365 vlib_process_suspend(vlib_get_main(), 1e-5);
3367 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3368 dpo = fib_entry_contribute_ip_forwarding(fei);
3369 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3370 "200.200.200.200/32 was inplace modified for 3rd path");
3371 FIB_TEST(2 == lb->lb_n_buckets,
3372 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3374 for (ii = 0; ii < 6; ii++)
3376 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3377 "LB Map for 200.200.200.200/32 at %d is %d",
3378 ii, lbm->lbm_buckets[ii]);
3380 for (ii = 6; ii < 16; ii++)
3382 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3383 "LB Map for 200.200.200.200/32 at %d is %d",
3384 ii, lbm->lbm_buckets[ii]);
3386 load_balance_map_unlock(lbmi);
3391 fib_table_entry_path_add(fib_index,
3394 FIB_ENTRY_FLAG_NONE,
3397 tm->hw[0]->sw_if_index,
3401 FIB_ROUTE_PATH_FLAG_NONE);
3403 for (ii = 0; ii < N_P; ii++)
3405 fib_table_entry_delete(fib_index,
3408 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3409 fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3411 format_fib_prefix, &bgp_78s[ii]);
3413 fib_table_entry_path_remove(fib_index,
3417 &pfx_1_1_1_2_s_32.fp_addr,
3421 MPLS_LABEL_INVALID);
3422 fib_table_entry_path_remove(fib_index,
3430 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3431 fib_table_entry_path_remove(fib_index,
3435 &pfx_1_1_1_3_s_32.fp_addr,
3439 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3440 fib_table_entry_delete(fib_index,
3443 fib_table_entry_delete(fib_index,
3446 /* suspend so the update walk kicks int */
3447 vlib_process_suspend(vlib_get_main(), 1e-5);
3448 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3449 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3450 "1.1.1.1/28 removed");
3451 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3452 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3453 "1.1.1.3/32 removed");
3454 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3455 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3456 "200.200.200.200/32 removed");
3459 * add-remove test. no change.
3461 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3462 fib_path_list_db_size());
3463 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3464 fib_path_list_pool_size());
3465 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3466 fib_entry_pool_size());
3469 * A route whose paths are built up iteratively and then removed
3472 fib_prefix_t pfx_4_4_4_4_s_32 = {
3474 .fp_proto = FIB_PROTOCOL_IP4,
3477 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3481 fib_table_entry_path_add(fib_index,
3484 FIB_ENTRY_FLAG_NONE,
3487 tm->hw[0]->sw_if_index,
3491 FIB_ROUTE_PATH_FLAG_NONE);
3492 fib_table_entry_path_add(fib_index,
3495 FIB_ENTRY_FLAG_NONE,
3498 tm->hw[0]->sw_if_index,
3502 FIB_ROUTE_PATH_FLAG_NONE);
3503 fib_table_entry_path_add(fib_index,
3506 FIB_ENTRY_FLAG_NONE,
3509 tm->hw[0]->sw_if_index,
3513 FIB_ROUTE_PATH_FLAG_NONE);
3514 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3515 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3516 "4.4.4.4/32 present");
3518 fib_table_entry_delete(fib_index,
3521 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3522 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3523 "4.4.4.4/32 removed");
3526 * add-remove test. no change.
3528 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3529 fib_path_list_db_size());
3530 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3531 fib_path_list_pool_size());
3532 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3533 fib_entry_pool_size());
3536 * A route with multiple paths at once
3538 fib_route_path_t *r_paths = NULL;
3540 for (ii = 0; ii < 4; ii++)
3542 fib_route_path_t r_path = {
3543 .frp_proto = DPO_PROTO_IP4,
3545 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3547 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3549 .frp_fib_index = ~0,
3551 vec_add1(r_paths, r_path);
3554 fib_table_entry_update(fib_index,
3557 FIB_ENTRY_FLAG_NONE,
3560 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3561 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3562 dpo = fib_entry_contribute_ip_forwarding(fei);
3564 lb = load_balance_get(dpo->dpoi_index);
3565 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3567 fib_table_entry_delete(fib_index,
3570 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3571 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3572 "4.4.4.4/32 removed");
3576 * add-remove test. no change.
3578 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3579 fib_path_list_db_size());
3580 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3581 fib_path_list_pool_size());
3582 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3583 fib_entry_pool_size());
3586 * A route deag route
3588 fib_table_entry_path_add(fib_index,
3591 FIB_ENTRY_FLAG_NONE,
3598 FIB_ROUTE_PATH_FLAG_NONE);
3600 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3601 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3603 dpo = fib_entry_contribute_ip_forwarding(fei);
3604 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3605 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3607 FIB_TEST((fib_index == lkd->lkd_fib_index),
3608 "4.4.4.4/32 is deag in %d %U",
3610 format_dpo_id, dpo, 0);
3611 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
3612 "4.4.4.4/32 is source deag in %d %U",
3614 format_dpo_id, dpo, 0);
3616 fib_table_entry_delete(fib_index,
3619 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3620 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3621 "4.4.4.4/32 removed");
3625 * A route deag route in a source lookup table
3627 fib_table_entry_path_add(fib_index,
3630 FIB_ENTRY_FLAG_NONE,
3637 FIB_ROUTE_PATH_SOURCE_LOOKUP);
3639 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3640 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3642 dpo = fib_entry_contribute_ip_forwarding(fei);
3643 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3644 lkd = lookup_dpo_get(dpo->dpoi_index);
3646 FIB_TEST((fib_index == lkd->lkd_fib_index),
3647 "4.4.4.4/32 is deag in %d %U",
3649 format_dpo_id, dpo, 0);
3650 FIB_TEST((LOOKUP_INPUT_SRC_ADDR == lkd->lkd_input),
3651 "4.4.4.4/32 is source deag in %d %U",
3653 format_dpo_id, dpo, 0);
3655 fib_table_entry_delete(fib_index,
3658 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3659 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3660 "4.4.4.4/32 removed");
3664 * add-remove test. no change.
3666 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3667 fib_path_list_db_size());
3668 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3669 fib_path_list_pool_size());
3670 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3671 fib_entry_pool_size());
3675 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3677 fib_prefix_t pfx_34_1_1_1_s_32 = {
3679 .fp_proto = FIB_PROTOCOL_IP4,
3681 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3684 fib_prefix_t pfx_34_34_1_1_s_32 = {
3686 .fp_proto = FIB_PROTOCOL_IP4,
3688 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3691 fei = fib_table_entry_path_add(fib_index,
3692 &pfx_34_34_1_1_s_32,
3694 FIB_ENTRY_FLAG_NONE,
3697 tm->hw[0]->sw_if_index,
3701 FIB_ROUTE_PATH_FLAG_NONE);
3702 fei = fib_table_entry_path_add(fib_index,
3705 FIB_ENTRY_FLAG_NONE,
3707 &pfx_34_34_1_1_s_32.fp_addr,
3712 FIB_ROUTE_PATH_FLAG_NONE);
3713 fei = fib_table_entry_path_add(fib_index,
3716 FIB_ENTRY_FLAG_NONE,
3718 &pfx_34_34_1_1_s_32.fp_addr,
3723 FIB_ROUTE_PATH_FLAG_NONE);
3724 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3725 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3726 fib_table_entry_delete(fib_index,
3727 &pfx_34_34_1_1_s_32,
3732 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3733 * all of which are via 10.10.10.1, Itf1
3735 fib_table_entry_path_remove(fib_index,
3740 tm->hw[0]->sw_if_index,
3743 FIB_ROUTE_PATH_FLAG_NONE);
3744 fib_table_entry_path_remove(fib_index,
3749 tm->hw[0]->sw_if_index,
3752 FIB_ROUTE_PATH_FLAG_NONE);
3753 fib_table_entry_path_remove(fib_index,
3758 tm->hw[0]->sw_if_index,
3761 FIB_ROUTE_PATH_FLAG_NONE);
3763 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3764 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3765 "1.1.1.1/32 removed");
3766 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3767 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3768 "1.1.1.2/32 removed");
3769 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3770 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3771 "1.1.2.0/24 removed");
3774 * -3 entries and -1 shared path-list
3776 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3777 fib_path_list_db_size());
3778 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3779 fib_path_list_pool_size());
3780 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3781 fib_entry_pool_size());
3784 * An attached-host route. Expect to link to the incomplete adj
3786 fib_prefix_t pfx_4_1_1_1_s_32 = {
3788 .fp_proto = FIB_PROTOCOL_IP4,
3791 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3794 fib_table_entry_path_add(fib_index,
3797 FIB_ENTRY_FLAG_NONE,
3800 tm->hw[0]->sw_if_index,
3804 FIB_ROUTE_PATH_FLAG_NONE);
3806 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3807 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3808 ai = fib_entry_get_adj(fei);
3810 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3812 &pfx_4_1_1_1_s_32.fp_addr,
3813 tm->hw[0]->sw_if_index);
3814 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3818 * +1 entry and +1 shared path-list
3820 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3821 fib_path_list_db_size());
3822 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3823 fib_path_list_pool_size());
3824 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3825 fib_entry_pool_size());
3827 fib_table_entry_delete(fib_index,
3831 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3832 fib_path_list_db_size());
3833 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3834 fib_path_list_pool_size());
3835 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3836 fib_entry_pool_size());
3839 * add a v6 prefix via v4 next-hops
3841 fib_prefix_t pfx_2001_s_64 = {
3843 .fp_proto = FIB_PROTOCOL_IP6,
3845 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3848 fei = fib_table_entry_path_add(0, //default v6 table
3851 FIB_ENTRY_FLAG_NONE,
3854 tm->hw[0]->sw_if_index,
3858 FIB_ROUTE_PATH_FLAG_NONE);
3860 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3861 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3862 ai = fib_entry_get_adj(fei);
3864 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3865 "2001::/64 via ARP-adj");
3866 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3867 "2001::/64 is link type v6");
3868 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3869 "2001::/64 ADJ-adj is NH proto v4");
3870 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3873 * add a uRPF exempt prefix:
3875 * - it's forwarding is drop
3876 * - it's uRPF list is not empty
3877 * - the uRPF list for the default route (it's cover) is empty
3879 fei = fib_table_entry_special_add(fib_index,
3881 FIB_SOURCE_URPF_EXEMPT,
3882 FIB_ENTRY_FLAG_DROP);
3883 dpo = fib_entry_contribute_ip_forwarding(fei);
3884 FIB_TEST(load_balance_is_drop(dpo),
3885 "uRPF exempt 4.1.1.1/32 DROP");
3886 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3887 "uRPF list for exempt prefix has itf index 0");
3888 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3889 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3890 "uRPF list for 0.0.0.0/0 empty");
3892 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3895 * An adj-fib that fails the refinement criteria - no connected cover
3897 fib_prefix_t pfx_12_10_10_2_s_32 = {
3899 .fp_proto = FIB_PROTOCOL_IP4,
3902 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3906 fib_table_entry_path_add(fib_index,
3907 &pfx_12_10_10_2_s_32,
3909 FIB_ENTRY_FLAG_ATTACHED,
3911 &pfx_12_10_10_2_s_32.fp_addr,
3912 tm->hw[0]->sw_if_index,
3913 ~0, // invalid fib index
3916 FIB_ROUTE_PATH_FLAG_NONE);
3918 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3919 dpo = fib_entry_contribute_ip_forwarding(fei);
3920 FIB_TEST(!dpo_id_is_valid(dpo),
3921 "no connected cover adj-fib fails refinement");
3923 fib_table_entry_delete(fib_index,
3924 &pfx_12_10_10_2_s_32,
3928 * An adj-fib that fails the refinement criteria - cover is connected
3929 * but on a different interface
3931 fib_prefix_t pfx_10_10_10_127_s_32 = {
3933 .fp_proto = FIB_PROTOCOL_IP4,
3936 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3940 fib_table_entry_path_add(fib_index,
3941 &pfx_10_10_10_127_s_32,
3943 FIB_ENTRY_FLAG_ATTACHED,
3945 &pfx_10_10_10_127_s_32.fp_addr,
3946 tm->hw[1]->sw_if_index,
3947 ~0, // invalid fib index
3950 FIB_ROUTE_PATH_FLAG_NONE);
3952 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3953 dpo = fib_entry_contribute_ip_forwarding(fei);
3954 FIB_TEST(!dpo_id_is_valid(dpo),
3955 "wrong interface adj-fib fails refinement");
3957 fib_table_entry_delete(fib_index,
3958 &pfx_10_10_10_127_s_32,
3962 * add a second path to an adj-fib
3963 * this is a sumiluation of another ARP entry created
3964 * on an interface on which the connected prefi does not exist.
3965 * The second path fails refinement. Expect to forward through the
3968 fib_prefix_t pfx_10_10_10_3_s_32 = {
3970 .fp_proto = FIB_PROTOCOL_IP4,
3973 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
3977 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3980 tm->hw[0]->sw_if_index);
3982 fib_test_lb_bucket_t ip_o_10_10_10_3 = {
3988 fei = fib_table_entry_path_add(fib_index,
3989 &pfx_10_10_10_3_s_32,
3991 FIB_ENTRY_FLAG_NONE,
3994 tm->hw[0]->sw_if_index,
3998 FIB_ROUTE_PATH_FLAG_NONE);
3999 fei = fib_table_entry_path_add(fib_index,
4000 &pfx_10_10_10_3_s_32,
4002 FIB_ENTRY_FLAG_NONE,
4005 tm->hw[1]->sw_if_index,
4009 FIB_ROUTE_PATH_FLAG_NONE);
4010 FIB_TEST(fib_test_validate_entry(fei,
4011 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4014 "10.10.10.3 via 10.10.10.3/Eth0 only");
4017 * remove the path that refines the cover, should go unresolved
4019 fib_table_entry_path_remove(fib_index,
4020 &pfx_10_10_10_3_s_32,
4024 tm->hw[0]->sw_if_index,
4027 FIB_ROUTE_PATH_FLAG_NONE);
4028 dpo = fib_entry_contribute_ip_forwarding(fei);
4029 FIB_TEST(!dpo_id_is_valid(dpo),
4030 "wrong interface adj-fib fails refinement");
4033 * add back the path that refines the cover
4035 fei = fib_table_entry_path_add(fib_index,
4036 &pfx_10_10_10_3_s_32,
4038 FIB_ENTRY_FLAG_NONE,
4041 tm->hw[0]->sw_if_index,
4045 FIB_ROUTE_PATH_FLAG_NONE);
4046 FIB_TEST(fib_test_validate_entry(fei,
4047 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4050 "10.10.10.3 via 10.10.10.3/Eth0 only");
4053 * remove the path that does not refine the cover
4055 fib_table_entry_path_remove(fib_index,
4056 &pfx_10_10_10_3_s_32,
4060 tm->hw[1]->sw_if_index,
4063 FIB_ROUTE_PATH_FLAG_NONE);
4064 FIB_TEST(fib_test_validate_entry(fei,
4065 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4068 "10.10.10.3 via 10.10.10.3/Eth0 only");
4071 * remove the path that does refine, it's the last path, so
4072 * the entry should be gone
4074 fib_table_entry_path_remove(fib_index,
4075 &pfx_10_10_10_3_s_32,
4079 tm->hw[0]->sw_if_index,
4082 FIB_ROUTE_PATH_FLAG_NONE);
4083 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4084 FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
4089 * change the table's flow-hash config - expect the update to propagete to
4090 * the entries' load-balance objects
4092 flow_hash_config_t old_hash_config, new_hash_config;
4094 old_hash_config = fib_table_get_flow_hash_config(fib_index,
4096 new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
4097 IP_FLOW_HASH_DST_ADDR);
4099 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4100 dpo = fib_entry_contribute_ip_forwarding(fei);
4101 lb = load_balance_get(dpo->dpoi_index);
4102 FIB_TEST((lb->lb_hash_config == old_hash_config),
4103 "Table and LB hash config match: %U",
4104 format_ip_flow_hash_config, lb->lb_hash_config);
4106 fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
4108 FIB_TEST((lb->lb_hash_config == new_hash_config),
4109 "Table and LB newhash config match: %U",
4110 format_ip_flow_hash_config, lb->lb_hash_config);
4113 * A route via an L2 Bridge
4115 fei = fib_table_entry_path_add(fib_index,
4116 &pfx_10_10_10_3_s_32,
4118 FIB_ENTRY_FLAG_NONE,
4121 tm->hw[0]->sw_if_index,
4125 FIB_ROUTE_PATH_FLAG_NONE);
4126 dpo_id_t l2_dpo = DPO_INVALID;
4127 l2_bridge_dpo_add_or_lock(tm->hw[0]->sw_if_index, &l2_dpo);
4128 fib_test_lb_bucket_t ip_o_l2 = {
4131 .adj = l2_dpo.dpoi_index,
4135 FIB_TEST(fib_test_validate_entry(fei,
4136 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4139 "10.10.10.3 via L2 on Eth0");
4140 fib_table_entry_path_remove(fib_index,
4141 &pfx_10_10_10_3_s_32,
4145 tm->hw[0]->sw_if_index,
4148 FIB_ROUTE_PATH_FLAG_NONE);
4155 fib_table_entry_delete(fib_index,
4156 &pfx_10_10_10_1_s_32,
4158 fib_table_entry_delete(fib_index,
4159 &pfx_10_10_10_2_s_32,
4161 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4162 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4163 "10.10.10.1/32 adj-fib removed");
4164 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4165 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4166 "10.10.10.2/32 adj-fib removed");
4169 * -2 entries and -2 non-shared path-list
4171 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4172 fib_path_list_db_size());
4173 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4174 fib_path_list_pool_size());
4175 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4176 fib_entry_pool_size());
4179 * unlock the adjacencies for which this test provided a rewrite.
4180 * These are the last locks on these adjs. they should thus go away.
4184 adj_unlock(ai_12_12_12_12);
4186 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4191 * remove the interface prefixes
4193 local_pfx.fp_len = 32;
4194 fib_table_entry_special_remove(fib_index, &local_pfx,
4195 FIB_SOURCE_INTERFACE);
4196 fei = fib_table_lookup(fib_index, &local_pfx);
4198 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4199 fib_table_lookup_exact_match(fib_index, &local_pfx),
4200 "10.10.10.10/32 adj-fib removed");
4202 local_pfx.fp_len = 24;
4203 fib_table_entry_delete(fib_index, &local_pfx,
4204 FIB_SOURCE_INTERFACE);
4206 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4207 fib_table_lookup_exact_match(fib_index, &local_pfx),
4208 "10.10.10.10/24 adj-fib removed");
4211 * -2 entries and -2 non-shared path-list
4213 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4214 fib_path_list_db_size());
4215 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4216 fib_path_list_pool_size());
4217 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4218 fib_entry_pool_size());
4221 * Last but not least, remove the VRF
4223 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4226 "NO API Source'd prefixes");
4227 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4230 "NO RR Source'd prefixes");
4231 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4233 FIB_SOURCE_INTERFACE)),
4234 "NO INterface Source'd prefixes");
4236 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
4238 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4239 fib_path_list_db_size());
4240 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4241 fib_path_list_pool_size());
4242 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4243 fib_entry_pool_size());
4244 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4245 pool_elts(fib_urpf_list_pool));
4246 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4247 pool_elts(load_balance_map_pool));
4248 FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4249 pool_elts(load_balance_pool));
4250 FIB_TEST((0 == pool_elts(l2_bridge_dpo_pool)), "L2 DPO pool size is %d",
4251 pool_elts(l2_bridge_dpo_pool));
4260 * In the default table check for the presence and correct forwarding
4261 * of the special entries
4263 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4264 const dpo_id_t *dpo, *dpo_drop;
4265 const ip_adjacency_t *adj;
4266 const receive_dpo_t *rd;
4271 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4274 /* via 2001:0:0:1::2 */
4275 ip46_address_t nh_2001_2 = {
4278 [0] = clib_host_to_net_u64(0x2001000000000001),
4279 [1] = clib_host_to_net_u64(0x0000000000000002),
4286 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4288 /* Find or create FIB table 11 */
4289 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
4292 for (ii = 0; ii < 4; ii++)
4294 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4297 fib_prefix_t pfx_0_0 = {
4299 .fp_proto = FIB_PROTOCOL_IP6,
4307 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4308 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4309 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4310 "Default route is DROP");
4312 dpo = fib_entry_contribute_ip_forwarding(dfrt);
4313 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4316 &pfx_0_0.fp_addr.ip6)),
4317 "default-route; fwd and non-fwd tables match");
4319 // FIXME - check specials.
4322 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4323 * each with 2 entries and a v6 mfib with 4 path-lists.
4324 * All entries are special so no path-list sharing.
4327 #define PNPS (5+4+4)
4328 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4329 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4330 fib_path_list_pool_size());
4331 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4332 fib_entry_pool_size());
4335 * add interface routes.
4336 * validate presence of /64 attached and /128 recieve.
4337 * test for the presence of the receive address in the glean and local adj
4339 * receive on 2001:0:0:1::1/128
4341 fib_prefix_t local_pfx = {
4343 .fp_proto = FIB_PROTOCOL_IP6,
4347 [0] = clib_host_to_net_u64(0x2001000000000001),
4348 [1] = clib_host_to_net_u64(0x0000000000000001),
4354 fib_table_entry_update_one_path(fib_index, &local_pfx,
4355 FIB_SOURCE_INTERFACE,
4356 (FIB_ENTRY_FLAG_CONNECTED |
4357 FIB_ENTRY_FLAG_ATTACHED),
4360 tm->hw[0]->sw_if_index,
4364 FIB_ROUTE_PATH_FLAG_NONE);
4365 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4367 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4369 ai = fib_entry_get_adj(fei);
4370 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4372 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4373 "attached interface adj is glean");
4374 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4375 &adj->sub_type.glean.receive_addr)),
4376 "attached interface adj is receive ok");
4377 dpo = fib_entry_contribute_ip_forwarding(fei);
4378 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4381 &local_pfx.fp_addr.ip6)),
4382 "attached-route; fwd and non-fwd tables match");
4384 local_pfx.fp_len = 128;
4385 fib_table_entry_update_one_path(fib_index, &local_pfx,
4386 FIB_SOURCE_INTERFACE,
4387 (FIB_ENTRY_FLAG_CONNECTED |
4388 FIB_ENTRY_FLAG_LOCAL),
4391 tm->hw[0]->sw_if_index,
4392 ~0, // invalid fib index
4395 FIB_ROUTE_PATH_FLAG_NONE);
4396 fei = fib_table_lookup(fib_index, &local_pfx);
4398 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4400 dpo = fib_entry_contribute_ip_forwarding(fei);
4401 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4402 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4403 "local interface adj is local");
4404 rd = receive_dpo_get(dpo->dpoi_index);
4406 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4408 "local interface adj is receive ok");
4410 dpo = fib_entry_contribute_ip_forwarding(fei);
4411 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4414 &local_pfx.fp_addr.ip6)),
4415 "local-route; fwd and non-fwd tables match");
4418 * +2 entries. +2 unshared path-lists
4420 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4421 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4422 fib_path_list_pool_size());
4423 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4424 fib_entry_pool_size());
4427 * Modify the default route to be via an adj not yet known.
4428 * this sources the defalut route with the API source, which is
4429 * a higher preference to the DEFAULT_ROUTE source
4431 fib_table_entry_path_add(fib_index, &pfx_0_0,
4433 FIB_ENTRY_FLAG_NONE,
4436 tm->hw[0]->sw_if_index,
4440 FIB_ROUTE_PATH_FLAG_NONE);
4441 fei = fib_table_lookup(fib_index, &pfx_0_0);
4443 FIB_TEST((fei == dfrt), "default route same index");
4444 ai = fib_entry_get_adj(fei);
4445 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4447 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4448 "adj is incomplete");
4449 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4450 "adj nbr next-hop ok");
4453 * find the adj in the shared db
4455 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4458 tm->hw[0]->sw_if_index);
4459 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4460 adj_unlock(locked_ai);
4463 * no more entires. +1 shared path-list
4465 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4466 fib_path_list_db_size());
4467 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4468 fib_path_list_pool_size());
4469 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4470 fib_entry_pool_size());
4473 * remove the API source from the default route. We expected
4474 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4476 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4480 tm->hw[0]->sw_if_index,
4483 FIB_ROUTE_PATH_FLAG_NONE);
4484 fei = fib_table_lookup(fib_index, &pfx_0_0);
4486 FIB_TEST((fei == dfrt), "default route same index");
4487 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4488 "Default route is DROP");
4491 * no more entires. -1 shared path-list
4493 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4494 fib_path_list_db_size());
4495 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4496 fib_path_list_pool_size());
4497 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4498 fib_entry_pool_size());
4501 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4503 fib_prefix_t pfx_2001_1_2_s_128 = {
4505 .fp_proto = FIB_PROTOCOL_IP6,
4509 [0] = clib_host_to_net_u64(0x2001000000000001),
4510 [1] = clib_host_to_net_u64(0x0000000000000002),
4515 fib_prefix_t pfx_2001_1_3_s_128 = {
4517 .fp_proto = FIB_PROTOCOL_IP6,
4521 [0] = clib_host_to_net_u64(0x2001000000000001),
4522 [1] = clib_host_to_net_u64(0x0000000000000003),
4528 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4531 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4533 &pfx_2001_1_2_s_128.fp_addr,
4534 tm->hw[0]->sw_if_index);
4535 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4536 adj = adj_get(ai_01);
4537 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4538 "adj is incomplete");
4539 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4540 &adj->sub_type.nbr.next_hop)),
4541 "adj nbr next-hop ok");
4543 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4544 fib_test_build_rewrite(eth_addr));
4545 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4547 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4548 &adj->sub_type.nbr.next_hop)),
4549 "adj nbr next-hop ok");
4551 fib_table_entry_path_add(fib_index,
4552 &pfx_2001_1_2_s_128,
4554 FIB_ENTRY_FLAG_ATTACHED,
4556 &pfx_2001_1_2_s_128.fp_addr,
4557 tm->hw[0]->sw_if_index,
4561 FIB_ROUTE_PATH_FLAG_NONE);
4563 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4564 ai = fib_entry_get_adj(fei);
4565 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4569 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4571 &pfx_2001_1_3_s_128.fp_addr,
4572 tm->hw[0]->sw_if_index);
4573 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4574 adj = adj_get(ai_02);
4575 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4576 "adj is incomplete");
4577 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4578 &adj->sub_type.nbr.next_hop)),
4579 "adj nbr next-hop ok");
4581 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4582 fib_test_build_rewrite(eth_addr));
4583 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4585 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4586 &adj->sub_type.nbr.next_hop)),
4587 "adj nbr next-hop ok");
4588 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4590 fib_table_entry_path_add(fib_index,
4591 &pfx_2001_1_3_s_128,
4593 FIB_ENTRY_FLAG_ATTACHED,
4595 &pfx_2001_1_3_s_128.fp_addr,
4596 tm->hw[0]->sw_if_index,
4600 FIB_ROUTE_PATH_FLAG_NONE);
4602 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4603 ai = fib_entry_get_adj(fei);
4604 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4607 * +2 entries, +2 unshread path-lists.
4609 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4610 fib_path_list_db_size());
4611 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4612 fib_path_list_pool_size());
4613 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4614 fib_entry_pool_size());
4617 * Add a 2 routes via the first ADJ. ensure path-list sharing
4619 fib_prefix_t pfx_2001_a_s_64 = {
4621 .fp_proto = FIB_PROTOCOL_IP6,
4625 [0] = clib_host_to_net_u64(0x200100000000000a),
4626 [1] = clib_host_to_net_u64(0x0000000000000000),
4631 fib_prefix_t pfx_2001_b_s_64 = {
4633 .fp_proto = FIB_PROTOCOL_IP6,
4637 [0] = clib_host_to_net_u64(0x200100000000000b),
4638 [1] = clib_host_to_net_u64(0x0000000000000000),
4644 fib_table_entry_path_add(fib_index,
4647 FIB_ENTRY_FLAG_NONE,
4650 tm->hw[0]->sw_if_index,
4654 FIB_ROUTE_PATH_FLAG_NONE);
4655 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4656 ai = fib_entry_get_adj(fei);
4657 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4658 fib_table_entry_path_add(fib_index,
4661 FIB_ENTRY_FLAG_NONE,
4664 tm->hw[0]->sw_if_index,
4668 FIB_ROUTE_PATH_FLAG_NONE);
4669 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4670 ai = fib_entry_get_adj(fei);
4671 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4674 * +2 entries, +1 shared path-list.
4676 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4677 fib_path_list_db_size());
4678 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4679 fib_path_list_pool_size());
4680 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4681 fib_entry_pool_size());
4684 * add a v4 prefix via a v6 next-hop
4686 fib_prefix_t pfx_1_1_1_1_s_32 = {
4688 .fp_proto = FIB_PROTOCOL_IP4,
4690 .ip4.as_u32 = 0x01010101,
4693 fei = fib_table_entry_path_add(0, // default table
4696 FIB_ENTRY_FLAG_NONE,
4699 tm->hw[0]->sw_if_index,
4703 FIB_ROUTE_PATH_FLAG_NONE);
4704 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4705 "1.1.1.1/32 o v6 route present");
4706 ai = fib_entry_get_adj(fei);
4708 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4709 "1.1.1.1/32 via ARP-adj");
4710 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4711 "1.1.1.1/32 ADJ-adj is link type v4");
4712 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4713 "1.1.1.1/32 ADJ-adj is NH proto v6");
4714 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4719 fib_prefix_t pfx_2001_c_s_64 = {
4721 .fp_proto = FIB_PROTOCOL_IP6,
4725 [0] = clib_host_to_net_u64(0x200100000000000c),
4726 [1] = clib_host_to_net_u64(0x0000000000000000),
4731 fib_table_entry_path_add(fib_index,
4734 FIB_ENTRY_FLAG_ATTACHED,
4737 tm->hw[0]->sw_if_index,
4741 FIB_ROUTE_PATH_FLAG_NONE);
4742 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4743 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4744 ai = fib_entry_get_adj(fei);
4746 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4747 "2001:0:0:c/64 attached resolves via glean");
4749 fib_table_entry_path_remove(fib_index,
4754 tm->hw[0]->sw_if_index,
4757 FIB_ROUTE_PATH_FLAG_NONE);
4758 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4759 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4762 * Shutdown the interface on which we have a connected and through
4763 * which the routes are reachable.
4764 * This will result in the connected, adj-fibs, and routes linking to drop
4765 * The local/for-us prefix continues to receive.
4767 clib_error_t * error;
4769 error = vnet_sw_interface_set_flags(vnet_get_main(),
4770 tm->hw[0]->sw_if_index,
4771 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4772 FIB_TEST((NULL == error), "Interface shutdown OK");
4774 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4775 dpo = fib_entry_contribute_ip_forwarding(fei);
4776 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4777 "2001::b/64 resolves via drop");
4779 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4780 dpo = fib_entry_contribute_ip_forwarding(fei);
4781 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4782 "2001::a/64 resolves via drop");
4783 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4784 dpo = fib_entry_contribute_ip_forwarding(fei);
4785 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4786 "2001:0:0:1::3/64 resolves via drop");
4787 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4788 dpo = fib_entry_contribute_ip_forwarding(fei);
4789 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4790 "2001:0:0:1::2/64 resolves via drop");
4791 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4792 dpo = fib_entry_contribute_ip_forwarding(fei);
4793 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4794 "2001:0:0:1::1/128 not drop");
4795 local_pfx.fp_len = 64;
4796 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4797 dpo = fib_entry_contribute_ip_forwarding(fei);
4798 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4799 "2001:0:0:1/64 resolves via drop");
4804 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4805 fib_path_list_db_size());
4806 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4807 fib_path_list_pool_size());
4808 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4809 fib_entry_pool_size());
4812 * shutdown one of the other interfaces, then add a connected.
4813 * and swap one of the routes to it.
4815 error = vnet_sw_interface_set_flags(vnet_get_main(),
4816 tm->hw[1]->sw_if_index,
4817 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4818 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4820 fib_prefix_t connected_pfx = {
4822 .fp_proto = FIB_PROTOCOL_IP6,
4825 /* 2001:0:0:2::1/64 */
4827 [0] = clib_host_to_net_u64(0x2001000000000002),
4828 [1] = clib_host_to_net_u64(0x0000000000000001),
4833 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4834 FIB_SOURCE_INTERFACE,
4835 (FIB_ENTRY_FLAG_CONNECTED |
4836 FIB_ENTRY_FLAG_ATTACHED),
4839 tm->hw[1]->sw_if_index,
4843 FIB_ROUTE_PATH_FLAG_NONE);
4844 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4845 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4846 dpo = fib_entry_contribute_ip_forwarding(fei);
4847 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4848 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4849 "2001:0:0:2/64 not resolves via drop");
4851 connected_pfx.fp_len = 128;
4852 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4853 FIB_SOURCE_INTERFACE,
4854 (FIB_ENTRY_FLAG_CONNECTED |
4855 FIB_ENTRY_FLAG_LOCAL),
4858 tm->hw[0]->sw_if_index,
4859 ~0, // invalid fib index
4862 FIB_ROUTE_PATH_FLAG_NONE);
4863 fei = fib_table_lookup(fib_index, &connected_pfx);
4865 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4866 dpo = fib_entry_contribute_ip_forwarding(fei);
4867 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4868 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4869 "local interface adj is local");
4870 rd = receive_dpo_get(dpo->dpoi_index);
4871 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4873 "local interface adj is receive ok");
4876 * +2 entries, +2 unshared path-lists
4878 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4879 fib_path_list_db_size());
4880 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4881 fib_path_list_pool_size());
4882 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4883 fib_entry_pool_size());
4887 * bring the interface back up. we expected the routes to return
4888 * to normal forwarding.
4890 error = vnet_sw_interface_set_flags(vnet_get_main(),
4891 tm->hw[0]->sw_if_index,
4892 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4893 FIB_TEST((NULL == error), "Interface bring-up OK");
4894 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4895 ai = fib_entry_get_adj(fei);
4896 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4897 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4898 ai = fib_entry_get_adj(fei);
4899 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4900 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4901 ai = fib_entry_get_adj(fei);
4902 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4903 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4904 ai = fib_entry_get_adj(fei);
4905 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4906 local_pfx.fp_len = 64;
4907 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4908 ai = fib_entry_get_adj(fei);
4910 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4911 "attached interface adj is glean");
4914 * Same test as above, but this time the HW interface goes down
4916 error = vnet_hw_interface_set_flags(vnet_get_main(),
4917 tm->hw_if_indicies[0],
4918 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4919 FIB_TEST((NULL == error), "Interface shutdown OK");
4921 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4922 dpo = fib_entry_contribute_ip_forwarding(fei);
4923 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4924 "2001::b/64 resolves via drop");
4925 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4926 dpo = fib_entry_contribute_ip_forwarding(fei);
4927 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4928 "2001::a/64 resolves via drop");
4929 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4930 dpo = fib_entry_contribute_ip_forwarding(fei);
4931 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4932 "2001:0:0:1::3/128 resolves via drop");
4933 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4934 dpo = fib_entry_contribute_ip_forwarding(fei);
4935 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4936 "2001:0:0:1::2/128 resolves via drop");
4937 local_pfx.fp_len = 128;
4938 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4939 dpo = fib_entry_contribute_ip_forwarding(fei);
4940 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4941 "2001:0:0:1::1/128 not drop");
4942 local_pfx.fp_len = 64;
4943 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4944 dpo = fib_entry_contribute_ip_forwarding(fei);
4945 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4946 "2001:0:0:1/64 resolves via drop");
4948 error = vnet_hw_interface_set_flags(vnet_get_main(),
4949 tm->hw_if_indicies[0],
4950 VNET_HW_INTERFACE_FLAG_LINK_UP);
4951 FIB_TEST((NULL == error), "Interface bring-up OK");
4952 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4953 ai = fib_entry_get_adj(fei);
4954 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4955 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4956 ai = fib_entry_get_adj(fei);
4957 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4958 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4959 ai = fib_entry_get_adj(fei);
4960 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4961 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4962 ai = fib_entry_get_adj(fei);
4963 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4964 local_pfx.fp_len = 64;
4965 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4966 ai = fib_entry_get_adj(fei);
4968 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4969 "attached interface adj is glean");
4972 * Delete the interface that the routes reolve through.
4973 * Again no routes are removed. They all point to drop.
4975 * This is considered an error case. The control plane should
4976 * not remove interfaces through which routes resolve, but
4977 * such things can happen. ALL affected routes will drop.
4979 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4981 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4982 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4983 "2001::b/64 resolves via drop");
4984 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4985 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4986 "2001::b/64 resolves via drop");
4987 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4988 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4989 "2001:0:0:1::3/64 resolves via drop");
4990 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4991 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4992 "2001:0:0:1::2/64 resolves via drop");
4993 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4994 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4995 "2001:0:0:1::1/128 is drop");
4996 local_pfx.fp_len = 64;
4997 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4998 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4999 "2001:0:0:1/64 resolves via drop");
5004 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
5005 fib_path_list_db_size());
5006 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
5007 fib_path_list_pool_size());
5008 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
5009 fib_entry_pool_size());
5012 * Add the interface back. routes stay unresolved.
5014 error = ethernet_register_interface(vnet_get_main(),
5015 test_interface_device_class.index,
5018 &tm->hw_if_indicies[0],
5019 /* flag change */ 0);
5021 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5022 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5023 "2001::b/64 resolves via drop");
5024 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5025 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5026 "2001::b/64 resolves via drop");
5027 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5028 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5029 "2001:0:0:1::3/64 resolves via drop");
5030 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5031 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5032 "2001:0:0:1::2/64 resolves via drop");
5033 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5034 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5035 "2001:0:0:1::1/128 is drop");
5036 local_pfx.fp_len = 64;
5037 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5038 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5039 "2001:0:0:1/64 resolves via drop");
5042 * CLEANUP ALL the routes
5044 fib_table_entry_delete(fib_index,
5047 fib_table_entry_delete(fib_index,
5050 fib_table_entry_delete(fib_index,
5053 fib_table_entry_delete(fib_index,
5054 &pfx_2001_1_3_s_128,
5056 fib_table_entry_delete(fib_index,
5057 &pfx_2001_1_2_s_128,
5059 local_pfx.fp_len = 64;
5060 fib_table_entry_delete(fib_index, &local_pfx,
5061 FIB_SOURCE_INTERFACE);
5062 local_pfx.fp_len = 128;
5063 fib_table_entry_special_remove(fib_index, &local_pfx,
5064 FIB_SOURCE_INTERFACE);
5065 connected_pfx.fp_len = 64;
5066 fib_table_entry_delete(fib_index, &connected_pfx,
5067 FIB_SOURCE_INTERFACE);
5068 connected_pfx.fp_len = 128;
5069 fib_table_entry_special_remove(fib_index, &connected_pfx,
5070 FIB_SOURCE_INTERFACE);
5072 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5073 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
5074 "2001::a/64 removed");
5075 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5076 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
5077 "2001::b/64 removed");
5078 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5079 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
5080 "2001:0:0:1::3/128 removed");
5081 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5082 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
5083 "2001:0:0:1::3/128 removed");
5084 local_pfx.fp_len = 64;
5085 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5086 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5087 "2001:0:0:1/64 removed");
5088 local_pfx.fp_len = 128;
5089 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5090 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5091 "2001:0:0:1::1/128 removed");
5092 connected_pfx.fp_len = 64;
5093 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5094 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5095 "2001:0:0:2/64 removed");
5096 connected_pfx.fp_len = 128;
5097 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5098 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5099 "2001:0:0:2::1/128 removed");
5102 * -8 entries. -7 path-lists (1 was shared).
5104 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5105 fib_path_list_db_size());
5106 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5107 fib_path_list_pool_size());
5108 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5109 fib_entry_pool_size());
5112 * now remove the VRF
5114 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
5116 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5117 fib_path_list_db_size());
5118 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5119 fib_path_list_pool_size());
5120 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5121 fib_entry_pool_size());
5127 * return the interfaces to up state
5129 error = vnet_sw_interface_set_flags(vnet_get_main(),
5130 tm->hw[0]->sw_if_index,
5131 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5132 error = vnet_sw_interface_set_flags(vnet_get_main(),
5133 tm->hw[1]->sw_if_index,
5134 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5136 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5143 * Test Attached Exports
5148 const dpo_id_t *dpo, *dpo_drop;
5149 const u32 fib_index = 0;
5150 fib_node_index_t fei;
5157 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5161 * add interface routes. We'll assume this works. It's more rigorously
5164 fib_prefix_t local_pfx = {
5166 .fp_proto = FIB_PROTOCOL_IP4,
5170 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5175 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5176 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5178 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5180 fib_table_entry_update_one_path(fib_index, &local_pfx,
5181 FIB_SOURCE_INTERFACE,
5182 (FIB_ENTRY_FLAG_CONNECTED |
5183 FIB_ENTRY_FLAG_ATTACHED),
5186 tm->hw[0]->sw_if_index,
5190 FIB_ROUTE_PATH_FLAG_NONE);
5191 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5192 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5193 "attached interface route present");
5195 local_pfx.fp_len = 32;
5196 fib_table_entry_update_one_path(fib_index, &local_pfx,
5197 FIB_SOURCE_INTERFACE,
5198 (FIB_ENTRY_FLAG_CONNECTED |
5199 FIB_ENTRY_FLAG_LOCAL),
5202 tm->hw[0]->sw_if_index,
5203 ~0, // invalid fib index
5206 FIB_ROUTE_PATH_FLAG_NONE);
5207 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5209 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5210 "local interface route present");
5213 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5215 fib_prefix_t pfx_10_10_10_1_s_32 = {
5217 .fp_proto = FIB_PROTOCOL_IP4,
5220 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5223 fib_node_index_t ai;
5225 fib_table_entry_path_add(fib_index,
5226 &pfx_10_10_10_1_s_32,
5228 FIB_ENTRY_FLAG_ATTACHED,
5230 &pfx_10_10_10_1_s_32.fp_addr,
5231 tm->hw[0]->sw_if_index,
5232 ~0, // invalid fib index
5235 FIB_ROUTE_PATH_FLAG_NONE);
5237 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5238 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5239 ai = fib_entry_get_adj(fei);
5242 * create another FIB table into which routes will be imported
5244 u32 import_fib_index1;
5246 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
5251 * Add an attached route in the import FIB
5253 local_pfx.fp_len = 24;
5254 fib_table_entry_update_one_path(import_fib_index1,
5257 FIB_ENTRY_FLAG_NONE,
5260 tm->hw[0]->sw_if_index,
5261 ~0, // invalid fib index
5264 FIB_ROUTE_PATH_FLAG_NONE);
5265 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5266 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5269 * check for the presence of the adj-fibs in the import table
5271 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5272 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5273 FIB_TEST((ai == fib_entry_get_adj(fei)),
5274 "adj-fib1 Import uses same adj as export");
5277 * check for the presence of the local in the import table
5279 local_pfx.fp_len = 32;
5280 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5281 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5284 * Add another adj-fin in the export table. Expect this
5285 * to get magically exported;
5287 fib_prefix_t pfx_10_10_10_2_s_32 = {
5289 .fp_proto = FIB_PROTOCOL_IP4,
5292 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5296 fib_table_entry_path_add(fib_index,
5297 &pfx_10_10_10_2_s_32,
5299 FIB_ENTRY_FLAG_ATTACHED,
5301 &pfx_10_10_10_2_s_32.fp_addr,
5302 tm->hw[0]->sw_if_index,
5303 ~0, // invalid fib index
5306 FIB_ROUTE_PATH_FLAG_NONE);
5307 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5308 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5309 ai = fib_entry_get_adj(fei);
5311 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5312 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5313 FIB_TEST((ai == fib_entry_get_adj(fei)),
5314 "Import uses same adj as export");
5315 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5316 "ADJ-fib2 imported flags %d",
5317 fib_entry_get_flags(fei));
5320 * create a 2nd FIB table into which routes will be imported
5322 u32 import_fib_index2;
5324 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
5328 * Add an attached route in the import FIB
5330 local_pfx.fp_len = 24;
5331 fib_table_entry_update_one_path(import_fib_index2,
5334 FIB_ENTRY_FLAG_NONE,
5337 tm->hw[0]->sw_if_index,
5338 ~0, // invalid fib index
5341 FIB_ROUTE_PATH_FLAG_NONE);
5342 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5343 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5346 * check for the presence of all the adj-fibs and local in the import table
5348 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5349 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5350 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5351 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5352 local_pfx.fp_len = 32;
5353 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5354 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5357 * add a 3rd adj-fib. expect it to be exported to both tables.
5359 fib_prefix_t pfx_10_10_10_3_s_32 = {
5361 .fp_proto = FIB_PROTOCOL_IP4,
5364 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5368 fib_table_entry_path_add(fib_index,
5369 &pfx_10_10_10_3_s_32,
5371 FIB_ENTRY_FLAG_ATTACHED,
5373 &pfx_10_10_10_3_s_32.fp_addr,
5374 tm->hw[0]->sw_if_index,
5375 ~0, // invalid fib index
5378 FIB_ROUTE_PATH_FLAG_NONE);
5379 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5380 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5381 ai = fib_entry_get_adj(fei);
5383 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5384 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5385 FIB_TEST((ai == fib_entry_get_adj(fei)),
5386 "Import uses same adj as export");
5387 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5388 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5389 FIB_TEST((ai == fib_entry_get_adj(fei)),
5390 "Import uses same adj as export");
5393 * remove the 3rd adj fib. we expect it to be removed from both FIBs
5395 fib_table_entry_delete(fib_index,
5396 &pfx_10_10_10_3_s_32,
5399 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5400 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5402 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5403 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5405 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5406 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5409 * remove the attached route from the 2nd FIB. expect the imported
5410 * entires to be removed
5412 local_pfx.fp_len = 24;
5413 fib_table_entry_delete(import_fib_index2,
5416 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5417 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5419 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5420 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5421 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5422 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5423 local_pfx.fp_len = 32;
5424 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5425 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5427 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5428 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5429 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5430 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5431 local_pfx.fp_len = 32;
5432 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5433 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5436 * modify the route in FIB1 so it is no longer attached. expect the imported
5437 * entires to be removed
5439 local_pfx.fp_len = 24;
5440 fib_table_entry_update_one_path(import_fib_index1,
5443 FIB_ENTRY_FLAG_NONE,
5445 &pfx_10_10_10_2_s_32.fp_addr,
5446 tm->hw[0]->sw_if_index,
5447 ~0, // invalid fib index
5450 FIB_ROUTE_PATH_FLAG_NONE);
5451 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5452 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5453 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5454 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5455 local_pfx.fp_len = 32;
5456 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5457 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5460 * modify it back to attached. expect the adj-fibs back
5462 local_pfx.fp_len = 24;
5463 fib_table_entry_update_one_path(import_fib_index1,
5466 FIB_ENTRY_FLAG_NONE,
5469 tm->hw[0]->sw_if_index,
5470 ~0, // invalid fib index
5473 FIB_ROUTE_PATH_FLAG_NONE);
5474 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5475 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5476 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5477 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5478 local_pfx.fp_len = 32;
5479 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5480 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5483 * add a covering attached next-hop for the interface address, so we have
5484 * a valid adj to find when we check the forwarding tables
5486 fib_prefix_t pfx_10_0_0_0_s_8 = {
5488 .fp_proto = FIB_PROTOCOL_IP4,
5491 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5495 fei = fib_table_entry_update_one_path(fib_index,
5498 FIB_ENTRY_FLAG_NONE,
5500 &pfx_10_10_10_3_s_32.fp_addr,
5501 tm->hw[0]->sw_if_index,
5502 ~0, // invalid fib index
5505 FIB_ROUTE_PATH_FLAG_NONE);
5506 dpo = fib_entry_contribute_ip_forwarding(fei);
5509 * remove the route in the export fib. expect the adj-fibs to be removed
5511 local_pfx.fp_len = 24;
5512 fib_table_entry_delete(fib_index,
5514 FIB_SOURCE_INTERFACE);
5516 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5517 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5518 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5519 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5520 local_pfx.fp_len = 32;
5521 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5522 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5525 * the adj-fibs in the export VRF are present in the FIB table,
5526 * but not installed in forwarding, since they have no attached cover.
5527 * Consequently a lookup in the MTRIE gives the adj for the covering
5530 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5531 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5534 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5535 FIB_TEST(lbi == dpo->dpoi_index,
5536 "10.10.10.1 forwards on \n%U not \n%U",
5537 format_load_balance, lbi, 0,
5538 format_dpo_id, dpo, 0);
5539 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5540 FIB_TEST(lbi == dpo->dpoi_index,
5541 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5542 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5543 FIB_TEST(lbi == dpo->dpoi_index,
5544 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5547 * add the export prefix back, but not as attached.
5548 * No adj-fibs in export nor import tables
5550 local_pfx.fp_len = 24;
5551 fei = fib_table_entry_update_one_path(fib_index,
5554 FIB_ENTRY_FLAG_NONE,
5556 &pfx_10_10_10_1_s_32.fp_addr,
5557 tm->hw[0]->sw_if_index,
5558 ~0, // invalid fib index
5561 FIB_ROUTE_PATH_FLAG_NONE);
5562 dpo = fib_entry_contribute_ip_forwarding(fei);
5564 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5565 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5566 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5567 FIB_TEST(lbi == dpo->dpoi_index,
5568 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5569 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5570 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5571 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5572 FIB_TEST(lbi == dpo->dpoi_index,
5573 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5575 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5576 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5577 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5578 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5579 local_pfx.fp_len = 32;
5580 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5581 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5584 * modify the export prefix so it is attached. expect all covereds to return
5586 local_pfx.fp_len = 24;
5587 fib_table_entry_update_one_path(fib_index,
5590 FIB_ENTRY_FLAG_NONE,
5593 tm->hw[0]->sw_if_index,
5594 ~0, // invalid fib index
5597 FIB_ROUTE_PATH_FLAG_NONE);
5599 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5600 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5601 dpo = fib_entry_contribute_ip_forwarding(fei);
5602 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5603 "Adj-fib1 is not drop in export");
5604 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5605 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5606 local_pfx.fp_len = 32;
5607 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5608 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5609 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5610 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5611 dpo = fib_entry_contribute_ip_forwarding(fei);
5612 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5613 "Adj-fib1 is not drop in export");
5614 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5615 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5616 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5617 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5618 local_pfx.fp_len = 32;
5619 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5620 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5623 * modify the export prefix so connected. no change.
5625 local_pfx.fp_len = 24;
5626 fib_table_entry_update_one_path(fib_index, &local_pfx,
5627 FIB_SOURCE_INTERFACE,
5628 (FIB_ENTRY_FLAG_CONNECTED |
5629 FIB_ENTRY_FLAG_ATTACHED),
5632 tm->hw[0]->sw_if_index,
5636 FIB_ROUTE_PATH_FLAG_NONE);
5638 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5639 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5640 dpo = fib_entry_contribute_ip_forwarding(fei);
5641 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5642 "Adj-fib1 is not drop in export");
5643 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5644 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5645 local_pfx.fp_len = 32;
5646 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5647 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5648 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5649 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5650 dpo = fib_entry_contribute_ip_forwarding(fei);
5651 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5652 "Adj-fib1 is not drop in export");
5653 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5654 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5655 local_pfx.fp_len = 32;
5656 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5657 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5662 fib_table_entry_delete(fib_index,
5665 fib_table_entry_delete(fib_index,
5666 &pfx_10_10_10_1_s_32,
5668 fib_table_entry_delete(fib_index,
5669 &pfx_10_10_10_2_s_32,
5671 local_pfx.fp_len = 32;
5672 fib_table_entry_delete(fib_index,
5674 FIB_SOURCE_INTERFACE);
5675 local_pfx.fp_len = 24;
5676 fib_table_entry_delete(fib_index,
5679 fib_table_entry_delete(fib_index,
5681 FIB_SOURCE_INTERFACE);
5682 local_pfx.fp_len = 24;
5683 fib_table_entry_delete(import_fib_index1,
5687 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5688 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5690 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5697 * Test Path Preference
5700 fib_test_pref (void)
5702 test_main_t *tm = &test_main;
5704 const fib_prefix_t pfx_1_1_1_1_s_32 = {
5706 .fp_proto = FIB_PROTOCOL_IP4,
5709 .as_u32 = clib_host_to_net_u32(0x01010101),
5715 * 2 high, 2 medium and 2 low preference non-recursive paths
5717 fib_route_path_t nr_path_hi_1 = {
5718 .frp_proto = DPO_PROTO_IP4,
5719 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5720 .frp_fib_index = ~0,
5722 .frp_preference = 0,
5723 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5725 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5728 fib_route_path_t nr_path_hi_2 = {
5729 .frp_proto = DPO_PROTO_IP4,
5730 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5731 .frp_fib_index = ~0,
5733 .frp_preference = 0,
5734 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5736 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5739 fib_route_path_t nr_path_med_1 = {
5740 .frp_proto = DPO_PROTO_IP4,
5741 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5742 .frp_fib_index = ~0,
5744 .frp_preference = 1,
5745 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5747 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5750 fib_route_path_t nr_path_med_2 = {
5751 .frp_proto = DPO_PROTO_IP4,
5752 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5753 .frp_fib_index = ~0,
5755 .frp_preference = 1,
5756 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5758 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5761 fib_route_path_t nr_path_low_1 = {
5762 .frp_proto = DPO_PROTO_IP4,
5763 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5764 .frp_fib_index = ~0,
5766 .frp_preference = 2,
5767 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5769 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5772 fib_route_path_t nr_path_low_2 = {
5773 .frp_proto = DPO_PROTO_IP4,
5774 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5775 .frp_fib_index = ~0,
5777 .frp_preference = 2,
5778 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5780 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5783 fib_route_path_t *nr_paths = NULL;
5785 vec_add1(nr_paths, nr_path_hi_1);
5786 vec_add1(nr_paths, nr_path_hi_2);
5787 vec_add1(nr_paths, nr_path_med_1);
5788 vec_add1(nr_paths, nr_path_med_2);
5789 vec_add1(nr_paths, nr_path_low_1);
5790 vec_add1(nr_paths, nr_path_low_2);
5792 adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5794 &nr_path_hi_1.frp_addr,
5795 nr_path_hi_1.frp_sw_if_index);
5796 adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5798 &nr_path_hi_2.frp_addr,
5799 nr_path_hi_2.frp_sw_if_index);
5800 adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5802 &nr_path_med_1.frp_addr,
5803 nr_path_med_1.frp_sw_if_index);
5804 adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5806 &nr_path_med_2.frp_addr,
5807 nr_path_med_2.frp_sw_if_index);
5808 adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5810 &nr_path_low_1.frp_addr,
5811 nr_path_low_1.frp_sw_if_index);
5812 adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5814 &nr_path_low_2.frp_addr,
5815 nr_path_low_2.frp_sw_if_index);
5817 fib_test_lb_bucket_t ip_hi_1 = {
5823 fib_test_lb_bucket_t ip_hi_2 = {
5829 fib_test_lb_bucket_t ip_med_1 = {
5835 fib_test_lb_bucket_t ip_med_2 = {
5841 fib_test_lb_bucket_t ip_low_1 = {
5847 fib_test_lb_bucket_t ip_low_2 = {
5854 fib_node_index_t fei;
5856 fei = fib_table_entry_path_add2(0,
5859 FIB_ENTRY_FLAG_NONE,
5862 FIB_TEST(fib_test_validate_entry(fei,
5863 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5867 "1.1.1.1/32 via high preference paths");
5870 * bring down the interface on which the high preference path lie
5872 vnet_sw_interface_set_flags(vnet_get_main(),
5873 tm->hw[0]->sw_if_index,
5876 FIB_TEST(fib_test_validate_entry(fei,
5877 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5881 "1.1.1.1/32 via medium preference paths");
5884 * bring down the interface on which the medium preference path lie
5886 vnet_sw_interface_set_flags(vnet_get_main(),
5887 tm->hw[1]->sw_if_index,
5890 FIB_TEST(fib_test_validate_entry(fei,
5891 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5895 "1.1.1.1/32 via low preference paths");
5898 * bring up the interface on which the high preference path lie
5900 vnet_sw_interface_set_flags(vnet_get_main(),
5901 tm->hw[0]->sw_if_index,
5902 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5904 FIB_TEST(fib_test_validate_entry(fei,
5905 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5909 "1.1.1.1/32 via high preference paths");
5912 * bring up the interface on which the medium preference path lie
5914 vnet_sw_interface_set_flags(vnet_get_main(),
5915 tm->hw[1]->sw_if_index,
5916 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5918 FIB_TEST(fib_test_validate_entry(fei,
5919 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5923 "1.1.1.1/32 via high preference paths");
5925 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
5926 fib_entry_contribute_forwarding(fei,
5927 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5931 * 3 recursive paths of different preference
5933 const fib_prefix_t pfx_1_1_1_2_s_32 = {
5935 .fp_proto = FIB_PROTOCOL_IP4,
5938 .as_u32 = clib_host_to_net_u32(0x01010102),
5942 const fib_prefix_t pfx_1_1_1_3_s_32 = {
5944 .fp_proto = FIB_PROTOCOL_IP4,
5947 .as_u32 = clib_host_to_net_u32(0x01010103),
5951 fei = fib_table_entry_path_add2(0,
5954 FIB_ENTRY_FLAG_NONE,
5956 dpo_id_t ip_1_1_1_2 = DPO_INVALID;
5957 fib_entry_contribute_forwarding(fei,
5958 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5960 fei = fib_table_entry_path_add2(0,
5963 FIB_ENTRY_FLAG_NONE,
5965 dpo_id_t ip_1_1_1_3 = DPO_INVALID;
5966 fib_entry_contribute_forwarding(fei,
5967 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5970 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5973 .lb = ip_1_1_1_1.dpoi_index,
5976 fib_test_lb_bucket_t ip_o_1_1_1_2 = {
5979 .lb = ip_1_1_1_2.dpoi_index,
5982 fib_test_lb_bucket_t ip_o_1_1_1_3 = {
5985 .lb = ip_1_1_1_3.dpoi_index,
5988 fib_route_path_t r_path_hi = {
5989 .frp_proto = DPO_PROTO_IP4,
5990 .frp_sw_if_index = ~0,
5993 .frp_preference = 0,
5994 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5995 .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
5997 fib_route_path_t r_path_med = {
5998 .frp_proto = DPO_PROTO_IP4,
5999 .frp_sw_if_index = ~0,
6002 .frp_preference = 10,
6003 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6004 .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
6006 fib_route_path_t r_path_low = {
6007 .frp_proto = DPO_PROTO_IP4,
6008 .frp_sw_if_index = ~0,
6011 .frp_preference = 255,
6012 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6013 .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
6015 fib_route_path_t *r_paths = NULL;
6017 vec_add1(r_paths, r_path_hi);
6018 vec_add1(r_paths, r_path_low);
6019 vec_add1(r_paths, r_path_med);
6022 * add many recursive so we get the LB MAp created
6025 fib_prefix_t pfx_r[N_PFXS];
6026 unsigned int n_pfxs;
6027 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6029 pfx_r[n_pfxs].fp_len = 32;
6030 pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
6031 pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
6032 clib_host_to_net_u32(0x02000000 + n_pfxs);
6034 fei = fib_table_entry_path_add2(0,
6037 FIB_ENTRY_FLAG_NONE,
6040 FIB_TEST(fib_test_validate_entry(fei,
6041 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6044 "recursive via high preference paths");
6047 * withdraw hig pref resolving entry
6049 fib_table_entry_delete(0,
6053 /* suspend so the update walk kicks int */
6054 vlib_process_suspend(vlib_get_main(), 1e-5);
6056 FIB_TEST(fib_test_validate_entry(fei,
6057 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6060 "recursive via medium preference paths");
6063 * withdraw medium pref resolving entry
6065 fib_table_entry_delete(0,
6069 /* suspend so the update walk kicks int */
6070 vlib_process_suspend(vlib_get_main(), 1e-5);
6072 FIB_TEST(fib_test_validate_entry(fei,
6073 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6076 "recursive via low preference paths");
6079 * add back paths for next iteration
6081 fei = fib_table_entry_update(0,
6084 FIB_ENTRY_FLAG_NONE,
6086 fei = fib_table_entry_update(0,
6089 FIB_ENTRY_FLAG_NONE,
6092 /* suspend so the update walk kicks int */
6093 vlib_process_suspend(vlib_get_main(), 1e-5);
6095 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6096 FIB_TEST(fib_test_validate_entry(fei,
6097 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6100 "recursive via high preference paths");
6104 fib_table_entry_delete(0,
6108 /* suspend so the update walk kicks int */
6109 vlib_process_suspend(vlib_get_main(), 1e-5);
6111 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6113 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6115 FIB_TEST(fib_test_validate_entry(fei,
6116 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6119 "recursive via medium preference paths");
6121 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6123 fib_table_entry_delete(0,
6131 fib_table_entry_delete(0,
6134 fib_table_entry_delete(0,
6138 dpo_reset(&ip_1_1_1_1);
6139 dpo_reset(&ip_1_1_1_2);
6140 dpo_reset(&ip_1_1_1_3);
6141 adj_unlock(ai_low_2);
6142 adj_unlock(ai_low_1);
6143 adj_unlock(ai_med_2);
6144 adj_unlock(ai_med_1);
6145 adj_unlock(ai_hi_2);
6146 adj_unlock(ai_hi_1);
6151 * Test the recursive route route handling for GRE tunnels
6154 fib_test_label (void)
6156 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;
6157 const u32 fib_index = 0;
6162 lb_count = pool_elts(load_balance_pool);
6167 * add interface routes. We'll assume this works. It's more rigorously
6170 fib_prefix_t local0_pfx = {
6172 .fp_proto = FIB_PROTOCOL_IP4,
6176 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6181 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6184 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6185 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6187 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6188 FIB_SOURCE_INTERFACE,
6189 (FIB_ENTRY_FLAG_CONNECTED |
6190 FIB_ENTRY_FLAG_ATTACHED),
6193 tm->hw[0]->sw_if_index,
6197 FIB_ROUTE_PATH_FLAG_NONE);
6198 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6199 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6200 "attached interface route present");
6202 local0_pfx.fp_len = 32;
6203 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6204 FIB_SOURCE_INTERFACE,
6205 (FIB_ENTRY_FLAG_CONNECTED |
6206 FIB_ENTRY_FLAG_LOCAL),
6209 tm->hw[0]->sw_if_index,
6210 ~0, // invalid fib index
6213 FIB_ROUTE_PATH_FLAG_NONE);
6214 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6216 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6217 "local interface route present");
6219 fib_prefix_t local1_pfx = {
6221 .fp_proto = FIB_PROTOCOL_IP4,
6225 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6230 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6231 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6233 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6234 FIB_SOURCE_INTERFACE,
6235 (FIB_ENTRY_FLAG_CONNECTED |
6236 FIB_ENTRY_FLAG_ATTACHED),
6239 tm->hw[1]->sw_if_index,
6243 FIB_ROUTE_PATH_FLAG_NONE);
6244 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6245 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6246 "attached interface route present");
6248 local1_pfx.fp_len = 32;
6249 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6250 FIB_SOURCE_INTERFACE,
6251 (FIB_ENTRY_FLAG_CONNECTED |
6252 FIB_ENTRY_FLAG_LOCAL),
6255 tm->hw[1]->sw_if_index,
6256 ~0, // invalid fib index
6259 FIB_ROUTE_PATH_FLAG_NONE);
6260 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6262 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6263 "local interface route present");
6265 ip46_address_t nh_10_10_10_1 = {
6267 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6270 ip46_address_t nh_10_10_11_1 = {
6272 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6275 ip46_address_t nh_10_10_11_2 = {
6277 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6281 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6284 tm->hw[1]->sw_if_index);
6285 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6288 tm->hw[1]->sw_if_index);
6289 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6292 tm->hw[0]->sw_if_index);
6293 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6296 tm->hw[1]->sw_if_index);
6297 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6300 tm->hw[1]->sw_if_index);
6303 * Add an etry with one path with a real out-going label
6305 fib_prefix_t pfx_1_1_1_1_s_32 = {
6307 .fp_proto = FIB_PROTOCOL_IP4,
6309 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6312 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6313 .type = FT_LB_LABEL_O_ADJ,
6315 .adj = ai_mpls_10_10_10_1,
6320 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6321 .type = FT_LB_LABEL_O_ADJ,
6323 .adj = ai_mpls_10_10_10_1,
6325 .eos = MPLS_NON_EOS,
6328 mpls_label_t *l99 = NULL;
6331 fib_table_entry_update_one_path(fib_index,
6334 FIB_ENTRY_FLAG_NONE,
6337 tm->hw[0]->sw_if_index,
6338 ~0, // invalid fib index
6341 FIB_ROUTE_PATH_FLAG_NONE);
6343 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6344 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6346 FIB_TEST(fib_test_validate_entry(fei,
6347 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6349 &l99_eos_o_10_10_10_1),
6350 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6353 * add a path with an implicit NULL label
6355 fib_test_lb_bucket_t a_o_10_10_11_1 = {
6358 .adj = ai_v4_10_10_11_1,
6361 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6364 .adj = ai_mpls_10_10_11_1,
6367 mpls_label_t *l_imp_null = NULL;
6368 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6370 fei = fib_table_entry_path_add(fib_index,
6373 FIB_ENTRY_FLAG_NONE,
6376 tm->hw[1]->sw_if_index,
6377 ~0, // invalid fib index
6380 FIB_ROUTE_PATH_FLAG_NONE);
6382 FIB_TEST(fib_test_validate_entry(fei,
6383 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6385 &l99_eos_o_10_10_10_1,
6387 "1.1.1.1/32 LB 2 buckets via: "
6388 "label 99 over 10.10.10.1, "
6389 "adj over 10.10.11.1");
6392 * assign the route a local label
6394 fib_table_entry_local_label_add(fib_index,
6398 fib_prefix_t pfx_24001_eos = {
6399 .fp_proto = FIB_PROTOCOL_MPLS,
6403 fib_prefix_t pfx_24001_neos = {
6404 .fp_proto = FIB_PROTOCOL_MPLS,
6406 .fp_eos = MPLS_NON_EOS,
6408 fib_test_lb_bucket_t disp_o_10_10_11_1 = {
6409 .type = FT_LB_MPLS_DISP_O_ADJ,
6411 .adj = ai_v4_10_10_11_1,
6416 * The EOS entry should link to both the paths,
6417 * and use an ip adj for the imp-null
6418 * The NON-EOS entry should link to both the paths,
6419 * and use an mpls adj for the imp-null
6421 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6423 FIB_TEST(fib_test_validate_entry(fei,
6424 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6426 &l99_eos_o_10_10_10_1,
6427 &disp_o_10_10_11_1),
6428 "24001/eos LB 2 buckets via: "
6429 "label 99 over 10.10.10.1, "
6430 "mpls disp adj over 10.10.11.1");
6433 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6435 FIB_TEST(fib_test_validate_entry(fei,
6436 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6438 &l99_neos_o_10_10_10_1,
6439 &a_mpls_o_10_10_11_1),
6440 "24001/neos LB 1 bucket via: "
6441 "label 99 over 10.10.10.1 ",
6442 "mpls-adj via 10.10.11.1");
6445 * add an unlabelled path, this is excluded from the neos chains,
6447 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6450 .adj = ai_v4_10_10_11_2,
6453 fib_test_lb_bucket_t disp_o_10_10_11_2 = {
6454 .type = FT_LB_MPLS_DISP_O_ADJ,
6456 .adj = ai_v4_10_10_11_2,
6461 fei = fib_table_entry_path_add(fib_index,
6464 FIB_ENTRY_FLAG_NONE,
6467 tm->hw[1]->sw_if_index,
6468 ~0, // invalid fib index
6471 FIB_ROUTE_PATH_FLAG_NONE);
6473 FIB_TEST(fib_test_validate_entry(fei,
6474 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6475 16, // 3 choices spread over 16 buckets
6476 &l99_eos_o_10_10_10_1,
6477 &l99_eos_o_10_10_10_1,
6478 &l99_eos_o_10_10_10_1,
6479 &l99_eos_o_10_10_10_1,
6480 &l99_eos_o_10_10_10_1,
6481 &l99_eos_o_10_10_10_1,
6492 "1.1.1.1/32 LB 16 buckets via: "
6493 "label 99 over 10.10.10.1, "
6494 "adj over 10.10.11.1",
6495 "adj over 10.10.11.2");
6498 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6500 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6501 fib_entry_contribute_forwarding(fei,
6502 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6506 * n-eos has only the 2 labelled paths
6508 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6511 FIB_TEST(fib_test_validate_entry(fei,
6512 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6514 &l99_neos_o_10_10_10_1,
6515 &a_mpls_o_10_10_11_1),
6516 "24001/neos LB 2 buckets via: "
6517 "label 99 over 10.10.10.1, "
6518 "adj-mpls over 10.10.11.2");
6521 * A labelled recursive
6523 fib_prefix_t pfx_2_2_2_2_s_32 = {
6525 .fp_proto = FIB_PROTOCOL_IP4,
6527 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6530 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6531 .type = FT_LB_LABEL_O_LB,
6533 .lb = non_eos_1_1_1_1.dpoi_index,
6538 mpls_label_t *l1600 = NULL;
6539 vec_add1(l1600, 1600);
6541 fib_table_entry_update_one_path(fib_index,
6544 FIB_ENTRY_FLAG_NONE,
6546 &pfx_1_1_1_1_s_32.fp_addr,
6551 FIB_ROUTE_PATH_FLAG_NONE);
6553 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6554 FIB_TEST(fib_test_validate_entry(fei,
6555 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6557 &l1600_eos_o_1_1_1_1),
6558 "2.2.2.2.2/32 LB 1 buckets via: "
6559 "label 1600 over 1.1.1.1");
6561 dpo_id_t dpo_44 = DPO_INVALID;
6564 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6565 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6567 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6568 "uRPF check for 2.2.2.2/32 on %d OK",
6569 tm->hw[0]->sw_if_index);
6570 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6571 "uRPF check for 2.2.2.2/32 on %d OK",
6572 tm->hw[1]->sw_if_index);
6573 FIB_TEST(!fib_urpf_check(urpfi, 99),
6574 "uRPF check for 2.2.2.2/32 on 99 not-OK",
6577 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6578 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6579 "Shared uRPF on IP and non-EOS chain");
6584 * we are holding a lock on the non-eos LB of the via-entry.
6585 * do a PIC-core failover by shutting the link of the via-entry.
6587 * shut down the link with the valid label
6589 vnet_sw_interface_set_flags(vnet_get_main(),
6590 tm->hw[0]->sw_if_index,
6593 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6594 FIB_TEST(fib_test_validate_entry(fei,
6595 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6599 "1.1.1.1/32 LB 2 buckets via: "
6600 "adj over 10.10.11.1, ",
6601 "adj-v4 over 10.10.11.2");
6603 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6605 FIB_TEST(fib_test_validate_entry(fei,
6606 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6609 &disp_o_10_10_11_2),
6610 "24001/eos LB 2 buckets via: "
6611 "mpls-disp adj over 10.10.11.1, ",
6612 "mpls-disp adj-v4 over 10.10.11.2");
6614 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6616 FIB_TEST(fib_test_validate_entry(fei,
6617 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6619 &a_mpls_o_10_10_11_1),
6620 "24001/neos LB 1 buckets via: "
6621 "adj-mpls over 10.10.11.2");
6624 * test that the pre-failover load-balance has been in-place
6627 dpo_id_t current = DPO_INVALID;
6628 fib_entry_contribute_forwarding(fei,
6629 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6632 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6634 "PIC-core LB inplace modified %U %U",
6635 format_dpo_id, &non_eos_1_1_1_1, 0,
6636 format_dpo_id, ¤t, 0);
6638 dpo_reset(&non_eos_1_1_1_1);
6639 dpo_reset(¤t);
6642 * no-shut the link with the valid label
6644 vnet_sw_interface_set_flags(vnet_get_main(),
6645 tm->hw[0]->sw_if_index,
6646 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6648 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6649 FIB_TEST(fib_test_validate_entry(fei,
6650 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6651 16, // 3 choices spread over 16 buckets
6652 &l99_eos_o_10_10_10_1,
6653 &l99_eos_o_10_10_10_1,
6654 &l99_eos_o_10_10_10_1,
6655 &l99_eos_o_10_10_10_1,
6656 &l99_eos_o_10_10_10_1,
6657 &l99_eos_o_10_10_10_1,
6668 "1.1.1.1/32 LB 16 buckets via: "
6669 "label 99 over 10.10.10.1, "
6670 "adj over 10.10.11.1",
6671 "adj-v4 over 10.10.11.2");
6674 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6676 FIB_TEST(fib_test_validate_entry(fei,
6677 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6678 16, // 3 choices spread over 16 buckets
6679 &l99_eos_o_10_10_10_1,
6680 &l99_eos_o_10_10_10_1,
6681 &l99_eos_o_10_10_10_1,
6682 &l99_eos_o_10_10_10_1,
6683 &l99_eos_o_10_10_10_1,
6684 &l99_eos_o_10_10_10_1,
6694 &disp_o_10_10_11_2),
6695 "24001/eos LB 16 buckets via: "
6696 "label 99 over 10.10.10.1, "
6697 "MPLS disp adj over 10.10.11.1",
6698 "MPLS disp adj-v4 over 10.10.11.2");
6700 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6702 FIB_TEST(fib_test_validate_entry(fei,
6703 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6705 &l99_neos_o_10_10_10_1,
6706 &a_mpls_o_10_10_11_1),
6707 "24001/neos LB 2 buckets via: "
6708 "label 99 over 10.10.10.1, "
6709 "adj-mpls over 10.10.11.2");
6712 * remove the first path with the valid label
6714 fib_table_entry_path_remove(fib_index,
6719 tm->hw[0]->sw_if_index,
6720 ~0, // invalid fib index
6722 FIB_ROUTE_PATH_FLAG_NONE);
6724 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6725 FIB_TEST(fib_test_validate_entry(fei,
6726 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6730 "1.1.1.1/32 LB 2 buckets via: "
6731 "adj over 10.10.11.1, "
6732 "adj-v4 over 10.10.11.2");
6734 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6736 FIB_TEST(fib_test_validate_entry(fei,
6737 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6740 &disp_o_10_10_11_2),
6741 "24001/eos LB 2 buckets via: "
6742 "MPLS disp adj over 10.10.11.1, "
6743 "MPLS disp adj-v4 over 10.10.11.2");
6745 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6748 FIB_TEST(fib_test_validate_entry(fei,
6749 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6751 &a_mpls_o_10_10_11_1),
6752 "24001/neos LB 1 buckets via: "
6753 "adj-mpls over 10.10.11.2");
6756 * remove the other path with a valid label
6758 fib_test_lb_bucket_t bucket_drop = {
6761 fib_test_lb_bucket_t mpls_bucket_drop = {
6764 .adj = DPO_PROTO_MPLS,
6768 fib_table_entry_path_remove(fib_index,
6773 tm->hw[1]->sw_if_index,
6774 ~0, // invalid fib index
6776 FIB_ROUTE_PATH_FLAG_NONE);
6778 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6779 FIB_TEST(fib_test_validate_entry(fei,
6780 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6783 "1.1.1.1/32 LB 1 buckets via: "
6784 "adj over 10.10.11.2");
6786 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6788 FIB_TEST(fib_test_validate_entry(fei,
6789 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6791 &disp_o_10_10_11_2),
6792 "24001/eos LB 1 buckets via: "
6793 "MPLS disp adj over 10.10.11.2");
6795 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6797 FIB_TEST(fib_test_validate_entry(fei,
6798 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6801 "24001/neos LB 1 buckets via: DROP");
6804 * add back the path with the valid label
6809 fib_table_entry_path_add(fib_index,
6812 FIB_ENTRY_FLAG_NONE,
6815 tm->hw[0]->sw_if_index,
6816 ~0, // invalid fib index
6819 FIB_ROUTE_PATH_FLAG_NONE);
6821 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6822 FIB_TEST(fib_test_validate_entry(fei,
6823 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6825 &l99_eos_o_10_10_10_1,
6827 "1.1.1.1/32 LB 2 buckets via: "
6828 "label 99 over 10.10.10.1, "
6829 "adj over 10.10.11.2");
6831 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6833 FIB_TEST(fib_test_validate_entry(fei,
6834 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6836 &l99_eos_o_10_10_10_1,
6837 &disp_o_10_10_11_2),
6838 "24001/eos LB 2 buckets via: "
6839 "label 99 over 10.10.10.1, "
6840 "MPLS disp adj over 10.10.11.2");
6842 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6844 FIB_TEST(fib_test_validate_entry(fei,
6845 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6847 &l99_neos_o_10_10_10_1),
6848 "24001/neos LB 1 buckets via: "
6849 "label 99 over 10.10.10.1");
6852 * change the local label
6854 fib_table_entry_local_label_add(fib_index,
6858 fib_prefix_t pfx_25005_eos = {
6859 .fp_proto = FIB_PROTOCOL_MPLS,
6863 fib_prefix_t pfx_25005_neos = {
6864 .fp_proto = FIB_PROTOCOL_MPLS,
6866 .fp_eos = MPLS_NON_EOS,
6869 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6870 fib_table_lookup(fib_index, &pfx_24001_eos)),
6871 "24001/eos removed after label change");
6872 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6873 fib_table_lookup(fib_index, &pfx_24001_neos)),
6874 "24001/eos removed after label change");
6876 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6878 FIB_TEST(fib_test_validate_entry(fei,
6879 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6881 &l99_eos_o_10_10_10_1,
6882 &disp_o_10_10_11_2),
6883 "25005/eos LB 2 buckets via: "
6884 "label 99 over 10.10.10.1, "
6885 "MPLS disp adj over 10.10.11.2");
6887 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6889 FIB_TEST(fib_test_validate_entry(fei,
6890 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6892 &l99_neos_o_10_10_10_1),
6893 "25005/neos LB 1 buckets via: "
6894 "label 99 over 10.10.10.1");
6897 * remove the local label.
6898 * the check that the MPLS entries are gone is done by the fact the
6899 * MPLS table is no longer present.
6901 fib_table_entry_local_label_remove(fib_index,
6905 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6906 FIB_TEST(fib_test_validate_entry(fei,
6907 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6909 &l99_eos_o_10_10_10_1,
6911 "24001/eos LB 2 buckets via: "
6912 "label 99 over 10.10.10.1, "
6913 "adj over 10.10.11.2");
6915 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6916 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6917 "No more MPLS FIB entries => table removed");
6920 * add another via-entry for the recursive
6922 fib_prefix_t pfx_1_1_1_2_s_32 = {
6924 .fp_proto = FIB_PROTOCOL_IP4,
6926 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6929 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6930 .type = FT_LB_LABEL_O_ADJ,
6932 .adj = ai_mpls_10_10_10_1,
6937 mpls_label_t *l101 = NULL;
6938 vec_add1(l101, 101);
6940 fei = fib_table_entry_update_one_path(fib_index,
6943 FIB_ENTRY_FLAG_NONE,
6946 tm->hw[0]->sw_if_index,
6947 ~0, // invalid fib index
6950 FIB_ROUTE_PATH_FLAG_NONE);
6952 FIB_TEST(fib_test_validate_entry(fei,
6953 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6955 &l101_eos_o_10_10_10_1),
6956 "1.1.1.2/32 LB 1 buckets via: "
6957 "label 101 over 10.10.10.1");
6959 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6960 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6962 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6964 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6966 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6969 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6970 .type = FT_LB_LABEL_O_LB,
6972 .lb = non_eos_1_1_1_2.dpoi_index,
6977 mpls_label_t *l1601 = NULL;
6978 vec_add1(l1601, 1601);
6980 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6982 fei = fib_table_entry_path_add(fib_index,
6985 FIB_ENTRY_FLAG_NONE,
6987 &pfx_1_1_1_2_s_32.fp_addr,
6992 FIB_ROUTE_PATH_FLAG_NONE);
6994 FIB_TEST(fib_test_validate_entry(fei,
6995 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6997 &l1600_eos_o_1_1_1_1,
6998 &l1601_eos_o_1_1_1_2),
6999 "2.2.2.2/32 LB 2 buckets via: "
7000 "label 1600 via 1.1,1.1, "
7001 "label 16001 via 1.1.1.2");
7004 * update the via-entry so it no longer has an imp-null path.
7005 * the LB for the recursive can use an imp-null
7008 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
7010 fei = fib_table_entry_update_one_path(fib_index,
7013 FIB_ENTRY_FLAG_NONE,
7016 tm->hw[1]->sw_if_index,
7017 ~0, // invalid fib index
7020 FIB_ROUTE_PATH_FLAG_NONE);
7022 FIB_TEST(fib_test_validate_entry(fei,
7023 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7026 "1.1.1.2/32 LB 1 buckets via: "
7029 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7030 FIB_TEST(fib_test_validate_entry(fei,
7031 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7033 &l1600_eos_o_1_1_1_1,
7034 &l1601_eos_o_1_1_1_2),
7035 "2.2.2.2/32 LB 2 buckets via: "
7036 "label 1600 via 1.1,1.1, "
7037 "label 16001 via 1.1.1.2");
7040 * update the via-entry so it no longer has labelled paths.
7041 * the LB for the recursive should exclue this via form its LB
7043 fei = fib_table_entry_update_one_path(fib_index,
7046 FIB_ENTRY_FLAG_NONE,
7049 tm->hw[1]->sw_if_index,
7050 ~0, // invalid fib index
7053 FIB_ROUTE_PATH_FLAG_NONE);
7055 FIB_TEST(fib_test_validate_entry(fei,
7056 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7059 "1.1.1.2/32 LB 1 buckets via: "
7062 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7063 FIB_TEST(fib_test_validate_entry(fei,
7064 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7066 &l1600_eos_o_1_1_1_1),
7067 "2.2.2.2/32 LB 1 buckets via: "
7068 "label 1600 via 1.1,1.1");
7070 dpo_reset(&non_eos_1_1_1_1);
7071 dpo_reset(&non_eos_1_1_1_2);
7074 * Add a recursive with no out-labels. We expect to use the IP of the via
7076 fib_prefix_t pfx_2_2_2_3_s_32 = {
7078 .fp_proto = FIB_PROTOCOL_IP4,
7080 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7083 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
7085 fib_table_entry_update_one_path(fib_index,
7088 FIB_ENTRY_FLAG_NONE,
7090 &pfx_1_1_1_1_s_32.fp_addr,
7095 FIB_ROUTE_PATH_FLAG_NONE);
7097 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7099 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7102 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7105 .lb = ip_1_1_1_1.dpoi_index,
7109 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7110 FIB_TEST(fib_test_validate_entry(fei,
7111 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7114 "2.2.2.2.3/32 LB 1 buckets via: "
7118 * Add a recursive with an imp-null out-label.
7119 * We expect to use the IP of the via
7121 fib_prefix_t pfx_2_2_2_4_s_32 = {
7123 .fp_proto = FIB_PROTOCOL_IP4,
7125 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7129 fib_table_entry_update_one_path(fib_index,
7132 FIB_ENTRY_FLAG_NONE,
7134 &pfx_1_1_1_1_s_32.fp_addr,
7139 FIB_ROUTE_PATH_FLAG_NONE);
7141 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7142 FIB_TEST(fib_test_validate_entry(fei,
7143 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7146 "2.2.2.2.4/32 LB 1 buckets via: "
7149 dpo_reset(&ip_1_1_1_1);
7152 * Create an entry with a deep label stack
7154 fib_prefix_t pfx_2_2_5_5_s_32 = {
7156 .fp_proto = FIB_PROTOCOL_IP4,
7158 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7161 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7162 .type = FT_LB_LABEL_STACK_O_ADJ,
7163 .label_stack_o_adj = {
7164 .adj = ai_mpls_10_10_11_1,
7165 .label_stack_size = 8,
7167 200, 201, 202, 203, 204, 205, 206, 207
7172 mpls_label_t *label_stack = NULL;
7173 vec_validate(label_stack, 7);
7174 for (ii = 0; ii < 8; ii++)
7176 label_stack[ii] = ii + 200;
7179 fei = fib_table_entry_update_one_path(fib_index,
7182 FIB_ENTRY_FLAG_NONE,
7185 tm->hw[1]->sw_if_index,
7186 ~0, // invalid fib index
7189 FIB_ROUTE_PATH_FLAG_NONE);
7191 FIB_TEST(fib_test_validate_entry(fei,
7192 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7194 &ls_eos_o_10_10_10_1),
7195 "2.2.5.5/32 LB 1 buckets via: "
7197 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7202 fib_table_entry_delete(fib_index,
7206 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7207 FIB_TEST(fib_test_validate_entry(fei,
7208 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7210 &l1600_eos_o_1_1_1_1),
7211 "2.2.2.2/32 LB 1 buckets via: "
7212 "label 1600 via 1.1,1.1");
7214 fib_table_entry_delete(fib_index,
7218 FIB_TEST(fib_test_validate_entry(fei,
7219 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7222 "2.2.2.2/32 LB 1 buckets via: DROP");
7224 fib_table_entry_delete(fib_index,
7227 fib_table_entry_delete(fib_index,
7230 fib_table_entry_delete(fib_index,
7234 adj_unlock(ai_mpls_10_10_10_1);
7235 adj_unlock(ai_mpls_10_10_11_2);
7236 adj_unlock(ai_v4_10_10_11_1);
7237 adj_unlock(ai_v4_10_10_11_2);
7238 adj_unlock(ai_mpls_10_10_11_1);
7240 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7243 local0_pfx.fp_len = 32;
7244 fib_table_entry_delete(fib_index,
7246 FIB_SOURCE_INTERFACE);
7247 local0_pfx.fp_len = 24;
7248 fib_table_entry_delete(fib_index,
7250 FIB_SOURCE_INTERFACE);
7251 local1_pfx.fp_len = 32;
7252 fib_table_entry_delete(fib_index,
7254 FIB_SOURCE_INTERFACE);
7255 local1_pfx.fp_len = 24;
7256 fib_table_entry_delete(fib_index,
7258 FIB_SOURCE_INTERFACE);
7261 * +1 for the drop LB in the MPLS tables.
7263 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7264 "Load-balance resources freed %d of %d",
7265 lb_count+1, pool_elts(load_balance_pool));
7270 #define N_TEST_CHILDREN 4
7271 #define PARENT_INDEX 0
7273 typedef struct fib_node_test_t_
7278 fib_node_back_walk_ctx_t *ctxs;
7282 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7284 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7286 #define FOR_EACH_TEST_CHILD(_tc) \
7287 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
7288 ii < N_TEST_CHILDREN+1; \
7289 ii++, (_tc) = &fib_test_nodes[ii])
7292 fib_test_child_get_node (fib_node_index_t index)
7294 return (&fib_test_nodes[index].node);
7297 static int fib_test_walk_spawns_walks;
7299 static fib_node_back_walk_rc_t
7300 fib_test_child_back_walk_notify (fib_node_t *node,
7301 fib_node_back_walk_ctx_t *ctx)
7303 fib_node_test_t *tc = (fib_node_test_t*) node;
7305 vec_add1(tc->ctxs, *ctx);
7307 if (1 == fib_test_walk_spawns_walks)
7308 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7309 if (2 == fib_test_walk_spawns_walks)
7310 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7311 FIB_WALK_PRIORITY_HIGH, ctx);
7313 return (FIB_NODE_BACK_WALK_CONTINUE);
7317 fib_test_child_last_lock_gone (fib_node_t *node)
7319 fib_node_test_t *tc = (fib_node_test_t *)node;
7325 * The FIB walk's graph node virtual function table
7327 static const fib_node_vft_t fib_test_child_vft = {
7328 .fnv_get = fib_test_child_get_node,
7329 .fnv_last_lock = fib_test_child_last_lock_gone,
7330 .fnv_back_walk = fib_test_child_back_walk_notify,
7334 * the function (that should have been static but isn't so I can do this)
7335 * that processes the walk from the async queue,
7337 f64 fib_walk_process_queues(vlib_main_t * vm,
7339 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7342 fib_test_walk (void)
7344 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7345 fib_node_test_t *tc;
7349 vm = vlib_get_main();
7350 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7353 * init a fake node on which we will add children
7355 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7356 FIB_NODE_TYPE_TEST);
7358 FOR_EACH_TEST_CHILD(tc)
7360 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7361 fib_node_lock(&tc->node);
7364 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7366 FIB_NODE_TYPE_TEST, ii);
7370 * enqueue a walk across the parents children.
7372 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7374 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7375 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7376 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7377 "Parent has %d children pre-walk",
7378 fib_node_list_get_size(PARENT()->fn_children));
7381 * give the walk a large amount of time so it gets to the end
7383 fib_walk_process_queues(vm, 1);
7385 FOR_EACH_TEST_CHILD(tc)
7387 FIB_TEST(1 == vec_len(tc->ctxs),
7388 "%d child visitsed %d times",
7389 ii, vec_len(tc->ctxs));
7392 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7393 "Queue is empty post walk");
7394 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7395 "Parent has %d children post walk",
7396 fib_node_list_get_size(PARENT()->fn_children));
7399 * walk again. should be no increase in the number of visits, since
7400 * the walk will have terminated.
7402 fib_walk_process_queues(vm, 1);
7404 FOR_EACH_TEST_CHILD(tc)
7406 FIB_TEST(0 == vec_len(tc->ctxs),
7407 "%d child visitsed %d times",
7408 ii, vec_len(tc->ctxs));
7412 * schedule a low and hig priority walk. expect the high to be performed
7414 * schedule the high prio walk first so that it is further from the head
7415 * of the dependency list. that way it won't merge with the low one.
7417 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7418 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7420 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7421 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7422 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7423 FIB_WALK_PRIORITY_LOW, &low_ctx);
7425 fib_walk_process_queues(vm, 1);
7427 FOR_EACH_TEST_CHILD(tc)
7429 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7430 "%d child visitsed by high prio walk", ii);
7431 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7432 "%d child visitsed by low prio walk", ii);
7435 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7436 "Queue is empty post prio walk");
7437 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7438 "Parent has %d children post prio walk",
7439 fib_node_list_get_size(PARENT()->fn_children));
7442 * schedule 2 walks of the same priority that can be megred.
7443 * expect that each child is thus visited only once.
7445 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7446 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7448 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7449 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7450 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7451 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7453 fib_walk_process_queues(vm, 1);
7455 FOR_EACH_TEST_CHILD(tc)
7457 FIB_TEST(1 == vec_len(tc->ctxs),
7458 "%d child visitsed %d times during merge walk",
7459 ii, vec_len(tc->ctxs));
7462 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7463 "Queue is empty post merge walk");
7464 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7465 "Parent has %d children post merge walk",
7466 fib_node_list_get_size(PARENT()->fn_children));
7469 * schedule 2 walks of the same priority that cannot be megred.
7470 * expect that each child is thus visited twice and in the order
7471 * in which the walks were scheduled.
7473 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7474 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7476 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7477 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7478 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7479 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7481 fib_walk_process_queues(vm, 1);
7483 FOR_EACH_TEST_CHILD(tc)
7485 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7486 "%d child visitsed by high prio walk", ii);
7487 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7488 "%d child visitsed by low prio walk", ii);
7491 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7492 "Queue is empty post no-merge walk");
7493 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7494 "Parent has %d children post no-merge walk",
7495 fib_node_list_get_size(PARENT()->fn_children));
7498 * schedule a walk that makes one one child progress.
7499 * we do this by giving the queue draining process zero
7500 * time quanta. it's a do..while loop, so it does something.
7502 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7504 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7505 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7506 fib_walk_process_queues(vm, 0);
7508 FOR_EACH_TEST_CHILD(tc)
7510 if (ii == N_TEST_CHILDREN)
7512 FIB_TEST(1 == vec_len(tc->ctxs),
7513 "%d child visitsed %d times in zero quanta walk",
7514 ii, vec_len(tc->ctxs));
7518 FIB_TEST(0 == vec_len(tc->ctxs),
7519 "%d child visitsed %d times in 0 quanta walk",
7520 ii, vec_len(tc->ctxs));
7523 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7524 "Queue is not empty post zero quanta walk");
7525 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7526 "Parent has %d children post zero qunta walk",
7527 fib_node_list_get_size(PARENT()->fn_children));
7532 fib_walk_process_queues(vm, 0);
7534 FOR_EACH_TEST_CHILD(tc)
7536 if (ii >= N_TEST_CHILDREN-1)
7538 FIB_TEST(1 == vec_len(tc->ctxs),
7539 "%d child visitsed %d times in 2nd zero quanta walk",
7540 ii, vec_len(tc->ctxs));
7544 FIB_TEST(0 == vec_len(tc->ctxs),
7545 "%d child visitsed %d times in 2nd 0 quanta walk",
7546 ii, vec_len(tc->ctxs));
7549 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7550 "Queue is not empty post zero quanta walk");
7551 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7552 "Parent has %d children post zero qunta walk",
7553 fib_node_list_get_size(PARENT()->fn_children));
7556 * schedule another walk that will catch-up and merge.
7558 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7559 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7560 fib_walk_process_queues(vm, 1);
7562 FOR_EACH_TEST_CHILD(tc)
7564 if (ii >= N_TEST_CHILDREN-1)
7566 FIB_TEST(2 == vec_len(tc->ctxs),
7567 "%d child visitsed %d times in 2nd zero quanta merge walk",
7568 ii, vec_len(tc->ctxs));
7573 FIB_TEST(1 == vec_len(tc->ctxs),
7574 "%d child visitsed %d times in 2nd 0 quanta merge walk",
7575 ii, vec_len(tc->ctxs));
7579 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7580 "Queue is not empty post 2nd zero quanta merge walk");
7581 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7582 "Parent has %d children post 2nd zero qunta merge walk",
7583 fib_node_list_get_size(PARENT()->fn_children));
7586 * park a async walk in the middle of the list, then have an sync walk catch
7587 * it. same expectations as async catches async.
7589 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7591 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7592 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7594 fib_walk_process_queues(vm, 0);
7595 fib_walk_process_queues(vm, 0);
7597 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7599 FOR_EACH_TEST_CHILD(tc)
7601 if (ii >= N_TEST_CHILDREN-1)
7603 FIB_TEST(2 == vec_len(tc->ctxs),
7604 "%d child visitsed %d times in sync catches async walk",
7605 ii, vec_len(tc->ctxs));
7610 FIB_TEST(1 == vec_len(tc->ctxs),
7611 "%d child visitsed %d times in sync catches async walk",
7612 ii, vec_len(tc->ctxs));
7616 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7617 "Queue is not empty post 2nd zero quanta merge walk");
7618 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7619 "Parent has %d children post 2nd zero qunta merge walk",
7620 fib_node_list_get_size(PARENT()->fn_children));
7623 * make the parent a child of one of its children, thus inducing a routing loop.
7625 fib_test_nodes[PARENT_INDEX].sibling =
7626 fib_node_child_add(FIB_NODE_TYPE_TEST,
7627 1, // the first child
7632 * execute a sync walk from the parent. each child visited spawns more sync
7633 * walks. we expect the walk to terminate.
7635 fib_test_walk_spawns_walks = 1;
7637 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7639 FOR_EACH_TEST_CHILD(tc)
7642 * child 1 - which is last in the list - has the loop.
7643 * the other children a re thus visitsed first. the we meet
7644 * child 1. we go round the loop again, visting the other children.
7645 * then we meet the walk in the dep list and bail. child 1 is not visitsed
7650 FIB_TEST(1 == vec_len(tc->ctxs),
7651 "child %d visitsed %d times during looped sync walk",
7652 ii, vec_len(tc->ctxs));
7656 FIB_TEST(2 == vec_len(tc->ctxs),
7657 "child %d visitsed %d times during looped sync walk",
7658 ii, vec_len(tc->ctxs));
7662 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7663 "Parent has %d children post sync loop walk",
7664 fib_node_list_get_size(PARENT()->fn_children));
7667 * the walk doesn't reach the max depth because the infra knows that sync
7668 * meets sync implies a loop and bails early.
7670 FIB_TEST(high_ctx.fnbw_depth == 9,
7671 "Walk context depth %d post sync loop walk",
7672 high_ctx.fnbw_depth);
7675 * execute an async walk of the graph loop, with each child spawns sync walks
7677 high_ctx.fnbw_depth = 0;
7678 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7679 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7681 fib_walk_process_queues(vm, 1);
7683 FOR_EACH_TEST_CHILD(tc)
7686 * we don't really care how many times the children are visisted, as long as
7687 * it is more than once.
7689 FIB_TEST(1 <= vec_len(tc->ctxs),
7690 "child %d visitsed %d times during looped aync spawns sync walk",
7691 ii, vec_len(tc->ctxs));
7696 * execute an async walk of the graph loop, with each child spawns async walks
7698 fib_test_walk_spawns_walks = 2;
7699 high_ctx.fnbw_depth = 0;
7700 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7701 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7703 fib_walk_process_queues(vm, 1);
7705 FOR_EACH_TEST_CHILD(tc)
7708 * we don't really care how many times the children are visisted, as long as
7709 * it is more than once.
7711 FIB_TEST(1 <= vec_len(tc->ctxs),
7712 "child %d visitsed %d times during looped async spawns async walk",
7713 ii, vec_len(tc->ctxs));
7718 fib_node_child_remove(FIB_NODE_TYPE_TEST,
7719 1, // the first child
7720 fib_test_nodes[PARENT_INDEX].sibling);
7725 FOR_EACH_TEST_CHILD(tc)
7727 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7729 fib_node_deinit(&tc->node);
7730 fib_node_unlock(&tc->node);
7732 fib_node_deinit(PARENT());
7735 * The parent will be destroyed when the last lock on it goes.
7736 * this test ensures all the walk objects are unlocking it.
7738 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7739 "Parent was destroyed");
7745 * declaration of the otherwise static callback functions
7747 void fib_bfd_notify (bfd_listen_event_e event,
7748 const bfd_session_t *session);
7749 void adj_bfd_notify (bfd_listen_event_e event,
7750 const bfd_session_t *session);
7753 * Test BFD session interaction with FIB
7758 fib_node_index_t fei;
7762 /* via 10.10.10.1 */
7763 ip46_address_t nh_10_10_10_1 = {
7764 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7766 /* via 10.10.10.2 */
7767 ip46_address_t nh_10_10_10_2 = {
7768 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7770 /* via 10.10.10.10 */
7771 ip46_address_t nh_10_10_10_10 = {
7772 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7774 n_feis = fib_entry_pool_size();
7779 * add interface routes. we'll assume this works. it's tested elsewhere
7781 fib_prefix_t pfx_10_10_10_10_s_24 = {
7783 .fp_proto = FIB_PROTOCOL_IP4,
7784 .fp_addr = nh_10_10_10_10,
7787 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7788 FIB_SOURCE_INTERFACE,
7789 (FIB_ENTRY_FLAG_CONNECTED |
7790 FIB_ENTRY_FLAG_ATTACHED),
7793 tm->hw[0]->sw_if_index,
7794 ~0, // invalid fib index
7797 FIB_ROUTE_PATH_FLAG_NONE);
7799 fib_prefix_t pfx_10_10_10_10_s_32 = {
7801 .fp_proto = FIB_PROTOCOL_IP4,
7802 .fp_addr = nh_10_10_10_10,
7804 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7805 FIB_SOURCE_INTERFACE,
7806 (FIB_ENTRY_FLAG_CONNECTED |
7807 FIB_ENTRY_FLAG_LOCAL),
7810 tm->hw[0]->sw_if_index,
7811 ~0, // invalid fib index
7814 FIB_ROUTE_PATH_FLAG_NONE);
7817 * A BFD session via a neighbour we do not yet know
7819 bfd_session_t bfd_10_10_10_1 = {
7823 .peer_addr = nh_10_10_10_1,
7826 .hop_type = BFD_HOP_TYPE_MULTI,
7827 .local_state = BFD_STATE_init,
7830 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7833 * A new entry will be created that forwards via the adj
7835 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7838 tm->hw[0]->sw_if_index);
7839 fib_prefix_t pfx_10_10_10_1_s_32 = {
7840 .fp_addr = nh_10_10_10_1,
7842 .fp_proto = FIB_PROTOCOL_IP4,
7844 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7847 .adj = ai_10_10_10_1,
7851 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7852 FIB_TEST(fib_test_validate_entry(fei,
7853 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7856 "BFD sourced %U via %U",
7857 format_fib_prefix, &pfx_10_10_10_1_s_32,
7858 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7861 * Delete the BFD session. Expect the fib_entry to be removed
7863 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7865 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7866 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7867 "BFD sourced %U removed",
7868 format_fib_prefix, &pfx_10_10_10_1_s_32);
7871 * Add the BFD source back
7873 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7876 * source the entry via the ADJ fib
7878 fei = fib_table_entry_path_add(0,
7879 &pfx_10_10_10_1_s_32,
7881 FIB_ENTRY_FLAG_ATTACHED,
7884 tm->hw[0]->sw_if_index,
7885 ~0, // invalid fib index
7888 FIB_ROUTE_PATH_FLAG_NONE);
7891 * Delete the BFD session. Expect the fib_entry to remain
7893 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7895 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7896 FIB_TEST(fib_test_validate_entry(fei,
7897 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7900 "BFD sourced %U remains via %U",
7901 format_fib_prefix, &pfx_10_10_10_1_s_32,
7902 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7905 * Add the BFD source back
7907 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7910 * Create another ADJ FIB
7912 fib_prefix_t pfx_10_10_10_2_s_32 = {
7913 .fp_addr = nh_10_10_10_2,
7915 .fp_proto = FIB_PROTOCOL_IP4,
7917 fib_table_entry_path_add(0,
7918 &pfx_10_10_10_2_s_32,
7920 FIB_ENTRY_FLAG_ATTACHED,
7923 tm->hw[0]->sw_if_index,
7924 ~0, // invalid fib index
7927 FIB_ROUTE_PATH_FLAG_NONE);
7929 * A BFD session for the new ADJ FIB
7931 bfd_session_t bfd_10_10_10_2 = {
7935 .peer_addr = nh_10_10_10_2,
7938 .hop_type = BFD_HOP_TYPE_MULTI,
7939 .local_state = BFD_STATE_init,
7942 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7945 * remove the adj-fib source whilst the session is present
7948 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7949 fib_table_entry_path_add(0,
7950 &pfx_10_10_10_2_s_32,
7952 FIB_ENTRY_FLAG_ATTACHED,
7955 tm->hw[0]->sw_if_index,
7956 ~0, // invalid fib index
7959 FIB_ROUTE_PATH_FLAG_NONE);
7962 * Before adding a recursive via the BFD tracked ADJ-FIBs,
7963 * bring one of the sessions UP, leave the other down
7965 bfd_10_10_10_1.local_state = BFD_STATE_up;
7966 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7967 bfd_10_10_10_2.local_state = BFD_STATE_down;
7968 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7971 * A recursive prefix via both of the ADJ FIBs
7973 fib_prefix_t pfx_200_0_0_0_s_24 = {
7974 .fp_proto = FIB_PROTOCOL_IP4,
7977 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7980 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7983 fib_entry_contribute_ip_forwarding(
7984 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7986 fib_entry_contribute_ip_forwarding(
7987 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7989 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7992 .lb = dpo_10_10_10_1->dpoi_index,
7995 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7998 .lb = dpo_10_10_10_2->dpoi_index,
8003 * A prefix via the adj-fib that is BFD down => DROP
8005 fei = fib_table_entry_path_add(0,
8006 &pfx_200_0_0_0_s_24,
8008 FIB_ENTRY_FLAG_NONE,
8012 0, // default fib index
8015 FIB_ROUTE_PATH_FLAG_NONE);
8016 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8017 "%U resolves via drop",
8018 format_fib_prefix, &pfx_200_0_0_0_s_24);
8021 * add a path via the UP BFD adj-fib.
8022 * we expect that the DOWN BFD ADJ FIB is not used.
8024 fei = fib_table_entry_path_add(0,
8025 &pfx_200_0_0_0_s_24,
8027 FIB_ENTRY_FLAG_NONE,
8031 0, // default fib index
8034 FIB_ROUTE_PATH_FLAG_NONE);
8036 FIB_TEST(fib_test_validate_entry(fei,
8037 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8040 "Recursive %U only UP BFD adj-fibs",
8041 format_fib_prefix, &pfx_200_0_0_0_s_24);
8044 * Send a BFD state change to UP - both sessions are now up
8045 * the recursive prefix should LB over both
8047 bfd_10_10_10_2.local_state = BFD_STATE_up;
8048 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8051 FIB_TEST(fib_test_validate_entry(fei,
8052 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8056 "Recursive %U via both UP BFD adj-fibs",
8057 format_fib_prefix, &pfx_200_0_0_0_s_24);
8060 * Send a BFD state change to DOWN
8061 * the recursive prefix should exclude the down
8063 bfd_10_10_10_2.local_state = BFD_STATE_down;
8064 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8067 FIB_TEST(fib_test_validate_entry(fei,
8068 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8071 "Recursive %U via only UP",
8072 format_fib_prefix, &pfx_200_0_0_0_s_24);
8075 * Delete the BFD session while it is in the DOWN state.
8076 * FIB should consider the entry's state as back up
8078 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
8080 FIB_TEST(fib_test_validate_entry(fei,
8081 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8085 "Recursive %U via both UP BFD adj-fibs post down session delete",
8086 format_fib_prefix, &pfx_200_0_0_0_s_24);
8089 * Delete the BFD other session while it is in the UP state.
8091 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8093 FIB_TEST(fib_test_validate_entry(fei,
8094 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8098 "Recursive %U via both UP BFD adj-fibs post up session delete",
8099 format_fib_prefix, &pfx_200_0_0_0_s_24);
8104 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8105 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8106 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8108 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8109 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8111 adj_unlock(ai_10_10_10_1);
8113 * test no-one left behind
8115 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8116 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8119 * Single-hop BFD tests
8121 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8122 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8124 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8126 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8129 tm->hw[0]->sw_if_index);
8131 * whilst the BFD session is not signalled, the adj is up
8133 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
8136 * bring the BFD session up
8138 bfd_10_10_10_1.local_state = BFD_STATE_up;
8139 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8140 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8143 * bring the BFD session down
8145 bfd_10_10_10_1.local_state = BFD_STATE_down;
8146 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8147 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8151 * add an attached next hop FIB entry via the down adj
8153 fib_prefix_t pfx_5_5_5_5_s_32 = {
8156 .as_u32 = clib_host_to_net_u32(0x05050505),
8160 .fp_proto = FIB_PROTOCOL_IP4,
8163 fei = fib_table_entry_path_add(0,
8166 FIB_ENTRY_FLAG_NONE,
8169 tm->hw[0]->sw_if_index,
8170 ~0, // invalid fib index
8173 FIB_ROUTE_PATH_FLAG_NONE);
8174 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8175 "%U resolves via drop",
8176 format_fib_prefix, &pfx_5_5_5_5_s_32);
8179 * Add a path via an ADJ that is up
8181 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8184 tm->hw[0]->sw_if_index);
8186 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8189 .adj = ai_10_10_10_2,
8192 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8194 fei = fib_table_entry_path_add(0,
8197 FIB_ENTRY_FLAG_NONE,
8200 tm->hw[0]->sw_if_index,
8201 ~0, // invalid fib index
8204 FIB_ROUTE_PATH_FLAG_NONE);
8206 FIB_TEST(fib_test_validate_entry(fei,
8207 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8210 "BFD sourced %U via %U",
8211 format_fib_prefix, &pfx_5_5_5_5_s_32,
8212 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8215 * Bring up the down session - should now LB
8217 bfd_10_10_10_1.local_state = BFD_STATE_up;
8218 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8219 FIB_TEST(fib_test_validate_entry(fei,
8220 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8224 "BFD sourced %U via noth adjs",
8225 format_fib_prefix, &pfx_5_5_5_5_s_32);
8228 * remove the BFD session state from the adj
8230 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8235 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8236 adj_unlock(ai_10_10_10_1);
8237 adj_unlock(ai_10_10_10_2);
8240 * test no-one left behind
8242 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8243 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8250 const mpls_label_t deag_label = 50;
8251 const u32 lfib_index = 0;
8252 const u32 fib_index = 0;
8253 dpo_id_t dpo = DPO_INVALID;
8254 const dpo_id_t *dpo1;
8255 fib_node_index_t lfe;
8259 adj_index_t ai_mpls_10_10_10_1;
8262 lb_count = pool_elts(load_balance_pool);
8264 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8268 * MPLS enable an interface so we get the MPLS table created
8270 mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8271 mpls_sw_interface_enable_disable(&mpls_main,
8272 tm->hw[0]->sw_if_index,
8275 ip46_address_t nh_10_10_10_1 = {
8276 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8278 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8281 tm->hw[0]->sw_if_index);
8284 * Test the specials stack properly.
8286 fib_prefix_t exp_null_v6_pfx = {
8287 .fp_proto = FIB_PROTOCOL_MPLS,
8289 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8290 .fp_payload_proto = DPO_PROTO_IP6,
8292 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8293 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8295 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8296 format_mpls_eos_bit, MPLS_EOS);
8297 fib_entry_contribute_forwarding(lfe,
8298 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8300 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8301 lkd = lookup_dpo_get(dpo1->dpoi_index);
8303 FIB_TEST((fib_index == lkd->lkd_fib_index),
8304 "%U/%U is deag in %d %U",
8305 format_mpls_unicast_label, deag_label,
8306 format_mpls_eos_bit, MPLS_EOS,
8308 format_dpo_id, &dpo, 0);
8309 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8310 "%U/%U is dst deag",
8311 format_mpls_unicast_label, deag_label,
8312 format_mpls_eos_bit, MPLS_EOS);
8313 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8314 "%U/%U is lookup in interface's table",
8315 format_mpls_unicast_label, deag_label,
8316 format_mpls_eos_bit, MPLS_EOS);
8317 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8318 "%U/%U is %U dst deag",
8319 format_mpls_unicast_label, deag_label,
8320 format_mpls_eos_bit, MPLS_EOS,
8321 format_dpo_proto, lkd->lkd_proto);
8325 * A route deag route for EOS
8327 fib_prefix_t pfx = {
8328 .fp_proto = FIB_PROTOCOL_MPLS,
8330 .fp_label = deag_label,
8331 .fp_payload_proto = DPO_PROTO_IP4,
8333 lfe = fib_table_entry_path_add(lfib_index,
8336 FIB_ENTRY_FLAG_NONE,
8343 FIB_ROUTE_PATH_FLAG_NONE);
8345 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8347 format_mpls_unicast_label, deag_label,
8348 format_mpls_eos_bit, MPLS_EOS);
8350 fib_entry_contribute_forwarding(lfe,
8351 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8353 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8354 lkd = lookup_dpo_get(dpo1->dpoi_index);
8356 FIB_TEST((fib_index == lkd->lkd_fib_index),
8357 "%U/%U is deag in %d %U",
8358 format_mpls_unicast_label, deag_label,
8359 format_mpls_eos_bit, MPLS_EOS,
8361 format_dpo_id, &dpo, 0);
8362 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8363 "%U/%U is dst deag",
8364 format_mpls_unicast_label, deag_label,
8365 format_mpls_eos_bit, MPLS_EOS);
8366 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8367 "%U/%U is %U dst deag",
8368 format_mpls_unicast_label, deag_label,
8369 format_mpls_eos_bit, MPLS_EOS,
8370 format_dpo_proto, lkd->lkd_proto);
8372 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8374 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8376 "%U/%U not present",
8377 format_mpls_unicast_label, deag_label,
8378 format_mpls_eos_bit, MPLS_EOS);
8381 * A route deag route for non-EOS
8383 pfx.fp_eos = MPLS_NON_EOS;
8384 lfe = fib_table_entry_path_add(lfib_index,
8387 FIB_ENTRY_FLAG_NONE,
8394 FIB_ROUTE_PATH_FLAG_NONE);
8396 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8398 format_mpls_unicast_label, deag_label,
8399 format_mpls_eos_bit, MPLS_NON_EOS);
8401 fib_entry_contribute_forwarding(lfe,
8402 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8404 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8405 lkd = lookup_dpo_get(dpo1->dpoi_index);
8407 FIB_TEST((fib_index == lkd->lkd_fib_index),
8408 "%U/%U is deag in %d %U",
8409 format_mpls_unicast_label, deag_label,
8410 format_mpls_eos_bit, MPLS_NON_EOS,
8412 format_dpo_id, &dpo, 0);
8413 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8414 "%U/%U is dst deag",
8415 format_mpls_unicast_label, deag_label,
8416 format_mpls_eos_bit, MPLS_NON_EOS);
8418 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8419 "%U/%U is %U dst deag",
8420 format_mpls_unicast_label, deag_label,
8421 format_mpls_eos_bit, MPLS_NON_EOS,
8422 format_dpo_proto, lkd->lkd_proto);
8424 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8426 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8428 "%U/%U not present",
8429 format_mpls_unicast_label, deag_label,
8430 format_mpls_eos_bit, MPLS_EOS);
8437 fib_prefix_t pfx_1200 = {
8439 .fp_proto = FIB_PROTOCOL_MPLS,
8441 .fp_eos = MPLS_NON_EOS,
8443 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8444 .type = FT_LB_LABEL_STACK_O_ADJ,
8445 .label_stack_o_adj = {
8446 .adj = ai_mpls_10_10_10_1,
8447 .label_stack_size = 4,
8451 .eos = MPLS_NON_EOS,
8454 dpo_id_t neos_1200 = DPO_INVALID;
8455 dpo_id_t ip_1200 = DPO_INVALID;
8456 mpls_label_t *l200 = NULL;
8457 vec_add1(l200, 200);
8458 vec_add1(l200, 300);
8459 vec_add1(l200, 400);
8460 vec_add1(l200, 500);
8462 lfe = fib_table_entry_update_one_path(fib_index,
8465 FIB_ENTRY_FLAG_NONE,
8468 tm->hw[0]->sw_if_index,
8469 ~0, // invalid fib index
8472 FIB_ROUTE_PATH_FLAG_NONE);
8474 FIB_TEST(fib_test_validate_entry(lfe,
8475 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8477 &neos_o_10_10_10_1),
8478 "1200/0 LB 1 buckets via: "
8482 * A recursive route via the MPLS x-connect
8484 fib_prefix_t pfx_2_2_2_3_s_32 = {
8486 .fp_proto = FIB_PROTOCOL_IP4,
8488 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8491 fib_route_path_t *rpaths = NULL, rpath = {
8492 .frp_proto = DPO_PROTO_MPLS,
8493 .frp_local_label = 1200,
8494 .frp_eos = MPLS_NON_EOS,
8495 .frp_sw_if_index = ~0, // recurive
8496 .frp_fib_index = 0, // Default MPLS fib
8498 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8499 .frp_label_stack = NULL,
8501 vec_add1(rpaths, rpath);
8503 fib_table_entry_path_add2(fib_index,
8506 FIB_ENTRY_FLAG_NONE,
8510 * A labelled recursive route via the MPLS x-connect
8512 fib_prefix_t pfx_2_2_2_4_s_32 = {
8514 .fp_proto = FIB_PROTOCOL_IP4,
8516 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8519 mpls_label_t *l999 = NULL;
8520 vec_add1(l999, 999);
8521 rpaths[0].frp_label_stack = l999,
8523 fib_table_entry_path_add2(fib_index,
8526 FIB_ENTRY_FLAG_NONE,
8529 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8530 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8532 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8533 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8536 fib_test_lb_bucket_t ip_o_1200 = {
8539 .lb = ip_1200.dpoi_index,
8542 fib_test_lb_bucket_t mpls_o_1200 = {
8543 .type = FT_LB_LABEL_O_LB,
8545 .lb = neos_1200.dpoi_index,
8551 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8552 FIB_TEST(fib_test_validate_entry(lfe,
8553 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8556 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8557 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8558 FIB_TEST(fib_test_validate_entry(lfe,
8559 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8562 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8564 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8565 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8566 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8568 dpo_reset(&neos_1200);
8569 dpo_reset(&ip_1200);
8572 * A recursive via a label that does not exist
8574 fib_test_lb_bucket_t bucket_drop = {
8577 .adj = DPO_PROTO_IP4,
8580 fib_test_lb_bucket_t mpls_bucket_drop = {
8583 .adj = DPO_PROTO_MPLS,
8587 rpaths[0].frp_label_stack = NULL;
8588 lfe = fib_table_entry_path_add2(fib_index,
8591 FIB_ENTRY_FLAG_NONE,
8594 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8595 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8597 ip_o_1200.lb.lb = ip_1200.dpoi_index;
8599 FIB_TEST(fib_test_validate_entry(lfe,
8600 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8603 "2.2.2.2.4/32 LB 1 buckets via: drop");
8604 lfe = fib_table_lookup(fib_index, &pfx_1200);
8605 FIB_TEST(fib_test_validate_entry(lfe,
8606 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8609 "1200/neos LB 1 buckets via: ip4-DROP");
8610 FIB_TEST(fib_test_validate_entry(lfe,
8611 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8614 "1200/neos LB 1 buckets via: mpls-DROP");
8616 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8618 dpo_reset(&ip_1200);
8621 * An rx-interface route.
8622 * like the tail of an mcast LSP
8624 dpo_id_t idpo = DPO_INVALID;
8626 interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8627 tm->hw[0]->sw_if_index,
8630 fib_prefix_t pfx_2500 = {
8632 .fp_proto = FIB_PROTOCOL_MPLS,
8635 .fp_payload_proto = DPO_PROTO_IP4,
8637 fib_test_lb_bucket_t rx_intf_0 = {
8640 .adj = idpo.dpoi_index,
8644 lfe = fib_table_entry_update_one_path(fib_index,
8647 FIB_ENTRY_FLAG_NONE,
8650 tm->hw[0]->sw_if_index,
8651 ~0, // invalid fib index
8654 FIB_ROUTE_PATH_INTF_RX);
8655 FIB_TEST(fib_test_validate_entry(lfe,
8656 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8659 "2500 rx-interface 0");
8660 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8663 * An MPLS mulicast entry
8665 fib_prefix_t pfx_3500 = {
8667 .fp_proto = FIB_PROTOCOL_MPLS,
8670 .fp_payload_proto = DPO_PROTO_IP4,
8672 fib_test_rep_bucket_t mc_0 = {
8673 .type = FT_REP_LABEL_O_ADJ,
8675 .adj = ai_mpls_10_10_10_1,
8680 fib_test_rep_bucket_t mc_intf_0 = {
8681 .type = FT_REP_INTF,
8683 .adj = idpo.dpoi_index,
8686 mpls_label_t *l3300 = NULL;
8687 vec_add1(l3300, 3300);
8689 lfe = fib_table_entry_update_one_path(lfib_index,
8692 FIB_ENTRY_FLAG_MULTICAST,
8695 tm->hw[0]->sw_if_index,
8696 ~0, // invalid fib index
8699 FIB_ROUTE_PATH_FLAG_NONE);
8700 FIB_TEST(fib_test_validate_entry(lfe,
8701 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8704 "3500 via replicate over 10.10.10.1");
8707 * MPLS Bud-node. Add a replication via an interface-receieve path
8709 lfe = fib_table_entry_path_add(lfib_index,
8712 FIB_ENTRY_FLAG_MULTICAST,
8715 tm->hw[0]->sw_if_index,
8716 ~0, // invalid fib index
8719 FIB_ROUTE_PATH_INTF_RX);
8720 FIB_TEST(fib_test_validate_entry(lfe,
8721 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8725 "3500 via replicate over 10.10.10.1 and interface-rx");
8728 * Add a replication via an interface-free for-us path
8730 fib_test_rep_bucket_t mc_disp = {
8731 .type = FT_REP_DISP_MFIB_LOOKUP,
8733 .adj = idpo.dpoi_index,
8736 lfe = fib_table_entry_path_add(lfib_index,
8739 FIB_ENTRY_FLAG_MULTICAST,
8746 FIB_ROUTE_PATH_RPF_ID);
8747 FIB_TEST(fib_test_validate_entry(lfe,
8748 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8753 "3500 via replicate over 10.10.10.1 and interface-rx");
8757 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8763 mpls_sw_interface_enable_disable(&mpls_main,
8764 tm->hw[0]->sw_if_index,
8766 mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
8768 FIB_TEST(lb_count == pool_elts(load_balance_pool),
8769 "Load-balance resources freed %d of %d",
8770 lb_count, pool_elts(load_balance_pool));
8771 FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
8772 "interface_rx_dpo resources freed %d of %d",
8773 0, pool_elts(interface_rx_dpo_pool));
8778 static clib_error_t *
8779 fib_test (vlib_main_t * vm,
8780 unformat_input_t * input,
8781 vlib_cli_command_t * cmd_arg)
8786 fib_test_mk_intf(4);
8788 if (unformat (input, "debug"))
8790 fib_test_do_debug = 1;
8793 if (unformat (input, "ip"))
8795 res += fib_test_v4();
8796 res += fib_test_v6();
8798 else if (unformat (input, "label"))
8800 res += fib_test_label();
8802 else if (unformat (input, "ae"))
8804 res += fib_test_ae();
8806 else if (unformat (input, "pref"))
8808 res += fib_test_pref();
8810 else if (unformat (input, "lfib"))
8814 else if (unformat (input, "walk"))
8816 res += fib_test_walk();
8818 else if (unformat (input, "bfd"))
8820 res += fib_test_bfd();
8824 res += fib_test_v4();
8825 res += fib_test_v6();
8826 res += fib_test_ae();
8827 res += fib_test_bfd();
8828 res += fib_test_pref();
8829 res += fib_test_label();
8833 * fib-walk process must be disabled in order for the walk tests to work
8835 fib_walk_process_disable();
8836 res += fib_test_walk();
8837 fib_walk_process_enable();
8842 return clib_error_return(0, "FIB Unit Test Failed");
8850 VLIB_CLI_COMMAND (test_fib_command, static) = {
8852 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
8853 .function = fib_test,
8857 fib_test_init (vlib_main_t *vm)
8862 VLIB_INIT_FUNCTION (fib_test_init);