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/dvr_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_DVR == 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 if (FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
617 format_dpo_type, dpo->dpoi_type))
619 lb = load_balance_get(dpo->dpoi_index);
621 res = fib_test_validate_lb_v(lb, n_buckets, &ap);
634 fib_test_validate_entry (fib_node_index_t fei,
635 fib_forward_chain_type_t fct,
639 dpo_id_t dpo = DPO_INVALID;
646 va_start(ap, n_buckets);
648 fib_entry_get_prefix(fei, &pfx);
649 fib_index = fib_entry_get_fib_index(fei);
650 fib_entry_contribute_forwarding(fei, fct, &dpo);
652 if (DPO_REPLICATE == dpo.dpoi_type)
654 const replicate_t *rep;
656 rep = replicate_get(dpo.dpoi_index);
657 res = fib_test_validate_rep_v(rep, n_buckets, &ap);
661 const load_balance_t *lb;
663 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
664 "%U Entry links to %U",
665 format_fib_prefix, &pfx,
666 format_dpo_type, dpo.dpoi_type);
668 lb = load_balance_get(dpo.dpoi_index);
669 res = fib_test_validate_lb_v(lb, n_buckets, &ap);
672 * ensure that the LB contributed by the entry is the
673 * same as the LB in the forwarding tables
675 if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
677 switch (pfx.fp_proto)
679 case FIB_PROTOCOL_IP4:
680 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
682 case FIB_PROTOCOL_IP6:
683 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
685 case FIB_PROTOCOL_MPLS:
687 mpls_unicast_header_t hdr = {
688 .label_exp_s_ttl = 0,
691 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
692 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
693 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
695 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
701 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
702 "Contributed LB = FW LB:\n fwd:%U\n cont:%U",
703 format_load_balance, fw_lbi, 0,
704 format_load_balance, dpo.dpoi_index, 0);
719 * In the default table check for the presence and correct forwarding
720 * of the special entries
722 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
723 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
724 const ip_adjacency_t *adj;
725 const load_balance_t *lb;
732 ip46_address_t nh_10_10_10_1 = {
733 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
736 ip46_address_t nh_10_10_10_2 = {
737 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
740 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
741 pool_elts(load_balance_map_pool));
745 /* record the nubmer of load-balances in use before we start */
746 lb_count = pool_elts(load_balance_pool);
748 /* Find or create FIB table 11 */
749 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11,
752 for (ii = 0; ii < 4; ii++)
754 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
757 fib_prefix_t pfx_0_0_0_0_s_0 = {
759 .fp_proto = FIB_PROTOCOL_IP4,
769 .fp_proto = FIB_PROTOCOL_IP4,
777 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
779 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
780 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
781 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
782 "Default route is DROP");
785 fei = fib_table_lookup(fib_index, &pfx);
786 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
787 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
788 "all 0s route is DROP");
790 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
792 fei = fib_table_lookup(fib_index, &pfx);
793 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
794 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
795 "all 1s route is DROP");
797 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
799 fei = fib_table_lookup(fib_index, &pfx);
800 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
801 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
802 "all-mcast route is DROP");
804 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
806 fei = fib_table_lookup(fib_index, &pfx);
807 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
808 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
809 "class-e route is DROP");
812 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
813 * all of which are special sourced and so none of which share path-lists.
814 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
815 * table, and 4 path-lists in the v6 MFIB table
819 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
820 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
821 fib_path_list_pool_size());
822 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
823 fib_entry_pool_size());
826 * add interface routes.
827 * validate presence of /24 attached and /32 recieve.
828 * test for the presence of the receive address in the glean and local adj
830 fib_prefix_t local_pfx = {
832 .fp_proto = FIB_PROTOCOL_IP4,
835 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
840 fib_table_entry_update_one_path(fib_index, &local_pfx,
841 FIB_SOURCE_INTERFACE,
842 (FIB_ENTRY_FLAG_CONNECTED |
843 FIB_ENTRY_FLAG_ATTACHED),
846 tm->hw[0]->sw_if_index,
847 ~0, // invalid fib index
850 FIB_ROUTE_PATH_FLAG_NONE);
851 fei = fib_table_lookup(fib_index, &local_pfx);
852 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
853 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
854 fib_entry_get_flags(fei)),
855 "Flags set on attached interface");
857 ai = fib_entry_get_adj(fei);
858 FIB_TEST((FIB_NODE_INDEX_INVALID != ai),
859 "attached interface route adj present %d", ai);
861 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
862 "attached interface adj is glean");
863 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
864 &adj->sub_type.glean.receive_addr)),
865 "attached interface adj is receive ok");
867 local_pfx.fp_len = 32;
868 fib_table_entry_update_one_path(fib_index, &local_pfx,
869 FIB_SOURCE_INTERFACE,
870 (FIB_ENTRY_FLAG_CONNECTED |
871 FIB_ENTRY_FLAG_LOCAL),
874 tm->hw[0]->sw_if_index,
875 ~0, // invalid fib index
878 FIB_ROUTE_PATH_FLAG_NONE);
879 fei = fib_table_lookup(fib_index, &local_pfx);
880 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
881 fib_entry_get_flags(fei)),
882 "Flags set on local interface");
884 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
886 dpo = fib_entry_contribute_ip_forwarding(fei);
887 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
888 "RPF list for local length 0");
889 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
890 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
891 "local interface adj is local");
892 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
894 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
896 "local interface adj is receive ok");
898 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
900 FIB_SOURCE_INTERFACE)),
901 "2 Interface Source'd prefixes");
904 * +2 interface routes +2 non-shared path-lists
906 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
907 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
908 fib_path_list_pool_size());
909 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
910 fib_entry_pool_size());
913 * Modify the default route to be via an adj not yet known.
914 * this sources the defalut route with the API source, which is
915 * a higher preference to the DEFAULT_ROUTE source
917 pfx.fp_addr.ip4.as_u32 = 0;
919 fib_table_entry_path_add(fib_index, &pfx,
924 tm->hw[0]->sw_if_index,
925 ~0, // invalid fib index
928 FIB_ROUTE_PATH_FLAG_NONE);
929 fei = fib_table_lookup(fib_index, &pfx);
930 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
931 "Flags set on API route");
933 FIB_TEST((fei == dfrt), "default route same index");
934 ai = fib_entry_get_adj(fei);
935 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
937 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
938 "adj is incomplete");
939 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
940 "adj nbr next-hop ok");
941 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
944 "1 API Source'd prefixes");
947 * find the adj in the shared db
949 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
952 tm->hw[0]->sw_if_index);
953 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
954 adj_unlock(locked_ai);
957 * +1 shared path-list
959 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
960 fib_path_list_db_size());
961 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
962 fib_path_list_pool_size());
963 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
964 fib_entry_pool_size());
967 * remove the API source from the default route. We expected
968 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
970 pfx.fp_addr.ip4.as_u32 = 0;
972 fib_table_entry_path_remove(fib_index, &pfx,
976 tm->hw[0]->sw_if_index,
977 ~0, // non-recursive path, so no FIB index
979 FIB_ROUTE_PATH_FLAG_NONE);
981 fei = fib_table_lookup(fib_index, &pfx);
983 FIB_TEST((fei == dfrt), "default route same index");
984 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
985 "Default route is DROP");
988 * -1 shared-path-list
990 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
991 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
992 fib_path_list_pool_size());
993 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
994 fib_entry_pool_size());
997 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
999 fib_prefix_t pfx_10_10_10_1_s_32 = {
1001 .fp_proto = FIB_PROTOCOL_IP4,
1004 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
1007 fib_prefix_t pfx_10_10_10_2_s_32 = {
1009 .fp_proto = FIB_PROTOCOL_IP4,
1012 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
1015 fib_prefix_t pfx_11_11_11_11_s_32 = {
1017 .fp_proto = FIB_PROTOCOL_IP4,
1020 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
1024 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
1027 ip46_address_t nh_12_12_12_12 = {
1028 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
1030 adj_index_t ai_12_12_12_12;
1033 * Add a route via an incomplete ADJ. then complete the ADJ
1034 * Expect the route LB is updated to use complete adj type.
1036 fei = fib_table_entry_update_one_path(fib_index,
1037 &pfx_11_11_11_11_s_32,
1039 FIB_ENTRY_FLAG_ATTACHED,
1041 &pfx_10_10_10_1_s_32.fp_addr,
1042 tm->hw[0]->sw_if_index,
1043 ~0, // invalid fib index
1046 FIB_ROUTE_PATH_FLAG_NONE);
1048 dpo = fib_entry_contribute_ip_forwarding(fei);
1049 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1050 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1051 "11.11.11.11/32 via incomplete adj");
1053 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1055 &pfx_10_10_10_1_s_32.fp_addr,
1056 tm->hw[0]->sw_if_index);
1057 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1058 adj = adj_get(ai_01);
1059 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1060 "adj is incomplete");
1061 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1062 &adj->sub_type.nbr.next_hop)),
1063 "adj nbr next-hop ok");
1065 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1066 fib_test_build_rewrite(eth_addr));
1067 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1069 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1070 &adj->sub_type.nbr.next_hop)),
1071 "adj nbr next-hop ok");
1072 ai = fib_entry_get_adj(fei);
1073 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1075 dpo = fib_entry_contribute_ip_forwarding(fei);
1076 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1077 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1078 "11.11.11.11/32 via complete adj");
1079 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1080 tm->hw[0]->sw_if_index),
1081 "RPF list for adj-fib contains adj");
1083 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1086 tm->hw[1]->sw_if_index);
1087 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1088 adj = adj_get(ai_12_12_12_12);
1089 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1090 "adj is incomplete");
1091 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1092 &adj->sub_type.nbr.next_hop)),
1093 "adj nbr next-hop ok");
1094 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1095 fib_test_build_rewrite(eth_addr));
1096 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1102 fei = fib_table_entry_path_add(fib_index,
1103 &pfx_10_10_10_1_s_32,
1105 FIB_ENTRY_FLAG_ATTACHED,
1107 &pfx_10_10_10_1_s_32.fp_addr,
1108 tm->hw[0]->sw_if_index,
1109 ~0, // invalid fib index
1112 FIB_ROUTE_PATH_FLAG_NONE);
1113 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1114 "Flags set on adj-fib");
1115 ai = fib_entry_get_adj(fei);
1116 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
1118 fib_table_entry_path_remove(fib_index,
1119 &pfx_11_11_11_11_s_32,
1122 &pfx_10_10_10_1_s_32.fp_addr,
1123 tm->hw[0]->sw_if_index,
1124 ~0, // invalid fib index
1126 FIB_ROUTE_PATH_FLAG_NONE);
1130 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1132 &pfx_10_10_10_2_s_32.fp_addr,
1133 tm->hw[0]->sw_if_index);
1134 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1135 adj = adj_get(ai_02);
1136 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1137 "adj is incomplete");
1138 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1139 &adj->sub_type.nbr.next_hop)),
1140 "adj nbr next-hop ok");
1142 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1143 fib_test_build_rewrite(eth_addr));
1144 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1146 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1147 &adj->sub_type.nbr.next_hop)),
1148 "adj nbr next-hop ok");
1149 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1151 fib_table_entry_path_add(fib_index,
1152 &pfx_10_10_10_2_s_32,
1154 FIB_ENTRY_FLAG_ATTACHED,
1156 &pfx_10_10_10_2_s_32.fp_addr,
1157 tm->hw[0]->sw_if_index,
1158 ~0, // invalid fib index
1161 FIB_ROUTE_PATH_FLAG_NONE);
1163 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1164 ai = fib_entry_get_adj(fei);
1165 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1168 * +2 adj-fibs, and their non-shared path-lists
1170 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1171 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1172 fib_path_list_pool_size());
1173 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1174 fib_entry_pool_size());
1177 * Add 2 routes via the first ADJ. ensure path-list sharing
1179 fib_prefix_t pfx_1_1_1_1_s_32 = {
1181 .fp_proto = FIB_PROTOCOL_IP4,
1184 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1188 fib_table_entry_path_add(fib_index,
1191 FIB_ENTRY_FLAG_NONE,
1194 tm->hw[0]->sw_if_index,
1195 ~0, // invalid fib index
1198 FIB_ROUTE_PATH_FLAG_NONE);
1199 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1200 ai = fib_entry_get_adj(fei);
1201 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1204 * +1 entry and a shared path-list
1206 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1207 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1208 fib_path_list_pool_size());
1209 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1210 fib_entry_pool_size());
1213 fib_prefix_t pfx_1_1_2_0_s_24 = {
1215 .fp_proto = FIB_PROTOCOL_IP4,
1217 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1221 fib_table_entry_path_add(fib_index,
1224 FIB_ENTRY_FLAG_NONE,
1227 tm->hw[0]->sw_if_index,
1228 ~0, // invalid fib index
1231 FIB_ROUTE_PATH_FLAG_NONE);
1232 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1233 ai = fib_entry_get_adj(fei);
1234 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1239 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1240 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1241 fib_path_list_pool_size());
1242 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1243 fib_entry_pool_size());
1246 * modify 1.1.2.0/24 to use multipath.
1248 fib_table_entry_path_add(fib_index,
1251 FIB_ENTRY_FLAG_NONE,
1254 tm->hw[0]->sw_if_index,
1255 ~0, // invalid fib index
1258 FIB_ROUTE_PATH_FLAG_NONE);
1259 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1260 dpo = fib_entry_contribute_ip_forwarding(fei);
1261 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1262 1, tm->hw[0]->sw_if_index),
1263 "RPF list for 1.1.2.0/24 contains both adjs");
1265 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1266 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1267 FIB_TEST((ai_01 == dpo1->dpoi_index),
1268 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1269 ai_01, dpo1->dpoi_index);
1271 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1272 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1273 FIB_TEST((ai_02 == dpo1->dpoi_index),
1274 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1277 * +1 shared-pathlist
1279 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1280 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1281 fib_path_list_pool_size());
1282 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1283 fib_entry_pool_size());
1288 fib_table_entry_path_remove(fib_index,
1293 tm->hw[0]->sw_if_index,
1296 FIB_ROUTE_PATH_FLAG_NONE);
1297 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1298 dpo = fib_entry_contribute_ip_forwarding(fei);
1299 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1300 1, tm->hw[0]->sw_if_index),
1301 "RPF list for 1.1.2.0/24 contains one adj");
1303 ai = fib_entry_get_adj(fei);
1304 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1307 * +1 shared-pathlist
1309 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1310 fib_path_list_db_size());
1311 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1312 fib_path_list_pool_size());
1313 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1314 fib_entry_pool_size());
1317 * Add 2 recursive routes:
1318 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1319 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1321 fib_prefix_t bgp_100_pfx = {
1323 .fp_proto = FIB_PROTOCOL_IP4,
1325 /* 100.100.100.100/32 */
1326 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1330 ip46_address_t nh_1_1_1_1 = {
1331 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1334 fei = fib_table_entry_path_add(fib_index,
1337 FIB_ENTRY_FLAG_NONE,
1340 ~0, // no index provided.
1341 fib_index, // nexthop in same fib as route
1344 FIB_ROUTE_PATH_FLAG_NONE);
1346 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1347 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1348 tm->hw[0]->sw_if_index),
1349 "RPF list for adj-fib contains adj");
1352 * +1 entry and +1 shared-path-list
1354 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1355 fib_path_list_db_size());
1356 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1357 fib_path_list_pool_size());
1358 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1359 fib_entry_pool_size());
1361 fib_prefix_t bgp_101_pfx = {
1363 .fp_proto = FIB_PROTOCOL_IP4,
1365 /* 100.100.100.101/32 */
1366 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1370 fib_table_entry_path_add(fib_index,
1373 FIB_ENTRY_FLAG_NONE,
1376 ~0, // no index provided.
1377 fib_index, // nexthop in same fib as route
1380 FIB_ROUTE_PATH_FLAG_NONE);
1382 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1383 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1384 tm->hw[0]->sw_if_index),
1385 "RPF list for adj-fib contains adj");
1388 * +1 entry, but the recursive path-list is shared.
1390 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1391 fib_path_list_db_size());
1392 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1393 fib_path_list_pool_size());
1394 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1395 fib_entry_pool_size());
1398 * An special route; one where the user (me) provides the
1399 * adjacency through which the route will resovle by setting the flags
1401 fib_prefix_t ex_pfx = {
1403 .fp_proto = FIB_PROTOCOL_IP4,
1406 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1410 fib_table_entry_special_add(fib_index,
1413 FIB_ENTRY_FLAG_LOCAL);
1414 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1415 dpo = fib_entry_contribute_ip_forwarding(fei);
1416 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1417 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1418 "local interface adj is local");
1420 fib_table_entry_special_remove(fib_index,
1422 FIB_SOURCE_SPECIAL);
1423 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1424 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1425 "Exclusive reoute removed");
1428 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1429 * adjacency through which the route will resovle
1431 dpo_id_t ex_dpo = DPO_INVALID;
1433 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1436 LOOKUP_INPUT_DST_ADDR,
1437 LOOKUP_TABLE_FROM_CONFIG,
1440 fib_table_entry_special_dpo_add(fib_index,
1443 FIB_ENTRY_FLAG_EXCLUSIVE,
1445 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1446 dpo = fib_entry_contribute_ip_forwarding(fei);
1447 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1448 "exclusive remote uses lookup DPO");
1451 * update the exclusive to use a different DPO
1453 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1454 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1456 fib_table_entry_special_dpo_update(fib_index,
1459 FIB_ENTRY_FLAG_EXCLUSIVE,
1461 dpo = fib_entry_contribute_ip_forwarding(fei);
1462 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1463 "exclusive remote uses now uses NULL DPO");
1465 fib_table_entry_special_remove(fib_index,
1467 FIB_SOURCE_SPECIAL);
1468 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1469 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1470 "Exclusive reoute removed");
1474 * Add a recursive route:
1475 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1477 fib_prefix_t bgp_200_pfx = {
1479 .fp_proto = FIB_PROTOCOL_IP4,
1481 /* 200.200.200.200/32 */
1482 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1486 fib_prefix_t pfx_1_1_1_2_s_32 = {
1488 .fp_proto = FIB_PROTOCOL_IP4,
1490 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1494 fei = fib_table_entry_path_add(fib_index,
1497 FIB_ENTRY_FLAG_NONE,
1499 &pfx_1_1_1_2_s_32.fp_addr,
1500 ~0, // no index provided.
1501 fib_index, // nexthop in same fib as route
1504 FIB_ROUTE_PATH_FLAG_NONE);
1506 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1507 "Recursive via unresolved is drop");
1510 * the adj should be recursive via drop, since the route resolves via
1511 * the default route, which is itself a DROP
1513 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1514 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1515 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1516 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1517 "RPF list for 1.1.1.2/32 contains 0 adjs");
1520 * +2 entry and +1 shared-path-list
1522 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1523 fib_path_list_db_size());
1524 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1525 fib_path_list_pool_size());
1526 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1527 fib_entry_pool_size());
1530 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1531 * The paths are sort by NH first. in this case the the path with greater
1532 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1534 fib_prefix_t pfx_1_2_3_4_s_32 = {
1536 .fp_proto = FIB_PROTOCOL_IP4,
1538 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1541 fib_table_entry_path_add(fib_index,
1544 FIB_ENTRY_FLAG_NONE,
1547 tm->hw[0]->sw_if_index,
1551 FIB_ROUTE_PATH_FLAG_NONE);
1552 fei = fib_table_entry_path_add(fib_index,
1555 FIB_ENTRY_FLAG_NONE,
1558 tm->hw[1]->sw_if_index,
1562 FIB_ROUTE_PATH_FLAG_NONE);
1564 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1565 dpo = fib_entry_contribute_ip_forwarding(fei);
1566 lb = load_balance_get(dpo->dpoi_index);
1567 FIB_TEST((lb->lb_n_buckets == 4),
1568 "1.2.3.4/32 LB has %d bucket",
1571 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1572 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1573 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1574 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1576 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1577 tm->hw[0]->sw_if_index,
1578 tm->hw[1]->sw_if_index),
1579 "RPF list for 1.2.3.4/32 contains both adjs");
1583 * Unequal Cost load-balance. 4:1 ratio.
1584 * fits in a 16 bucket LB with ratio 13:3
1586 fib_prefix_t pfx_1_2_3_5_s_32 = {
1588 .fp_proto = FIB_PROTOCOL_IP4,
1590 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1593 fib_table_entry_path_add(fib_index,
1596 FIB_ENTRY_FLAG_NONE,
1599 tm->hw[1]->sw_if_index,
1603 FIB_ROUTE_PATH_FLAG_NONE);
1604 fei = fib_table_entry_path_add(fib_index,
1607 FIB_ENTRY_FLAG_NONE,
1610 tm->hw[0]->sw_if_index,
1614 FIB_ROUTE_PATH_FLAG_NONE);
1616 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1617 dpo = fib_entry_contribute_ip_forwarding(fei);
1618 lb = load_balance_get(dpo->dpoi_index);
1619 FIB_TEST((lb->lb_n_buckets == 16),
1620 "1.2.3.5/32 LB has %d bucket",
1623 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1624 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1625 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1626 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1627 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1628 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1629 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1630 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1631 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1632 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1633 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1634 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1635 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1636 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1637 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1638 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1640 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1641 tm->hw[0]->sw_if_index,
1642 tm->hw[1]->sw_if_index),
1643 "RPF list for 1.2.3.4/32 contains both adjs");
1646 * Test UCMP with a large weight skew - this produces load-balance objects with large
1647 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1648 * laso testing the LB in placce modify code when number of buckets is large.
1650 fib_prefix_t pfx_6_6_6_6_s_32 = {
1652 .fp_proto = FIB_PROTOCOL_IP4,
1655 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1658 fib_test_lb_bucket_t ip_o_10_10_10_1 = {
1664 fib_test_lb_bucket_t ip_o_10_10_10_2 = {
1670 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1673 .adj = ai_12_12_12_12,
1676 fib_table_entry_update_one_path(fib_index,
1679 FIB_ENTRY_FLAG_NONE,
1682 tm->hw[0]->sw_if_index,
1683 ~0, // invalid fib index
1686 FIB_ROUTE_PATH_FLAG_NONE);
1688 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1689 FIB_TEST(fib_test_validate_entry(fei,
1690 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1693 "6.6.6.6/32 via 10.10.10.1");
1695 fib_table_entry_path_add(fib_index,
1698 FIB_ENTRY_FLAG_NONE,
1701 tm->hw[0]->sw_if_index,
1702 ~0, // invalid fib index
1705 FIB_ROUTE_PATH_FLAG_NONE);
1707 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1708 FIB_TEST(fib_test_validate_entry(fei,
1709 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1775 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1777 fib_table_entry_path_add(fib_index,
1780 FIB_ENTRY_FLAG_NONE,
1783 tm->hw[1]->sw_if_index,
1784 ~0, // invalid fib index
1787 FIB_ROUTE_PATH_FLAG_NONE);
1789 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1790 FIB_TEST(fib_test_validate_entry(fei,
1791 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
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 &ip_6_6_6_6_o_12_12_12_12,
1915 &ip_6_6_6_6_o_12_12_12_12,
1916 &ip_6_6_6_6_o_12_12_12_12,
1917 &ip_6_6_6_6_o_12_12_12_12,
1918 &ip_6_6_6_6_o_12_12_12_12,
1919 &ip_6_6_6_6_o_12_12_12_12,
1920 &ip_6_6_6_6_o_12_12_12_12),
1921 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1923 fib_table_entry_path_remove(fib_index,
1928 tm->hw[1]->sw_if_index,
1929 ~0, // invalid fib index
1931 FIB_ROUTE_PATH_FLAG_NONE);
1933 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1934 FIB_TEST(fib_test_validate_entry(fei,
1935 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2001 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
2003 fib_table_entry_path_remove(fib_index,
2008 tm->hw[0]->sw_if_index,
2009 ~0, // invalid fib index
2011 FIB_ROUTE_PATH_FLAG_NONE);
2013 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2014 FIB_TEST(fib_test_validate_entry(fei,
2015 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2018 "6.6.6.6/32 via 10.10.10.1");
2020 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
2023 * A recursive via the two unequal cost entries
2025 fib_prefix_t bgp_44_s_32 = {
2027 .fp_proto = FIB_PROTOCOL_IP4,
2029 /* 200.200.200.201/32 */
2030 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2033 fei = fib_table_entry_path_add(fib_index,
2036 FIB_ENTRY_FLAG_NONE,
2038 &pfx_1_2_3_4_s_32.fp_addr,
2043 FIB_ROUTE_PATH_FLAG_NONE);
2044 fei = fib_table_entry_path_add(fib_index,
2047 FIB_ENTRY_FLAG_NONE,
2049 &pfx_1_2_3_5_s_32.fp_addr,
2054 FIB_ROUTE_PATH_FLAG_NONE);
2056 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2057 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2058 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2059 tm->hw[0]->sw_if_index,
2060 tm->hw[1]->sw_if_index),
2061 "RPF list for 1.2.3.4/32 contains both adjs");
2064 * test the uRPF check functions
2066 dpo_id_t dpo_44 = DPO_INVALID;
2069 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2070 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2072 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2073 "uRPF check for 68.68.68.68/32 on %d OK",
2074 tm->hw[0]->sw_if_index);
2075 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2076 "uRPF check for 68.68.68.68/32 on %d OK",
2077 tm->hw[1]->sw_if_index);
2078 FIB_TEST(!fib_urpf_check(urpfi, 99),
2079 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2083 fib_table_entry_delete(fib_index,
2086 fib_table_entry_delete(fib_index,
2089 fib_table_entry_delete(fib_index,
2094 * Add a recursive route:
2095 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2097 fib_prefix_t bgp_201_pfx = {
2099 .fp_proto = FIB_PROTOCOL_IP4,
2101 /* 200.200.200.201/32 */
2102 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2106 fib_prefix_t pfx_1_1_1_200_s_32 = {
2108 .fp_proto = FIB_PROTOCOL_IP4,
2110 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2114 fei = fib_table_entry_path_add(fib_index,
2117 FIB_ENTRY_FLAG_NONE,
2119 &pfx_1_1_1_200_s_32.fp_addr,
2120 ~0, // no index provided.
2121 fib_index, // nexthop in same fib as route
2124 FIB_ROUTE_PATH_FLAG_NONE);
2126 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2127 "Recursive via unresolved is drop");
2129 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2130 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2131 "Flags set on RR via non-attached");
2132 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2133 "RPF list for BGP route empty");
2136 * +2 entry (BGP & RR) and +1 shared-path-list
2138 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2139 fib_path_list_db_size());
2140 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2141 fib_path_list_pool_size());
2142 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2143 fib_entry_pool_size());
2146 * insert a route that covers the missing 1.1.1.2/32. we epxect
2147 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2149 fib_prefix_t pfx_1_1_1_0_s_24 = {
2151 .fp_proto = FIB_PROTOCOL_IP4,
2154 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2158 fib_table_entry_path_add(fib_index,
2161 FIB_ENTRY_FLAG_NONE,
2164 tm->hw[0]->sw_if_index,
2165 ~0, // invalid fib index
2168 FIB_ROUTE_PATH_FLAG_NONE);
2169 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2170 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2171 ai = fib_entry_get_adj(fei);
2172 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2173 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2174 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2175 ai = fib_entry_get_adj(fei);
2176 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2177 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2178 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2179 ai = fib_entry_get_adj(fei);
2180 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2183 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2185 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2186 fib_path_list_db_size());
2187 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2188 fib_path_list_pool_size());
2189 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2190 fib_entry_pool_size());
2193 * the recursive adj for 200.200.200.200 should be updated.
2195 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2196 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2197 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2198 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2199 tm->hw[0]->sw_if_index),
2200 "RPF list for BGP route has itf index 0");
2203 * insert a more specific route than 1.1.1.0/24 that also covers the
2204 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2205 * 200.200.200.200 to resolve through it.
2207 fib_prefix_t pfx_1_1_1_0_s_28 = {
2209 .fp_proto = FIB_PROTOCOL_IP4,
2212 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2216 fib_table_entry_path_add(fib_index,
2219 FIB_ENTRY_FLAG_NONE,
2222 tm->hw[0]->sw_if_index,
2223 ~0, // invalid fib index
2226 FIB_ROUTE_PATH_FLAG_NONE);
2227 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2228 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2229 ai = fib_entry_get_adj(fei);
2230 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2233 * +1 entry. +1 shared path-list
2235 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2236 fib_path_list_db_size());
2237 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2238 fib_path_list_pool_size());
2239 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2240 fib_entry_pool_size());
2243 * the recursive adj for 200.200.200.200 should be updated.
2244 * 200.200.200.201 remains unchanged.
2246 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2247 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2250 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2252 fib_table_entry_path_remove(fib_index,
2257 tm->hw[0]->sw_if_index,
2260 FIB_ROUTE_PATH_FLAG_NONE);
2261 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2262 FIB_NODE_INDEX_INVALID),
2263 "1.1.1.0/28 removed");
2264 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2265 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2266 "1.1.1.0/28 lookup via /24");
2267 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2268 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2271 * -1 entry. -1 shared path-list
2273 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2274 fib_path_list_db_size());
2275 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2276 fib_path_list_pool_size());
2277 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2278 fib_entry_pool_size());
2281 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2283 fib_table_entry_path_remove(fib_index,
2288 tm->hw[0]->sw_if_index,
2291 FIB_ROUTE_PATH_FLAG_NONE);
2292 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2293 FIB_NODE_INDEX_INVALID),
2294 "1.1.1.0/24 removed");
2296 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2297 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2298 "1.1.1.2/32 route is DROP");
2299 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2300 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2301 "1.1.1.200/32 route is DROP");
2303 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2304 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2306 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2307 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2313 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2314 fib_path_list_db_size());
2315 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2316 fib_path_list_pool_size());
2317 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2318 fib_entry_pool_size());
2321 * insert the missing 1.1.1.2/32
2323 fei = fib_table_entry_path_add(fib_index,
2326 FIB_ENTRY_FLAG_NONE,
2329 tm->hw[0]->sw_if_index,
2330 ~0, // invalid fib index
2333 FIB_ROUTE_PATH_FLAG_NONE);
2334 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2335 ai = fib_entry_get_adj(fei);
2336 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2338 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2339 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2341 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2344 * no change. 1.1.1.2/32 was already there RR sourced.
2346 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2347 fib_path_list_db_size());
2348 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2349 fib_path_list_pool_size());
2350 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2351 fib_entry_pool_size());
2354 * give 201 a resolved path.
2355 * it now has the unresolved 1.1.1.200 and the resolved 1.1.1.2,
2356 * only the latter contributes forwarding.
2358 fei = fib_table_entry_path_add(fib_index,
2361 FIB_ENTRY_FLAG_NONE,
2363 &pfx_1_1_1_2_s_32.fp_addr,
2368 FIB_ROUTE_PATH_FLAG_NONE);
2369 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_2_s_32, 0);
2370 fib_table_entry_path_remove(fib_index,
2374 &pfx_1_1_1_2_s_32.fp_addr,
2378 FIB_ROUTE_PATH_FLAG_NONE);
2381 * remove 200.200.200.201/32 which does not have a valid via FIB
2383 fib_table_entry_path_remove(fib_index,
2387 &pfx_1_1_1_200_s_32.fp_addr,
2388 ~0, // no index provided.
2391 FIB_ROUTE_PATH_FLAG_NONE);
2394 * -2 entries (BGP and RR). -1 shared path-list;
2396 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2397 FIB_NODE_INDEX_INVALID),
2398 "200.200.200.201/32 removed");
2399 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2400 FIB_NODE_INDEX_INVALID),
2401 "1.1.1.200/32 removed");
2403 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2404 fib_path_list_db_size());
2405 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2406 fib_path_list_pool_size());
2407 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2408 fib_entry_pool_size());
2411 * remove 200.200.200.200/32 which does have a valid via FIB
2413 fib_table_entry_path_remove(fib_index,
2417 &pfx_1_1_1_2_s_32.fp_addr,
2418 ~0, // no index provided.
2421 FIB_ROUTE_PATH_FLAG_NONE);
2423 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2424 FIB_NODE_INDEX_INVALID),
2425 "200.200.200.200/32 removed");
2426 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2427 FIB_NODE_INDEX_INVALID),
2428 "1.1.1.2/32 still present");
2431 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2433 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2434 fib_path_list_db_size());
2435 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2436 fib_path_list_pool_size());
2437 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2438 fib_entry_pool_size());
2441 * A recursive prefix that has a 2 path load-balance.
2442 * It also shares a next-hop with other BGP prefixes and hence
2443 * test the ref counting of RR sourced prefixes and 2 level LB.
2445 const fib_prefix_t bgp_102 = {
2447 .fp_proto = FIB_PROTOCOL_IP4,
2449 /* 100.100.100.101/32 */
2450 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2453 fib_table_entry_path_add(fib_index,
2456 FIB_ENTRY_FLAG_NONE,
2458 &pfx_1_1_1_1_s_32.fp_addr,
2459 ~0, // no index provided.
2460 fib_index, // same as route
2463 FIB_ROUTE_PATH_FLAG_NONE);
2464 fib_table_entry_path_add(fib_index,
2467 FIB_ENTRY_FLAG_NONE,
2469 &pfx_1_1_1_2_s_32.fp_addr,
2470 ~0, // no index provided.
2471 fib_index, // same as route's FIB
2474 FIB_ROUTE_PATH_FLAG_NONE);
2475 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2476 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2477 dpo = fib_entry_contribute_ip_forwarding(fei);
2479 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2480 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2481 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2482 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2484 lb = load_balance_get(dpo->dpoi_index);
2485 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2486 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2487 "First via 10.10.10.1");
2488 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2489 "Second via 10.10.10.1");
2491 fib_table_entry_path_remove(fib_index,
2495 &pfx_1_1_1_1_s_32.fp_addr,
2496 ~0, // no index provided.
2497 fib_index, // same as route's FIB
2499 FIB_ROUTE_PATH_FLAG_NONE);
2500 fib_table_entry_path_remove(fib_index,
2504 &pfx_1_1_1_2_s_32.fp_addr,
2505 ~0, // no index provided.
2506 fib_index, // same as route's FIB
2508 FIB_ROUTE_PATH_FLAG_NONE);
2509 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2510 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2513 * remove the remaining recursives
2515 fib_table_entry_path_remove(fib_index,
2519 &pfx_1_1_1_1_s_32.fp_addr,
2520 ~0, // no index provided.
2521 fib_index, // same as route's FIB
2523 FIB_ROUTE_PATH_FLAG_NONE);
2524 fib_table_entry_path_remove(fib_index,
2528 &pfx_1_1_1_1_s_32.fp_addr,
2529 ~0, // no index provided.
2530 fib_index, // same as route's FIB
2532 FIB_ROUTE_PATH_FLAG_NONE);
2533 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2534 FIB_NODE_INDEX_INVALID),
2535 "100.100.100.100/32 removed");
2536 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2537 FIB_NODE_INDEX_INVALID),
2538 "100.100.100.101/32 removed");
2541 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2543 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2544 fib_path_list_db_size());
2545 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2546 fib_path_list_pool_size());
2547 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2548 fib_entry_pool_size());
2551 * Add a recursive route via a connected cover, using an adj-fib that does exist
2553 fib_table_entry_path_add(fib_index,
2556 FIB_ENTRY_FLAG_NONE,
2559 ~0, // no index provided.
2560 fib_index, // Same as route's FIB
2563 FIB_ROUTE_PATH_FLAG_NONE);
2566 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2568 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2569 fib_path_list_db_size());
2570 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2571 fib_path_list_pool_size());
2572 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2573 fib_entry_pool_size());
2575 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2576 dpo = fib_entry_contribute_ip_forwarding(fei);
2578 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2579 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2581 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2582 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2584 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2585 "Flags set on RR via existing attached");
2588 * Add a recursive route via a connected cover, using and adj-fib that does
2591 ip46_address_t nh_10_10_10_3 = {
2592 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2594 fib_prefix_t pfx_10_10_10_3 = {
2596 .fp_proto = FIB_PROTOCOL_IP4,
2597 .fp_addr = nh_10_10_10_3,
2600 fib_table_entry_path_add(fib_index,
2603 FIB_ENTRY_FLAG_NONE,
2606 ~0, // no index provided.
2610 FIB_ROUTE_PATH_FLAG_NONE);
2613 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2614 * one unshared non-recursive via 10.10.10.3
2616 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2617 fib_path_list_db_size());
2618 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2619 fib_path_list_pool_size());
2620 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2621 fib_entry_pool_size());
2623 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2626 tm->hw[0]->sw_if_index);
2628 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2629 dpo = fib_entry_contribute_ip_forwarding(fei);
2630 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2631 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2633 ai = fib_entry_get_adj(fei);
2634 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2635 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2636 fib_entry_get_flags(fei)),
2637 "Flags set on RR via non-existing attached");
2639 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2640 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2645 * remove the recursives
2647 fib_table_entry_path_remove(fib_index,
2652 ~0, // no index provided.
2653 fib_index, // same as route's FIB
2655 FIB_ROUTE_PATH_FLAG_NONE);
2656 fib_table_entry_path_remove(fib_index,
2661 ~0, // no index provided.
2662 fib_index, // same as route's FIB
2664 FIB_ROUTE_PATH_FLAG_NONE);
2666 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2667 FIB_NODE_INDEX_INVALID),
2668 "200.200.200.201/32 removed");
2669 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2670 FIB_NODE_INDEX_INVALID),
2671 "200.200.200.200/32 removed");
2672 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2673 FIB_NODE_INDEX_INVALID),
2674 "10.10.10.3/32 removed");
2677 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2678 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2680 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2681 fib_path_list_db_size());
2682 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2683 fib_path_list_pool_size());
2684 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2685 fib_entry_pool_size());
2690 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2692 fib_prefix_t pfx_5_5_5_5_s_32 = {
2694 .fp_proto = FIB_PROTOCOL_IP4,
2696 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2699 fib_prefix_t pfx_5_5_5_6_s_32 = {
2701 .fp_proto = FIB_PROTOCOL_IP4,
2703 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2706 fib_prefix_t pfx_5_5_5_7_s_32 = {
2708 .fp_proto = FIB_PROTOCOL_IP4,
2710 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2714 fib_table_entry_path_add(fib_index,
2717 FIB_ENTRY_FLAG_NONE,
2719 &pfx_5_5_5_6_s_32.fp_addr,
2720 ~0, // no index provided.
2724 FIB_ROUTE_PATH_FLAG_NONE);
2725 fib_table_entry_path_add(fib_index,
2728 FIB_ENTRY_FLAG_NONE,
2730 &pfx_5_5_5_7_s_32.fp_addr,
2731 ~0, // no index provided.
2735 FIB_ROUTE_PATH_FLAG_NONE);
2736 fib_table_entry_path_add(fib_index,
2739 FIB_ENTRY_FLAG_NONE,
2741 &pfx_5_5_5_5_s_32.fp_addr,
2742 ~0, // no index provided.
2746 FIB_ROUTE_PATH_FLAG_NONE);
2748 * +3 entries, +3 shared path-list
2750 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2751 fib_path_list_db_size());
2752 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2753 fib_path_list_pool_size());
2754 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2755 fib_entry_pool_size());
2758 * All the entries have only looped paths, so they are all drop
2760 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2761 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2762 "LB for 5.5.5.7/32 is via adj for DROP");
2763 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2764 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2765 "LB for 5.5.5.5/32 is via adj for DROP");
2766 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2767 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2768 "LB for 5.5.5.6/32 is via adj for DROP");
2771 * provide 5.5.5.6/32 with alternate path.
2772 * this will allow only 5.5.5.6/32 to forward with this path, the others
2773 * are still drop since the loop is still present.
2775 fib_table_entry_path_add(fib_index,
2778 FIB_ENTRY_FLAG_NONE,
2781 tm->hw[0]->sw_if_index,
2785 FIB_ROUTE_PATH_FLAG_NONE);
2787 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2788 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2790 lb = load_balance_get(dpo1->dpoi_index);
2791 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2793 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2794 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2795 FIB_TEST((ai_01 == dpo2->dpoi_index),
2796 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2798 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2799 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2800 "LB for 5.5.5.7/32 is via adj for DROP");
2801 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2802 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2803 "LB for 5.5.5.5/32 is via adj for DROP");
2806 * remove the alternate path for 5.5.5.6/32
2809 fib_table_entry_path_remove(fib_index,
2814 tm->hw[0]->sw_if_index,
2817 FIB_ROUTE_PATH_FLAG_NONE);
2819 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2820 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2821 "LB for 5.5.5.7/32 is via adj for DROP");
2822 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2823 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2824 "LB for 5.5.5.5/32 is via adj for DROP");
2825 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2826 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2827 "LB for 5.5.5.6/32 is via adj for DROP");
2830 * break the loop by giving 5.5.5.5/32 a new set of paths
2831 * expect all to forward via this new path.
2833 fib_table_entry_update_one_path(fib_index,
2836 FIB_ENTRY_FLAG_NONE,
2839 tm->hw[0]->sw_if_index,
2840 ~0, // invalid fib index
2843 FIB_ROUTE_PATH_FLAG_NONE);
2845 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2846 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2847 lb = load_balance_get(dpo1->dpoi_index);
2848 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2850 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2851 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2852 FIB_TEST((ai_01 == dpo2->dpoi_index),
2853 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2855 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2856 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2858 lb = load_balance_get(dpo2->dpoi_index);
2859 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2860 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2861 "5.5.5.5.7 via 5.5.5.5");
2863 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2864 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2866 lb = load_balance_get(dpo1->dpoi_index);
2867 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2868 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2869 "5.5.5.5.6 via 5.5.5.7");
2872 * revert back to the loop. so we can remove the prefixes with
2875 fib_table_entry_update_one_path(fib_index,
2878 FIB_ENTRY_FLAG_NONE,
2880 &pfx_5_5_5_6_s_32.fp_addr,
2881 ~0, // no index provided.
2885 FIB_ROUTE_PATH_FLAG_NONE);
2887 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2888 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2889 "LB for 5.5.5.7/32 is via adj for DROP");
2890 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2891 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2892 "LB for 5.5.5.5/32 is via adj for DROP");
2893 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2894 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2895 "LB for 5.5.5.6/32 is via adj for DROP");
2898 * remove all the 5.5.5.x/32 prefixes
2900 fib_table_entry_path_remove(fib_index,
2904 &pfx_5_5_5_6_s_32.fp_addr,
2905 ~0, // no index provided.
2906 fib_index, // same as route's FIB
2908 FIB_ROUTE_PATH_FLAG_NONE);
2909 fib_table_entry_path_remove(fib_index,
2913 &pfx_5_5_5_7_s_32.fp_addr,
2914 ~0, // no index provided.
2915 fib_index, // same as route's FIB
2917 FIB_ROUTE_PATH_FLAG_NONE);
2918 fib_table_entry_path_remove(fib_index,
2922 &pfx_5_5_5_5_s_32.fp_addr,
2923 ~0, // no index provided.
2924 fib_index, // same as route's FIB
2926 FIB_ROUTE_PATH_FLAG_NONE);
2927 fib_table_entry_path_remove(fib_index,
2932 ~0, // no index provided.
2933 fib_index, // same as route's FIB
2935 FIB_ROUTE_PATH_FLAG_NONE);
2938 * -3 entries, -3 shared path-list
2940 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2941 fib_path_list_db_size());
2942 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2943 fib_path_list_pool_size());
2944 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2945 fib_entry_pool_size());
2948 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2950 fib_table_entry_path_add(fib_index,
2953 FIB_ENTRY_FLAG_NONE,
2955 &pfx_5_5_5_6_s_32.fp_addr,
2956 ~0, // no index provided.
2960 FIB_ROUTE_PATH_FLAG_NONE);
2961 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2962 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2963 "1-level 5.5.5.6/32 loop is via adj for DROP");
2965 fib_table_entry_path_remove(fib_index,
2969 &pfx_5_5_5_6_s_32.fp_addr,
2970 ~0, // no index provided.
2971 fib_index, // same as route's FIB
2973 FIB_ROUTE_PATH_FLAG_NONE);
2974 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2975 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2976 "1-level 5.5.5.6/32 loop is removed");
2979 * A recursive route whose next-hop is covered by the prefix.
2980 * This would mean the via-fib, which inherits forwarding from its
2981 * cover, thus picks up forwarding from the prfix, which is via the
2982 * via-fib, and we have a loop.
2984 fib_prefix_t pfx_23_23_23_0_s_24 = {
2986 .fp_proto = FIB_PROTOCOL_IP4,
2988 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2991 fib_prefix_t pfx_23_23_23_23_s_32 = {
2993 .fp_proto = FIB_PROTOCOL_IP4,
2995 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2998 fei = fib_table_entry_path_add(fib_index,
2999 &pfx_23_23_23_0_s_24,
3001 FIB_ENTRY_FLAG_NONE,
3003 &pfx_23_23_23_23_s_32.fp_addr,
3008 FIB_ROUTE_PATH_FLAG_NONE);
3009 dpo = fib_entry_contribute_ip_forwarding(fei);
3010 FIB_TEST(load_balance_is_drop(dpo),
3011 "23.23.23.0/24 via covered is DROP");
3012 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3015 * add-remove test. no change.
3017 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3018 fib_path_list_db_size());
3019 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3020 fib_path_list_pool_size());
3021 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3022 fib_entry_pool_size());
3025 * Make the default route recursive via a unknown next-hop. Thus the
3026 * next hop's cover would be the default route
3028 fei = fib_table_entry_path_add(fib_index,
3031 FIB_ENTRY_FLAG_NONE,
3033 &pfx_23_23_23_23_s_32.fp_addr,
3038 FIB_ROUTE_PATH_FLAG_NONE);
3039 dpo = fib_entry_contribute_ip_forwarding(fei);
3040 FIB_TEST(load_balance_is_drop(dpo),
3041 "0.0.0.0.0/0 via is DROP");
3042 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3043 "no resolving interface for looped 0.0.0.0/0");
3045 fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
3046 dpo = fib_entry_contribute_ip_forwarding(fei);
3047 FIB_TEST(load_balance_is_drop(dpo),
3048 "23.23.23.23/32 via is DROP");
3049 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3050 "no resolving interface for looped 23.23.23.23/32");
3052 fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
3055 * A recursive route with recursion constraints.
3056 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
3058 fib_table_entry_path_add(fib_index,
3061 FIB_ENTRY_FLAG_NONE,
3068 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3070 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3071 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3073 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3074 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3076 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3077 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3080 * save the load-balance. we expect it to be inplace modified
3082 lb = load_balance_get(dpo1->dpoi_index);
3085 * add a covering prefix for the via fib that would otherwise serve
3086 * as the resolving route when the host is removed
3088 fib_table_entry_path_add(fib_index,
3091 FIB_ENTRY_FLAG_NONE,
3094 tm->hw[0]->sw_if_index,
3095 ~0, // invalid fib index
3098 FIB_ROUTE_PATH_FLAG_NONE);
3099 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3100 ai = fib_entry_get_adj(fei);
3101 FIB_TEST((ai == ai_01),
3102 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3105 * remove the host via FIB - expect the BGP prefix to be drop
3107 fib_table_entry_path_remove(fib_index,
3112 tm->hw[0]->sw_if_index,
3113 ~0, // invalid fib index
3115 FIB_ROUTE_PATH_FLAG_NONE);
3117 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3118 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3121 * add the via-entry host reoute back. expect to resolve again
3123 fib_table_entry_path_add(fib_index,
3126 FIB_ENTRY_FLAG_NONE,
3129 tm->hw[0]->sw_if_index,
3130 ~0, // invalid fib index
3133 FIB_ROUTE_PATH_FLAG_NONE);
3134 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3135 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3138 * add another path for the recursive. it will then have 2.
3140 fib_prefix_t pfx_1_1_1_3_s_32 = {
3142 .fp_proto = FIB_PROTOCOL_IP4,
3144 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3147 fib_table_entry_path_add(fib_index,
3150 FIB_ENTRY_FLAG_NONE,
3153 tm->hw[0]->sw_if_index,
3154 ~0, // invalid fib index
3157 FIB_ROUTE_PATH_FLAG_NONE);
3159 fib_table_entry_path_add(fib_index,
3162 FIB_ENTRY_FLAG_NONE,
3164 &pfx_1_1_1_3_s_32.fp_addr,
3169 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3172 * add a bunch load more entries using this path combo so that we get
3173 * an LB-map created.
3176 fib_prefix_t bgp_78s[N_P];
3177 for (ii = 0; ii < N_P; ii++)
3179 bgp_78s[ii].fp_len = 32;
3180 bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3181 bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3184 fib_table_entry_path_add(fib_index,
3187 FIB_ENTRY_FLAG_NONE,
3189 &pfx_1_1_1_3_s_32.fp_addr,
3194 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3195 fib_table_entry_path_add(fib_index,
3198 FIB_ENTRY_FLAG_NONE,
3205 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3208 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3209 dpo = fib_entry_contribute_ip_forwarding(fei);
3211 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3212 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3213 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3214 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3215 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3216 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3217 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3218 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3221 * expect the lb-map used by the recursive's load-balance is using both buckets
3223 load_balance_map_t *lbm;
3226 lb = load_balance_get(dpo->dpoi_index);
3228 load_balance_map_lock(lbmi);
3229 lbm = load_balance_map_get(lbmi);
3231 FIB_TEST(lbm->lbm_buckets[0] == 0,
3232 "LB maps's bucket 0 is %d",
3233 lbm->lbm_buckets[0]);
3234 FIB_TEST(lbm->lbm_buckets[1] == 1,
3235 "LB maps's bucket 1 is %d",
3236 lbm->lbm_buckets[1]);
3239 * withdraw one of the /32 via-entrys.
3240 * that ECMP path will be unresolved and forwarding should continue on the
3241 * other available path. this is an iBGP PIC edge failover.
3242 * Test the forwarding changes without re-fetching the adj from the
3243 * recursive entry. this ensures its the same one that is updated; i.e. an
3246 fib_table_entry_path_remove(fib_index,
3251 tm->hw[0]->sw_if_index,
3252 ~0, // invalid fib index
3254 FIB_ROUTE_PATH_FLAG_NONE);
3256 /* suspend so the update walk kicks int */
3257 vlib_process_suspend(vlib_get_main(), 1e-5);
3259 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3260 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3261 "post PIC 200.200.200.200/32 was inplace modified");
3263 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3264 "post PIC adj for 200.200.200.200/32 is recursive"
3265 " via adj for 1.1.1.3");
3268 * the LB maps that was locked above should have been modified to remove
3269 * the path that was down, and thus its bucket points to a path that is
3272 FIB_TEST(lbm->lbm_buckets[0] == 1,
3273 "LB maps's bucket 0 is %d",
3274 lbm->lbm_buckets[0]);
3275 FIB_TEST(lbm->lbm_buckets[1] == 1,
3276 "LB maps's bucket 1 is %d",
3277 lbm->lbm_buckets[1]);
3279 load_balance_map_unlock(lbmi);
3282 * add it back. again
3284 fib_table_entry_path_add(fib_index,
3287 FIB_ENTRY_FLAG_NONE,
3290 tm->hw[0]->sw_if_index,
3291 ~0, // invalid fib index
3294 FIB_ROUTE_PATH_FLAG_NONE);
3296 /* suspend so the update walk kicks in */
3297 vlib_process_suspend(vlib_get_main(), 1e-5);
3299 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3300 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3301 "via adj for 1.1.1.1");
3302 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3303 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3304 "via adj for 1.1.1.3");
3306 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3307 dpo = fib_entry_contribute_ip_forwarding(fei);
3308 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3309 "post PIC 200.200.200.200/32 was inplace modified");
3312 * add a 3rd path. this makes the LB 16 buckets.
3314 fib_table_entry_path_add(fib_index,
3317 FIB_ENTRY_FLAG_NONE,
3319 &pfx_1_1_1_2_s_32.fp_addr,
3324 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3325 for (ii = 0; ii < N_P; ii++)
3327 fib_table_entry_path_add(fib_index,
3330 FIB_ENTRY_FLAG_NONE,
3332 &pfx_1_1_1_2_s_32.fp_addr,
3337 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3340 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3341 dpo = fib_entry_contribute_ip_forwarding(fei);
3342 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3343 "200.200.200.200/32 was inplace modified for 3rd path");
3344 FIB_TEST(16 == lb->lb_n_buckets,
3345 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3348 load_balance_map_lock(lbmi);
3349 lbm = load_balance_map_get(lbmi);
3351 for (ii = 0; ii < 16; ii++)
3353 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3354 "LB Map for 200.200.200.200/32 at %d is %d",
3355 ii, lbm->lbm_buckets[ii]);
3359 * trigger PIC by removing the first via-entry
3360 * the first 6 buckets of the map should map to the next 6
3362 fib_table_entry_path_remove(fib_index,
3367 tm->hw[0]->sw_if_index,
3370 FIB_ROUTE_PATH_FLAG_NONE);
3371 /* suspend so the update walk kicks int */
3372 vlib_process_suspend(vlib_get_main(), 1e-5);
3374 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3375 dpo = fib_entry_contribute_ip_forwarding(fei);
3376 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3377 "200.200.200.200/32 was inplace modified for 3rd path");
3378 FIB_TEST(2 == lb->lb_n_buckets,
3379 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3381 for (ii = 0; ii < 6; ii++)
3383 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3384 "LB Map for 200.200.200.200/32 at %d is %d",
3385 ii, lbm->lbm_buckets[ii]);
3387 for (ii = 6; ii < 16; ii++)
3389 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3390 "LB Map for 200.200.200.200/32 at %d is %d",
3391 ii, lbm->lbm_buckets[ii]);
3393 load_balance_map_unlock(lbmi);
3398 fib_table_entry_path_add(fib_index,
3401 FIB_ENTRY_FLAG_NONE,
3404 tm->hw[0]->sw_if_index,
3408 FIB_ROUTE_PATH_FLAG_NONE);
3410 for (ii = 0; ii < N_P; ii++)
3412 fib_table_entry_delete(fib_index,
3415 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3416 fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3418 format_fib_prefix, &bgp_78s[ii]);
3420 fib_table_entry_path_remove(fib_index,
3424 &pfx_1_1_1_2_s_32.fp_addr,
3428 MPLS_LABEL_INVALID);
3429 fib_table_entry_path_remove(fib_index,
3437 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3438 fib_table_entry_path_remove(fib_index,
3442 &pfx_1_1_1_3_s_32.fp_addr,
3446 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3447 fib_table_entry_delete(fib_index,
3450 fib_table_entry_delete(fib_index,
3453 /* suspend so the update walk kicks int */
3454 vlib_process_suspend(vlib_get_main(), 1e-5);
3455 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3456 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3457 "1.1.1.1/28 removed");
3458 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3459 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3460 "1.1.1.3/32 removed");
3461 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3462 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3463 "200.200.200.200/32 removed");
3466 * add-remove test. no change.
3468 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3469 fib_path_list_db_size());
3470 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3471 fib_path_list_pool_size());
3472 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3473 fib_entry_pool_size());
3476 * A route whose paths are built up iteratively and then removed
3479 fib_prefix_t pfx_4_4_4_4_s_32 = {
3481 .fp_proto = FIB_PROTOCOL_IP4,
3484 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3488 fib_table_entry_path_add(fib_index,
3491 FIB_ENTRY_FLAG_NONE,
3494 tm->hw[0]->sw_if_index,
3498 FIB_ROUTE_PATH_FLAG_NONE);
3499 fib_table_entry_path_add(fib_index,
3502 FIB_ENTRY_FLAG_NONE,
3505 tm->hw[0]->sw_if_index,
3509 FIB_ROUTE_PATH_FLAG_NONE);
3510 fib_table_entry_path_add(fib_index,
3513 FIB_ENTRY_FLAG_NONE,
3516 tm->hw[0]->sw_if_index,
3520 FIB_ROUTE_PATH_FLAG_NONE);
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 present");
3525 fib_table_entry_delete(fib_index,
3528 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3529 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3530 "4.4.4.4/32 removed");
3533 * add-remove test. no change.
3535 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3536 fib_path_list_db_size());
3537 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3538 fib_path_list_pool_size());
3539 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3540 fib_entry_pool_size());
3543 * A route with multiple paths at once
3545 fib_route_path_t *r_paths = NULL;
3547 for (ii = 0; ii < 4; ii++)
3549 fib_route_path_t r_path = {
3550 .frp_proto = DPO_PROTO_IP4,
3552 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3554 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3556 .frp_fib_index = ~0,
3558 vec_add1(r_paths, r_path);
3561 fib_table_entry_update(fib_index,
3564 FIB_ENTRY_FLAG_NONE,
3567 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3568 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3569 dpo = fib_entry_contribute_ip_forwarding(fei);
3571 lb = load_balance_get(dpo->dpoi_index);
3572 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3574 fib_table_entry_delete(fib_index,
3577 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3578 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3579 "4.4.4.4/32 removed");
3583 * add-remove test. no change.
3585 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3586 fib_path_list_db_size());
3587 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3588 fib_path_list_pool_size());
3589 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3590 fib_entry_pool_size());
3593 * A route deag route
3595 fib_table_entry_path_add(fib_index,
3598 FIB_ENTRY_FLAG_NONE,
3605 FIB_ROUTE_PATH_FLAG_NONE);
3607 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3608 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3610 dpo = fib_entry_contribute_ip_forwarding(fei);
3611 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3612 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3614 FIB_TEST((fib_index == lkd->lkd_fib_index),
3615 "4.4.4.4/32 is deag in %d %U",
3617 format_dpo_id, dpo, 0);
3618 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
3619 "4.4.4.4/32 is source deag in %d %U",
3621 format_dpo_id, dpo, 0);
3623 fib_table_entry_delete(fib_index,
3626 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3627 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3628 "4.4.4.4/32 removed");
3632 * A route deag route in a source lookup table
3634 fib_table_entry_path_add(fib_index,
3637 FIB_ENTRY_FLAG_NONE,
3644 FIB_ROUTE_PATH_SOURCE_LOOKUP);
3646 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3647 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3649 dpo = fib_entry_contribute_ip_forwarding(fei);
3650 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3651 lkd = lookup_dpo_get(dpo->dpoi_index);
3653 FIB_TEST((fib_index == lkd->lkd_fib_index),
3654 "4.4.4.4/32 is deag in %d %U",
3656 format_dpo_id, dpo, 0);
3657 FIB_TEST((LOOKUP_INPUT_SRC_ADDR == lkd->lkd_input),
3658 "4.4.4.4/32 is source deag in %d %U",
3660 format_dpo_id, dpo, 0);
3662 fib_table_entry_delete(fib_index,
3665 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3666 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3667 "4.4.4.4/32 removed");
3671 * add-remove test. no change.
3673 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3674 fib_path_list_db_size());
3675 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3676 fib_path_list_pool_size());
3677 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3678 fib_entry_pool_size());
3682 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3684 fib_prefix_t pfx_34_1_1_1_s_32 = {
3686 .fp_proto = FIB_PROTOCOL_IP4,
3688 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3691 fib_prefix_t pfx_34_34_1_1_s_32 = {
3693 .fp_proto = FIB_PROTOCOL_IP4,
3695 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3698 fei = fib_table_entry_path_add(fib_index,
3699 &pfx_34_34_1_1_s_32,
3701 FIB_ENTRY_FLAG_NONE,
3704 tm->hw[0]->sw_if_index,
3708 FIB_ROUTE_PATH_FLAG_NONE);
3709 fei = fib_table_entry_path_add(fib_index,
3712 FIB_ENTRY_FLAG_NONE,
3714 &pfx_34_34_1_1_s_32.fp_addr,
3719 FIB_ROUTE_PATH_FLAG_NONE);
3720 fei = fib_table_entry_path_add(fib_index,
3723 FIB_ENTRY_FLAG_NONE,
3725 &pfx_34_34_1_1_s_32.fp_addr,
3730 FIB_ROUTE_PATH_FLAG_NONE);
3731 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3732 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3733 fib_table_entry_delete(fib_index,
3734 &pfx_34_34_1_1_s_32,
3739 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3740 * all of which are via 10.10.10.1, Itf1
3742 fib_table_entry_path_remove(fib_index,
3747 tm->hw[0]->sw_if_index,
3750 FIB_ROUTE_PATH_FLAG_NONE);
3751 fib_table_entry_path_remove(fib_index,
3756 tm->hw[0]->sw_if_index,
3759 FIB_ROUTE_PATH_FLAG_NONE);
3760 fib_table_entry_path_remove(fib_index,
3765 tm->hw[0]->sw_if_index,
3768 FIB_ROUTE_PATH_FLAG_NONE);
3770 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3771 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3772 "1.1.1.1/32 removed");
3773 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3774 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3775 "1.1.1.2/32 removed");
3776 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3777 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3778 "1.1.2.0/24 removed");
3781 * -3 entries and -1 shared path-list
3783 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3784 fib_path_list_db_size());
3785 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3786 fib_path_list_pool_size());
3787 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3788 fib_entry_pool_size());
3791 * An attached-host route. Expect to link to the incomplete adj
3793 fib_prefix_t pfx_4_1_1_1_s_32 = {
3795 .fp_proto = FIB_PROTOCOL_IP4,
3798 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3801 fib_table_entry_path_add(fib_index,
3804 FIB_ENTRY_FLAG_NONE,
3807 tm->hw[0]->sw_if_index,
3811 FIB_ROUTE_PATH_FLAG_NONE);
3813 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3814 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3815 ai = fib_entry_get_adj(fei);
3817 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3819 &pfx_4_1_1_1_s_32.fp_addr,
3820 tm->hw[0]->sw_if_index);
3821 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3825 * +1 entry and +1 shared path-list
3827 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3828 fib_path_list_db_size());
3829 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3830 fib_path_list_pool_size());
3831 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3832 fib_entry_pool_size());
3834 fib_table_entry_delete(fib_index,
3838 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3839 fib_path_list_db_size());
3840 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3841 fib_path_list_pool_size());
3842 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3843 fib_entry_pool_size());
3846 * add a v6 prefix via v4 next-hops
3848 fib_prefix_t pfx_2001_s_64 = {
3850 .fp_proto = FIB_PROTOCOL_IP6,
3852 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3855 fei = fib_table_entry_path_add(0, //default v6 table
3858 FIB_ENTRY_FLAG_NONE,
3861 tm->hw[0]->sw_if_index,
3865 FIB_ROUTE_PATH_FLAG_NONE);
3867 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3868 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3869 ai = fib_entry_get_adj(fei);
3871 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3872 "2001::/64 via ARP-adj");
3873 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3874 "2001::/64 is link type v6");
3875 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3876 "2001::/64 ADJ-adj is NH proto v4");
3877 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3880 * add a uRPF exempt prefix:
3882 * - it's forwarding is drop
3883 * - it's uRPF list is not empty
3884 * - the uRPF list for the default route (it's cover) is empty
3886 fei = fib_table_entry_special_add(fib_index,
3888 FIB_SOURCE_URPF_EXEMPT,
3889 FIB_ENTRY_FLAG_DROP);
3890 dpo = fib_entry_contribute_ip_forwarding(fei);
3891 FIB_TEST(load_balance_is_drop(dpo),
3892 "uRPF exempt 4.1.1.1/32 DROP");
3893 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3894 "uRPF list for exempt prefix has itf index 0");
3895 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3896 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3897 "uRPF list for 0.0.0.0/0 empty");
3899 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3902 * An adj-fib that fails the refinement criteria - no connected cover
3904 fib_prefix_t pfx_12_10_10_2_s_32 = {
3906 .fp_proto = FIB_PROTOCOL_IP4,
3909 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3913 fib_table_entry_path_add(fib_index,
3914 &pfx_12_10_10_2_s_32,
3916 FIB_ENTRY_FLAG_ATTACHED,
3918 &pfx_12_10_10_2_s_32.fp_addr,
3919 tm->hw[0]->sw_if_index,
3920 ~0, // invalid fib index
3923 FIB_ROUTE_PATH_FLAG_NONE);
3925 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3926 dpo = fib_entry_contribute_ip_forwarding(fei);
3927 FIB_TEST(!dpo_id_is_valid(dpo),
3928 "no connected cover adj-fib fails refinement");
3930 fib_table_entry_delete(fib_index,
3931 &pfx_12_10_10_2_s_32,
3935 * An adj-fib that fails the refinement criteria - cover is connected
3936 * but on a different interface
3938 fib_prefix_t pfx_10_10_10_127_s_32 = {
3940 .fp_proto = FIB_PROTOCOL_IP4,
3943 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3947 fib_table_entry_path_add(fib_index,
3948 &pfx_10_10_10_127_s_32,
3950 FIB_ENTRY_FLAG_ATTACHED,
3952 &pfx_10_10_10_127_s_32.fp_addr,
3953 tm->hw[1]->sw_if_index,
3954 ~0, // invalid fib index
3957 FIB_ROUTE_PATH_FLAG_NONE);
3959 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3960 dpo = fib_entry_contribute_ip_forwarding(fei);
3961 FIB_TEST(!dpo_id_is_valid(dpo),
3962 "wrong interface adj-fib fails refinement");
3964 fib_table_entry_delete(fib_index,
3965 &pfx_10_10_10_127_s_32,
3969 * add a second path to an adj-fib
3970 * this is a sumiluation of another ARP entry created
3971 * on an interface on which the connected prefi does not exist.
3972 * The second path fails refinement. Expect to forward through the
3975 fib_prefix_t pfx_10_10_10_3_s_32 = {
3977 .fp_proto = FIB_PROTOCOL_IP4,
3980 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
3984 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3987 tm->hw[0]->sw_if_index);
3989 fib_test_lb_bucket_t ip_o_10_10_10_3 = {
3995 fei = fib_table_entry_path_add(fib_index,
3996 &pfx_10_10_10_3_s_32,
3998 FIB_ENTRY_FLAG_NONE,
4001 tm->hw[0]->sw_if_index,
4005 FIB_ROUTE_PATH_FLAG_NONE);
4006 fei = fib_table_entry_path_add(fib_index,
4007 &pfx_10_10_10_3_s_32,
4009 FIB_ENTRY_FLAG_NONE,
4012 tm->hw[1]->sw_if_index,
4016 FIB_ROUTE_PATH_FLAG_NONE);
4017 FIB_TEST(fib_test_validate_entry(fei,
4018 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4021 "10.10.10.3 via 10.10.10.3/Eth0 only");
4024 * remove the path that refines the cover, should go unresolved
4026 fib_table_entry_path_remove(fib_index,
4027 &pfx_10_10_10_3_s_32,
4031 tm->hw[0]->sw_if_index,
4034 FIB_ROUTE_PATH_FLAG_NONE);
4035 dpo = fib_entry_contribute_ip_forwarding(fei);
4036 FIB_TEST(!dpo_id_is_valid(dpo),
4037 "wrong interface adj-fib fails refinement");
4040 * add back the path that refines the cover
4042 fei = fib_table_entry_path_add(fib_index,
4043 &pfx_10_10_10_3_s_32,
4045 FIB_ENTRY_FLAG_NONE,
4048 tm->hw[0]->sw_if_index,
4052 FIB_ROUTE_PATH_FLAG_NONE);
4053 FIB_TEST(fib_test_validate_entry(fei,
4054 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4057 "10.10.10.3 via 10.10.10.3/Eth0 only");
4060 * remove the path that does not refine the cover
4062 fib_table_entry_path_remove(fib_index,
4063 &pfx_10_10_10_3_s_32,
4067 tm->hw[1]->sw_if_index,
4070 FIB_ROUTE_PATH_FLAG_NONE);
4071 FIB_TEST(fib_test_validate_entry(fei,
4072 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4075 "10.10.10.3 via 10.10.10.3/Eth0 only");
4078 * remove the path that does refine, it's the last path, so
4079 * the entry should be gone
4081 fib_table_entry_path_remove(fib_index,
4082 &pfx_10_10_10_3_s_32,
4086 tm->hw[0]->sw_if_index,
4089 FIB_ROUTE_PATH_FLAG_NONE);
4090 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4091 FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
4096 * change the table's flow-hash config - expect the update to propagete to
4097 * the entries' load-balance objects
4099 flow_hash_config_t old_hash_config, new_hash_config;
4101 old_hash_config = fib_table_get_flow_hash_config(fib_index,
4103 new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
4104 IP_FLOW_HASH_DST_ADDR);
4106 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4107 dpo = fib_entry_contribute_ip_forwarding(fei);
4108 lb = load_balance_get(dpo->dpoi_index);
4109 FIB_TEST((lb->lb_hash_config == old_hash_config),
4110 "Table and LB hash config match: %U",
4111 format_ip_flow_hash_config, lb->lb_hash_config);
4113 fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
4115 FIB_TEST((lb->lb_hash_config == new_hash_config),
4116 "Table and LB newhash config match: %U",
4117 format_ip_flow_hash_config, lb->lb_hash_config);
4120 * A route via DVR DPO
4122 fei = fib_table_entry_path_add(fib_index,
4123 &pfx_10_10_10_3_s_32,
4125 FIB_ENTRY_FLAG_NONE,
4128 tm->hw[0]->sw_if_index,
4132 FIB_ROUTE_PATH_DVR);
4133 dpo_id_t dvr_dpo = DPO_INVALID;
4134 dvr_dpo_add_or_lock(tm->hw[0]->sw_if_index, DPO_PROTO_IP4, &dvr_dpo);
4135 fib_test_lb_bucket_t ip_o_l2 = {
4138 .adj = dvr_dpo.dpoi_index,
4142 FIB_TEST(fib_test_validate_entry(fei,
4143 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4146 "10.10.10.3 via L2 on Eth0");
4147 fib_table_entry_path_remove(fib_index,
4148 &pfx_10_10_10_3_s_32,
4152 tm->hw[0]->sw_if_index,
4155 FIB_ROUTE_PATH_DVR);
4156 dpo_reset(&dvr_dpo);
4162 fib_table_entry_delete(fib_index,
4163 &pfx_10_10_10_1_s_32,
4165 fib_table_entry_delete(fib_index,
4166 &pfx_10_10_10_2_s_32,
4168 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4169 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4170 "10.10.10.1/32 adj-fib removed");
4171 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4172 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4173 "10.10.10.2/32 adj-fib removed");
4176 * -2 entries and -2 non-shared path-list
4178 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4179 fib_path_list_db_size());
4180 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4181 fib_path_list_pool_size());
4182 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4183 fib_entry_pool_size());
4186 * unlock the adjacencies for which this test provided a rewrite.
4187 * These are the last locks on these adjs. they should thus go away.
4191 adj_unlock(ai_12_12_12_12);
4193 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4198 * remove the interface prefixes
4200 local_pfx.fp_len = 32;
4201 fib_table_entry_special_remove(fib_index, &local_pfx,
4202 FIB_SOURCE_INTERFACE);
4203 fei = fib_table_lookup(fib_index, &local_pfx);
4205 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4206 fib_table_lookup_exact_match(fib_index, &local_pfx),
4207 "10.10.10.10/32 adj-fib removed");
4209 local_pfx.fp_len = 24;
4210 fib_table_entry_delete(fib_index, &local_pfx,
4211 FIB_SOURCE_INTERFACE);
4213 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4214 fib_table_lookup_exact_match(fib_index, &local_pfx),
4215 "10.10.10.10/24 adj-fib removed");
4218 * -2 entries and -2 non-shared path-list
4220 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4221 fib_path_list_db_size());
4222 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4223 fib_path_list_pool_size());
4224 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4225 fib_entry_pool_size());
4228 * Last but not least, remove the VRF
4230 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4233 "NO API Source'd prefixes");
4234 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4237 "NO RR Source'd prefixes");
4238 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4240 FIB_SOURCE_INTERFACE)),
4241 "NO INterface Source'd prefixes");
4243 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
4245 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4246 fib_path_list_db_size());
4247 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4248 fib_path_list_pool_size());
4249 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4250 fib_entry_pool_size());
4251 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4252 pool_elts(fib_urpf_list_pool));
4253 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4254 pool_elts(load_balance_map_pool));
4255 FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4256 pool_elts(load_balance_pool));
4257 FIB_TEST((0 == pool_elts(dvr_dpo_pool)), "L2 DPO pool size is %d",
4258 pool_elts(dvr_dpo_pool));
4267 * In the default table check for the presence and correct forwarding
4268 * of the special entries
4270 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4271 const dpo_id_t *dpo, *dpo_drop;
4272 const ip_adjacency_t *adj;
4273 const receive_dpo_t *rd;
4278 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4281 /* via 2001:0:0:1::2 */
4282 ip46_address_t nh_2001_2 = {
4285 [0] = clib_host_to_net_u64(0x2001000000000001),
4286 [1] = clib_host_to_net_u64(0x0000000000000002),
4293 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4295 /* Find or create FIB table 11 */
4296 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
4299 for (ii = 0; ii < 4; ii++)
4301 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4304 fib_prefix_t pfx_0_0 = {
4306 .fp_proto = FIB_PROTOCOL_IP6,
4314 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4315 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4316 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4317 "Default route is DROP");
4319 dpo = fib_entry_contribute_ip_forwarding(dfrt);
4320 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4323 &pfx_0_0.fp_addr.ip6)),
4324 "default-route; fwd and non-fwd tables match");
4326 // FIXME - check specials.
4329 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4330 * each with 2 entries and a v6 mfib with 4 path-lists.
4331 * All entries are special so no path-list sharing.
4334 #define PNPS (5+4+4)
4335 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4336 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4337 fib_path_list_pool_size());
4338 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4339 fib_entry_pool_size());
4342 * add interface routes.
4343 * validate presence of /64 attached and /128 recieve.
4344 * test for the presence of the receive address in the glean and local adj
4346 * receive on 2001:0:0:1::1/128
4348 fib_prefix_t local_pfx = {
4350 .fp_proto = FIB_PROTOCOL_IP6,
4354 [0] = clib_host_to_net_u64(0x2001000000000001),
4355 [1] = clib_host_to_net_u64(0x0000000000000001),
4361 fib_table_entry_update_one_path(fib_index, &local_pfx,
4362 FIB_SOURCE_INTERFACE,
4363 (FIB_ENTRY_FLAG_CONNECTED |
4364 FIB_ENTRY_FLAG_ATTACHED),
4367 tm->hw[0]->sw_if_index,
4371 FIB_ROUTE_PATH_FLAG_NONE);
4372 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4374 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4376 ai = fib_entry_get_adj(fei);
4377 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4379 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4380 "attached interface adj is glean");
4381 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4382 &adj->sub_type.glean.receive_addr)),
4383 "attached interface adj is receive ok");
4384 dpo = fib_entry_contribute_ip_forwarding(fei);
4385 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4388 &local_pfx.fp_addr.ip6)),
4389 "attached-route; fwd and non-fwd tables match");
4391 local_pfx.fp_len = 128;
4392 fib_table_entry_update_one_path(fib_index, &local_pfx,
4393 FIB_SOURCE_INTERFACE,
4394 (FIB_ENTRY_FLAG_CONNECTED |
4395 FIB_ENTRY_FLAG_LOCAL),
4398 tm->hw[0]->sw_if_index,
4399 ~0, // invalid fib index
4402 FIB_ROUTE_PATH_FLAG_NONE);
4403 fei = fib_table_lookup(fib_index, &local_pfx);
4405 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4407 dpo = fib_entry_contribute_ip_forwarding(fei);
4408 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4409 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4410 "local interface adj is local");
4411 rd = receive_dpo_get(dpo->dpoi_index);
4413 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4415 "local interface adj is receive ok");
4417 dpo = fib_entry_contribute_ip_forwarding(fei);
4418 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4421 &local_pfx.fp_addr.ip6)),
4422 "local-route; fwd and non-fwd tables match");
4425 * +2 entries. +2 unshared path-lists
4427 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4428 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4429 fib_path_list_pool_size());
4430 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4431 fib_entry_pool_size());
4434 * Modify the default route to be via an adj not yet known.
4435 * this sources the defalut route with the API source, which is
4436 * a higher preference to the DEFAULT_ROUTE source
4438 fib_table_entry_path_add(fib_index, &pfx_0_0,
4440 FIB_ENTRY_FLAG_NONE,
4443 tm->hw[0]->sw_if_index,
4447 FIB_ROUTE_PATH_FLAG_NONE);
4448 fei = fib_table_lookup(fib_index, &pfx_0_0);
4450 FIB_TEST((fei == dfrt), "default route same index");
4451 ai = fib_entry_get_adj(fei);
4452 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4454 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4455 "adj is incomplete");
4456 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4457 "adj nbr next-hop ok");
4460 * find the adj in the shared db
4462 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4465 tm->hw[0]->sw_if_index);
4466 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4467 adj_unlock(locked_ai);
4470 * no more entires. +1 shared path-list
4472 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4473 fib_path_list_db_size());
4474 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4475 fib_path_list_pool_size());
4476 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4477 fib_entry_pool_size());
4480 * remove the API source from the default route. We expected
4481 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4483 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4487 tm->hw[0]->sw_if_index,
4490 FIB_ROUTE_PATH_FLAG_NONE);
4491 fei = fib_table_lookup(fib_index, &pfx_0_0);
4493 FIB_TEST((fei == dfrt), "default route same index");
4494 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4495 "Default route is DROP");
4498 * no more entires. -1 shared path-list
4500 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4501 fib_path_list_db_size());
4502 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4503 fib_path_list_pool_size());
4504 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4505 fib_entry_pool_size());
4508 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4510 fib_prefix_t pfx_2001_1_2_s_128 = {
4512 .fp_proto = FIB_PROTOCOL_IP6,
4516 [0] = clib_host_to_net_u64(0x2001000000000001),
4517 [1] = clib_host_to_net_u64(0x0000000000000002),
4522 fib_prefix_t pfx_2001_1_3_s_128 = {
4524 .fp_proto = FIB_PROTOCOL_IP6,
4528 [0] = clib_host_to_net_u64(0x2001000000000001),
4529 [1] = clib_host_to_net_u64(0x0000000000000003),
4535 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4538 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4540 &pfx_2001_1_2_s_128.fp_addr,
4541 tm->hw[0]->sw_if_index);
4542 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4543 adj = adj_get(ai_01);
4544 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4545 "adj is incomplete");
4546 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4547 &adj->sub_type.nbr.next_hop)),
4548 "adj nbr next-hop ok");
4550 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4551 fib_test_build_rewrite(eth_addr));
4552 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4554 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4555 &adj->sub_type.nbr.next_hop)),
4556 "adj nbr next-hop ok");
4558 fib_table_entry_path_add(fib_index,
4559 &pfx_2001_1_2_s_128,
4561 FIB_ENTRY_FLAG_ATTACHED,
4563 &pfx_2001_1_2_s_128.fp_addr,
4564 tm->hw[0]->sw_if_index,
4568 FIB_ROUTE_PATH_FLAG_NONE);
4570 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4571 ai = fib_entry_get_adj(fei);
4572 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4576 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4578 &pfx_2001_1_3_s_128.fp_addr,
4579 tm->hw[0]->sw_if_index);
4580 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4581 adj = adj_get(ai_02);
4582 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4583 "adj is incomplete");
4584 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4585 &adj->sub_type.nbr.next_hop)),
4586 "adj nbr next-hop ok");
4588 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4589 fib_test_build_rewrite(eth_addr));
4590 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4592 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4593 &adj->sub_type.nbr.next_hop)),
4594 "adj nbr next-hop ok");
4595 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4597 fib_table_entry_path_add(fib_index,
4598 &pfx_2001_1_3_s_128,
4600 FIB_ENTRY_FLAG_ATTACHED,
4602 &pfx_2001_1_3_s_128.fp_addr,
4603 tm->hw[0]->sw_if_index,
4607 FIB_ROUTE_PATH_FLAG_NONE);
4609 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4610 ai = fib_entry_get_adj(fei);
4611 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4614 * +2 entries, +2 unshread path-lists.
4616 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4617 fib_path_list_db_size());
4618 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4619 fib_path_list_pool_size());
4620 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4621 fib_entry_pool_size());
4624 * Add a 2 routes via the first ADJ. ensure path-list sharing
4626 fib_prefix_t pfx_2001_a_s_64 = {
4628 .fp_proto = FIB_PROTOCOL_IP6,
4632 [0] = clib_host_to_net_u64(0x200100000000000a),
4633 [1] = clib_host_to_net_u64(0x0000000000000000),
4638 fib_prefix_t pfx_2001_b_s_64 = {
4640 .fp_proto = FIB_PROTOCOL_IP6,
4644 [0] = clib_host_to_net_u64(0x200100000000000b),
4645 [1] = clib_host_to_net_u64(0x0000000000000000),
4651 fib_table_entry_path_add(fib_index,
4654 FIB_ENTRY_FLAG_NONE,
4657 tm->hw[0]->sw_if_index,
4661 FIB_ROUTE_PATH_FLAG_NONE);
4662 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4663 ai = fib_entry_get_adj(fei);
4664 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4665 fib_table_entry_path_add(fib_index,
4668 FIB_ENTRY_FLAG_NONE,
4671 tm->hw[0]->sw_if_index,
4675 FIB_ROUTE_PATH_FLAG_NONE);
4676 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4677 ai = fib_entry_get_adj(fei);
4678 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4681 * +2 entries, +1 shared path-list.
4683 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4684 fib_path_list_db_size());
4685 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4686 fib_path_list_pool_size());
4687 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4688 fib_entry_pool_size());
4691 * add a v4 prefix via a v6 next-hop
4693 fib_prefix_t pfx_1_1_1_1_s_32 = {
4695 .fp_proto = FIB_PROTOCOL_IP4,
4697 .ip4.as_u32 = 0x01010101,
4700 fei = fib_table_entry_path_add(0, // default table
4703 FIB_ENTRY_FLAG_NONE,
4706 tm->hw[0]->sw_if_index,
4710 FIB_ROUTE_PATH_FLAG_NONE);
4711 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4712 "1.1.1.1/32 o v6 route present");
4713 ai = fib_entry_get_adj(fei);
4715 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4716 "1.1.1.1/32 via ARP-adj");
4717 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4718 "1.1.1.1/32 ADJ-adj is link type v4");
4719 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4720 "1.1.1.1/32 ADJ-adj is NH proto v6");
4721 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4726 fib_prefix_t pfx_2001_c_s_64 = {
4728 .fp_proto = FIB_PROTOCOL_IP6,
4732 [0] = clib_host_to_net_u64(0x200100000000000c),
4733 [1] = clib_host_to_net_u64(0x0000000000000000),
4738 fib_table_entry_path_add(fib_index,
4741 FIB_ENTRY_FLAG_ATTACHED,
4744 tm->hw[0]->sw_if_index,
4748 FIB_ROUTE_PATH_FLAG_NONE);
4749 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4750 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4751 ai = fib_entry_get_adj(fei);
4753 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4754 "2001:0:0:c/64 attached resolves via glean");
4756 fib_table_entry_path_remove(fib_index,
4761 tm->hw[0]->sw_if_index,
4764 FIB_ROUTE_PATH_FLAG_NONE);
4765 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4766 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4769 * Shutdown the interface on which we have a connected and through
4770 * which the routes are reachable.
4771 * This will result in the connected, adj-fibs, and routes linking to drop
4772 * The local/for-us prefix continues to receive.
4774 clib_error_t * error;
4776 error = vnet_sw_interface_set_flags(vnet_get_main(),
4777 tm->hw[0]->sw_if_index,
4778 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4779 FIB_TEST((NULL == error), "Interface shutdown OK");
4781 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4782 dpo = fib_entry_contribute_ip_forwarding(fei);
4783 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4784 "2001::b/64 resolves via drop");
4786 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4787 dpo = fib_entry_contribute_ip_forwarding(fei);
4788 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4789 "2001::a/64 resolves via drop");
4790 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4791 dpo = fib_entry_contribute_ip_forwarding(fei);
4792 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4793 "2001:0:0:1::3/64 resolves via drop");
4794 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4795 dpo = fib_entry_contribute_ip_forwarding(fei);
4796 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4797 "2001:0:0:1::2/64 resolves via drop");
4798 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4799 dpo = fib_entry_contribute_ip_forwarding(fei);
4800 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4801 "2001:0:0:1::1/128 not drop");
4802 local_pfx.fp_len = 64;
4803 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4804 dpo = fib_entry_contribute_ip_forwarding(fei);
4805 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4806 "2001:0:0:1/64 resolves via drop");
4811 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4812 fib_path_list_db_size());
4813 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4814 fib_path_list_pool_size());
4815 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4816 fib_entry_pool_size());
4819 * shutdown one of the other interfaces, then add a connected.
4820 * and swap one of the routes to it.
4822 error = vnet_sw_interface_set_flags(vnet_get_main(),
4823 tm->hw[1]->sw_if_index,
4824 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4825 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4827 fib_prefix_t connected_pfx = {
4829 .fp_proto = FIB_PROTOCOL_IP6,
4832 /* 2001:0:0:2::1/64 */
4834 [0] = clib_host_to_net_u64(0x2001000000000002),
4835 [1] = clib_host_to_net_u64(0x0000000000000001),
4840 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4841 FIB_SOURCE_INTERFACE,
4842 (FIB_ENTRY_FLAG_CONNECTED |
4843 FIB_ENTRY_FLAG_ATTACHED),
4846 tm->hw[1]->sw_if_index,
4850 FIB_ROUTE_PATH_FLAG_NONE);
4851 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4852 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4853 dpo = fib_entry_contribute_ip_forwarding(fei);
4854 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4855 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4856 "2001:0:0:2/64 not resolves via drop");
4858 connected_pfx.fp_len = 128;
4859 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4860 FIB_SOURCE_INTERFACE,
4861 (FIB_ENTRY_FLAG_CONNECTED |
4862 FIB_ENTRY_FLAG_LOCAL),
4865 tm->hw[0]->sw_if_index,
4866 ~0, // invalid fib index
4869 FIB_ROUTE_PATH_FLAG_NONE);
4870 fei = fib_table_lookup(fib_index, &connected_pfx);
4872 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4873 dpo = fib_entry_contribute_ip_forwarding(fei);
4874 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4875 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4876 "local interface adj is local");
4877 rd = receive_dpo_get(dpo->dpoi_index);
4878 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4880 "local interface adj is receive ok");
4883 * +2 entries, +2 unshared path-lists
4885 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4886 fib_path_list_db_size());
4887 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4888 fib_path_list_pool_size());
4889 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4890 fib_entry_pool_size());
4894 * bring the interface back up. we expected the routes to return
4895 * to normal forwarding.
4897 error = vnet_sw_interface_set_flags(vnet_get_main(),
4898 tm->hw[0]->sw_if_index,
4899 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4900 FIB_TEST((NULL == error), "Interface bring-up OK");
4901 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4902 ai = fib_entry_get_adj(fei);
4903 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4904 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4905 ai = fib_entry_get_adj(fei);
4906 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4907 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4908 ai = fib_entry_get_adj(fei);
4909 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4910 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4911 ai = fib_entry_get_adj(fei);
4912 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4913 local_pfx.fp_len = 64;
4914 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4915 ai = fib_entry_get_adj(fei);
4917 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4918 "attached interface adj is glean");
4921 * Same test as above, but this time the HW interface goes down
4923 error = vnet_hw_interface_set_flags(vnet_get_main(),
4924 tm->hw_if_indicies[0],
4925 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4926 FIB_TEST((NULL == error), "Interface shutdown OK");
4928 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4929 dpo = fib_entry_contribute_ip_forwarding(fei);
4930 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4931 "2001::b/64 resolves via drop");
4932 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4933 dpo = fib_entry_contribute_ip_forwarding(fei);
4934 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4935 "2001::a/64 resolves via drop");
4936 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4937 dpo = fib_entry_contribute_ip_forwarding(fei);
4938 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4939 "2001:0:0:1::3/128 resolves via drop");
4940 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4941 dpo = fib_entry_contribute_ip_forwarding(fei);
4942 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4943 "2001:0:0:1::2/128 resolves via drop");
4944 local_pfx.fp_len = 128;
4945 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4946 dpo = fib_entry_contribute_ip_forwarding(fei);
4947 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4948 "2001:0:0:1::1/128 not drop");
4949 local_pfx.fp_len = 64;
4950 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4951 dpo = fib_entry_contribute_ip_forwarding(fei);
4952 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4953 "2001:0:0:1/64 resolves via drop");
4955 error = vnet_hw_interface_set_flags(vnet_get_main(),
4956 tm->hw_if_indicies[0],
4957 VNET_HW_INTERFACE_FLAG_LINK_UP);
4958 FIB_TEST((NULL == error), "Interface bring-up OK");
4959 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4960 ai = fib_entry_get_adj(fei);
4961 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4962 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4963 ai = fib_entry_get_adj(fei);
4964 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4965 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4966 ai = fib_entry_get_adj(fei);
4967 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4968 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4969 ai = fib_entry_get_adj(fei);
4970 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4971 local_pfx.fp_len = 64;
4972 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4973 ai = fib_entry_get_adj(fei);
4975 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4976 "attached interface adj is glean");
4979 * Delete the interface that the routes reolve through.
4980 * Again no routes are removed. They all point to drop.
4982 * This is considered an error case. The control plane should
4983 * not remove interfaces through which routes resolve, but
4984 * such things can happen. ALL affected routes will drop.
4986 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4988 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4989 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4990 "2001::b/64 resolves via drop");
4991 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4992 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4993 "2001::b/64 resolves via drop");
4994 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4995 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4996 "2001:0:0:1::3/64 resolves via drop");
4997 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4998 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4999 "2001:0:0:1::2/64 resolves via drop");
5000 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5001 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5002 "2001:0:0:1::1/128 is drop");
5003 local_pfx.fp_len = 64;
5004 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5005 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5006 "2001:0:0:1/64 resolves via drop");
5011 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
5012 fib_path_list_db_size());
5013 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
5014 fib_path_list_pool_size());
5015 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
5016 fib_entry_pool_size());
5019 * Add the interface back. routes stay unresolved.
5021 error = ethernet_register_interface(vnet_get_main(),
5022 test_interface_device_class.index,
5025 &tm->hw_if_indicies[0],
5026 /* flag change */ 0);
5028 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5029 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5030 "2001::b/64 resolves via drop");
5031 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5032 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5033 "2001::b/64 resolves via drop");
5034 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5035 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5036 "2001:0:0:1::3/64 resolves via drop");
5037 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5038 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5039 "2001:0:0:1::2/64 resolves via drop");
5040 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5041 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5042 "2001:0:0:1::1/128 is drop");
5043 local_pfx.fp_len = 64;
5044 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5045 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5046 "2001:0:0:1/64 resolves via drop");
5049 * CLEANUP ALL the routes
5051 fib_table_entry_delete(fib_index,
5054 fib_table_entry_delete(fib_index,
5057 fib_table_entry_delete(fib_index,
5060 fib_table_entry_delete(fib_index,
5061 &pfx_2001_1_3_s_128,
5063 fib_table_entry_delete(fib_index,
5064 &pfx_2001_1_2_s_128,
5066 local_pfx.fp_len = 64;
5067 fib_table_entry_delete(fib_index, &local_pfx,
5068 FIB_SOURCE_INTERFACE);
5069 local_pfx.fp_len = 128;
5070 fib_table_entry_special_remove(fib_index, &local_pfx,
5071 FIB_SOURCE_INTERFACE);
5072 connected_pfx.fp_len = 64;
5073 fib_table_entry_delete(fib_index, &connected_pfx,
5074 FIB_SOURCE_INTERFACE);
5075 connected_pfx.fp_len = 128;
5076 fib_table_entry_special_remove(fib_index, &connected_pfx,
5077 FIB_SOURCE_INTERFACE);
5079 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5080 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
5081 "2001::a/64 removed");
5082 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5083 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
5084 "2001::b/64 removed");
5085 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5086 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
5087 "2001:0:0:1::3/128 removed");
5088 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5089 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
5090 "2001:0:0:1::3/128 removed");
5091 local_pfx.fp_len = 64;
5092 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5093 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5094 "2001:0:0:1/64 removed");
5095 local_pfx.fp_len = 128;
5096 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5097 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5098 "2001:0:0:1::1/128 removed");
5099 connected_pfx.fp_len = 64;
5100 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5101 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5102 "2001:0:0:2/64 removed");
5103 connected_pfx.fp_len = 128;
5104 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5105 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5106 "2001:0:0:2::1/128 removed");
5109 * -8 entries. -7 path-lists (1 was shared).
5111 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5112 fib_path_list_db_size());
5113 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5114 fib_path_list_pool_size());
5115 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5116 fib_entry_pool_size());
5119 * now remove the VRF
5121 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
5123 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5124 fib_path_list_db_size());
5125 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5126 fib_path_list_pool_size());
5127 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5128 fib_entry_pool_size());
5134 * return the interfaces to up state
5136 error = vnet_sw_interface_set_flags(vnet_get_main(),
5137 tm->hw[0]->sw_if_index,
5138 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5139 error = vnet_sw_interface_set_flags(vnet_get_main(),
5140 tm->hw[1]->sw_if_index,
5141 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5143 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5150 * Test Attached Exports
5155 const dpo_id_t *dpo, *dpo_drop;
5156 const u32 fib_index = 0;
5157 fib_node_index_t fei;
5164 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5168 * add interface routes. We'll assume this works. It's more rigorously
5171 fib_prefix_t local_pfx = {
5173 .fp_proto = FIB_PROTOCOL_IP4,
5177 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5182 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5183 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5185 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5187 fib_table_entry_update_one_path(fib_index, &local_pfx,
5188 FIB_SOURCE_INTERFACE,
5189 (FIB_ENTRY_FLAG_CONNECTED |
5190 FIB_ENTRY_FLAG_ATTACHED),
5193 tm->hw[0]->sw_if_index,
5197 FIB_ROUTE_PATH_FLAG_NONE);
5198 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5199 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5200 "attached interface route present");
5202 local_pfx.fp_len = 32;
5203 fib_table_entry_update_one_path(fib_index, &local_pfx,
5204 FIB_SOURCE_INTERFACE,
5205 (FIB_ENTRY_FLAG_CONNECTED |
5206 FIB_ENTRY_FLAG_LOCAL),
5209 tm->hw[0]->sw_if_index,
5210 ~0, // invalid fib index
5213 FIB_ROUTE_PATH_FLAG_NONE);
5214 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5216 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5217 "local interface route present");
5220 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5222 fib_prefix_t pfx_10_10_10_1_s_32 = {
5224 .fp_proto = FIB_PROTOCOL_IP4,
5227 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5230 fib_node_index_t ai;
5232 fib_table_entry_path_add(fib_index,
5233 &pfx_10_10_10_1_s_32,
5235 FIB_ENTRY_FLAG_ATTACHED,
5237 &pfx_10_10_10_1_s_32.fp_addr,
5238 tm->hw[0]->sw_if_index,
5239 ~0, // invalid fib index
5242 FIB_ROUTE_PATH_FLAG_NONE);
5244 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5245 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5246 ai = fib_entry_get_adj(fei);
5249 * create another FIB table into which routes will be imported
5251 u32 import_fib_index1;
5253 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
5258 * Add an attached route in the import FIB
5260 local_pfx.fp_len = 24;
5261 fib_table_entry_update_one_path(import_fib_index1,
5264 FIB_ENTRY_FLAG_NONE,
5267 tm->hw[0]->sw_if_index,
5268 ~0, // invalid fib index
5271 FIB_ROUTE_PATH_FLAG_NONE);
5272 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5273 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5276 * check for the presence of the adj-fibs in the import table
5278 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5279 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5280 FIB_TEST((ai == fib_entry_get_adj(fei)),
5281 "adj-fib1 Import uses same adj as export");
5284 * check for the presence of the local in the import table
5286 local_pfx.fp_len = 32;
5287 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5288 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5291 * Add another adj-fin in the export table. Expect this
5292 * to get magically exported;
5294 fib_prefix_t pfx_10_10_10_2_s_32 = {
5296 .fp_proto = FIB_PROTOCOL_IP4,
5299 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5303 fib_table_entry_path_add(fib_index,
5304 &pfx_10_10_10_2_s_32,
5306 FIB_ENTRY_FLAG_ATTACHED,
5308 &pfx_10_10_10_2_s_32.fp_addr,
5309 tm->hw[0]->sw_if_index,
5310 ~0, // invalid fib index
5313 FIB_ROUTE_PATH_FLAG_NONE);
5314 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5315 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5316 ai = fib_entry_get_adj(fei);
5318 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5319 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5320 FIB_TEST((ai == fib_entry_get_adj(fei)),
5321 "Import uses same adj as export");
5322 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5323 "ADJ-fib2 imported flags %d",
5324 fib_entry_get_flags(fei));
5327 * create a 2nd FIB table into which routes will be imported
5329 u32 import_fib_index2;
5331 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
5335 * Add an attached route in the import FIB
5337 local_pfx.fp_len = 24;
5338 fib_table_entry_update_one_path(import_fib_index2,
5341 FIB_ENTRY_FLAG_NONE,
5344 tm->hw[0]->sw_if_index,
5345 ~0, // invalid fib index
5348 FIB_ROUTE_PATH_FLAG_NONE);
5349 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5350 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5353 * check for the presence of all the adj-fibs and local in the import table
5355 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5356 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5357 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5358 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5359 local_pfx.fp_len = 32;
5360 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5361 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5364 * add a 3rd adj-fib. expect it to be exported to both tables.
5366 fib_prefix_t pfx_10_10_10_3_s_32 = {
5368 .fp_proto = FIB_PROTOCOL_IP4,
5371 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5375 fib_table_entry_path_add(fib_index,
5376 &pfx_10_10_10_3_s_32,
5378 FIB_ENTRY_FLAG_ATTACHED,
5380 &pfx_10_10_10_3_s_32.fp_addr,
5381 tm->hw[0]->sw_if_index,
5382 ~0, // invalid fib index
5385 FIB_ROUTE_PATH_FLAG_NONE);
5386 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5387 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5388 ai = fib_entry_get_adj(fei);
5390 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5391 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5392 FIB_TEST((ai == fib_entry_get_adj(fei)),
5393 "Import uses same adj as export");
5394 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5395 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5396 FIB_TEST((ai == fib_entry_get_adj(fei)),
5397 "Import uses same adj as export");
5400 * remove the 3rd adj fib. we expect it to be removed from both FIBs
5402 fib_table_entry_delete(fib_index,
5403 &pfx_10_10_10_3_s_32,
5406 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5407 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5409 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5410 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5412 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5413 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5416 * remove the attached route from the 2nd FIB. expect the imported
5417 * entires to be removed
5419 local_pfx.fp_len = 24;
5420 fib_table_entry_delete(import_fib_index2,
5423 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5424 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5426 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5427 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5428 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5429 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5430 local_pfx.fp_len = 32;
5431 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5432 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5434 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5435 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5436 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5437 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5438 local_pfx.fp_len = 32;
5439 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5440 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5443 * modify the route in FIB1 so it is no longer attached. expect the imported
5444 * entires to be removed
5446 local_pfx.fp_len = 24;
5447 fib_table_entry_update_one_path(import_fib_index1,
5450 FIB_ENTRY_FLAG_NONE,
5452 &pfx_10_10_10_2_s_32.fp_addr,
5453 tm->hw[0]->sw_if_index,
5454 ~0, // invalid fib index
5457 FIB_ROUTE_PATH_FLAG_NONE);
5458 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5459 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5460 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5461 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5462 local_pfx.fp_len = 32;
5463 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5464 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5467 * modify it back to attached. expect the adj-fibs back
5469 local_pfx.fp_len = 24;
5470 fib_table_entry_update_one_path(import_fib_index1,
5473 FIB_ENTRY_FLAG_NONE,
5476 tm->hw[0]->sw_if_index,
5477 ~0, // invalid fib index
5480 FIB_ROUTE_PATH_FLAG_NONE);
5481 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5482 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5483 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5484 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5485 local_pfx.fp_len = 32;
5486 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5487 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5490 * add a covering attached next-hop for the interface address, so we have
5491 * a valid adj to find when we check the forwarding tables
5493 fib_prefix_t pfx_10_0_0_0_s_8 = {
5495 .fp_proto = FIB_PROTOCOL_IP4,
5498 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5502 fei = fib_table_entry_update_one_path(fib_index,
5505 FIB_ENTRY_FLAG_NONE,
5507 &pfx_10_10_10_3_s_32.fp_addr,
5508 tm->hw[0]->sw_if_index,
5509 ~0, // invalid fib index
5512 FIB_ROUTE_PATH_FLAG_NONE);
5513 dpo = fib_entry_contribute_ip_forwarding(fei);
5516 * remove the route in the export fib. expect the adj-fibs to be removed
5518 local_pfx.fp_len = 24;
5519 fib_table_entry_delete(fib_index,
5521 FIB_SOURCE_INTERFACE);
5523 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5524 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5525 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5526 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5527 local_pfx.fp_len = 32;
5528 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5529 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5532 * the adj-fibs in the export VRF are present in the FIB table,
5533 * but not installed in forwarding, since they have no attached cover.
5534 * Consequently a lookup in the MTRIE gives the adj for the covering
5537 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5538 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5541 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5542 FIB_TEST(lbi == dpo->dpoi_index,
5543 "10.10.10.1 forwards on \n%U not \n%U",
5544 format_load_balance, lbi, 0,
5545 format_dpo_id, dpo, 0);
5546 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5547 FIB_TEST(lbi == dpo->dpoi_index,
5548 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5549 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5550 FIB_TEST(lbi == dpo->dpoi_index,
5551 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5554 * add the export prefix back, but not as attached.
5555 * No adj-fibs in export nor import tables
5557 local_pfx.fp_len = 24;
5558 fei = fib_table_entry_update_one_path(fib_index,
5561 FIB_ENTRY_FLAG_NONE,
5563 &pfx_10_10_10_1_s_32.fp_addr,
5564 tm->hw[0]->sw_if_index,
5565 ~0, // invalid fib index
5568 FIB_ROUTE_PATH_FLAG_NONE);
5569 dpo = fib_entry_contribute_ip_forwarding(fei);
5571 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5572 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5573 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5574 FIB_TEST(lbi == dpo->dpoi_index,
5575 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5576 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5577 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5578 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5579 FIB_TEST(lbi == dpo->dpoi_index,
5580 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5582 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5583 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5584 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5585 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5586 local_pfx.fp_len = 32;
5587 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5588 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5591 * modify the export prefix so it is attached. expect all covereds to return
5593 local_pfx.fp_len = 24;
5594 fib_table_entry_update_one_path(fib_index,
5597 FIB_ENTRY_FLAG_NONE,
5600 tm->hw[0]->sw_if_index,
5601 ~0, // invalid fib index
5604 FIB_ROUTE_PATH_FLAG_NONE);
5606 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5607 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5608 dpo = fib_entry_contribute_ip_forwarding(fei);
5609 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5610 "Adj-fib1 is not drop in export");
5611 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5612 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5613 local_pfx.fp_len = 32;
5614 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5615 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5616 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5617 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5618 dpo = fib_entry_contribute_ip_forwarding(fei);
5619 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5620 "Adj-fib1 is not drop in export");
5621 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5622 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5623 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5624 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5625 local_pfx.fp_len = 32;
5626 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5627 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5630 * modify the export prefix so connected. no change.
5632 local_pfx.fp_len = 24;
5633 fib_table_entry_update_one_path(fib_index, &local_pfx,
5634 FIB_SOURCE_INTERFACE,
5635 (FIB_ENTRY_FLAG_CONNECTED |
5636 FIB_ENTRY_FLAG_ATTACHED),
5639 tm->hw[0]->sw_if_index,
5643 FIB_ROUTE_PATH_FLAG_NONE);
5645 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5646 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5647 dpo = fib_entry_contribute_ip_forwarding(fei);
5648 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5649 "Adj-fib1 is not drop in export");
5650 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5651 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5652 local_pfx.fp_len = 32;
5653 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5654 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5655 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5656 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5657 dpo = fib_entry_contribute_ip_forwarding(fei);
5658 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5659 "Adj-fib1 is not drop in export");
5660 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5661 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5662 local_pfx.fp_len = 32;
5663 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5664 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5669 fib_table_entry_delete(fib_index,
5672 fib_table_entry_delete(fib_index,
5673 &pfx_10_10_10_1_s_32,
5675 fib_table_entry_delete(fib_index,
5676 &pfx_10_10_10_2_s_32,
5678 local_pfx.fp_len = 32;
5679 fib_table_entry_delete(fib_index,
5681 FIB_SOURCE_INTERFACE);
5682 local_pfx.fp_len = 24;
5683 fib_table_entry_delete(fib_index,
5686 fib_table_entry_delete(fib_index,
5688 FIB_SOURCE_INTERFACE);
5689 local_pfx.fp_len = 24;
5690 fib_table_entry_delete(import_fib_index1,
5694 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5695 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5697 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5704 * Test Path Preference
5707 fib_test_pref (void)
5709 test_main_t *tm = &test_main;
5711 const fib_prefix_t pfx_1_1_1_1_s_32 = {
5713 .fp_proto = FIB_PROTOCOL_IP4,
5716 .as_u32 = clib_host_to_net_u32(0x01010101),
5722 * 2 high, 2 medium and 2 low preference non-recursive paths
5724 fib_route_path_t nr_path_hi_1 = {
5725 .frp_proto = DPO_PROTO_IP4,
5726 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5727 .frp_fib_index = ~0,
5729 .frp_preference = 0,
5730 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5732 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5735 fib_route_path_t nr_path_hi_2 = {
5736 .frp_proto = DPO_PROTO_IP4,
5737 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5738 .frp_fib_index = ~0,
5740 .frp_preference = 0,
5741 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5743 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5746 fib_route_path_t nr_path_med_1 = {
5747 .frp_proto = DPO_PROTO_IP4,
5748 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5749 .frp_fib_index = ~0,
5751 .frp_preference = 1,
5752 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5754 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5757 fib_route_path_t nr_path_med_2 = {
5758 .frp_proto = DPO_PROTO_IP4,
5759 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5760 .frp_fib_index = ~0,
5762 .frp_preference = 1,
5763 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5765 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5768 fib_route_path_t nr_path_low_1 = {
5769 .frp_proto = DPO_PROTO_IP4,
5770 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5771 .frp_fib_index = ~0,
5773 .frp_preference = 2,
5774 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5776 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5779 fib_route_path_t nr_path_low_2 = {
5780 .frp_proto = DPO_PROTO_IP4,
5781 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5782 .frp_fib_index = ~0,
5784 .frp_preference = 2,
5785 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5787 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5790 fib_route_path_t *nr_paths = NULL;
5792 vec_add1(nr_paths, nr_path_hi_1);
5793 vec_add1(nr_paths, nr_path_hi_2);
5794 vec_add1(nr_paths, nr_path_med_1);
5795 vec_add1(nr_paths, nr_path_med_2);
5796 vec_add1(nr_paths, nr_path_low_1);
5797 vec_add1(nr_paths, nr_path_low_2);
5799 adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5801 &nr_path_hi_1.frp_addr,
5802 nr_path_hi_1.frp_sw_if_index);
5803 adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5805 &nr_path_hi_2.frp_addr,
5806 nr_path_hi_2.frp_sw_if_index);
5807 adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5809 &nr_path_med_1.frp_addr,
5810 nr_path_med_1.frp_sw_if_index);
5811 adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5813 &nr_path_med_2.frp_addr,
5814 nr_path_med_2.frp_sw_if_index);
5815 adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5817 &nr_path_low_1.frp_addr,
5818 nr_path_low_1.frp_sw_if_index);
5819 adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5821 &nr_path_low_2.frp_addr,
5822 nr_path_low_2.frp_sw_if_index);
5824 fib_test_lb_bucket_t ip_hi_1 = {
5830 fib_test_lb_bucket_t ip_hi_2 = {
5836 fib_test_lb_bucket_t ip_med_1 = {
5842 fib_test_lb_bucket_t ip_med_2 = {
5848 fib_test_lb_bucket_t ip_low_1 = {
5854 fib_test_lb_bucket_t ip_low_2 = {
5861 fib_node_index_t fei;
5863 fei = fib_table_entry_path_add2(0,
5866 FIB_ENTRY_FLAG_NONE,
5869 FIB_TEST(fib_test_validate_entry(fei,
5870 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5874 "1.1.1.1/32 via high preference paths");
5877 * bring down the interface on which the high preference path lie
5879 vnet_sw_interface_set_flags(vnet_get_main(),
5880 tm->hw[0]->sw_if_index,
5883 FIB_TEST(fib_test_validate_entry(fei,
5884 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5888 "1.1.1.1/32 via medium preference paths");
5891 * bring down the interface on which the medium preference path lie
5893 vnet_sw_interface_set_flags(vnet_get_main(),
5894 tm->hw[1]->sw_if_index,
5897 FIB_TEST(fib_test_validate_entry(fei,
5898 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5902 "1.1.1.1/32 via low preference paths");
5905 * bring up the interface on which the high preference path lie
5907 vnet_sw_interface_set_flags(vnet_get_main(),
5908 tm->hw[0]->sw_if_index,
5909 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5911 FIB_TEST(fib_test_validate_entry(fei,
5912 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5916 "1.1.1.1/32 via high preference paths");
5919 * bring up the interface on which the medium preference path lie
5921 vnet_sw_interface_set_flags(vnet_get_main(),
5922 tm->hw[1]->sw_if_index,
5923 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5925 FIB_TEST(fib_test_validate_entry(fei,
5926 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5930 "1.1.1.1/32 via high preference paths");
5932 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
5933 fib_entry_contribute_forwarding(fei,
5934 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5938 * 3 recursive paths of different preference
5940 const fib_prefix_t pfx_1_1_1_2_s_32 = {
5942 .fp_proto = FIB_PROTOCOL_IP4,
5945 .as_u32 = clib_host_to_net_u32(0x01010102),
5949 const fib_prefix_t pfx_1_1_1_3_s_32 = {
5951 .fp_proto = FIB_PROTOCOL_IP4,
5954 .as_u32 = clib_host_to_net_u32(0x01010103),
5958 fei = fib_table_entry_path_add2(0,
5961 FIB_ENTRY_FLAG_NONE,
5963 dpo_id_t ip_1_1_1_2 = DPO_INVALID;
5964 fib_entry_contribute_forwarding(fei,
5965 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5967 fei = fib_table_entry_path_add2(0,
5970 FIB_ENTRY_FLAG_NONE,
5972 dpo_id_t ip_1_1_1_3 = DPO_INVALID;
5973 fib_entry_contribute_forwarding(fei,
5974 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5977 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5980 .lb = ip_1_1_1_1.dpoi_index,
5983 fib_test_lb_bucket_t ip_o_1_1_1_2 = {
5986 .lb = ip_1_1_1_2.dpoi_index,
5989 fib_test_lb_bucket_t ip_o_1_1_1_3 = {
5992 .lb = ip_1_1_1_3.dpoi_index,
5995 fib_route_path_t r_path_hi = {
5996 .frp_proto = DPO_PROTO_IP4,
5997 .frp_sw_if_index = ~0,
6000 .frp_preference = 0,
6001 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6002 .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
6004 fib_route_path_t r_path_med = {
6005 .frp_proto = DPO_PROTO_IP4,
6006 .frp_sw_if_index = ~0,
6009 .frp_preference = 10,
6010 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6011 .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
6013 fib_route_path_t r_path_low = {
6014 .frp_proto = DPO_PROTO_IP4,
6015 .frp_sw_if_index = ~0,
6018 .frp_preference = 255,
6019 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6020 .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
6022 fib_route_path_t *r_paths = NULL;
6024 vec_add1(r_paths, r_path_hi);
6025 vec_add1(r_paths, r_path_low);
6026 vec_add1(r_paths, r_path_med);
6029 * add many recursive so we get the LB MAp created
6032 fib_prefix_t pfx_r[N_PFXS];
6033 unsigned int n_pfxs;
6034 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6036 pfx_r[n_pfxs].fp_len = 32;
6037 pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
6038 pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
6039 clib_host_to_net_u32(0x02000000 + n_pfxs);
6041 fei = fib_table_entry_path_add2(0,
6044 FIB_ENTRY_FLAG_NONE,
6047 FIB_TEST(fib_test_validate_entry(fei,
6048 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6051 "recursive via high preference paths");
6054 * withdraw hig pref resolving entry
6056 fib_table_entry_delete(0,
6060 /* suspend so the update walk kicks int */
6061 vlib_process_suspend(vlib_get_main(), 1e-5);
6063 FIB_TEST(fib_test_validate_entry(fei,
6064 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6067 "recursive via medium preference paths");
6070 * withdraw medium pref resolving entry
6072 fib_table_entry_delete(0,
6076 /* suspend so the update walk kicks int */
6077 vlib_process_suspend(vlib_get_main(), 1e-5);
6079 FIB_TEST(fib_test_validate_entry(fei,
6080 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6083 "recursive via low preference paths");
6086 * add back paths for next iteration
6088 fei = fib_table_entry_update(0,
6091 FIB_ENTRY_FLAG_NONE,
6093 fei = fib_table_entry_update(0,
6096 FIB_ENTRY_FLAG_NONE,
6099 /* suspend so the update walk kicks int */
6100 vlib_process_suspend(vlib_get_main(), 1e-5);
6102 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6103 FIB_TEST(fib_test_validate_entry(fei,
6104 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6107 "recursive via high preference paths");
6111 fib_table_entry_delete(0,
6115 /* suspend so the update walk kicks int */
6116 vlib_process_suspend(vlib_get_main(), 1e-5);
6118 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6120 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6122 FIB_TEST(fib_test_validate_entry(fei,
6123 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6126 "recursive via medium preference paths");
6128 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6130 fib_table_entry_delete(0,
6138 fib_table_entry_delete(0,
6141 fib_table_entry_delete(0,
6145 dpo_reset(&ip_1_1_1_1);
6146 dpo_reset(&ip_1_1_1_2);
6147 dpo_reset(&ip_1_1_1_3);
6148 adj_unlock(ai_low_2);
6149 adj_unlock(ai_low_1);
6150 adj_unlock(ai_med_2);
6151 adj_unlock(ai_med_1);
6152 adj_unlock(ai_hi_2);
6153 adj_unlock(ai_hi_1);
6158 * Test the recursive route route handling for GRE tunnels
6161 fib_test_label (void)
6163 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;
6164 const u32 fib_index = 0;
6169 lb_count = pool_elts(load_balance_pool);
6174 * add interface routes. We'll assume this works. It's more rigorously
6177 fib_prefix_t local0_pfx = {
6179 .fp_proto = FIB_PROTOCOL_IP4,
6183 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6188 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6191 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6192 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6194 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6195 FIB_SOURCE_INTERFACE,
6196 (FIB_ENTRY_FLAG_CONNECTED |
6197 FIB_ENTRY_FLAG_ATTACHED),
6200 tm->hw[0]->sw_if_index,
6204 FIB_ROUTE_PATH_FLAG_NONE);
6205 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6206 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6207 "attached interface route present");
6209 local0_pfx.fp_len = 32;
6210 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6211 FIB_SOURCE_INTERFACE,
6212 (FIB_ENTRY_FLAG_CONNECTED |
6213 FIB_ENTRY_FLAG_LOCAL),
6216 tm->hw[0]->sw_if_index,
6217 ~0, // invalid fib index
6220 FIB_ROUTE_PATH_FLAG_NONE);
6221 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6223 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6224 "local interface route present");
6226 fib_prefix_t local1_pfx = {
6228 .fp_proto = FIB_PROTOCOL_IP4,
6232 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6237 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6238 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6240 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6241 FIB_SOURCE_INTERFACE,
6242 (FIB_ENTRY_FLAG_CONNECTED |
6243 FIB_ENTRY_FLAG_ATTACHED),
6246 tm->hw[1]->sw_if_index,
6250 FIB_ROUTE_PATH_FLAG_NONE);
6251 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6252 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6253 "attached interface route present");
6255 local1_pfx.fp_len = 32;
6256 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6257 FIB_SOURCE_INTERFACE,
6258 (FIB_ENTRY_FLAG_CONNECTED |
6259 FIB_ENTRY_FLAG_LOCAL),
6262 tm->hw[1]->sw_if_index,
6263 ~0, // invalid fib index
6266 FIB_ROUTE_PATH_FLAG_NONE);
6267 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6269 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6270 "local interface route present");
6272 ip46_address_t nh_10_10_10_1 = {
6274 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6277 ip46_address_t nh_10_10_11_1 = {
6279 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6282 ip46_address_t nh_10_10_11_2 = {
6284 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6288 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6291 tm->hw[1]->sw_if_index);
6292 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6295 tm->hw[1]->sw_if_index);
6296 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6299 tm->hw[0]->sw_if_index);
6300 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6303 tm->hw[1]->sw_if_index);
6304 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6307 tm->hw[1]->sw_if_index);
6310 * Add an etry with one path with a real out-going label
6312 fib_prefix_t pfx_1_1_1_1_s_32 = {
6314 .fp_proto = FIB_PROTOCOL_IP4,
6316 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6319 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6320 .type = FT_LB_LABEL_O_ADJ,
6322 .adj = ai_mpls_10_10_10_1,
6327 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6328 .type = FT_LB_LABEL_O_ADJ,
6330 .adj = ai_mpls_10_10_10_1,
6332 .eos = MPLS_NON_EOS,
6335 mpls_label_t *l99 = NULL;
6338 fib_table_entry_update_one_path(fib_index,
6341 FIB_ENTRY_FLAG_NONE,
6344 tm->hw[0]->sw_if_index,
6345 ~0, // invalid fib index
6348 FIB_ROUTE_PATH_FLAG_NONE);
6350 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6351 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6353 FIB_TEST(fib_test_validate_entry(fei,
6354 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6356 &l99_eos_o_10_10_10_1),
6357 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6360 * add a path with an implicit NULL label
6362 fib_test_lb_bucket_t a_o_10_10_11_1 = {
6365 .adj = ai_v4_10_10_11_1,
6368 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6371 .adj = ai_mpls_10_10_11_1,
6374 mpls_label_t *l_imp_null = NULL;
6375 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6377 fei = fib_table_entry_path_add(fib_index,
6380 FIB_ENTRY_FLAG_NONE,
6383 tm->hw[1]->sw_if_index,
6384 ~0, // invalid fib index
6387 FIB_ROUTE_PATH_FLAG_NONE);
6389 FIB_TEST(fib_test_validate_entry(fei,
6390 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6392 &l99_eos_o_10_10_10_1,
6394 "1.1.1.1/32 LB 2 buckets via: "
6395 "label 99 over 10.10.10.1, "
6396 "adj over 10.10.11.1");
6399 * assign the route a local label
6401 fib_table_entry_local_label_add(fib_index,
6405 fib_prefix_t pfx_24001_eos = {
6406 .fp_proto = FIB_PROTOCOL_MPLS,
6410 fib_prefix_t pfx_24001_neos = {
6411 .fp_proto = FIB_PROTOCOL_MPLS,
6413 .fp_eos = MPLS_NON_EOS,
6415 fib_test_lb_bucket_t disp_o_10_10_11_1 = {
6416 .type = FT_LB_MPLS_DISP_O_ADJ,
6418 .adj = ai_v4_10_10_11_1,
6423 * The EOS entry should link to both the paths,
6424 * and use an ip adj for the imp-null
6425 * The NON-EOS entry should link to both the paths,
6426 * and use an mpls adj for the imp-null
6428 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6430 FIB_TEST(fib_test_validate_entry(fei,
6431 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6433 &l99_eos_o_10_10_10_1,
6434 &disp_o_10_10_11_1),
6435 "24001/eos LB 2 buckets via: "
6436 "label 99 over 10.10.10.1, "
6437 "mpls disp adj over 10.10.11.1");
6440 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6442 FIB_TEST(fib_test_validate_entry(fei,
6443 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6445 &l99_neos_o_10_10_10_1,
6446 &a_mpls_o_10_10_11_1),
6447 "24001/neos LB 1 bucket via: "
6448 "label 99 over 10.10.10.1 ",
6449 "mpls-adj via 10.10.11.1");
6452 * add an unlabelled path, this is excluded from the neos chains,
6454 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6457 .adj = ai_v4_10_10_11_2,
6460 fib_test_lb_bucket_t disp_o_10_10_11_2 = {
6461 .type = FT_LB_MPLS_DISP_O_ADJ,
6463 .adj = ai_v4_10_10_11_2,
6468 fei = fib_table_entry_path_add(fib_index,
6471 FIB_ENTRY_FLAG_NONE,
6474 tm->hw[1]->sw_if_index,
6475 ~0, // invalid fib index
6478 FIB_ROUTE_PATH_FLAG_NONE);
6480 FIB_TEST(fib_test_validate_entry(fei,
6481 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6482 16, // 3 choices spread over 16 buckets
6483 &l99_eos_o_10_10_10_1,
6484 &l99_eos_o_10_10_10_1,
6485 &l99_eos_o_10_10_10_1,
6486 &l99_eos_o_10_10_10_1,
6487 &l99_eos_o_10_10_10_1,
6488 &l99_eos_o_10_10_10_1,
6499 "1.1.1.1/32 LB 16 buckets via: "
6500 "label 99 over 10.10.10.1, "
6501 "adj over 10.10.11.1",
6502 "adj over 10.10.11.2");
6505 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6507 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6508 fib_entry_contribute_forwarding(fei,
6509 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6513 * n-eos has only the 2 labelled paths
6515 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6518 FIB_TEST(fib_test_validate_entry(fei,
6519 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6521 &l99_neos_o_10_10_10_1,
6522 &a_mpls_o_10_10_11_1),
6523 "24001/neos LB 2 buckets via: "
6524 "label 99 over 10.10.10.1, "
6525 "adj-mpls over 10.10.11.2");
6528 * A labelled recursive
6530 fib_prefix_t pfx_2_2_2_2_s_32 = {
6532 .fp_proto = FIB_PROTOCOL_IP4,
6534 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6537 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6538 .type = FT_LB_LABEL_O_LB,
6540 .lb = non_eos_1_1_1_1.dpoi_index,
6545 mpls_label_t *l1600 = NULL;
6546 vec_add1(l1600, 1600);
6548 fib_table_entry_update_one_path(fib_index,
6551 FIB_ENTRY_FLAG_NONE,
6553 &pfx_1_1_1_1_s_32.fp_addr,
6558 FIB_ROUTE_PATH_FLAG_NONE);
6560 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6561 FIB_TEST(fib_test_validate_entry(fei,
6562 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6564 &l1600_eos_o_1_1_1_1),
6565 "2.2.2.2.2/32 LB 1 buckets via: "
6566 "label 1600 over 1.1.1.1");
6568 dpo_id_t dpo_44 = DPO_INVALID;
6571 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6572 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6574 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6575 "uRPF check for 2.2.2.2/32 on %d OK",
6576 tm->hw[0]->sw_if_index);
6577 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6578 "uRPF check for 2.2.2.2/32 on %d OK",
6579 tm->hw[1]->sw_if_index);
6580 FIB_TEST(!fib_urpf_check(urpfi, 99),
6581 "uRPF check for 2.2.2.2/32 on 99 not-OK",
6584 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6585 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6586 "Shared uRPF on IP and non-EOS chain");
6591 * we are holding a lock on the non-eos LB of the via-entry.
6592 * do a PIC-core failover by shutting the link of the via-entry.
6594 * shut down the link with the valid label
6596 vnet_sw_interface_set_flags(vnet_get_main(),
6597 tm->hw[0]->sw_if_index,
6600 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6601 FIB_TEST(fib_test_validate_entry(fei,
6602 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6606 "1.1.1.1/32 LB 2 buckets via: "
6607 "adj over 10.10.11.1, ",
6608 "adj-v4 over 10.10.11.2");
6610 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6612 FIB_TEST(fib_test_validate_entry(fei,
6613 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6616 &disp_o_10_10_11_2),
6617 "24001/eos LB 2 buckets via: "
6618 "mpls-disp adj over 10.10.11.1, ",
6619 "mpls-disp adj-v4 over 10.10.11.2");
6621 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6623 FIB_TEST(fib_test_validate_entry(fei,
6624 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6626 &a_mpls_o_10_10_11_1),
6627 "24001/neos LB 1 buckets via: "
6628 "adj-mpls over 10.10.11.2");
6631 * test that the pre-failover load-balance has been in-place
6634 dpo_id_t current = DPO_INVALID;
6635 fib_entry_contribute_forwarding(fei,
6636 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6639 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6641 "PIC-core LB inplace modified %U %U",
6642 format_dpo_id, &non_eos_1_1_1_1, 0,
6643 format_dpo_id, ¤t, 0);
6645 dpo_reset(&non_eos_1_1_1_1);
6646 dpo_reset(¤t);
6649 * no-shut the link with the valid label
6651 vnet_sw_interface_set_flags(vnet_get_main(),
6652 tm->hw[0]->sw_if_index,
6653 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6655 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6656 FIB_TEST(fib_test_validate_entry(fei,
6657 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6658 16, // 3 choices spread over 16 buckets
6659 &l99_eos_o_10_10_10_1,
6660 &l99_eos_o_10_10_10_1,
6661 &l99_eos_o_10_10_10_1,
6662 &l99_eos_o_10_10_10_1,
6663 &l99_eos_o_10_10_10_1,
6664 &l99_eos_o_10_10_10_1,
6675 "1.1.1.1/32 LB 16 buckets via: "
6676 "label 99 over 10.10.10.1, "
6677 "adj over 10.10.11.1",
6678 "adj-v4 over 10.10.11.2");
6681 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6683 FIB_TEST(fib_test_validate_entry(fei,
6684 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6685 16, // 3 choices spread over 16 buckets
6686 &l99_eos_o_10_10_10_1,
6687 &l99_eos_o_10_10_10_1,
6688 &l99_eos_o_10_10_10_1,
6689 &l99_eos_o_10_10_10_1,
6690 &l99_eos_o_10_10_10_1,
6691 &l99_eos_o_10_10_10_1,
6701 &disp_o_10_10_11_2),
6702 "24001/eos LB 16 buckets via: "
6703 "label 99 over 10.10.10.1, "
6704 "MPLS disp adj over 10.10.11.1",
6705 "MPLS disp adj-v4 over 10.10.11.2");
6707 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6709 FIB_TEST(fib_test_validate_entry(fei,
6710 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6712 &l99_neos_o_10_10_10_1,
6713 &a_mpls_o_10_10_11_1),
6714 "24001/neos LB 2 buckets via: "
6715 "label 99 over 10.10.10.1, "
6716 "adj-mpls over 10.10.11.2");
6719 * remove the first path with the valid label
6721 fib_table_entry_path_remove(fib_index,
6726 tm->hw[0]->sw_if_index,
6727 ~0, // invalid fib index
6729 FIB_ROUTE_PATH_FLAG_NONE);
6731 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6732 FIB_TEST(fib_test_validate_entry(fei,
6733 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6737 "1.1.1.1/32 LB 2 buckets via: "
6738 "adj over 10.10.11.1, "
6739 "adj-v4 over 10.10.11.2");
6741 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6743 FIB_TEST(fib_test_validate_entry(fei,
6744 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6747 &disp_o_10_10_11_2),
6748 "24001/eos LB 2 buckets via: "
6749 "MPLS disp adj over 10.10.11.1, "
6750 "MPLS disp adj-v4 over 10.10.11.2");
6752 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6755 FIB_TEST(fib_test_validate_entry(fei,
6756 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6758 &a_mpls_o_10_10_11_1),
6759 "24001/neos LB 1 buckets via: "
6760 "adj-mpls over 10.10.11.2");
6763 * remove the other path with a valid label
6765 fib_test_lb_bucket_t bucket_drop = {
6768 fib_test_lb_bucket_t mpls_bucket_drop = {
6771 .adj = DPO_PROTO_MPLS,
6775 fib_table_entry_path_remove(fib_index,
6780 tm->hw[1]->sw_if_index,
6781 ~0, // invalid fib index
6783 FIB_ROUTE_PATH_FLAG_NONE);
6785 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6786 FIB_TEST(fib_test_validate_entry(fei,
6787 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6790 "1.1.1.1/32 LB 1 buckets via: "
6791 "adj over 10.10.11.2");
6793 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6795 FIB_TEST(fib_test_validate_entry(fei,
6796 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6798 &disp_o_10_10_11_2),
6799 "24001/eos LB 1 buckets via: "
6800 "MPLS disp adj over 10.10.11.2");
6802 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6804 FIB_TEST(fib_test_validate_entry(fei,
6805 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6808 "24001/neos LB 1 buckets via: DROP");
6811 * add back the path with the valid label
6816 fib_table_entry_path_add(fib_index,
6819 FIB_ENTRY_FLAG_NONE,
6822 tm->hw[0]->sw_if_index,
6823 ~0, // invalid fib index
6826 FIB_ROUTE_PATH_FLAG_NONE);
6828 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6829 FIB_TEST(fib_test_validate_entry(fei,
6830 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6832 &l99_eos_o_10_10_10_1,
6834 "1.1.1.1/32 LB 2 buckets via: "
6835 "label 99 over 10.10.10.1, "
6836 "adj over 10.10.11.2");
6838 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6840 FIB_TEST(fib_test_validate_entry(fei,
6841 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6843 &l99_eos_o_10_10_10_1,
6844 &disp_o_10_10_11_2),
6845 "24001/eos LB 2 buckets via: "
6846 "label 99 over 10.10.10.1, "
6847 "MPLS disp adj over 10.10.11.2");
6849 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6851 FIB_TEST(fib_test_validate_entry(fei,
6852 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6854 &l99_neos_o_10_10_10_1),
6855 "24001/neos LB 1 buckets via: "
6856 "label 99 over 10.10.10.1");
6859 * change the local label
6861 fib_table_entry_local_label_add(fib_index,
6865 fib_prefix_t pfx_25005_eos = {
6866 .fp_proto = FIB_PROTOCOL_MPLS,
6870 fib_prefix_t pfx_25005_neos = {
6871 .fp_proto = FIB_PROTOCOL_MPLS,
6873 .fp_eos = MPLS_NON_EOS,
6876 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6877 fib_table_lookup(fib_index, &pfx_24001_eos)),
6878 "24001/eos removed after label change");
6879 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6880 fib_table_lookup(fib_index, &pfx_24001_neos)),
6881 "24001/eos removed after label change");
6883 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6885 FIB_TEST(fib_test_validate_entry(fei,
6886 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6888 &l99_eos_o_10_10_10_1,
6889 &disp_o_10_10_11_2),
6890 "25005/eos LB 2 buckets via: "
6891 "label 99 over 10.10.10.1, "
6892 "MPLS disp adj over 10.10.11.2");
6894 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6896 FIB_TEST(fib_test_validate_entry(fei,
6897 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6899 &l99_neos_o_10_10_10_1),
6900 "25005/neos LB 1 buckets via: "
6901 "label 99 over 10.10.10.1");
6904 * remove the local label.
6905 * the check that the MPLS entries are gone is done by the fact the
6906 * MPLS table is no longer present.
6908 fib_table_entry_local_label_remove(fib_index,
6912 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6913 FIB_TEST(fib_test_validate_entry(fei,
6914 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6916 &l99_eos_o_10_10_10_1,
6918 "24001/eos LB 2 buckets via: "
6919 "label 99 over 10.10.10.1, "
6920 "adj over 10.10.11.2");
6922 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6923 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6924 "No more MPLS FIB entries => table removed");
6927 * add another via-entry for the recursive
6929 fib_prefix_t pfx_1_1_1_2_s_32 = {
6931 .fp_proto = FIB_PROTOCOL_IP4,
6933 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6936 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6937 .type = FT_LB_LABEL_O_ADJ,
6939 .adj = ai_mpls_10_10_10_1,
6944 mpls_label_t *l101 = NULL;
6945 vec_add1(l101, 101);
6947 fei = fib_table_entry_update_one_path(fib_index,
6950 FIB_ENTRY_FLAG_NONE,
6953 tm->hw[0]->sw_if_index,
6954 ~0, // invalid fib index
6957 FIB_ROUTE_PATH_FLAG_NONE);
6959 FIB_TEST(fib_test_validate_entry(fei,
6960 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6962 &l101_eos_o_10_10_10_1),
6963 "1.1.1.2/32 LB 1 buckets via: "
6964 "label 101 over 10.10.10.1");
6966 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6967 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6969 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6971 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6973 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6976 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6977 .type = FT_LB_LABEL_O_LB,
6979 .lb = non_eos_1_1_1_2.dpoi_index,
6984 mpls_label_t *l1601 = NULL;
6985 vec_add1(l1601, 1601);
6987 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6989 fei = fib_table_entry_path_add(fib_index,
6992 FIB_ENTRY_FLAG_NONE,
6994 &pfx_1_1_1_2_s_32.fp_addr,
6999 FIB_ROUTE_PATH_FLAG_NONE);
7001 FIB_TEST(fib_test_validate_entry(fei,
7002 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7004 &l1600_eos_o_1_1_1_1,
7005 &l1601_eos_o_1_1_1_2),
7006 "2.2.2.2/32 LB 2 buckets via: "
7007 "label 1600 via 1.1,1.1, "
7008 "label 16001 via 1.1.1.2");
7011 * update the via-entry so it no longer has an imp-null path.
7012 * the LB for the recursive can use an imp-null
7015 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
7017 fei = fib_table_entry_update_one_path(fib_index,
7020 FIB_ENTRY_FLAG_NONE,
7023 tm->hw[1]->sw_if_index,
7024 ~0, // invalid fib index
7027 FIB_ROUTE_PATH_FLAG_NONE);
7029 FIB_TEST(fib_test_validate_entry(fei,
7030 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7033 "1.1.1.2/32 LB 1 buckets via: "
7036 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7037 FIB_TEST(fib_test_validate_entry(fei,
7038 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7040 &l1600_eos_o_1_1_1_1,
7041 &l1601_eos_o_1_1_1_2),
7042 "2.2.2.2/32 LB 2 buckets via: "
7043 "label 1600 via 1.1,1.1, "
7044 "label 16001 via 1.1.1.2");
7047 * update the via-entry so it no longer has labelled paths.
7048 * the LB for the recursive should exclue this via form its LB
7050 fei = fib_table_entry_update_one_path(fib_index,
7053 FIB_ENTRY_FLAG_NONE,
7056 tm->hw[1]->sw_if_index,
7057 ~0, // invalid fib index
7060 FIB_ROUTE_PATH_FLAG_NONE);
7062 FIB_TEST(fib_test_validate_entry(fei,
7063 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7066 "1.1.1.2/32 LB 1 buckets via: "
7069 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7070 FIB_TEST(fib_test_validate_entry(fei,
7071 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7073 &l1600_eos_o_1_1_1_1),
7074 "2.2.2.2/32 LB 1 buckets via: "
7075 "label 1600 via 1.1,1.1");
7077 dpo_reset(&non_eos_1_1_1_1);
7078 dpo_reset(&non_eos_1_1_1_2);
7081 * Add a recursive with no out-labels. We expect to use the IP of the via
7083 fib_prefix_t pfx_2_2_2_3_s_32 = {
7085 .fp_proto = FIB_PROTOCOL_IP4,
7087 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7090 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
7092 fib_table_entry_update_one_path(fib_index,
7095 FIB_ENTRY_FLAG_NONE,
7097 &pfx_1_1_1_1_s_32.fp_addr,
7102 FIB_ROUTE_PATH_FLAG_NONE);
7104 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7106 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7109 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7112 .lb = ip_1_1_1_1.dpoi_index,
7116 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7117 FIB_TEST(fib_test_validate_entry(fei,
7118 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7121 "2.2.2.2.3/32 LB 1 buckets via: "
7125 * Add a recursive with an imp-null out-label.
7126 * We expect to use the IP of the via
7128 fib_prefix_t pfx_2_2_2_4_s_32 = {
7130 .fp_proto = FIB_PROTOCOL_IP4,
7132 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7136 fib_table_entry_update_one_path(fib_index,
7139 FIB_ENTRY_FLAG_NONE,
7141 &pfx_1_1_1_1_s_32.fp_addr,
7146 FIB_ROUTE_PATH_FLAG_NONE);
7148 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7149 FIB_TEST(fib_test_validate_entry(fei,
7150 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7153 "2.2.2.2.4/32 LB 1 buckets via: "
7156 dpo_reset(&ip_1_1_1_1);
7159 * Create an entry with a deep label stack
7161 fib_prefix_t pfx_2_2_5_5_s_32 = {
7163 .fp_proto = FIB_PROTOCOL_IP4,
7165 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7168 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7169 .type = FT_LB_LABEL_STACK_O_ADJ,
7170 .label_stack_o_adj = {
7171 .adj = ai_mpls_10_10_11_1,
7172 .label_stack_size = 8,
7174 200, 201, 202, 203, 204, 205, 206, 207
7179 mpls_label_t *label_stack = NULL;
7180 vec_validate(label_stack, 7);
7181 for (ii = 0; ii < 8; ii++)
7183 label_stack[ii] = ii + 200;
7186 fei = fib_table_entry_update_one_path(fib_index,
7189 FIB_ENTRY_FLAG_NONE,
7192 tm->hw[1]->sw_if_index,
7193 ~0, // invalid fib index
7196 FIB_ROUTE_PATH_FLAG_NONE);
7198 FIB_TEST(fib_test_validate_entry(fei,
7199 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7201 &ls_eos_o_10_10_10_1),
7202 "2.2.5.5/32 LB 1 buckets via: "
7204 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7209 fib_table_entry_delete(fib_index,
7213 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7214 FIB_TEST(fib_test_validate_entry(fei,
7215 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7217 &l1600_eos_o_1_1_1_1),
7218 "2.2.2.2/32 LB 1 buckets via: "
7219 "label 1600 via 1.1,1.1");
7221 fib_table_entry_delete(fib_index,
7225 FIB_TEST(fib_test_validate_entry(fei,
7226 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7229 "2.2.2.2/32 LB 1 buckets via: DROP");
7231 fib_table_entry_delete(fib_index,
7234 fib_table_entry_delete(fib_index,
7237 fib_table_entry_delete(fib_index,
7241 adj_unlock(ai_mpls_10_10_10_1);
7242 adj_unlock(ai_mpls_10_10_11_2);
7243 adj_unlock(ai_v4_10_10_11_1);
7244 adj_unlock(ai_v4_10_10_11_2);
7245 adj_unlock(ai_mpls_10_10_11_1);
7247 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7250 local0_pfx.fp_len = 32;
7251 fib_table_entry_delete(fib_index,
7253 FIB_SOURCE_INTERFACE);
7254 local0_pfx.fp_len = 24;
7255 fib_table_entry_delete(fib_index,
7257 FIB_SOURCE_INTERFACE);
7258 local1_pfx.fp_len = 32;
7259 fib_table_entry_delete(fib_index,
7261 FIB_SOURCE_INTERFACE);
7262 local1_pfx.fp_len = 24;
7263 fib_table_entry_delete(fib_index,
7265 FIB_SOURCE_INTERFACE);
7268 * +1 for the drop LB in the MPLS tables.
7270 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7271 "Load-balance resources freed %d of %d",
7272 lb_count+1, pool_elts(load_balance_pool));
7277 #define N_TEST_CHILDREN 4
7278 #define PARENT_INDEX 0
7280 typedef struct fib_node_test_t_
7285 fib_node_back_walk_ctx_t *ctxs;
7289 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7291 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7293 #define FOR_EACH_TEST_CHILD(_tc) \
7294 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
7295 ii < N_TEST_CHILDREN+1; \
7296 ii++, (_tc) = &fib_test_nodes[ii])
7299 fib_test_child_get_node (fib_node_index_t index)
7301 return (&fib_test_nodes[index].node);
7304 static int fib_test_walk_spawns_walks;
7306 static fib_node_back_walk_rc_t
7307 fib_test_child_back_walk_notify (fib_node_t *node,
7308 fib_node_back_walk_ctx_t *ctx)
7310 fib_node_test_t *tc = (fib_node_test_t*) node;
7312 vec_add1(tc->ctxs, *ctx);
7314 if (1 == fib_test_walk_spawns_walks)
7315 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7316 if (2 == fib_test_walk_spawns_walks)
7317 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7318 FIB_WALK_PRIORITY_HIGH, ctx);
7320 return (FIB_NODE_BACK_WALK_CONTINUE);
7324 fib_test_child_last_lock_gone (fib_node_t *node)
7326 fib_node_test_t *tc = (fib_node_test_t *)node;
7332 * The FIB walk's graph node virtual function table
7334 static const fib_node_vft_t fib_test_child_vft = {
7335 .fnv_get = fib_test_child_get_node,
7336 .fnv_last_lock = fib_test_child_last_lock_gone,
7337 .fnv_back_walk = fib_test_child_back_walk_notify,
7341 * the function (that should have been static but isn't so I can do this)
7342 * that processes the walk from the async queue,
7344 f64 fib_walk_process_queues(vlib_main_t * vm,
7346 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7349 fib_test_walk (void)
7351 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7352 fib_node_test_t *tc;
7356 vm = vlib_get_main();
7357 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7360 * init a fake node on which we will add children
7362 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7363 FIB_NODE_TYPE_TEST);
7365 FOR_EACH_TEST_CHILD(tc)
7367 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7368 fib_node_lock(&tc->node);
7371 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7373 FIB_NODE_TYPE_TEST, ii);
7377 * enqueue a walk across the parents children.
7379 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7381 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7382 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7383 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7384 "Parent has %d children pre-walk",
7385 fib_node_list_get_size(PARENT()->fn_children));
7388 * give the walk a large amount of time so it gets to the end
7390 fib_walk_process_queues(vm, 1);
7392 FOR_EACH_TEST_CHILD(tc)
7394 FIB_TEST(1 == vec_len(tc->ctxs),
7395 "%d child visitsed %d times",
7396 ii, vec_len(tc->ctxs));
7399 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7400 "Queue is empty post walk");
7401 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7402 "Parent has %d children post walk",
7403 fib_node_list_get_size(PARENT()->fn_children));
7406 * walk again. should be no increase in the number of visits, since
7407 * the walk will have terminated.
7409 fib_walk_process_queues(vm, 1);
7411 FOR_EACH_TEST_CHILD(tc)
7413 FIB_TEST(0 == vec_len(tc->ctxs),
7414 "%d child visitsed %d times",
7415 ii, vec_len(tc->ctxs));
7419 * schedule a low and hig priority walk. expect the high to be performed
7421 * schedule the high prio walk first so that it is further from the head
7422 * of the dependency list. that way it won't merge with the low one.
7424 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7425 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7427 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7428 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7429 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7430 FIB_WALK_PRIORITY_LOW, &low_ctx);
7432 fib_walk_process_queues(vm, 1);
7434 FOR_EACH_TEST_CHILD(tc)
7436 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7437 "%d child visitsed by high prio walk", ii);
7438 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7439 "%d child visitsed by low prio walk", ii);
7442 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7443 "Queue is empty post prio walk");
7444 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7445 "Parent has %d children post prio walk",
7446 fib_node_list_get_size(PARENT()->fn_children));
7449 * schedule 2 walks of the same priority that can be megred.
7450 * expect that each child is thus visited only once.
7452 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7453 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7455 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7456 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7457 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7458 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7460 fib_walk_process_queues(vm, 1);
7462 FOR_EACH_TEST_CHILD(tc)
7464 FIB_TEST(1 == vec_len(tc->ctxs),
7465 "%d child visitsed %d times during merge walk",
7466 ii, vec_len(tc->ctxs));
7469 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7470 "Queue is empty post merge walk");
7471 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7472 "Parent has %d children post merge walk",
7473 fib_node_list_get_size(PARENT()->fn_children));
7476 * schedule 2 walks of the same priority that cannot be megred.
7477 * expect that each child is thus visited twice and in the order
7478 * in which the walks were scheduled.
7480 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7481 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7483 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7484 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7485 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7486 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7488 fib_walk_process_queues(vm, 1);
7490 FOR_EACH_TEST_CHILD(tc)
7492 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7493 "%d child visitsed by high prio walk", ii);
7494 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7495 "%d child visitsed by low prio walk", ii);
7498 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7499 "Queue is empty post no-merge walk");
7500 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7501 "Parent has %d children post no-merge walk",
7502 fib_node_list_get_size(PARENT()->fn_children));
7505 * schedule a walk that makes one one child progress.
7506 * we do this by giving the queue draining process zero
7507 * time quanta. it's a do..while loop, so it does something.
7509 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7511 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7512 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7513 fib_walk_process_queues(vm, 0);
7515 FOR_EACH_TEST_CHILD(tc)
7517 if (ii == N_TEST_CHILDREN)
7519 FIB_TEST(1 == vec_len(tc->ctxs),
7520 "%d child visitsed %d times in zero quanta walk",
7521 ii, vec_len(tc->ctxs));
7525 FIB_TEST(0 == vec_len(tc->ctxs),
7526 "%d child visitsed %d times in 0 quanta walk",
7527 ii, vec_len(tc->ctxs));
7530 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7531 "Queue is not empty post zero quanta walk");
7532 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7533 "Parent has %d children post zero qunta walk",
7534 fib_node_list_get_size(PARENT()->fn_children));
7539 fib_walk_process_queues(vm, 0);
7541 FOR_EACH_TEST_CHILD(tc)
7543 if (ii >= N_TEST_CHILDREN-1)
7545 FIB_TEST(1 == vec_len(tc->ctxs),
7546 "%d child visitsed %d times in 2nd zero quanta walk",
7547 ii, vec_len(tc->ctxs));
7551 FIB_TEST(0 == vec_len(tc->ctxs),
7552 "%d child visitsed %d times in 2nd 0 quanta walk",
7553 ii, vec_len(tc->ctxs));
7556 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7557 "Queue is not empty post zero quanta walk");
7558 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7559 "Parent has %d children post zero qunta walk",
7560 fib_node_list_get_size(PARENT()->fn_children));
7563 * schedule another walk that will catch-up and merge.
7565 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7566 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7567 fib_walk_process_queues(vm, 1);
7569 FOR_EACH_TEST_CHILD(tc)
7571 if (ii >= N_TEST_CHILDREN-1)
7573 FIB_TEST(2 == vec_len(tc->ctxs),
7574 "%d child visitsed %d times in 2nd zero quanta merge walk",
7575 ii, vec_len(tc->ctxs));
7580 FIB_TEST(1 == vec_len(tc->ctxs),
7581 "%d child visitsed %d times in 2nd 0 quanta merge walk",
7582 ii, vec_len(tc->ctxs));
7586 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7587 "Queue is not empty post 2nd zero quanta merge walk");
7588 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7589 "Parent has %d children post 2nd zero qunta merge walk",
7590 fib_node_list_get_size(PARENT()->fn_children));
7593 * park a async walk in the middle of the list, then have an sync walk catch
7594 * it. same expectations as async catches async.
7596 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7598 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7599 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7601 fib_walk_process_queues(vm, 0);
7602 fib_walk_process_queues(vm, 0);
7604 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7606 FOR_EACH_TEST_CHILD(tc)
7608 if (ii >= N_TEST_CHILDREN-1)
7610 FIB_TEST(2 == vec_len(tc->ctxs),
7611 "%d child visitsed %d times in sync catches async walk",
7612 ii, vec_len(tc->ctxs));
7617 FIB_TEST(1 == vec_len(tc->ctxs),
7618 "%d child visitsed %d times in sync catches async walk",
7619 ii, vec_len(tc->ctxs));
7623 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7624 "Queue is not empty post 2nd zero quanta merge walk");
7625 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7626 "Parent has %d children post 2nd zero qunta merge walk",
7627 fib_node_list_get_size(PARENT()->fn_children));
7630 * make the parent a child of one of its children, thus inducing a routing loop.
7632 fib_test_nodes[PARENT_INDEX].sibling =
7633 fib_node_child_add(FIB_NODE_TYPE_TEST,
7634 1, // the first child
7639 * execute a sync walk from the parent. each child visited spawns more sync
7640 * walks. we expect the walk to terminate.
7642 fib_test_walk_spawns_walks = 1;
7644 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7646 FOR_EACH_TEST_CHILD(tc)
7649 * child 1 - which is last in the list - has the loop.
7650 * the other children a re thus visitsed first. the we meet
7651 * child 1. we go round the loop again, visting the other children.
7652 * then we meet the walk in the dep list and bail. child 1 is not visitsed
7657 FIB_TEST(1 == vec_len(tc->ctxs),
7658 "child %d visitsed %d times during looped sync walk",
7659 ii, vec_len(tc->ctxs));
7663 FIB_TEST(2 == vec_len(tc->ctxs),
7664 "child %d visitsed %d times during looped sync walk",
7665 ii, vec_len(tc->ctxs));
7669 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7670 "Parent has %d children post sync loop walk",
7671 fib_node_list_get_size(PARENT()->fn_children));
7674 * the walk doesn't reach the max depth because the infra knows that sync
7675 * meets sync implies a loop and bails early.
7677 FIB_TEST(high_ctx.fnbw_depth == 9,
7678 "Walk context depth %d post sync loop walk",
7679 high_ctx.fnbw_depth);
7682 * execute an async walk of the graph loop, with each child spawns sync walks
7684 high_ctx.fnbw_depth = 0;
7685 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7686 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7688 fib_walk_process_queues(vm, 1);
7690 FOR_EACH_TEST_CHILD(tc)
7693 * we don't really care how many times the children are visisted, as long as
7694 * it is more than once.
7696 FIB_TEST(1 <= vec_len(tc->ctxs),
7697 "child %d visitsed %d times during looped aync spawns sync walk",
7698 ii, vec_len(tc->ctxs));
7703 * execute an async walk of the graph loop, with each child spawns async walks
7705 fib_test_walk_spawns_walks = 2;
7706 high_ctx.fnbw_depth = 0;
7707 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7708 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7710 fib_walk_process_queues(vm, 1);
7712 FOR_EACH_TEST_CHILD(tc)
7715 * we don't really care how many times the children are visisted, as long as
7716 * it is more than once.
7718 FIB_TEST(1 <= vec_len(tc->ctxs),
7719 "child %d visitsed %d times during looped async spawns async walk",
7720 ii, vec_len(tc->ctxs));
7725 fib_node_child_remove(FIB_NODE_TYPE_TEST,
7726 1, // the first child
7727 fib_test_nodes[PARENT_INDEX].sibling);
7732 FOR_EACH_TEST_CHILD(tc)
7734 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7736 fib_node_deinit(&tc->node);
7737 fib_node_unlock(&tc->node);
7739 fib_node_deinit(PARENT());
7742 * The parent will be destroyed when the last lock on it goes.
7743 * this test ensures all the walk objects are unlocking it.
7745 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7746 "Parent was destroyed");
7752 * declaration of the otherwise static callback functions
7754 void fib_bfd_notify (bfd_listen_event_e event,
7755 const bfd_session_t *session);
7756 void adj_bfd_notify (bfd_listen_event_e event,
7757 const bfd_session_t *session);
7760 * Test BFD session interaction with FIB
7765 fib_node_index_t fei;
7769 /* via 10.10.10.1 */
7770 ip46_address_t nh_10_10_10_1 = {
7771 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7773 /* via 10.10.10.2 */
7774 ip46_address_t nh_10_10_10_2 = {
7775 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7777 /* via 10.10.10.10 */
7778 ip46_address_t nh_10_10_10_10 = {
7779 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7781 n_feis = fib_entry_pool_size();
7786 * add interface routes. we'll assume this works. it's tested elsewhere
7788 fib_prefix_t pfx_10_10_10_10_s_24 = {
7790 .fp_proto = FIB_PROTOCOL_IP4,
7791 .fp_addr = nh_10_10_10_10,
7794 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7795 FIB_SOURCE_INTERFACE,
7796 (FIB_ENTRY_FLAG_CONNECTED |
7797 FIB_ENTRY_FLAG_ATTACHED),
7800 tm->hw[0]->sw_if_index,
7801 ~0, // invalid fib index
7804 FIB_ROUTE_PATH_FLAG_NONE);
7806 fib_prefix_t pfx_10_10_10_10_s_32 = {
7808 .fp_proto = FIB_PROTOCOL_IP4,
7809 .fp_addr = nh_10_10_10_10,
7811 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7812 FIB_SOURCE_INTERFACE,
7813 (FIB_ENTRY_FLAG_CONNECTED |
7814 FIB_ENTRY_FLAG_LOCAL),
7817 tm->hw[0]->sw_if_index,
7818 ~0, // invalid fib index
7821 FIB_ROUTE_PATH_FLAG_NONE);
7824 * A BFD session via a neighbour we do not yet know
7826 bfd_session_t bfd_10_10_10_1 = {
7830 .peer_addr = nh_10_10_10_1,
7833 .hop_type = BFD_HOP_TYPE_MULTI,
7834 .local_state = BFD_STATE_init,
7837 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7840 * A new entry will be created that forwards via the adj
7842 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7845 tm->hw[0]->sw_if_index);
7846 fib_prefix_t pfx_10_10_10_1_s_32 = {
7847 .fp_addr = nh_10_10_10_1,
7849 .fp_proto = FIB_PROTOCOL_IP4,
7851 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7854 .adj = ai_10_10_10_1,
7858 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7859 FIB_TEST(fib_test_validate_entry(fei,
7860 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7863 "BFD sourced %U via %U",
7864 format_fib_prefix, &pfx_10_10_10_1_s_32,
7865 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7868 * Delete the BFD session. Expect the fib_entry to be removed
7870 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7872 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7873 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7874 "BFD sourced %U removed",
7875 format_fib_prefix, &pfx_10_10_10_1_s_32);
7878 * Add the BFD source back
7880 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7883 * source the entry via the ADJ fib
7885 fei = fib_table_entry_path_add(0,
7886 &pfx_10_10_10_1_s_32,
7888 FIB_ENTRY_FLAG_ATTACHED,
7891 tm->hw[0]->sw_if_index,
7892 ~0, // invalid fib index
7895 FIB_ROUTE_PATH_FLAG_NONE);
7898 * Delete the BFD session. Expect the fib_entry to remain
7900 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7902 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7903 FIB_TEST(fib_test_validate_entry(fei,
7904 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7907 "BFD sourced %U remains via %U",
7908 format_fib_prefix, &pfx_10_10_10_1_s_32,
7909 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7912 * Add the BFD source back
7914 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7917 * Create another ADJ FIB
7919 fib_prefix_t pfx_10_10_10_2_s_32 = {
7920 .fp_addr = nh_10_10_10_2,
7922 .fp_proto = FIB_PROTOCOL_IP4,
7924 fib_table_entry_path_add(0,
7925 &pfx_10_10_10_2_s_32,
7927 FIB_ENTRY_FLAG_ATTACHED,
7930 tm->hw[0]->sw_if_index,
7931 ~0, // invalid fib index
7934 FIB_ROUTE_PATH_FLAG_NONE);
7936 * A BFD session for the new ADJ FIB
7938 bfd_session_t bfd_10_10_10_2 = {
7942 .peer_addr = nh_10_10_10_2,
7945 .hop_type = BFD_HOP_TYPE_MULTI,
7946 .local_state = BFD_STATE_init,
7949 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7952 * remove the adj-fib source whilst the session is present
7955 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7956 fib_table_entry_path_add(0,
7957 &pfx_10_10_10_2_s_32,
7959 FIB_ENTRY_FLAG_ATTACHED,
7962 tm->hw[0]->sw_if_index,
7963 ~0, // invalid fib index
7966 FIB_ROUTE_PATH_FLAG_NONE);
7969 * Before adding a recursive via the BFD tracked ADJ-FIBs,
7970 * bring one of the sessions UP, leave the other down
7972 bfd_10_10_10_1.local_state = BFD_STATE_up;
7973 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7974 bfd_10_10_10_2.local_state = BFD_STATE_down;
7975 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7978 * A recursive prefix via both of the ADJ FIBs
7980 fib_prefix_t pfx_200_0_0_0_s_24 = {
7981 .fp_proto = FIB_PROTOCOL_IP4,
7984 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7987 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7990 fib_entry_contribute_ip_forwarding(
7991 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7993 fib_entry_contribute_ip_forwarding(
7994 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7996 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7999 .lb = dpo_10_10_10_1->dpoi_index,
8002 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
8005 .lb = dpo_10_10_10_2->dpoi_index,
8010 * A prefix via the adj-fib that is BFD down => DROP
8012 fei = fib_table_entry_path_add(0,
8013 &pfx_200_0_0_0_s_24,
8015 FIB_ENTRY_FLAG_NONE,
8019 0, // default fib index
8022 FIB_ROUTE_PATH_FLAG_NONE);
8023 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8024 "%U resolves via drop",
8025 format_fib_prefix, &pfx_200_0_0_0_s_24);
8028 * add a path via the UP BFD adj-fib.
8029 * we expect that the DOWN BFD ADJ FIB is not used.
8031 fei = fib_table_entry_path_add(0,
8032 &pfx_200_0_0_0_s_24,
8034 FIB_ENTRY_FLAG_NONE,
8038 0, // default fib index
8041 FIB_ROUTE_PATH_FLAG_NONE);
8043 FIB_TEST(fib_test_validate_entry(fei,
8044 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8047 "Recursive %U only UP BFD adj-fibs",
8048 format_fib_prefix, &pfx_200_0_0_0_s_24);
8051 * Send a BFD state change to UP - both sessions are now up
8052 * the recursive prefix should LB over both
8054 bfd_10_10_10_2.local_state = BFD_STATE_up;
8055 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8058 FIB_TEST(fib_test_validate_entry(fei,
8059 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8063 "Recursive %U via both UP BFD adj-fibs",
8064 format_fib_prefix, &pfx_200_0_0_0_s_24);
8067 * Send a BFD state change to DOWN
8068 * the recursive prefix should exclude the down
8070 bfd_10_10_10_2.local_state = BFD_STATE_down;
8071 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8074 FIB_TEST(fib_test_validate_entry(fei,
8075 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8078 "Recursive %U via only UP",
8079 format_fib_prefix, &pfx_200_0_0_0_s_24);
8082 * Delete the BFD session while it is in the DOWN state.
8083 * FIB should consider the entry's state as back up
8085 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
8087 FIB_TEST(fib_test_validate_entry(fei,
8088 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8092 "Recursive %U via both UP BFD adj-fibs post down session delete",
8093 format_fib_prefix, &pfx_200_0_0_0_s_24);
8096 * Delete the BFD other session while it is in the UP state.
8098 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8100 FIB_TEST(fib_test_validate_entry(fei,
8101 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8105 "Recursive %U via both UP BFD adj-fibs post up session delete",
8106 format_fib_prefix, &pfx_200_0_0_0_s_24);
8111 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8112 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8113 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8115 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8116 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8118 adj_unlock(ai_10_10_10_1);
8120 * test no-one left behind
8122 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8123 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8126 * Single-hop BFD tests
8128 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8129 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8131 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8133 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8136 tm->hw[0]->sw_if_index);
8138 * whilst the BFD session is not signalled, the adj is up
8140 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
8143 * bring the BFD session up
8145 bfd_10_10_10_1.local_state = BFD_STATE_up;
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 up on UP session");
8150 * bring the BFD session down
8152 bfd_10_10_10_1.local_state = BFD_STATE_down;
8153 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8154 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8158 * add an attached next hop FIB entry via the down adj
8160 fib_prefix_t pfx_5_5_5_5_s_32 = {
8163 .as_u32 = clib_host_to_net_u32(0x05050505),
8167 .fp_proto = FIB_PROTOCOL_IP4,
8170 fei = fib_table_entry_path_add(0,
8173 FIB_ENTRY_FLAG_NONE,
8176 tm->hw[0]->sw_if_index,
8177 ~0, // invalid fib index
8180 FIB_ROUTE_PATH_FLAG_NONE);
8181 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8182 "%U resolves via drop",
8183 format_fib_prefix, &pfx_5_5_5_5_s_32);
8186 * Add a path via an ADJ that is up
8188 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8191 tm->hw[0]->sw_if_index);
8193 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8196 .adj = ai_10_10_10_2,
8199 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8201 fei = fib_table_entry_path_add(0,
8204 FIB_ENTRY_FLAG_NONE,
8207 tm->hw[0]->sw_if_index,
8208 ~0, // invalid fib index
8211 FIB_ROUTE_PATH_FLAG_NONE);
8213 FIB_TEST(fib_test_validate_entry(fei,
8214 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8217 "BFD sourced %U via %U",
8218 format_fib_prefix, &pfx_5_5_5_5_s_32,
8219 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8222 * Bring up the down session - should now LB
8224 bfd_10_10_10_1.local_state = BFD_STATE_up;
8225 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8226 FIB_TEST(fib_test_validate_entry(fei,
8227 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8231 "BFD sourced %U via noth adjs",
8232 format_fib_prefix, &pfx_5_5_5_5_s_32);
8235 * remove the BFD session state from the adj
8237 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8242 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8243 adj_unlock(ai_10_10_10_1);
8244 adj_unlock(ai_10_10_10_2);
8247 * test no-one left behind
8249 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8250 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8257 const mpls_label_t deag_label = 50;
8258 const u32 lfib_index = 0;
8259 const u32 fib_index = 0;
8260 dpo_id_t dpo = DPO_INVALID;
8261 const dpo_id_t *dpo1;
8262 fib_node_index_t lfe;
8266 adj_index_t ai_mpls_10_10_10_1;
8269 lb_count = pool_elts(load_balance_pool);
8271 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8275 * MPLS enable an interface so we get the MPLS table created
8277 mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8278 mpls_sw_interface_enable_disable(&mpls_main,
8279 tm->hw[0]->sw_if_index,
8282 ip46_address_t nh_10_10_10_1 = {
8283 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8285 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8288 tm->hw[0]->sw_if_index);
8291 * Test the specials stack properly.
8293 fib_prefix_t exp_null_v6_pfx = {
8294 .fp_proto = FIB_PROTOCOL_MPLS,
8296 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8297 .fp_payload_proto = DPO_PROTO_IP6,
8299 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8300 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8302 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8303 format_mpls_eos_bit, MPLS_EOS);
8304 fib_entry_contribute_forwarding(lfe,
8305 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8307 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8308 lkd = lookup_dpo_get(dpo1->dpoi_index);
8310 FIB_TEST((fib_index == lkd->lkd_fib_index),
8311 "%U/%U is deag in %d %U",
8312 format_mpls_unicast_label, deag_label,
8313 format_mpls_eos_bit, MPLS_EOS,
8315 format_dpo_id, &dpo, 0);
8316 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8317 "%U/%U is dst deag",
8318 format_mpls_unicast_label, deag_label,
8319 format_mpls_eos_bit, MPLS_EOS);
8320 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8321 "%U/%U is lookup in interface's table",
8322 format_mpls_unicast_label, deag_label,
8323 format_mpls_eos_bit, MPLS_EOS);
8324 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8325 "%U/%U is %U dst deag",
8326 format_mpls_unicast_label, deag_label,
8327 format_mpls_eos_bit, MPLS_EOS,
8328 format_dpo_proto, lkd->lkd_proto);
8332 * A route deag route for EOS
8334 fib_prefix_t pfx = {
8335 .fp_proto = FIB_PROTOCOL_MPLS,
8337 .fp_label = deag_label,
8338 .fp_payload_proto = DPO_PROTO_IP4,
8340 lfe = fib_table_entry_path_add(lfib_index,
8343 FIB_ENTRY_FLAG_NONE,
8350 FIB_ROUTE_PATH_FLAG_NONE);
8352 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8354 format_mpls_unicast_label, deag_label,
8355 format_mpls_eos_bit, MPLS_EOS);
8357 fib_entry_contribute_forwarding(lfe,
8358 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8360 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8361 lkd = lookup_dpo_get(dpo1->dpoi_index);
8363 FIB_TEST((fib_index == lkd->lkd_fib_index),
8364 "%U/%U is deag in %d %U",
8365 format_mpls_unicast_label, deag_label,
8366 format_mpls_eos_bit, MPLS_EOS,
8368 format_dpo_id, &dpo, 0);
8369 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8370 "%U/%U is dst deag",
8371 format_mpls_unicast_label, deag_label,
8372 format_mpls_eos_bit, MPLS_EOS);
8373 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8374 "%U/%U is %U dst deag",
8375 format_mpls_unicast_label, deag_label,
8376 format_mpls_eos_bit, MPLS_EOS,
8377 format_dpo_proto, lkd->lkd_proto);
8379 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8381 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8383 "%U/%U not present",
8384 format_mpls_unicast_label, deag_label,
8385 format_mpls_eos_bit, MPLS_EOS);
8388 * A route deag route for non-EOS
8390 pfx.fp_eos = MPLS_NON_EOS;
8391 lfe = fib_table_entry_path_add(lfib_index,
8394 FIB_ENTRY_FLAG_NONE,
8401 FIB_ROUTE_PATH_FLAG_NONE);
8403 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8405 format_mpls_unicast_label, deag_label,
8406 format_mpls_eos_bit, MPLS_NON_EOS);
8408 fib_entry_contribute_forwarding(lfe,
8409 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8411 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8412 lkd = lookup_dpo_get(dpo1->dpoi_index);
8414 FIB_TEST((fib_index == lkd->lkd_fib_index),
8415 "%U/%U is deag in %d %U",
8416 format_mpls_unicast_label, deag_label,
8417 format_mpls_eos_bit, MPLS_NON_EOS,
8419 format_dpo_id, &dpo, 0);
8420 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8421 "%U/%U is dst deag",
8422 format_mpls_unicast_label, deag_label,
8423 format_mpls_eos_bit, MPLS_NON_EOS);
8425 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8426 "%U/%U is %U dst deag",
8427 format_mpls_unicast_label, deag_label,
8428 format_mpls_eos_bit, MPLS_NON_EOS,
8429 format_dpo_proto, lkd->lkd_proto);
8431 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8433 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8435 "%U/%U not present",
8436 format_mpls_unicast_label, deag_label,
8437 format_mpls_eos_bit, MPLS_EOS);
8444 fib_prefix_t pfx_1200 = {
8446 .fp_proto = FIB_PROTOCOL_MPLS,
8448 .fp_eos = MPLS_NON_EOS,
8450 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8451 .type = FT_LB_LABEL_STACK_O_ADJ,
8452 .label_stack_o_adj = {
8453 .adj = ai_mpls_10_10_10_1,
8454 .label_stack_size = 4,
8458 .eos = MPLS_NON_EOS,
8461 dpo_id_t neos_1200 = DPO_INVALID;
8462 dpo_id_t ip_1200 = DPO_INVALID;
8463 mpls_label_t *l200 = NULL;
8464 vec_add1(l200, 200);
8465 vec_add1(l200, 300);
8466 vec_add1(l200, 400);
8467 vec_add1(l200, 500);
8469 lfe = fib_table_entry_update_one_path(fib_index,
8472 FIB_ENTRY_FLAG_NONE,
8475 tm->hw[0]->sw_if_index,
8476 ~0, // invalid fib index
8479 FIB_ROUTE_PATH_FLAG_NONE);
8481 FIB_TEST(fib_test_validate_entry(lfe,
8482 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8484 &neos_o_10_10_10_1),
8485 "1200/0 LB 1 buckets via: "
8489 * A recursive route via the MPLS x-connect
8491 fib_prefix_t pfx_2_2_2_3_s_32 = {
8493 .fp_proto = FIB_PROTOCOL_IP4,
8495 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8498 fib_route_path_t *rpaths = NULL, rpath = {
8499 .frp_proto = DPO_PROTO_MPLS,
8500 .frp_local_label = 1200,
8501 .frp_eos = MPLS_NON_EOS,
8502 .frp_sw_if_index = ~0, // recurive
8503 .frp_fib_index = 0, // Default MPLS fib
8505 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8506 .frp_label_stack = NULL,
8508 vec_add1(rpaths, rpath);
8510 fib_table_entry_path_add2(fib_index,
8513 FIB_ENTRY_FLAG_NONE,
8517 * A labelled recursive route via the MPLS x-connect
8519 fib_prefix_t pfx_2_2_2_4_s_32 = {
8521 .fp_proto = FIB_PROTOCOL_IP4,
8523 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8526 mpls_label_t *l999 = NULL;
8527 vec_add1(l999, 999);
8528 rpaths[0].frp_label_stack = l999,
8530 fib_table_entry_path_add2(fib_index,
8533 FIB_ENTRY_FLAG_NONE,
8536 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8537 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8539 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8540 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8543 fib_test_lb_bucket_t ip_o_1200 = {
8546 .lb = ip_1200.dpoi_index,
8549 fib_test_lb_bucket_t mpls_o_1200 = {
8550 .type = FT_LB_LABEL_O_LB,
8552 .lb = neos_1200.dpoi_index,
8558 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8559 FIB_TEST(fib_test_validate_entry(lfe,
8560 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8563 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8564 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8565 FIB_TEST(fib_test_validate_entry(lfe,
8566 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8569 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8571 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8572 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8573 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8575 dpo_reset(&neos_1200);
8576 dpo_reset(&ip_1200);
8579 * A recursive via a label that does not exist
8581 fib_test_lb_bucket_t bucket_drop = {
8584 .adj = DPO_PROTO_IP4,
8587 fib_test_lb_bucket_t mpls_bucket_drop = {
8590 .adj = DPO_PROTO_MPLS,
8594 rpaths[0].frp_label_stack = NULL;
8595 lfe = fib_table_entry_path_add2(fib_index,
8598 FIB_ENTRY_FLAG_NONE,
8601 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8602 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8604 ip_o_1200.lb.lb = ip_1200.dpoi_index;
8606 FIB_TEST(fib_test_validate_entry(lfe,
8607 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8610 "2.2.2.2.4/32 LB 1 buckets via: drop");
8611 lfe = fib_table_lookup(fib_index, &pfx_1200);
8612 FIB_TEST(fib_test_validate_entry(lfe,
8613 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8616 "1200/neos LB 1 buckets via: ip4-DROP");
8617 FIB_TEST(fib_test_validate_entry(lfe,
8618 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8621 "1200/neos LB 1 buckets via: mpls-DROP");
8623 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8625 dpo_reset(&ip_1200);
8628 * An rx-interface route.
8629 * like the tail of an mcast LSP
8631 dpo_id_t idpo = DPO_INVALID;
8633 interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8634 tm->hw[0]->sw_if_index,
8637 fib_prefix_t pfx_2500 = {
8639 .fp_proto = FIB_PROTOCOL_MPLS,
8642 .fp_payload_proto = DPO_PROTO_IP4,
8644 fib_test_lb_bucket_t rx_intf_0 = {
8647 .adj = idpo.dpoi_index,
8651 lfe = fib_table_entry_update_one_path(fib_index,
8654 FIB_ENTRY_FLAG_NONE,
8657 tm->hw[0]->sw_if_index,
8658 ~0, // invalid fib index
8661 FIB_ROUTE_PATH_INTF_RX);
8662 FIB_TEST(fib_test_validate_entry(lfe,
8663 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8666 "2500 rx-interface 0");
8667 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8670 * An MPLS mulicast entry
8672 fib_prefix_t pfx_3500 = {
8674 .fp_proto = FIB_PROTOCOL_MPLS,
8677 .fp_payload_proto = DPO_PROTO_IP4,
8679 fib_test_rep_bucket_t mc_0 = {
8680 .type = FT_REP_LABEL_O_ADJ,
8682 .adj = ai_mpls_10_10_10_1,
8687 fib_test_rep_bucket_t mc_intf_0 = {
8688 .type = FT_REP_INTF,
8690 .adj = idpo.dpoi_index,
8693 mpls_label_t *l3300 = NULL;
8694 vec_add1(l3300, 3300);
8696 lfe = fib_table_entry_update_one_path(lfib_index,
8699 FIB_ENTRY_FLAG_MULTICAST,
8702 tm->hw[0]->sw_if_index,
8703 ~0, // invalid fib index
8706 FIB_ROUTE_PATH_FLAG_NONE);
8707 FIB_TEST(fib_test_validate_entry(lfe,
8708 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8711 "3500 via replicate over 10.10.10.1");
8714 * MPLS Bud-node. Add a replication via an interface-receieve path
8716 lfe = fib_table_entry_path_add(lfib_index,
8719 FIB_ENTRY_FLAG_MULTICAST,
8722 tm->hw[0]->sw_if_index,
8723 ~0, // invalid fib index
8726 FIB_ROUTE_PATH_INTF_RX);
8727 FIB_TEST(fib_test_validate_entry(lfe,
8728 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8732 "3500 via replicate over 10.10.10.1 and interface-rx");
8735 * Add a replication via an interface-free for-us path
8737 fib_test_rep_bucket_t mc_disp = {
8738 .type = FT_REP_DISP_MFIB_LOOKUP,
8740 .adj = idpo.dpoi_index,
8743 lfe = fib_table_entry_path_add(lfib_index,
8746 FIB_ENTRY_FLAG_MULTICAST,
8753 FIB_ROUTE_PATH_RPF_ID);
8754 FIB_TEST(fib_test_validate_entry(lfe,
8755 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8760 "3500 via replicate over 10.10.10.1 and interface-rx");
8764 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8770 mpls_sw_interface_enable_disable(&mpls_main,
8771 tm->hw[0]->sw_if_index,
8773 mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
8775 FIB_TEST(lb_count == pool_elts(load_balance_pool),
8776 "Load-balance resources freed %d of %d",
8777 lb_count, pool_elts(load_balance_pool));
8778 FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
8779 "interface_rx_dpo resources freed %d of %d",
8780 0, pool_elts(interface_rx_dpo_pool));
8786 fib_test_inherit (void)
8788 fib_node_index_t fei;
8792 n_feis = fib_entry_pool_size();
8795 const ip46_address_t nh_10_10_10_1 = {
8796 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8798 const ip46_address_t nh_10_10_10_2 = {
8799 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
8801 const ip46_address_t nh_10_10_10_16 = {
8802 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a10),
8804 const ip46_address_t nh_10_10_10_20 = {
8805 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a14),
8807 const ip46_address_t nh_10_10_10_21 = {
8808 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a15),
8810 const ip46_address_t nh_10_10_10_22 = {
8811 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a16),
8813 const ip46_address_t nh_10_10_10_255 = {
8814 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0aff),
8816 const ip46_address_t nh_10_10_10_0 = {
8817 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a00),
8819 const ip46_address_t nh_10_10_0_0 = {
8820 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0000),
8824 * prefixes at the base of a sub-tree
8826 const fib_prefix_t pfx_10_10_10_21_s_32 = {
8828 .fp_proto = FIB_PROTOCOL_IP4,
8829 .fp_addr = nh_10_10_10_21,
8831 const fib_prefix_t pfx_10_10_10_22_s_32 = {
8833 .fp_proto = FIB_PROTOCOL_IP4,
8834 .fp_addr = nh_10_10_10_22,
8836 const fib_prefix_t pfx_10_10_10_255_s_32 = {
8838 .fp_proto = FIB_PROTOCOL_IP4,
8839 .fp_addr = nh_10_10_10_255,
8842 fib_table_entry_special_add(0,
8843 &pfx_10_10_10_21_s_32,
8845 FIB_ENTRY_FLAG_DROP);
8846 fib_table_entry_special_add(0,
8847 &pfx_10_10_10_22_s_32,
8849 FIB_ENTRY_FLAG_DROP);
8850 fib_table_entry_special_add(0,
8851 &pfx_10_10_10_255_s_32,
8853 FIB_ENTRY_FLAG_DROP);
8856 * source an entry that pushes its state down the sub-tree
8858 const fib_prefix_t pfx_10_10_10_16_s_28 = {
8860 .fp_proto = FIB_PROTOCOL_IP4,
8861 .fp_addr = nh_10_10_10_16,
8863 fib_table_entry_update_one_path(0,
8864 &pfx_10_10_10_16_s_28,
8866 FIB_ENTRY_FLAG_COVERED_INHERIT,
8869 tm->hw[0]->sw_if_index,
8873 FIB_ROUTE_PATH_FLAG_NONE);
8876 * this covering entry and all those below it should have
8877 * the same forwarding information.
8879 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8882 tm->hw[0]->sw_if_index);
8883 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
8886 .adj = ai_10_10_10_1,
8890 fei = fib_table_lookup(0, &pfx_10_10_10_16_s_28);
8891 FIB_TEST(fib_test_validate_entry(fei,
8892 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8895 "%U via 10.10.10.1",
8896 format_fib_prefix, &pfx_10_10_10_16_s_28);
8897 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
8898 FIB_TEST(fib_test_validate_entry(fei,
8899 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8902 "%U via 10.10.10.1",
8903 format_fib_prefix, &pfx_10_10_10_21_s_32);
8904 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
8905 FIB_TEST(fib_test_validate_entry(fei,
8906 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8909 "%U via 10.10.10.1",
8910 format_fib_prefix, &pfx_10_10_10_22_s_32);
8911 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
8912 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8913 "%U resolves via drop",
8914 format_fib_prefix, &pfx_10_10_10_255_s_32);
8917 * remove the inherting cover - covereds go back to drop
8919 fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
8921 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
8922 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8923 "%U resolves via drop",
8924 format_fib_prefix, &pfx_10_10_10_21_s_32);
8927 * source an entry that pushes its state down the sub-tree
8929 const fib_prefix_t pfx_10_10_10_0_s_24 = {
8931 .fp_proto = FIB_PROTOCOL_IP4,
8932 .fp_addr = nh_10_10_10_0,
8934 fib_table_entry_update_one_path(0,
8935 &pfx_10_10_10_0_s_24,
8937 FIB_ENTRY_FLAG_COVERED_INHERIT,
8940 tm->hw[0]->sw_if_index,
8944 FIB_ROUTE_PATH_FLAG_NONE);
8947 * whole sub-tree now covered
8949 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
8950 FIB_TEST(fib_test_validate_entry(fei,
8951 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8954 "%U via 10.10.10.1",
8955 format_fib_prefix, &pfx_10_10_10_0_s_24);
8956 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
8957 FIB_TEST(fib_test_validate_entry(fei,
8958 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8961 "%U via 10.10.10.1",
8962 format_fib_prefix, &pfx_10_10_10_21_s_32);
8963 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
8964 FIB_TEST(fib_test_validate_entry(fei,
8965 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8968 "%U via 10.10.10.1",
8969 format_fib_prefix, &pfx_10_10_10_22_s_32);
8970 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
8971 FIB_TEST(fib_test_validate_entry(fei,
8972 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8975 "%U via 10.10.10.1",
8976 format_fib_prefix, &pfx_10_10_10_255_s_32);
8979 * insert a more specific into the sub-tree - expect inheritance
8980 * this one is directly covered by the root
8982 fib_table_entry_special_add(0,
8983 &pfx_10_10_10_16_s_28,
8985 FIB_ENTRY_FLAG_DROP);
8986 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
8987 FIB_TEST(fib_test_validate_entry(fei,
8988 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8991 "%U via 10.10.10.1",
8992 format_fib_prefix, &pfx_10_10_10_16_s_28);
8995 * insert a more specific into the sub-tree - expect inheritance
8996 * this one is indirectly covered by the root
8998 const fib_prefix_t pfx_10_10_10_20_s_30 = {
9000 .fp_proto = FIB_PROTOCOL_IP4,
9001 .fp_addr = nh_10_10_10_20,
9003 fib_table_entry_special_add(0,
9004 &pfx_10_10_10_20_s_30,
9006 FIB_ENTRY_FLAG_DROP);
9007 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9008 FIB_TEST(fib_test_validate_entry(fei,
9009 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9012 "%U via 10.10.10.1",
9013 format_fib_prefix, &pfx_10_10_10_20_s_30);
9016 * remove the prefix from the middle of the sub-tree
9017 * the inherited source will be the only one remaining - expect
9018 * it to be withdrawn and hence the prefix is removed.
9020 fib_table_entry_special_remove(0,
9021 &pfx_10_10_10_20_s_30,
9023 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9024 FIB_TEST((FIB_NODE_INDEX_INVALID == fei),
9026 format_fib_prefix, &pfx_10_10_10_20_s_30);
9029 * inheriting source is modifed - expect the modification to be present
9030 * throughout the sub-tree
9032 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9035 tm->hw[0]->sw_if_index);
9036 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
9039 .adj = ai_10_10_10_2,
9043 fib_table_entry_update_one_path(0,
9044 &pfx_10_10_10_0_s_24,
9046 FIB_ENTRY_FLAG_COVERED_INHERIT,
9049 tm->hw[0]->sw_if_index,
9053 FIB_ROUTE_PATH_FLAG_NONE);
9054 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9055 FIB_TEST(fib_test_validate_entry(fei,
9056 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9059 "%U via 10.10.10.2",
9060 format_fib_prefix, &pfx_10_10_10_21_s_32);
9061 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9062 FIB_TEST(fib_test_validate_entry(fei,
9063 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9066 "%U via 10.10.10.2",
9067 format_fib_prefix, &pfx_10_10_10_22_s_32);
9068 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9069 FIB_TEST(fib_test_validate_entry(fei,
9070 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9073 "%U via 10.10.10.2",
9074 format_fib_prefix, &pfx_10_10_10_255_s_32);
9075 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9076 FIB_TEST(fib_test_validate_entry(fei,
9077 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9080 "%U via 10.10.10.2",
9081 format_fib_prefix, &pfx_10_10_10_0_s_24);
9084 * add the source that replaces inherited state.
9085 * inheriting source is not the best, so it doesn't push state.
9087 fib_table_entry_update_one_path(0,
9088 &pfx_10_10_10_0_s_24,
9089 FIB_SOURCE_PLUGIN_HI,
9090 FIB_ENTRY_FLAG_NONE,
9093 tm->hw[0]->sw_if_index,
9097 FIB_ROUTE_PATH_FLAG_NONE);
9098 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9099 FIB_TEST(fib_test_validate_entry(fei,
9100 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9103 "%U via 10.10.10.1",
9104 format_fib_prefix, &pfx_10_10_10_0_s_24);
9106 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9107 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9108 "%U resolves via drop",
9109 format_fib_prefix, &pfx_10_10_10_21_s_32);
9110 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9111 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9112 "%U resolves via drop",
9113 format_fib_prefix, &pfx_10_10_10_22_s_32);
9114 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9115 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9116 "%U resolves via drop",
9117 format_fib_prefix, &pfx_10_10_10_255_s_32);
9118 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9119 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9120 "%U resolves via drop",
9121 format_fib_prefix, &pfx_10_10_10_16_s_28);
9124 * withdraw the higher priority source and expect the inherited to return
9125 * throughout the sub-tree
9127 fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_PLUGIN_HI);
9129 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9130 FIB_TEST(fib_test_validate_entry(fei,
9131 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9134 "%U via 10.10.10.2",
9135 format_fib_prefix, &pfx_10_10_10_21_s_32);
9136 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9137 FIB_TEST(fib_test_validate_entry(fei,
9138 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9141 "%U via 10.10.10.2",
9142 format_fib_prefix, &pfx_10_10_10_22_s_32);
9143 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9144 FIB_TEST(fib_test_validate_entry(fei,
9145 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9148 "%U via 10.10.10.2",
9149 format_fib_prefix, &pfx_10_10_10_255_s_32);
9150 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9151 FIB_TEST(fib_test_validate_entry(fei,
9152 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9155 "%U via 10.10.10.2",
9156 format_fib_prefix, &pfx_10_10_10_0_s_24);
9157 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9158 FIB_TEST(fib_test_validate_entry(fei,
9159 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9162 "%U via 10.10.10.2",
9163 format_fib_prefix, &pfx_10_10_10_16_s_28);
9166 * source a covered entry in the sub-tree with the same inherting source
9167 * - expect that it now owns the sub-tree and thus over-rides its cover
9169 fib_table_entry_update_one_path(0,
9170 &pfx_10_10_10_16_s_28,
9172 FIB_ENTRY_FLAG_COVERED_INHERIT,
9175 tm->hw[0]->sw_if_index,
9179 FIB_ROUTE_PATH_FLAG_NONE);
9180 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9181 FIB_TEST(fib_test_validate_entry(fei,
9182 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9185 "%U via 10.10.10.1",
9186 format_fib_prefix, &pfx_10_10_10_16_s_28);
9187 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9188 FIB_TEST(fib_test_validate_entry(fei,
9189 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9192 "%U via 10.10.10.2",
9193 format_fib_prefix, &pfx_10_10_10_22_s_32);
9194 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9195 FIB_TEST(fib_test_validate_entry(fei,
9196 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9199 "%U via 10.10.10.2",
9200 format_fib_prefix, &pfx_10_10_10_21_s_32);
9202 /* these two unaffected by the sub-tree change */
9203 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9204 FIB_TEST(fib_test_validate_entry(fei,
9205 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9208 "%U via 10.10.10.2",
9209 format_fib_prefix, &pfx_10_10_10_255_s_32);
9210 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9211 FIB_TEST(fib_test_validate_entry(fei,
9212 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9215 "%U via 10.10.10.2",
9216 format_fib_prefix, &pfx_10_10_10_0_s_24);
9219 * removes the more specific, expect the /24 to now re-owns the sub-tree
9221 fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
9223 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9224 FIB_TEST(fib_test_validate_entry(fei,
9225 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9228 "%U via 10.10.10.2",
9229 format_fib_prefix, &pfx_10_10_10_16_s_28);
9230 FIB_TEST(fib_test_validate_entry(fei,
9231 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9234 "%U via 10.10.10.2",
9235 format_fib_prefix, &pfx_10_10_10_21_s_32);
9236 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9237 FIB_TEST(fib_test_validate_entry(fei,
9238 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9241 "%U via 10.10.10.2",
9242 format_fib_prefix, &pfx_10_10_10_22_s_32);
9243 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9244 FIB_TEST(fib_test_validate_entry(fei,
9245 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9248 "%U via 10.10.10.2",
9249 format_fib_prefix, &pfx_10_10_10_255_s_32);
9250 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9251 FIB_TEST(fib_test_validate_entry(fei,
9252 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9255 "%U via 10.10.10.2",
9256 format_fib_prefix, &pfx_10_10_10_0_s_24);
9258 * modify the /24. expect the new forwarding to be pushed down
9260 fib_table_entry_update_one_path(0,
9261 &pfx_10_10_10_0_s_24,
9263 FIB_ENTRY_FLAG_COVERED_INHERIT,
9266 tm->hw[0]->sw_if_index,
9270 FIB_ROUTE_PATH_FLAG_NONE);
9271 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9272 FIB_TEST(fib_test_validate_entry(fei,
9273 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9276 "%U via 10.10.10.1",
9277 format_fib_prefix, &pfx_10_10_10_16_s_28);
9278 FIB_TEST(fib_test_validate_entry(fei,
9279 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9282 "%U via 10.10.10.1",
9283 format_fib_prefix, &pfx_10_10_10_21_s_32);
9284 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9285 FIB_TEST(fib_test_validate_entry(fei,
9286 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9289 "%U via 10.10.10.1",
9290 format_fib_prefix, &pfx_10_10_10_22_s_32);
9291 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9292 FIB_TEST(fib_test_validate_entry(fei,
9293 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9296 "%U via 10.10.10.1",
9297 format_fib_prefix, &pfx_10_10_10_255_s_32);
9298 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9299 FIB_TEST(fib_test_validate_entry(fei,
9300 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9303 "%U via 10.10.10.1",
9304 format_fib_prefix, &pfx_10_10_10_0_s_24);
9307 * add an entry less specific to /24. it should not own the /24's tree
9309 const fib_prefix_t pfx_10_10_0_0_s_16 = {
9311 .fp_proto = FIB_PROTOCOL_IP4,
9312 .fp_addr = nh_10_10_0_0,
9314 fib_table_entry_update_one_path(0,
9315 &pfx_10_10_0_0_s_16,
9317 FIB_ENTRY_FLAG_COVERED_INHERIT,
9320 tm->hw[0]->sw_if_index,
9324 FIB_ROUTE_PATH_FLAG_NONE);
9325 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9326 FIB_TEST(fib_test_validate_entry(fei,
9327 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9330 "%U via 10.10.10.1",
9331 format_fib_prefix, &pfx_10_10_10_16_s_28);
9332 FIB_TEST(fib_test_validate_entry(fei,
9333 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9336 "%U via 10.10.10.1",
9337 format_fib_prefix, &pfx_10_10_10_21_s_32);
9338 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9339 FIB_TEST(fib_test_validate_entry(fei,
9340 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9343 "%U via 10.10.10.1",
9344 format_fib_prefix, &pfx_10_10_10_22_s_32);
9345 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9346 FIB_TEST(fib_test_validate_entry(fei,
9347 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9350 "%U via 10.10.10.1",
9351 format_fib_prefix, &pfx_10_10_10_255_s_32);
9352 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9353 FIB_TEST(fib_test_validate_entry(fei,
9354 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9357 "%U via 10.10.10.1",
9358 format_fib_prefix, &pfx_10_10_10_0_s_24);
9359 fei = fib_table_lookup_exact_match(0, &pfx_10_10_0_0_s_16);
9360 FIB_TEST(fib_test_validate_entry(fei,
9361 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9364 "%U via 10.10.10.2",
9365 format_fib_prefix, &pfx_10_10_0_0_s_16);
9370 fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_CLI);
9371 fib_table_entry_delete(0, &pfx_10_10_10_22_s_32, FIB_SOURCE_CLI);
9372 fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_CLI);
9373 fib_table_entry_delete(0, &pfx_10_10_10_255_s_32, FIB_SOURCE_CLI);
9374 fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_API);
9375 fib_table_entry_delete(0, &pfx_10_10_0_0_s_16, FIB_SOURCE_API);
9376 adj_unlock(ai_10_10_10_1);
9377 adj_unlock(ai_10_10_10_2);
9380 * test the v6 tree walk.
9381 * a /64 that covers everytinhg. a /96 that covers one /128
9382 * a second /128 covered only by the /64.
9384 const fib_prefix_t pfx_2001_s_64 = {
9386 .fp_proto = FIB_PROTOCOL_IP6,
9390 [0] = clib_host_to_net_u64(0x2001000000000000),
9391 [1] = clib_host_to_net_u64(0x0000000000000000),
9396 const fib_prefix_t pfx_2001_1_s_96 = {
9398 .fp_proto = FIB_PROTOCOL_IP6,
9402 [0] = clib_host_to_net_u64(0x2001000000000000),
9403 [1] = clib_host_to_net_u64(0x1000000000000000),
9408 const fib_prefix_t pfx_2001_1_1_s_128 = {
9410 .fp_proto = FIB_PROTOCOL_IP6,
9414 [0] = clib_host_to_net_u64(0x2001000000000000),
9415 [1] = clib_host_to_net_u64(0x1000000000000001),
9420 const fib_prefix_t pfx_2001_0_1_s_128 = {
9422 .fp_proto = FIB_PROTOCOL_IP6,
9426 [0] = clib_host_to_net_u64(0x2001000000000000),
9427 [1] = clib_host_to_net_u64(0x0000000000000001),
9432 const ip46_address_t nh_3000_1 = {
9435 [0] = clib_host_to_net_u64(0x3000000000000000),
9436 [1] = clib_host_to_net_u64(0x0000000000000001),
9440 const ip46_address_t nh_3000_2 = {
9443 [0] = clib_host_to_net_u64(0x3000000000000000),
9444 [1] = clib_host_to_net_u64(0x0000000000000002),
9448 adj_index_t ai_3000_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
9451 tm->hw[0]->sw_if_index);
9452 adj_index_t ai_3000_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
9455 tm->hw[0]->sw_if_index);
9456 fib_test_lb_bucket_t adj_o_3000_1 = {
9462 fib_test_lb_bucket_t adj_o_3000_2 = {
9469 fib_table_entry_special_add(0,
9470 &pfx_2001_0_1_s_128,
9472 FIB_ENTRY_FLAG_DROP);
9473 fib_table_entry_special_add(0,
9474 &pfx_2001_1_1_s_128,
9476 FIB_ENTRY_FLAG_DROP);
9479 * /96 has inherited forwarding pushed down to its covered /128
9481 fib_table_entry_update_one_path(0,
9484 FIB_ENTRY_FLAG_COVERED_INHERIT,
9487 tm->hw[0]->sw_if_index,
9491 FIB_ROUTE_PATH_FLAG_NONE);
9492 fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
9493 FIB_TEST(fib_test_validate_entry(fei,
9494 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
9498 format_fib_prefix, &pfx_2001_1_s_96);
9499 fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
9500 FIB_TEST(fib_test_validate_entry(fei,
9501 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
9505 format_fib_prefix, &pfx_2001_1_1_s_128);
9506 fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
9507 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9508 "%U resolves via drop",
9509 format_fib_prefix, &pfx_2001_0_1_s_128);
9512 * /64 has inherited forwarding pushed down to all, but the /96
9513 * and its sub-tree remain unaffected.
9515 fib_table_entry_update_one_path(0,
9518 FIB_ENTRY_FLAG_COVERED_INHERIT,
9521 tm->hw[0]->sw_if_index,
9525 FIB_ROUTE_PATH_FLAG_NONE);
9527 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
9528 FIB_TEST(fib_test_validate_entry(fei,
9529 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
9533 format_fib_prefix, &pfx_2001_s_64);
9534 fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
9535 FIB_TEST(fib_test_validate_entry(fei,
9536 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
9540 format_fib_prefix, &pfx_2001_0_1_s_128);
9542 fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
9543 FIB_TEST(fib_test_validate_entry(fei,
9544 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
9548 format_fib_prefix, &pfx_2001_1_s_96);
9549 fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
9550 FIB_TEST(fib_test_validate_entry(fei,
9551 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
9555 format_fib_prefix, &pfx_2001_1_1_s_128);
9560 fib_table_entry_delete(0, &pfx_2001_0_1_s_128, FIB_SOURCE_CLI);
9561 fib_table_entry_delete(0, &pfx_2001_1_1_s_128, FIB_SOURCE_CLI);
9562 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
9563 fib_table_entry_delete(0, &pfx_2001_1_s_96, FIB_SOURCE_API);
9564 adj_unlock(ai_3000_1);
9565 adj_unlock(ai_3000_2);
9568 * test no-one left behind
9570 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
9571 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
9575 static clib_error_t *
9576 fib_test (vlib_main_t * vm,
9577 unformat_input_t * input,
9578 vlib_cli_command_t * cmd_arg)
9583 fib_test_mk_intf(4);
9585 if (unformat (input, "debug"))
9587 fib_test_do_debug = 1;
9590 if (unformat (input, "ip"))
9592 res += fib_test_v4();
9593 res += fib_test_v6();
9595 else if (unformat (input, "label"))
9597 res += fib_test_label();
9599 else if (unformat (input, "ae"))
9601 res += fib_test_ae();
9603 else if (unformat (input, "pref"))
9605 res += fib_test_pref();
9607 else if (unformat (input, "lfib"))
9611 else if (unformat (input, "walk"))
9613 res += fib_test_walk();
9615 else if (unformat (input, "bfd"))
9617 res += fib_test_bfd();
9619 else if (unformat (input, "inherit"))
9621 res += fib_test_inherit();
9625 res += fib_test_v4();
9626 res += fib_test_v6();
9627 res += fib_test_ae();
9628 res += fib_test_bfd();
9629 res += fib_test_pref();
9630 res += fib_test_label();
9631 res += fib_test_inherit();
9635 * fib-walk process must be disabled in order for the walk tests to work
9637 fib_walk_process_disable();
9638 res += fib_test_walk();
9639 fib_walk_process_enable();
9644 return clib_error_return(0, "FIB Unit Test Failed");
9652 VLIB_CLI_COMMAND (test_fib_command, static) = {
9654 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
9655 .function = fib_test,
9659 fib_test_init (vlib_main_t *vm)
9664 VLIB_INIT_FUNCTION (fib_test_init);