2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/fib/fib_test.h>
17 #include <vnet/fib/ip6_fib.h>
18 #include <vnet/fib/ip4_fib.h>
19 #include <vnet/fib/mpls_fib.h>
20 #include <vnet/adj/adj.h>
21 #include <vnet/dpo/load_balance.h>
22 #include <vnet/dpo/load_balance_map.h>
23 #include <vnet/dpo/mpls_label_dpo.h>
24 #include <vnet/dpo/lookup_dpo.h>
25 #include <vnet/dpo/drop_dpo.h>
26 #include <vnet/dpo/receive_dpo.h>
27 #include <vnet/dpo/ip_null_dpo.h>
28 #include <vnet/bfd/bfd_main.h>
29 #include <vnet/dpo/interface_rx_dpo.h>
30 #include <vnet/dpo/replicate_dpo.h>
31 #include <vnet/dpo/l2_bridge_dpo.h>
33 #include <vnet/mpls/mpls.h>
35 #include <vnet/fib/fib_test.h>
36 #include <vnet/fib/fib_path_list.h>
37 #include <vnet/fib/fib_entry_src.h>
38 #include <vnet/fib/fib_walk.h>
39 #include <vnet/fib/fib_node_list.h>
40 #include <vnet/fib/fib_urpf_list.h>
43 * Add debugs for passing tests
45 static int fib_test_do_debug;
47 #define FIB_TEST_I(_cond, _comment, _args...) \
49 int _evald = (_cond); \
51 fformat(stderr, "FAIL:%d: " _comment "\n", \
54 if (fib_test_do_debug) \
55 fformat(stderr, "PASS:%d: " _comment "\n", \
60 #define FIB_TEST(_cond, _comment, _args...) \
62 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
64 ASSERT(!("FAIL: " _comment)); \
69 * A 'i'm not fussed is this is not efficient' store of test data
71 typedef struct test_main_t_ {
75 u32 hw_if_indicies[4];
79 vnet_hw_interface_t * hw[4];
82 static test_main_t test_main;
84 /* fake ethernet device class, distinct from "fake-ethX" */
85 static u8 * format_test_interface_name (u8 * s, va_list * args)
87 u32 dev_instance = va_arg (*args, u32);
88 return format (s, "test-eth%d", dev_instance);
91 static uword dummy_interface_tx (vlib_main_t * vm,
92 vlib_node_runtime_t * node,
95 clib_warning ("you shouldn't be here, leaking buffers...");
96 return frame->n_vectors;
100 test_interface_admin_up_down (vnet_main_t * vnm,
104 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
105 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
106 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
110 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
111 .name = "Test interface",
112 .format_device_name = format_test_interface_name,
113 .tx_function = dummy_interface_tx,
114 .admin_up_down_function = test_interface_admin_up_down,
117 static u8 *hw_address;
120 fib_test_mk_intf (u32 ninterfaces)
122 clib_error_t * error = NULL;
123 test_main_t *tm = &test_main;
127 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
132 vec_add1(hw_address, byte);
135 for (i = 0; i < ninterfaces; i++)
139 error = ethernet_register_interface(vnet_get_main(),
140 test_interface_device_class.index,
143 &tm->hw_if_indicies[i],
144 /* flag change */ 0);
146 FIB_TEST((NULL == error), "ADD interface %d", i);
148 error = vnet_hw_interface_set_flags(vnet_get_main(),
149 tm->hw_if_indicies[i],
150 VNET_HW_INTERFACE_FLAG_LINK_UP);
151 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
152 tm->hw_if_indicies[i]);
153 vec_validate (ip4_main.fib_index_by_sw_if_index,
154 tm->hw[i]->sw_if_index);
155 vec_validate (ip6_main.fib_index_by_sw_if_index,
156 tm->hw[i]->sw_if_index);
157 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
158 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
160 error = vnet_sw_interface_set_flags(vnet_get_main(),
161 tm->hw[i]->sw_if_index,
162 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
163 FIB_TEST((NULL == error), "UP interface %d", i);
166 * re-eval after the inevitable realloc
168 for (i = 0; i < ninterfaces; i++)
170 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
171 tm->hw_if_indicies[i]);
177 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
179 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
180 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
181 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
182 fib_table_lookup(fib_index, (_via_prefix))); \
183 FIB_TEST(!dpo_cmp(_via_dpo, \
184 load_balance_get_bucket(_rec_dpo->dpoi_index, \
186 "%U is recursive via %U", \
187 format_fib_prefix, (_rec_prefix), \
188 format_fib_prefix, _via_prefix); \
191 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
193 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
194 fib_table_lookup_exact_match(fib_index, (_prefix))); \
195 const dpo_id_t *_dpo1 = \
196 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
197 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
198 format_dpo_type, _dpo1->dpoi_type); \
199 FIB_TEST((_ai == _dpo1->dpoi_index), \
200 "%U bucket %d resolves via %U", \
201 format_fib_prefix, (_prefix), \
203 format_dpo_id, _dpo1, 0); \
206 #define FIB_TEST_RPF(_cond, _comment, _args...) \
208 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
214 fib_test_urpf_is_equal (fib_node_index_t fei,
215 fib_forward_chain_type_t fct,
218 dpo_id_t dpo = DPO_INVALID;
219 fib_urpf_list_t *urpf;
226 fib_entry_contribute_forwarding(fei, fct, &dpo);
227 ui = load_balance_get_urpf(dpo.dpoi_index);
229 urpf = fib_urpf_list_get(ui);
231 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
232 "RPF:%U len %d == %d",
233 format_fib_urpf_list, ui,
234 num, vec_len(urpf->furpf_itfs));
235 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
236 "RPF:%U check-size %d == %d",
237 format_fib_urpf_list, ui,
238 num, vec_len(urpf->furpf_itfs));
240 for (ii = 0; ii < num; ii++)
242 adj_index_t ai = va_arg(ap, adj_index_t);
244 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
245 "RPF:%d item:%d - %d == %d",
246 ui, ii, ai, urpf->furpf_itfs[ii]);
247 FIB_TEST_RPF(fib_urpf_check(ui, ai),
260 fib_test_build_rewrite (u8 *eth_addr)
264 vec_validate(rewrite, 13);
266 memcpy(rewrite, eth_addr, 6);
267 memcpy(rewrite+6, eth_addr, 6);
272 #define FIB_TEST_LB(_cond, _comment, _args...) \
274 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
280 fib_test_validate_rep_v (const replicate_t *rep,
284 const fib_test_rep_bucket_t *exp;
288 FIB_TEST_LB((n_buckets == rep->rep_n_buckets),
289 "n_buckets = %d", rep->rep_n_buckets);
291 for (bucket = 0; bucket < n_buckets; bucket++)
293 exp = va_arg(*ap, fib_test_rep_bucket_t*);
295 dpo = replicate_get_bucket_i(rep, bucket);
299 case FT_REP_LABEL_O_ADJ:
301 const mpls_label_dpo_t *mld;
303 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
304 "bucket %d stacks on %U",
306 format_dpo_type, dpo->dpoi_type);
308 mld = mpls_label_dpo_get(dpo->dpoi_index);
309 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
311 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
312 exp->label_o_adj.label),
313 "bucket %d stacks on label %d",
315 exp->label_o_adj.label);
317 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
318 exp->label_o_adj.eos),
319 "bucket %d stacks on label %d %U",
321 exp->label_o_adj.label,
322 format_mpls_eos_bit, exp->label_o_adj.eos);
324 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
325 "bucket %d label stacks on %U",
327 format_dpo_type, mld->mld_dpo.dpoi_type);
329 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
330 "bucket %d label stacks on adj %d",
332 exp->label_o_adj.adj);
336 FIB_TEST_LB((DPO_INTERFACE_RX == dpo->dpoi_type),
337 "bucket %d stacks on %U",
339 format_dpo_type, dpo->dpoi_type);
341 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
342 "bucket %d stacks on adj %d",
346 case FT_REP_DISP_MFIB_LOOKUP:
356 fib_test_validate_lb_v (const load_balance_t *lb,
363 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
365 for (bucket = 0; bucket < n_buckets; bucket++)
367 const fib_test_lb_bucket_t *exp;
369 exp = va_arg(*ap, fib_test_lb_bucket_t*);
370 dpo = load_balance_get_bucket_i(lb, bucket);
374 case FT_LB_LABEL_STACK_O_ADJ:
376 const mpls_label_dpo_t *mld;
380 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
381 "bucket %d stacks on %U",
383 format_dpo_type, dpo->dpoi_type);
385 mld = mpls_label_dpo_get(dpo->dpoi_index);
387 FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
391 for (ii = 0; ii < mld->mld_n_labels; ii++)
393 hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
394 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
395 exp->label_stack_o_adj.label_stack[ii]),
396 "bucket %d stacks on label %d",
398 exp->label_stack_o_adj.label_stack[ii]);
400 if (ii == mld->mld_n_labels-1)
402 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
403 exp->label_o_adj.eos),
404 "bucket %d stacks on label %d %U!=%U",
406 exp->label_stack_o_adj.label_stack[ii],
407 format_mpls_eos_bit, exp->label_o_adj.eos,
408 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
412 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
413 "bucket %d stacks on label %d %U",
415 exp->label_stack_o_adj.label_stack[ii],
416 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
420 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
421 "bucket %d label stacks on %U",
423 format_dpo_type, mld->mld_dpo.dpoi_type);
425 FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
426 "bucket %d label stacks on adj %d",
428 exp->label_stack_o_adj.adj);
431 case FT_LB_LABEL_O_ADJ:
433 const mpls_label_dpo_t *mld;
435 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
436 "bucket %d stacks on %U",
438 format_dpo_type, dpo->dpoi_type);
440 mld = mpls_label_dpo_get(dpo->dpoi_index);
441 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
443 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
444 exp->label_o_adj.label),
445 "bucket %d stacks on label %d",
447 exp->label_o_adj.label);
449 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
450 exp->label_o_adj.eos),
451 "bucket %d stacks on label %d %U",
453 exp->label_o_adj.label,
454 format_mpls_eos_bit, exp->label_o_adj.eos);
456 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
457 "bucket %d label stacks on %U",
459 format_dpo_type, mld->mld_dpo.dpoi_type);
461 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
462 "bucket %d label stacks on adj %d",
464 exp->label_o_adj.adj);
467 case FT_LB_LABEL_O_LB:
469 const mpls_label_dpo_t *mld;
472 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
473 "bucket %d stacks on %U",
475 format_dpo_type, dpo->dpoi_type);
477 mld = mpls_label_dpo_get(dpo->dpoi_index);
478 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
480 FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
482 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
483 exp->label_o_lb.label),
484 "bucket %d stacks on label %d",
486 exp->label_o_lb.label);
488 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
489 exp->label_o_lb.eos),
490 "bucket %d stacks on label %d %U",
492 exp->label_o_lb.label,
493 format_mpls_eos_bit, exp->label_o_lb.eos);
495 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
496 "bucket %d label stacks on %U",
498 format_dpo_type, mld->mld_dpo.dpoi_type);
500 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
501 "bucket %d label stacks on LB %d",
507 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
508 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
509 "bucket %d stacks on %U",
511 format_dpo_type, dpo->dpoi_type);
512 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
513 "bucket %d stacks on adj %d",
518 FIB_TEST_I((DPO_INTERFACE_RX == dpo->dpoi_type),
519 "bucket %d stacks on %U",
521 format_dpo_type, dpo->dpoi_type);
522 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
523 "bucket %d stacks on adj %d",
528 FIB_TEST_I((DPO_L2_BRIDGE == dpo->dpoi_type),
529 "bucket %d stacks on %U",
531 format_dpo_type, dpo->dpoi_type);
532 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
533 "bucket %d stacks on adj %d",
538 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
539 "bucket %d stacks on %U",
541 format_dpo_type, dpo->dpoi_type);
542 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
543 "bucket %d stacks on lb %d not %d",
548 case FT_LB_BIER_TABLE:
549 FIB_TEST_LB((DPO_BIER_TABLE == dpo->dpoi_type),
550 "bucket %d stacks on %U",
552 format_dpo_type, dpo->dpoi_type);
553 FIB_TEST_LB((exp->bier.table == dpo->dpoi_index),
554 "bucket %d stacks on lb %d",
558 case FT_LB_BIER_FMASK:
559 FIB_TEST_LB((DPO_BIER_FMASK == dpo->dpoi_type),
560 "bucket %d stacks on %U",
562 format_dpo_type, dpo->dpoi_type);
563 FIB_TEST_LB((exp->bier.fmask == dpo->dpoi_index),
564 "bucket %d stacks on lb %d",
569 FIB_TEST_LB((DPO_DROP == dpo->dpoi_type),
570 "bucket %d stacks on %U",
572 format_dpo_type, dpo->dpoi_type);
580 fib_test_validate_lb (const dpo_id_t *dpo,
584 const load_balance_t *lb;
588 va_start(ap, n_buckets);
590 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo->dpoi_type),
592 format_dpo_type, dpo->dpoi_type);
593 lb = load_balance_get(dpo->dpoi_index);
595 res = fib_test_validate_lb_v(lb, n_buckets, &ap);
603 fib_test_validate_entry (fib_node_index_t fei,
604 fib_forward_chain_type_t fct,
608 dpo_id_t dpo = DPO_INVALID;
615 va_start(ap, n_buckets);
617 fib_entry_get_prefix(fei, &pfx);
618 fib_index = fib_entry_get_fib_index(fei);
619 fib_entry_contribute_forwarding(fei, fct, &dpo);
621 if (DPO_REPLICATE == dpo.dpoi_type)
623 const replicate_t *rep;
625 rep = replicate_get(dpo.dpoi_index);
626 res = fib_test_validate_rep_v(rep, n_buckets, &ap);
630 const load_balance_t *lb;
632 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
634 format_dpo_type, dpo.dpoi_type);
636 lb = load_balance_get(dpo.dpoi_index);
637 res = fib_test_validate_lb_v(lb, n_buckets, &ap);
640 * ensure that the LB contributed by the entry is the
641 * same as the LB in the forwarding tables
643 if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
645 switch (pfx.fp_proto)
647 case FIB_PROTOCOL_IP4:
648 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
650 case FIB_PROTOCOL_IP6:
651 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
653 case FIB_PROTOCOL_MPLS:
655 mpls_unicast_header_t hdr = {
656 .label_exp_s_ttl = 0,
659 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
660 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
661 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
663 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
669 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
670 "Contributed LB = FW LB: %U\n %U",
671 format_load_balance, fw_lbi, 0,
672 format_load_balance, dpo.dpoi_index, 0);
687 * In the default table check for the presence and correct forwarding
688 * of the special entries
690 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
691 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
692 const ip_adjacency_t *adj;
693 const load_balance_t *lb;
700 ip46_address_t nh_10_10_10_1 = {
701 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
704 ip46_address_t nh_10_10_10_2 = {
705 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
708 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
709 pool_elts(load_balance_map_pool));
713 /* record the nubmer of load-balances in use before we start */
714 lb_count = pool_elts(load_balance_pool);
716 /* Find or create FIB table 11 */
717 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11,
720 for (ii = 0; ii < 4; ii++)
722 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
725 fib_prefix_t pfx_0_0_0_0_s_0 = {
727 .fp_proto = FIB_PROTOCOL_IP4,
737 .fp_proto = FIB_PROTOCOL_IP4,
745 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
747 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
748 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
749 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
750 "Default route is DROP");
753 fei = fib_table_lookup(fib_index, &pfx);
754 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
755 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
756 "all 0s route is DROP");
758 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
760 fei = fib_table_lookup(fib_index, &pfx);
761 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
762 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
763 "all 1s route is DROP");
765 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
767 fei = fib_table_lookup(fib_index, &pfx);
768 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
769 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
770 "all-mcast route is DROP");
772 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
774 fei = fib_table_lookup(fib_index, &pfx);
775 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
776 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
777 "class-e route is DROP");
780 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
781 * all of which are special sourced and so none of which share path-lists.
782 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
783 * table, and 4 path-lists in the v6 MFIB table
787 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
788 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
789 fib_path_list_pool_size());
790 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
791 fib_entry_pool_size());
794 * add interface routes.
795 * validate presence of /24 attached and /32 recieve.
796 * test for the presence of the receive address in the glean and local adj
798 fib_prefix_t local_pfx = {
800 .fp_proto = FIB_PROTOCOL_IP4,
803 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
808 fib_table_entry_update_one_path(fib_index, &local_pfx,
809 FIB_SOURCE_INTERFACE,
810 (FIB_ENTRY_FLAG_CONNECTED |
811 FIB_ENTRY_FLAG_ATTACHED),
814 tm->hw[0]->sw_if_index,
815 ~0, // invalid fib index
818 FIB_ROUTE_PATH_FLAG_NONE);
819 fei = fib_table_lookup(fib_index, &local_pfx);
820 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
821 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
822 fib_entry_get_flags(fei)),
823 "Flags set on attached interface");
825 ai = fib_entry_get_adj(fei);
826 FIB_TEST((FIB_NODE_INDEX_INVALID != ai),
827 "attached interface route adj present %d", ai);
829 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
830 "attached interface adj is glean");
831 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
832 &adj->sub_type.glean.receive_addr)),
833 "attached interface adj is receive ok");
835 local_pfx.fp_len = 32;
836 fib_table_entry_update_one_path(fib_index, &local_pfx,
837 FIB_SOURCE_INTERFACE,
838 (FIB_ENTRY_FLAG_CONNECTED |
839 FIB_ENTRY_FLAG_LOCAL),
842 tm->hw[0]->sw_if_index,
843 ~0, // invalid fib index
846 FIB_ROUTE_PATH_FLAG_NONE);
847 fei = fib_table_lookup(fib_index, &local_pfx);
848 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
849 fib_entry_get_flags(fei)),
850 "Flags set on local interface");
852 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
854 dpo = fib_entry_contribute_ip_forwarding(fei);
855 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
856 "RPF list for local length 0");
857 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
858 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
859 "local interface adj is local");
860 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
862 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
864 "local interface adj is receive ok");
866 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
868 FIB_SOURCE_INTERFACE)),
869 "2 Interface Source'd prefixes");
872 * +2 interface routes +2 non-shared path-lists
874 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
875 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
876 fib_path_list_pool_size());
877 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
878 fib_entry_pool_size());
881 * Modify the default route to be via an adj not yet known.
882 * this sources the defalut route with the API source, which is
883 * a higher preference to the DEFAULT_ROUTE source
885 pfx.fp_addr.ip4.as_u32 = 0;
887 fib_table_entry_path_add(fib_index, &pfx,
892 tm->hw[0]->sw_if_index,
893 ~0, // invalid fib index
896 FIB_ROUTE_PATH_FLAG_NONE);
897 fei = fib_table_lookup(fib_index, &pfx);
898 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
899 "Flags set on API route");
901 FIB_TEST((fei == dfrt), "default route same index");
902 ai = fib_entry_get_adj(fei);
903 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
905 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
906 "adj is incomplete");
907 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
908 "adj nbr next-hop ok");
909 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
912 "1 API Source'd prefixes");
915 * find the adj in the shared db
917 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
920 tm->hw[0]->sw_if_index);
921 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
922 adj_unlock(locked_ai);
925 * +1 shared path-list
927 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
928 fib_path_list_db_size());
929 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
930 fib_path_list_pool_size());
931 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
932 fib_entry_pool_size());
935 * remove the API source from the default route. We expected
936 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
938 pfx.fp_addr.ip4.as_u32 = 0;
940 fib_table_entry_path_remove(fib_index, &pfx,
944 tm->hw[0]->sw_if_index,
945 ~0, // non-recursive path, so no FIB index
947 FIB_ROUTE_PATH_FLAG_NONE);
949 fei = fib_table_lookup(fib_index, &pfx);
951 FIB_TEST((fei == dfrt), "default route same index");
952 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
953 "Default route is DROP");
956 * -1 shared-path-list
958 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
959 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
960 fib_path_list_pool_size());
961 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
962 fib_entry_pool_size());
965 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
967 fib_prefix_t pfx_10_10_10_1_s_32 = {
969 .fp_proto = FIB_PROTOCOL_IP4,
972 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
975 fib_prefix_t pfx_10_10_10_2_s_32 = {
977 .fp_proto = FIB_PROTOCOL_IP4,
980 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
983 fib_prefix_t pfx_11_11_11_11_s_32 = {
985 .fp_proto = FIB_PROTOCOL_IP4,
988 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
992 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
995 ip46_address_t nh_12_12_12_12 = {
996 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
998 adj_index_t ai_12_12_12_12;
1001 * Add a route via an incomplete ADJ. then complete the ADJ
1002 * Expect the route LB is updated to use complete adj type.
1004 fei = fib_table_entry_update_one_path(fib_index,
1005 &pfx_11_11_11_11_s_32,
1007 FIB_ENTRY_FLAG_ATTACHED,
1009 &pfx_10_10_10_1_s_32.fp_addr,
1010 tm->hw[0]->sw_if_index,
1011 ~0, // invalid fib index
1014 FIB_ROUTE_PATH_FLAG_NONE);
1016 dpo = fib_entry_contribute_ip_forwarding(fei);
1017 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1018 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1019 "11.11.11.11/32 via incomplete adj");
1021 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1023 &pfx_10_10_10_1_s_32.fp_addr,
1024 tm->hw[0]->sw_if_index);
1025 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1026 adj = adj_get(ai_01);
1027 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1028 "adj is incomplete");
1029 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1030 &adj->sub_type.nbr.next_hop)),
1031 "adj nbr next-hop ok");
1033 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1034 fib_test_build_rewrite(eth_addr));
1035 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1037 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1038 &adj->sub_type.nbr.next_hop)),
1039 "adj nbr next-hop ok");
1040 ai = fib_entry_get_adj(fei);
1041 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1043 dpo = fib_entry_contribute_ip_forwarding(fei);
1044 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1045 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1046 "11.11.11.11/32 via complete adj");
1047 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1048 tm->hw[0]->sw_if_index),
1049 "RPF list for adj-fib contains adj");
1051 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1054 tm->hw[1]->sw_if_index);
1055 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1056 adj = adj_get(ai_12_12_12_12);
1057 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1058 "adj is incomplete");
1059 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1060 &adj->sub_type.nbr.next_hop)),
1061 "adj nbr next-hop ok");
1062 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1063 fib_test_build_rewrite(eth_addr));
1064 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1070 fei = fib_table_entry_path_add(fib_index,
1071 &pfx_10_10_10_1_s_32,
1073 FIB_ENTRY_FLAG_ATTACHED,
1075 &pfx_10_10_10_1_s_32.fp_addr,
1076 tm->hw[0]->sw_if_index,
1077 ~0, // invalid fib index
1080 FIB_ROUTE_PATH_FLAG_NONE);
1081 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1082 "Flags set on adj-fib");
1083 ai = fib_entry_get_adj(fei);
1084 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
1086 fib_table_entry_path_remove(fib_index,
1087 &pfx_11_11_11_11_s_32,
1090 &pfx_10_10_10_1_s_32.fp_addr,
1091 tm->hw[0]->sw_if_index,
1092 ~0, // invalid fib index
1094 FIB_ROUTE_PATH_FLAG_NONE);
1098 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1100 &pfx_10_10_10_2_s_32.fp_addr,
1101 tm->hw[0]->sw_if_index);
1102 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1103 adj = adj_get(ai_02);
1104 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1105 "adj is incomplete");
1106 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1107 &adj->sub_type.nbr.next_hop)),
1108 "adj nbr next-hop ok");
1110 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1111 fib_test_build_rewrite(eth_addr));
1112 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1114 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1115 &adj->sub_type.nbr.next_hop)),
1116 "adj nbr next-hop ok");
1117 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1119 fib_table_entry_path_add(fib_index,
1120 &pfx_10_10_10_2_s_32,
1122 FIB_ENTRY_FLAG_ATTACHED,
1124 &pfx_10_10_10_2_s_32.fp_addr,
1125 tm->hw[0]->sw_if_index,
1126 ~0, // invalid fib index
1129 FIB_ROUTE_PATH_FLAG_NONE);
1131 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1132 ai = fib_entry_get_adj(fei);
1133 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1136 * +2 adj-fibs, and their non-shared path-lists
1138 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1139 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1140 fib_path_list_pool_size());
1141 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1142 fib_entry_pool_size());
1145 * Add 2 routes via the first ADJ. ensure path-list sharing
1147 fib_prefix_t pfx_1_1_1_1_s_32 = {
1149 .fp_proto = FIB_PROTOCOL_IP4,
1152 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1156 fib_table_entry_path_add(fib_index,
1159 FIB_ENTRY_FLAG_NONE,
1162 tm->hw[0]->sw_if_index,
1163 ~0, // invalid fib index
1166 FIB_ROUTE_PATH_FLAG_NONE);
1167 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1168 ai = fib_entry_get_adj(fei);
1169 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1172 * +1 entry and a shared path-list
1174 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1175 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1176 fib_path_list_pool_size());
1177 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1178 fib_entry_pool_size());
1181 fib_prefix_t pfx_1_1_2_0_s_24 = {
1183 .fp_proto = FIB_PROTOCOL_IP4,
1185 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1189 fib_table_entry_path_add(fib_index,
1192 FIB_ENTRY_FLAG_NONE,
1195 tm->hw[0]->sw_if_index,
1196 ~0, // invalid fib index
1199 FIB_ROUTE_PATH_FLAG_NONE);
1200 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1201 ai = fib_entry_get_adj(fei);
1202 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1207 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1208 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1209 fib_path_list_pool_size());
1210 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1211 fib_entry_pool_size());
1214 * modify 1.1.2.0/24 to use multipath.
1216 fib_table_entry_path_add(fib_index,
1219 FIB_ENTRY_FLAG_NONE,
1222 tm->hw[0]->sw_if_index,
1223 ~0, // invalid fib index
1226 FIB_ROUTE_PATH_FLAG_NONE);
1227 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1228 dpo = fib_entry_contribute_ip_forwarding(fei);
1229 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1230 1, tm->hw[0]->sw_if_index),
1231 "RPF list for 1.1.2.0/24 contains both adjs");
1233 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1234 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1235 FIB_TEST((ai_01 == dpo1->dpoi_index),
1236 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1237 ai_01, dpo1->dpoi_index);
1239 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1240 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1241 FIB_TEST((ai_02 == dpo1->dpoi_index),
1242 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1245 * +1 shared-pathlist
1247 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1248 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1249 fib_path_list_pool_size());
1250 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1251 fib_entry_pool_size());
1256 fib_table_entry_path_remove(fib_index,
1261 tm->hw[0]->sw_if_index,
1264 FIB_ROUTE_PATH_FLAG_NONE);
1265 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1266 dpo = fib_entry_contribute_ip_forwarding(fei);
1267 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1268 1, tm->hw[0]->sw_if_index),
1269 "RPF list for 1.1.2.0/24 contains one adj");
1271 ai = fib_entry_get_adj(fei);
1272 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1275 * +1 shared-pathlist
1277 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1278 fib_path_list_db_size());
1279 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1280 fib_path_list_pool_size());
1281 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1282 fib_entry_pool_size());
1285 * Add 2 recursive routes:
1286 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1287 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1289 fib_prefix_t bgp_100_pfx = {
1291 .fp_proto = FIB_PROTOCOL_IP4,
1293 /* 100.100.100.100/32 */
1294 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1298 ip46_address_t nh_1_1_1_1 = {
1299 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1302 fei = fib_table_entry_path_add(fib_index,
1305 FIB_ENTRY_FLAG_NONE,
1308 ~0, // no index provided.
1309 fib_index, // nexthop in same fib as route
1312 FIB_ROUTE_PATH_FLAG_NONE);
1314 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1315 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1316 tm->hw[0]->sw_if_index),
1317 "RPF list for adj-fib contains adj");
1320 * +1 entry and +1 shared-path-list
1322 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1323 fib_path_list_db_size());
1324 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1325 fib_path_list_pool_size());
1326 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1327 fib_entry_pool_size());
1329 fib_prefix_t bgp_101_pfx = {
1331 .fp_proto = FIB_PROTOCOL_IP4,
1333 /* 100.100.100.101/32 */
1334 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1338 fib_table_entry_path_add(fib_index,
1341 FIB_ENTRY_FLAG_NONE,
1344 ~0, // no index provided.
1345 fib_index, // nexthop in same fib as route
1348 FIB_ROUTE_PATH_FLAG_NONE);
1350 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1351 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1352 tm->hw[0]->sw_if_index),
1353 "RPF list for adj-fib contains adj");
1356 * +1 entry, but the recursive path-list is shared.
1358 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1359 fib_path_list_db_size());
1360 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1361 fib_path_list_pool_size());
1362 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1363 fib_entry_pool_size());
1366 * An special route; one where the user (me) provides the
1367 * adjacency through which the route will resovle by setting the flags
1369 fib_prefix_t ex_pfx = {
1371 .fp_proto = FIB_PROTOCOL_IP4,
1374 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1378 fib_table_entry_special_add(fib_index,
1381 FIB_ENTRY_FLAG_LOCAL);
1382 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1383 dpo = fib_entry_contribute_ip_forwarding(fei);
1384 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1385 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1386 "local interface adj is local");
1388 fib_table_entry_special_remove(fib_index,
1390 FIB_SOURCE_SPECIAL);
1391 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1392 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1393 "Exclusive reoute removed");
1396 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1397 * adjacency through which the route will resovle
1399 dpo_id_t ex_dpo = DPO_INVALID;
1401 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1404 LOOKUP_INPUT_DST_ADDR,
1405 LOOKUP_TABLE_FROM_CONFIG,
1408 fib_table_entry_special_dpo_add(fib_index,
1411 FIB_ENTRY_FLAG_EXCLUSIVE,
1413 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1414 dpo = fib_entry_contribute_ip_forwarding(fei);
1415 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1416 "exclusive remote uses lookup DPO");
1419 * update the exclusive to use a different DPO
1421 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1422 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1424 fib_table_entry_special_dpo_update(fib_index,
1427 FIB_ENTRY_FLAG_EXCLUSIVE,
1429 dpo = fib_entry_contribute_ip_forwarding(fei);
1430 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1431 "exclusive remote uses now uses NULL DPO");
1433 fib_table_entry_special_remove(fib_index,
1435 FIB_SOURCE_SPECIAL);
1436 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1437 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1438 "Exclusive reoute removed");
1442 * Add a recursive route:
1443 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1445 fib_prefix_t bgp_200_pfx = {
1447 .fp_proto = FIB_PROTOCOL_IP4,
1449 /* 200.200.200.200/32 */
1450 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1454 fib_prefix_t pfx_1_1_1_2_s_32 = {
1456 .fp_proto = FIB_PROTOCOL_IP4,
1458 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1462 fei = fib_table_entry_path_add(fib_index,
1465 FIB_ENTRY_FLAG_NONE,
1467 &pfx_1_1_1_2_s_32.fp_addr,
1468 ~0, // no index provided.
1469 fib_index, // nexthop in same fib as route
1472 FIB_ROUTE_PATH_FLAG_NONE);
1474 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1475 "Recursive via unresolved is drop");
1478 * the adj should be recursive via drop, since the route resolves via
1479 * the default route, which is itself a DROP
1481 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1482 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1483 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1484 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1485 "RPF list for 1.1.1.2/32 contains 0 adjs");
1488 * +2 entry and +1 shared-path-list
1490 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1491 fib_path_list_db_size());
1492 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1493 fib_path_list_pool_size());
1494 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1495 fib_entry_pool_size());
1498 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1499 * The paths are sort by NH first. in this case the the path with greater
1500 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1502 fib_prefix_t pfx_1_2_3_4_s_32 = {
1504 .fp_proto = FIB_PROTOCOL_IP4,
1506 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1509 fib_table_entry_path_add(fib_index,
1512 FIB_ENTRY_FLAG_NONE,
1515 tm->hw[0]->sw_if_index,
1519 FIB_ROUTE_PATH_FLAG_NONE);
1520 fei = fib_table_entry_path_add(fib_index,
1523 FIB_ENTRY_FLAG_NONE,
1526 tm->hw[1]->sw_if_index,
1530 FIB_ROUTE_PATH_FLAG_NONE);
1532 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1533 dpo = fib_entry_contribute_ip_forwarding(fei);
1534 lb = load_balance_get(dpo->dpoi_index);
1535 FIB_TEST((lb->lb_n_buckets == 4),
1536 "1.2.3.4/32 LB has %d bucket",
1539 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1540 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1541 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1542 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1544 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1545 tm->hw[0]->sw_if_index,
1546 tm->hw[1]->sw_if_index),
1547 "RPF list for 1.2.3.4/32 contains both adjs");
1551 * Unequal Cost load-balance. 4:1 ratio.
1552 * fits in a 16 bucket LB with ratio 13:3
1554 fib_prefix_t pfx_1_2_3_5_s_32 = {
1556 .fp_proto = FIB_PROTOCOL_IP4,
1558 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1561 fib_table_entry_path_add(fib_index,
1564 FIB_ENTRY_FLAG_NONE,
1567 tm->hw[1]->sw_if_index,
1571 FIB_ROUTE_PATH_FLAG_NONE);
1572 fei = fib_table_entry_path_add(fib_index,
1575 FIB_ENTRY_FLAG_NONE,
1578 tm->hw[0]->sw_if_index,
1582 FIB_ROUTE_PATH_FLAG_NONE);
1584 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1585 dpo = fib_entry_contribute_ip_forwarding(fei);
1586 lb = load_balance_get(dpo->dpoi_index);
1587 FIB_TEST((lb->lb_n_buckets == 16),
1588 "1.2.3.5/32 LB has %d bucket",
1591 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1592 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1593 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1594 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1595 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1596 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1597 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1598 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1599 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1600 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1601 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1602 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1603 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1604 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1605 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1606 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1608 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1609 tm->hw[0]->sw_if_index,
1610 tm->hw[1]->sw_if_index),
1611 "RPF list for 1.2.3.4/32 contains both adjs");
1614 * Test UCMP with a large weight skew - this produces load-balance objects with large
1615 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1616 * laso testing the LB in placce modify code when number of buckets is large.
1618 fib_prefix_t pfx_6_6_6_6_s_32 = {
1620 .fp_proto = FIB_PROTOCOL_IP4,
1623 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1626 fib_test_lb_bucket_t ip_o_10_10_10_1 = {
1632 fib_test_lb_bucket_t ip_o_10_10_10_2 = {
1638 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1641 .adj = ai_12_12_12_12,
1644 fib_table_entry_update_one_path(fib_index,
1647 FIB_ENTRY_FLAG_NONE,
1650 tm->hw[0]->sw_if_index,
1651 ~0, // invalid fib index
1654 FIB_ROUTE_PATH_FLAG_NONE);
1656 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1657 FIB_TEST(fib_test_validate_entry(fei,
1658 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1661 "6.6.6.6/32 via 10.10.10.1");
1663 fib_table_entry_path_add(fib_index,
1666 FIB_ENTRY_FLAG_NONE,
1669 tm->hw[0]->sw_if_index,
1670 ~0, // invalid fib index
1673 FIB_ROUTE_PATH_FLAG_NONE);
1675 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1676 FIB_TEST(fib_test_validate_entry(fei,
1677 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1743 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1745 fib_table_entry_path_add(fib_index,
1748 FIB_ENTRY_FLAG_NONE,
1751 tm->hw[1]->sw_if_index,
1752 ~0, // invalid fib index
1755 FIB_ROUTE_PATH_FLAG_NONE);
1757 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1758 FIB_TEST(fib_test_validate_entry(fei,
1759 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1826 &ip_6_6_6_6_o_12_12_12_12,
1827 &ip_6_6_6_6_o_12_12_12_12,
1828 &ip_6_6_6_6_o_12_12_12_12,
1829 &ip_6_6_6_6_o_12_12_12_12,
1830 &ip_6_6_6_6_o_12_12_12_12,
1831 &ip_6_6_6_6_o_12_12_12_12,
1832 &ip_6_6_6_6_o_12_12_12_12,
1833 &ip_6_6_6_6_o_12_12_12_12,
1834 &ip_6_6_6_6_o_12_12_12_12,
1835 &ip_6_6_6_6_o_12_12_12_12,
1836 &ip_6_6_6_6_o_12_12_12_12,
1837 &ip_6_6_6_6_o_12_12_12_12,
1838 &ip_6_6_6_6_o_12_12_12_12,
1839 &ip_6_6_6_6_o_12_12_12_12,
1840 &ip_6_6_6_6_o_12_12_12_12,
1841 &ip_6_6_6_6_o_12_12_12_12,
1842 &ip_6_6_6_6_o_12_12_12_12,
1843 &ip_6_6_6_6_o_12_12_12_12,
1844 &ip_6_6_6_6_o_12_12_12_12,
1845 &ip_6_6_6_6_o_12_12_12_12,
1846 &ip_6_6_6_6_o_12_12_12_12,
1847 &ip_6_6_6_6_o_12_12_12_12,
1848 &ip_6_6_6_6_o_12_12_12_12,
1849 &ip_6_6_6_6_o_12_12_12_12,
1850 &ip_6_6_6_6_o_12_12_12_12,
1851 &ip_6_6_6_6_o_12_12_12_12,
1852 &ip_6_6_6_6_o_12_12_12_12,
1853 &ip_6_6_6_6_o_12_12_12_12,
1854 &ip_6_6_6_6_o_12_12_12_12,
1855 &ip_6_6_6_6_o_12_12_12_12,
1856 &ip_6_6_6_6_o_12_12_12_12,
1857 &ip_6_6_6_6_o_12_12_12_12,
1858 &ip_6_6_6_6_o_12_12_12_12,
1859 &ip_6_6_6_6_o_12_12_12_12,
1860 &ip_6_6_6_6_o_12_12_12_12,
1861 &ip_6_6_6_6_o_12_12_12_12,
1862 &ip_6_6_6_6_o_12_12_12_12,
1863 &ip_6_6_6_6_o_12_12_12_12,
1864 &ip_6_6_6_6_o_12_12_12_12,
1865 &ip_6_6_6_6_o_12_12_12_12,
1866 &ip_6_6_6_6_o_12_12_12_12,
1867 &ip_6_6_6_6_o_12_12_12_12,
1868 &ip_6_6_6_6_o_12_12_12_12,
1869 &ip_6_6_6_6_o_12_12_12_12,
1870 &ip_6_6_6_6_o_12_12_12_12,
1871 &ip_6_6_6_6_o_12_12_12_12,
1872 &ip_6_6_6_6_o_12_12_12_12,
1873 &ip_6_6_6_6_o_12_12_12_12,
1874 &ip_6_6_6_6_o_12_12_12_12,
1875 &ip_6_6_6_6_o_12_12_12_12,
1876 &ip_6_6_6_6_o_12_12_12_12,
1877 &ip_6_6_6_6_o_12_12_12_12,
1878 &ip_6_6_6_6_o_12_12_12_12,
1879 &ip_6_6_6_6_o_12_12_12_12,
1880 &ip_6_6_6_6_o_12_12_12_12,
1881 &ip_6_6_6_6_o_12_12_12_12,
1882 &ip_6_6_6_6_o_12_12_12_12,
1883 &ip_6_6_6_6_o_12_12_12_12,
1884 &ip_6_6_6_6_o_12_12_12_12,
1885 &ip_6_6_6_6_o_12_12_12_12,
1886 &ip_6_6_6_6_o_12_12_12_12,
1887 &ip_6_6_6_6_o_12_12_12_12,
1888 &ip_6_6_6_6_o_12_12_12_12),
1889 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1891 fib_table_entry_path_remove(fib_index,
1896 tm->hw[1]->sw_if_index,
1897 ~0, // invalid fib index
1899 FIB_ROUTE_PATH_FLAG_NONE);
1901 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1902 FIB_TEST(fib_test_validate_entry(fei,
1903 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1969 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1971 fib_table_entry_path_remove(fib_index,
1976 tm->hw[0]->sw_if_index,
1977 ~0, // invalid fib index
1979 FIB_ROUTE_PATH_FLAG_NONE);
1981 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1982 FIB_TEST(fib_test_validate_entry(fei,
1983 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1986 "6.6.6.6/32 via 10.10.10.1");
1988 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
1991 * A recursive via the two unequal cost entries
1993 fib_prefix_t bgp_44_s_32 = {
1995 .fp_proto = FIB_PROTOCOL_IP4,
1997 /* 200.200.200.201/32 */
1998 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2001 fei = fib_table_entry_path_add(fib_index,
2004 FIB_ENTRY_FLAG_NONE,
2006 &pfx_1_2_3_4_s_32.fp_addr,
2011 FIB_ROUTE_PATH_FLAG_NONE);
2012 fei = fib_table_entry_path_add(fib_index,
2015 FIB_ENTRY_FLAG_NONE,
2017 &pfx_1_2_3_5_s_32.fp_addr,
2022 FIB_ROUTE_PATH_FLAG_NONE);
2024 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2025 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2026 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2027 tm->hw[0]->sw_if_index,
2028 tm->hw[1]->sw_if_index),
2029 "RPF list for 1.2.3.4/32 contains both adjs");
2032 * test the uRPF check functions
2034 dpo_id_t dpo_44 = DPO_INVALID;
2037 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2038 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2040 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2041 "uRPF check for 68.68.68.68/32 on %d OK",
2042 tm->hw[0]->sw_if_index);
2043 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2044 "uRPF check for 68.68.68.68/32 on %d OK",
2045 tm->hw[1]->sw_if_index);
2046 FIB_TEST(!fib_urpf_check(urpfi, 99),
2047 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2051 fib_table_entry_delete(fib_index,
2054 fib_table_entry_delete(fib_index,
2057 fib_table_entry_delete(fib_index,
2062 * Add a recursive route:
2063 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2065 fib_prefix_t bgp_201_pfx = {
2067 .fp_proto = FIB_PROTOCOL_IP4,
2069 /* 200.200.200.201/32 */
2070 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2074 fib_prefix_t pfx_1_1_1_200_s_32 = {
2076 .fp_proto = FIB_PROTOCOL_IP4,
2078 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2082 fei = fib_table_entry_path_add(fib_index,
2085 FIB_ENTRY_FLAG_NONE,
2087 &pfx_1_1_1_200_s_32.fp_addr,
2088 ~0, // no index provided.
2089 fib_index, // nexthop in same fib as route
2092 FIB_ROUTE_PATH_FLAG_NONE);
2094 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2095 "Recursive via unresolved is drop");
2097 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2098 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2099 "Flags set on RR via non-attached");
2100 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2101 "RPF list for BGP route empty");
2104 * +2 entry (BGP & RR) and +1 shared-path-list
2106 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2107 fib_path_list_db_size());
2108 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2109 fib_path_list_pool_size());
2110 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2111 fib_entry_pool_size());
2114 * insert a route that covers the missing 1.1.1.2/32. we epxect
2115 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2117 fib_prefix_t pfx_1_1_1_0_s_24 = {
2119 .fp_proto = FIB_PROTOCOL_IP4,
2122 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2126 fib_table_entry_path_add(fib_index,
2129 FIB_ENTRY_FLAG_NONE,
2132 tm->hw[0]->sw_if_index,
2133 ~0, // invalid fib index
2136 FIB_ROUTE_PATH_FLAG_NONE);
2137 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2138 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2139 ai = fib_entry_get_adj(fei);
2140 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2141 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2142 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2143 ai = fib_entry_get_adj(fei);
2144 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2145 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2146 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2147 ai = fib_entry_get_adj(fei);
2148 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2151 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2153 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2154 fib_path_list_db_size());
2155 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2156 fib_path_list_pool_size());
2157 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2158 fib_entry_pool_size());
2161 * the recursive adj for 200.200.200.200 should be updated.
2163 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2164 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2165 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2166 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2167 tm->hw[0]->sw_if_index),
2168 "RPF list for BGP route has itf index 0");
2171 * insert a more specific route than 1.1.1.0/24 that also covers the
2172 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2173 * 200.200.200.200 to resolve through it.
2175 fib_prefix_t pfx_1_1_1_0_s_28 = {
2177 .fp_proto = FIB_PROTOCOL_IP4,
2180 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2184 fib_table_entry_path_add(fib_index,
2187 FIB_ENTRY_FLAG_NONE,
2190 tm->hw[0]->sw_if_index,
2191 ~0, // invalid fib index
2194 FIB_ROUTE_PATH_FLAG_NONE);
2195 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2196 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2197 ai = fib_entry_get_adj(fei);
2198 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2201 * +1 entry. +1 shared path-list
2203 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2204 fib_path_list_db_size());
2205 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2206 fib_path_list_pool_size());
2207 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2208 fib_entry_pool_size());
2211 * the recursive adj for 200.200.200.200 should be updated.
2212 * 200.200.200.201 remains unchanged.
2214 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2215 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2218 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2220 fib_table_entry_path_remove(fib_index,
2225 tm->hw[0]->sw_if_index,
2228 FIB_ROUTE_PATH_FLAG_NONE);
2229 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2230 FIB_NODE_INDEX_INVALID),
2231 "1.1.1.0/28 removed");
2232 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2233 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2234 "1.1.1.0/28 lookup via /24");
2235 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2236 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2239 * -1 entry. -1 shared path-list
2241 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2242 fib_path_list_db_size());
2243 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2244 fib_path_list_pool_size());
2245 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2246 fib_entry_pool_size());
2249 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2251 fib_table_entry_path_remove(fib_index,
2256 tm->hw[0]->sw_if_index,
2259 FIB_ROUTE_PATH_FLAG_NONE);
2260 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2261 FIB_NODE_INDEX_INVALID),
2262 "1.1.1.0/24 removed");
2264 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2265 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2266 "1.1.1.2/32 route is DROP");
2267 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2268 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2269 "1.1.1.200/32 route is DROP");
2271 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2272 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2274 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2275 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2281 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2282 fib_path_list_db_size());
2283 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2284 fib_path_list_pool_size());
2285 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2286 fib_entry_pool_size());
2289 * insert the missing 1.1.1.2/32
2291 fei = fib_table_entry_path_add(fib_index,
2294 FIB_ENTRY_FLAG_NONE,
2297 tm->hw[0]->sw_if_index,
2298 ~0, // invalid fib index
2301 FIB_ROUTE_PATH_FLAG_NONE);
2302 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2303 ai = fib_entry_get_adj(fei);
2304 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2306 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2307 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2309 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2312 * no change. 1.1.1.2/32 was already there RR sourced.
2314 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2315 fib_path_list_db_size());
2316 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2317 fib_path_list_pool_size());
2318 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2319 fib_entry_pool_size());
2322 * give 201 a resolved path.
2323 * it now has the unresolved 1.1.1.200 and the resolved 1.1.1.2,
2324 * only the latter contributes forwarding.
2326 fei = fib_table_entry_path_add(fib_index,
2329 FIB_ENTRY_FLAG_NONE,
2331 &pfx_1_1_1_2_s_32.fp_addr,
2336 FIB_ROUTE_PATH_FLAG_NONE);
2337 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_2_s_32, 0);
2338 fib_table_entry_path_remove(fib_index,
2342 &pfx_1_1_1_2_s_32.fp_addr,
2346 FIB_ROUTE_PATH_FLAG_NONE);
2349 * remove 200.200.200.201/32 which does not have a valid via FIB
2351 fib_table_entry_path_remove(fib_index,
2355 &pfx_1_1_1_200_s_32.fp_addr,
2356 ~0, // no index provided.
2359 FIB_ROUTE_PATH_FLAG_NONE);
2362 * -2 entries (BGP and RR). -1 shared path-list;
2364 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2365 FIB_NODE_INDEX_INVALID),
2366 "200.200.200.201/32 removed");
2367 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2368 FIB_NODE_INDEX_INVALID),
2369 "1.1.1.200/32 removed");
2371 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2372 fib_path_list_db_size());
2373 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2374 fib_path_list_pool_size());
2375 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2376 fib_entry_pool_size());
2379 * remove 200.200.200.200/32 which does have a valid via FIB
2381 fib_table_entry_path_remove(fib_index,
2385 &pfx_1_1_1_2_s_32.fp_addr,
2386 ~0, // no index provided.
2389 FIB_ROUTE_PATH_FLAG_NONE);
2391 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2392 FIB_NODE_INDEX_INVALID),
2393 "200.200.200.200/32 removed");
2394 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2395 FIB_NODE_INDEX_INVALID),
2396 "1.1.1.2/32 still present");
2399 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2401 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2402 fib_path_list_db_size());
2403 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2404 fib_path_list_pool_size());
2405 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2406 fib_entry_pool_size());
2409 * A recursive prefix that has a 2 path load-balance.
2410 * It also shares a next-hop with other BGP prefixes and hence
2411 * test the ref counting of RR sourced prefixes and 2 level LB.
2413 const fib_prefix_t bgp_102 = {
2415 .fp_proto = FIB_PROTOCOL_IP4,
2417 /* 100.100.100.101/32 */
2418 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2421 fib_table_entry_path_add(fib_index,
2424 FIB_ENTRY_FLAG_NONE,
2426 &pfx_1_1_1_1_s_32.fp_addr,
2427 ~0, // no index provided.
2428 fib_index, // same as route
2431 FIB_ROUTE_PATH_FLAG_NONE);
2432 fib_table_entry_path_add(fib_index,
2435 FIB_ENTRY_FLAG_NONE,
2437 &pfx_1_1_1_2_s_32.fp_addr,
2438 ~0, // no index provided.
2439 fib_index, // same as route's FIB
2442 FIB_ROUTE_PATH_FLAG_NONE);
2443 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2444 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2445 dpo = fib_entry_contribute_ip_forwarding(fei);
2447 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2448 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2449 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2450 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2452 lb = load_balance_get(dpo->dpoi_index);
2453 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2454 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2455 "First via 10.10.10.1");
2456 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2457 "Second via 10.10.10.1");
2459 fib_table_entry_path_remove(fib_index,
2463 &pfx_1_1_1_1_s_32.fp_addr,
2464 ~0, // no index provided.
2465 fib_index, // same as route's FIB
2467 FIB_ROUTE_PATH_FLAG_NONE);
2468 fib_table_entry_path_remove(fib_index,
2472 &pfx_1_1_1_2_s_32.fp_addr,
2473 ~0, // no index provided.
2474 fib_index, // same as route's FIB
2476 FIB_ROUTE_PATH_FLAG_NONE);
2477 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2478 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2481 * remove the remaining recursives
2483 fib_table_entry_path_remove(fib_index,
2487 &pfx_1_1_1_1_s_32.fp_addr,
2488 ~0, // no index provided.
2489 fib_index, // same as route's FIB
2491 FIB_ROUTE_PATH_FLAG_NONE);
2492 fib_table_entry_path_remove(fib_index,
2496 &pfx_1_1_1_1_s_32.fp_addr,
2497 ~0, // no index provided.
2498 fib_index, // same as route's FIB
2500 FIB_ROUTE_PATH_FLAG_NONE);
2501 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2502 FIB_NODE_INDEX_INVALID),
2503 "100.100.100.100/32 removed");
2504 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2505 FIB_NODE_INDEX_INVALID),
2506 "100.100.100.101/32 removed");
2509 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2511 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2512 fib_path_list_db_size());
2513 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2514 fib_path_list_pool_size());
2515 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2516 fib_entry_pool_size());
2519 * Add a recursive route via a connected cover, using an adj-fib that does exist
2521 fib_table_entry_path_add(fib_index,
2524 FIB_ENTRY_FLAG_NONE,
2527 ~0, // no index provided.
2528 fib_index, // Same as route's FIB
2531 FIB_ROUTE_PATH_FLAG_NONE);
2534 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2536 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2537 fib_path_list_db_size());
2538 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2539 fib_path_list_pool_size());
2540 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2541 fib_entry_pool_size());
2543 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2544 dpo = fib_entry_contribute_ip_forwarding(fei);
2546 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2547 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2549 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2550 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2552 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2553 "Flags set on RR via existing attached");
2556 * Add a recursive route via a connected cover, using and adj-fib that does
2559 ip46_address_t nh_10_10_10_3 = {
2560 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2562 fib_prefix_t pfx_10_10_10_3 = {
2564 .fp_proto = FIB_PROTOCOL_IP4,
2565 .fp_addr = nh_10_10_10_3,
2568 fib_table_entry_path_add(fib_index,
2571 FIB_ENTRY_FLAG_NONE,
2574 ~0, // no index provided.
2578 FIB_ROUTE_PATH_FLAG_NONE);
2581 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2582 * one unshared non-recursive via 10.10.10.3
2584 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2585 fib_path_list_db_size());
2586 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2587 fib_path_list_pool_size());
2588 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2589 fib_entry_pool_size());
2591 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2594 tm->hw[0]->sw_if_index);
2596 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2597 dpo = fib_entry_contribute_ip_forwarding(fei);
2598 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2599 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2601 ai = fib_entry_get_adj(fei);
2602 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2603 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2604 fib_entry_get_flags(fei)),
2605 "Flags set on RR via non-existing attached");
2607 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2608 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2613 * remove the recursives
2615 fib_table_entry_path_remove(fib_index,
2620 ~0, // no index provided.
2621 fib_index, // same as route's FIB
2623 FIB_ROUTE_PATH_FLAG_NONE);
2624 fib_table_entry_path_remove(fib_index,
2629 ~0, // no index provided.
2630 fib_index, // same as route's FIB
2632 FIB_ROUTE_PATH_FLAG_NONE);
2634 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2635 FIB_NODE_INDEX_INVALID),
2636 "200.200.200.201/32 removed");
2637 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2638 FIB_NODE_INDEX_INVALID),
2639 "200.200.200.200/32 removed");
2640 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2641 FIB_NODE_INDEX_INVALID),
2642 "10.10.10.3/32 removed");
2645 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2646 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2648 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2649 fib_path_list_db_size());
2650 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2651 fib_path_list_pool_size());
2652 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2653 fib_entry_pool_size());
2658 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2660 fib_prefix_t pfx_5_5_5_5_s_32 = {
2662 .fp_proto = FIB_PROTOCOL_IP4,
2664 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2667 fib_prefix_t pfx_5_5_5_6_s_32 = {
2669 .fp_proto = FIB_PROTOCOL_IP4,
2671 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2674 fib_prefix_t pfx_5_5_5_7_s_32 = {
2676 .fp_proto = FIB_PROTOCOL_IP4,
2678 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2682 fib_table_entry_path_add(fib_index,
2685 FIB_ENTRY_FLAG_NONE,
2687 &pfx_5_5_5_6_s_32.fp_addr,
2688 ~0, // no index provided.
2692 FIB_ROUTE_PATH_FLAG_NONE);
2693 fib_table_entry_path_add(fib_index,
2696 FIB_ENTRY_FLAG_NONE,
2698 &pfx_5_5_5_7_s_32.fp_addr,
2699 ~0, // no index provided.
2703 FIB_ROUTE_PATH_FLAG_NONE);
2704 fib_table_entry_path_add(fib_index,
2707 FIB_ENTRY_FLAG_NONE,
2709 &pfx_5_5_5_5_s_32.fp_addr,
2710 ~0, // no index provided.
2714 FIB_ROUTE_PATH_FLAG_NONE);
2716 * +3 entries, +3 shared path-list
2718 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2719 fib_path_list_db_size());
2720 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2721 fib_path_list_pool_size());
2722 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2723 fib_entry_pool_size());
2726 * All the entries have only looped paths, so they are all drop
2728 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2729 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2730 "LB for 5.5.5.7/32 is via adj for DROP");
2731 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2732 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2733 "LB for 5.5.5.5/32 is via adj for DROP");
2734 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2735 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2736 "LB for 5.5.5.6/32 is via adj for DROP");
2739 * provide 5.5.5.6/32 with alternate path.
2740 * this will allow only 5.5.5.6/32 to forward with this path, the others
2741 * are still drop since the loop is still present.
2743 fib_table_entry_path_add(fib_index,
2746 FIB_ENTRY_FLAG_NONE,
2749 tm->hw[0]->sw_if_index,
2753 FIB_ROUTE_PATH_FLAG_NONE);
2755 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2756 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2758 lb = load_balance_get(dpo1->dpoi_index);
2759 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2761 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2762 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2763 FIB_TEST((ai_01 == dpo2->dpoi_index),
2764 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2766 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2767 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2768 "LB for 5.5.5.7/32 is via adj for DROP");
2769 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2770 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2771 "LB for 5.5.5.5/32 is via adj for DROP");
2774 * remove the alternate path for 5.5.5.6/32
2777 fib_table_entry_path_remove(fib_index,
2782 tm->hw[0]->sw_if_index,
2785 FIB_ROUTE_PATH_FLAG_NONE);
2787 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2788 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2789 "LB for 5.5.5.7/32 is via adj for DROP");
2790 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2791 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2792 "LB for 5.5.5.5/32 is via adj for DROP");
2793 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2794 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2795 "LB for 5.5.5.6/32 is via adj for DROP");
2798 * break the loop by giving 5.5.5.5/32 a new set of paths
2799 * expect all to forward via this new path.
2801 fib_table_entry_update_one_path(fib_index,
2804 FIB_ENTRY_FLAG_NONE,
2807 tm->hw[0]->sw_if_index,
2808 ~0, // invalid fib index
2811 FIB_ROUTE_PATH_FLAG_NONE);
2813 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2814 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2815 lb = load_balance_get(dpo1->dpoi_index);
2816 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2818 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2819 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2820 FIB_TEST((ai_01 == dpo2->dpoi_index),
2821 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2823 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2824 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2826 lb = load_balance_get(dpo2->dpoi_index);
2827 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2828 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2829 "5.5.5.5.7 via 5.5.5.5");
2831 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2832 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2834 lb = load_balance_get(dpo1->dpoi_index);
2835 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2836 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2837 "5.5.5.5.6 via 5.5.5.7");
2840 * revert back to the loop. so we can remove the prefixes with
2843 fib_table_entry_update_one_path(fib_index,
2846 FIB_ENTRY_FLAG_NONE,
2848 &pfx_5_5_5_6_s_32.fp_addr,
2849 ~0, // no index provided.
2853 FIB_ROUTE_PATH_FLAG_NONE);
2855 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2856 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2857 "LB for 5.5.5.7/32 is via adj for DROP");
2858 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2859 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2860 "LB for 5.5.5.5/32 is via adj for DROP");
2861 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2862 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2863 "LB for 5.5.5.6/32 is via adj for DROP");
2866 * remove all the 5.5.5.x/32 prefixes
2868 fib_table_entry_path_remove(fib_index,
2872 &pfx_5_5_5_6_s_32.fp_addr,
2873 ~0, // no index provided.
2874 fib_index, // same as route's FIB
2876 FIB_ROUTE_PATH_FLAG_NONE);
2877 fib_table_entry_path_remove(fib_index,
2881 &pfx_5_5_5_7_s_32.fp_addr,
2882 ~0, // no index provided.
2883 fib_index, // same as route's FIB
2885 FIB_ROUTE_PATH_FLAG_NONE);
2886 fib_table_entry_path_remove(fib_index,
2890 &pfx_5_5_5_5_s_32.fp_addr,
2891 ~0, // no index provided.
2892 fib_index, // same as route's FIB
2894 FIB_ROUTE_PATH_FLAG_NONE);
2895 fib_table_entry_path_remove(fib_index,
2900 ~0, // no index provided.
2901 fib_index, // same as route's FIB
2903 FIB_ROUTE_PATH_FLAG_NONE);
2906 * -3 entries, -3 shared path-list
2908 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2909 fib_path_list_db_size());
2910 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2911 fib_path_list_pool_size());
2912 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2913 fib_entry_pool_size());
2916 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2918 fib_table_entry_path_add(fib_index,
2921 FIB_ENTRY_FLAG_NONE,
2923 &pfx_5_5_5_6_s_32.fp_addr,
2924 ~0, // no index provided.
2928 FIB_ROUTE_PATH_FLAG_NONE);
2929 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2930 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2931 "1-level 5.5.5.6/32 loop is via adj for DROP");
2933 fib_table_entry_path_remove(fib_index,
2937 &pfx_5_5_5_6_s_32.fp_addr,
2938 ~0, // no index provided.
2939 fib_index, // same as route's FIB
2941 FIB_ROUTE_PATH_FLAG_NONE);
2942 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2943 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2944 "1-level 5.5.5.6/32 loop is removed");
2947 * A recursive route whose next-hop is covered by the prefix.
2948 * This would mean the via-fib, which inherits forwarding from its
2949 * cover, thus picks up forwarding from the prfix, which is via the
2950 * via-fib, and we have a loop.
2952 fib_prefix_t pfx_23_23_23_0_s_24 = {
2954 .fp_proto = FIB_PROTOCOL_IP4,
2956 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2959 fib_prefix_t pfx_23_23_23_23_s_32 = {
2961 .fp_proto = FIB_PROTOCOL_IP4,
2963 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2966 fei = fib_table_entry_path_add(fib_index,
2967 &pfx_23_23_23_0_s_24,
2969 FIB_ENTRY_FLAG_NONE,
2971 &pfx_23_23_23_23_s_32.fp_addr,
2976 FIB_ROUTE_PATH_FLAG_NONE);
2977 dpo = fib_entry_contribute_ip_forwarding(fei);
2978 FIB_TEST(load_balance_is_drop(dpo),
2979 "23.23.23.0/24 via covered is DROP");
2980 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2983 * add-remove test. no change.
2985 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2986 fib_path_list_db_size());
2987 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2988 fib_path_list_pool_size());
2989 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2990 fib_entry_pool_size());
2993 * Make the default route recursive via a unknown next-hop. Thus the
2994 * next hop's cover would be the default route
2996 fei = fib_table_entry_path_add(fib_index,
2999 FIB_ENTRY_FLAG_NONE,
3001 &pfx_23_23_23_23_s_32.fp_addr,
3006 FIB_ROUTE_PATH_FLAG_NONE);
3007 dpo = fib_entry_contribute_ip_forwarding(fei);
3008 FIB_TEST(load_balance_is_drop(dpo),
3009 "0.0.0.0.0/0 via is DROP");
3010 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3011 "no resolving interface for looped 0.0.0.0/0");
3013 fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
3014 dpo = fib_entry_contribute_ip_forwarding(fei);
3015 FIB_TEST(load_balance_is_drop(dpo),
3016 "23.23.23.23/32 via is DROP");
3017 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3018 "no resolving interface for looped 23.23.23.23/32");
3020 fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
3023 * A recursive route with recursion constraints.
3024 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
3026 fib_table_entry_path_add(fib_index,
3029 FIB_ENTRY_FLAG_NONE,
3036 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3038 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3039 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3041 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3042 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3044 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3045 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3048 * save the load-balance. we expect it to be inplace modified
3050 lb = load_balance_get(dpo1->dpoi_index);
3053 * add a covering prefix for the via fib that would otherwise serve
3054 * as the resolving route when the host is removed
3056 fib_table_entry_path_add(fib_index,
3059 FIB_ENTRY_FLAG_NONE,
3062 tm->hw[0]->sw_if_index,
3063 ~0, // invalid fib index
3066 FIB_ROUTE_PATH_FLAG_NONE);
3067 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3068 ai = fib_entry_get_adj(fei);
3069 FIB_TEST((ai == ai_01),
3070 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3073 * remove the host via FIB - expect the BGP prefix to be drop
3075 fib_table_entry_path_remove(fib_index,
3080 tm->hw[0]->sw_if_index,
3081 ~0, // invalid fib index
3083 FIB_ROUTE_PATH_FLAG_NONE);
3085 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3086 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3089 * add the via-entry host reoute back. expect to resolve again
3091 fib_table_entry_path_add(fib_index,
3094 FIB_ENTRY_FLAG_NONE,
3097 tm->hw[0]->sw_if_index,
3098 ~0, // invalid fib index
3101 FIB_ROUTE_PATH_FLAG_NONE);
3102 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3103 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3106 * add another path for the recursive. it will then have 2.
3108 fib_prefix_t pfx_1_1_1_3_s_32 = {
3110 .fp_proto = FIB_PROTOCOL_IP4,
3112 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3115 fib_table_entry_path_add(fib_index,
3118 FIB_ENTRY_FLAG_NONE,
3121 tm->hw[0]->sw_if_index,
3122 ~0, // invalid fib index
3125 FIB_ROUTE_PATH_FLAG_NONE);
3127 fib_table_entry_path_add(fib_index,
3130 FIB_ENTRY_FLAG_NONE,
3132 &pfx_1_1_1_3_s_32.fp_addr,
3137 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3140 * add a bunch load more entries using this path combo so that we get
3141 * an LB-map created.
3144 fib_prefix_t bgp_78s[N_P];
3145 for (ii = 0; ii < N_P; ii++)
3147 bgp_78s[ii].fp_len = 32;
3148 bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3149 bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3152 fib_table_entry_path_add(fib_index,
3155 FIB_ENTRY_FLAG_NONE,
3157 &pfx_1_1_1_3_s_32.fp_addr,
3162 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3163 fib_table_entry_path_add(fib_index,
3166 FIB_ENTRY_FLAG_NONE,
3173 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3176 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3177 dpo = fib_entry_contribute_ip_forwarding(fei);
3179 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3180 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3181 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3182 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3183 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3184 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3185 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3186 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3189 * expect the lb-map used by the recursive's load-balance is using both buckets
3191 load_balance_map_t *lbm;
3194 lb = load_balance_get(dpo->dpoi_index);
3196 load_balance_map_lock(lbmi);
3197 lbm = load_balance_map_get(lbmi);
3199 FIB_TEST(lbm->lbm_buckets[0] == 0,
3200 "LB maps's bucket 0 is %d",
3201 lbm->lbm_buckets[0]);
3202 FIB_TEST(lbm->lbm_buckets[1] == 1,
3203 "LB maps's bucket 1 is %d",
3204 lbm->lbm_buckets[1]);
3207 * withdraw one of the /32 via-entrys.
3208 * that ECMP path will be unresolved and forwarding should continue on the
3209 * other available path. this is an iBGP PIC edge failover.
3210 * Test the forwarding changes without re-fetching the adj from the
3211 * recursive entry. this ensures its the same one that is updated; i.e. an
3214 fib_table_entry_path_remove(fib_index,
3219 tm->hw[0]->sw_if_index,
3220 ~0, // invalid fib index
3222 FIB_ROUTE_PATH_FLAG_NONE);
3224 /* suspend so the update walk kicks int */
3225 vlib_process_suspend(vlib_get_main(), 1e-5);
3227 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3228 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3229 "post PIC 200.200.200.200/32 was inplace modified");
3231 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3232 "post PIC adj for 200.200.200.200/32 is recursive"
3233 " via adj for 1.1.1.3");
3236 * the LB maps that was locked above should have been modified to remove
3237 * the path that was down, and thus its bucket points to a path that is
3240 FIB_TEST(lbm->lbm_buckets[0] == 1,
3241 "LB maps's bucket 0 is %d",
3242 lbm->lbm_buckets[0]);
3243 FIB_TEST(lbm->lbm_buckets[1] == 1,
3244 "LB maps's bucket 1 is %d",
3245 lbm->lbm_buckets[1]);
3247 load_balance_map_unlock(lbmi);
3250 * add it back. again
3252 fib_table_entry_path_add(fib_index,
3255 FIB_ENTRY_FLAG_NONE,
3258 tm->hw[0]->sw_if_index,
3259 ~0, // invalid fib index
3262 FIB_ROUTE_PATH_FLAG_NONE);
3264 /* suspend so the update walk kicks in */
3265 vlib_process_suspend(vlib_get_main(), 1e-5);
3267 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3268 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3269 "via adj for 1.1.1.1");
3270 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3271 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3272 "via adj for 1.1.1.3");
3274 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3275 dpo = fib_entry_contribute_ip_forwarding(fei);
3276 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3277 "post PIC 200.200.200.200/32 was inplace modified");
3280 * add a 3rd path. this makes the LB 16 buckets.
3282 fib_table_entry_path_add(fib_index,
3285 FIB_ENTRY_FLAG_NONE,
3287 &pfx_1_1_1_2_s_32.fp_addr,
3292 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3293 for (ii = 0; ii < N_P; ii++)
3295 fib_table_entry_path_add(fib_index,
3298 FIB_ENTRY_FLAG_NONE,
3300 &pfx_1_1_1_2_s_32.fp_addr,
3305 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3308 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3309 dpo = fib_entry_contribute_ip_forwarding(fei);
3310 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3311 "200.200.200.200/32 was inplace modified for 3rd path");
3312 FIB_TEST(16 == lb->lb_n_buckets,
3313 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3316 load_balance_map_lock(lbmi);
3317 lbm = load_balance_map_get(lbmi);
3319 for (ii = 0; ii < 16; ii++)
3321 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3322 "LB Map for 200.200.200.200/32 at %d is %d",
3323 ii, lbm->lbm_buckets[ii]);
3327 * trigger PIC by removing the first via-entry
3328 * the first 6 buckets of the map should map to the next 6
3330 fib_table_entry_path_remove(fib_index,
3335 tm->hw[0]->sw_if_index,
3338 FIB_ROUTE_PATH_FLAG_NONE);
3339 /* suspend so the update walk kicks int */
3340 vlib_process_suspend(vlib_get_main(), 1e-5);
3342 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3343 dpo = fib_entry_contribute_ip_forwarding(fei);
3344 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3345 "200.200.200.200/32 was inplace modified for 3rd path");
3346 FIB_TEST(2 == lb->lb_n_buckets,
3347 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3349 for (ii = 0; ii < 6; ii++)
3351 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3352 "LB Map for 200.200.200.200/32 at %d is %d",
3353 ii, lbm->lbm_buckets[ii]);
3355 for (ii = 6; ii < 16; ii++)
3357 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3358 "LB Map for 200.200.200.200/32 at %d is %d",
3359 ii, lbm->lbm_buckets[ii]);
3361 load_balance_map_unlock(lbmi);
3366 fib_table_entry_path_add(fib_index,
3369 FIB_ENTRY_FLAG_NONE,
3372 tm->hw[0]->sw_if_index,
3376 FIB_ROUTE_PATH_FLAG_NONE);
3378 for (ii = 0; ii < N_P; ii++)
3380 fib_table_entry_delete(fib_index,
3383 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3384 fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3386 format_fib_prefix, &bgp_78s[ii]);
3388 fib_table_entry_path_remove(fib_index,
3392 &pfx_1_1_1_2_s_32.fp_addr,
3396 MPLS_LABEL_INVALID);
3397 fib_table_entry_path_remove(fib_index,
3405 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3406 fib_table_entry_path_remove(fib_index,
3410 &pfx_1_1_1_3_s_32.fp_addr,
3414 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3415 fib_table_entry_delete(fib_index,
3418 fib_table_entry_delete(fib_index,
3421 /* suspend so the update walk kicks int */
3422 vlib_process_suspend(vlib_get_main(), 1e-5);
3423 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3424 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3425 "1.1.1.1/28 removed");
3426 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3427 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3428 "1.1.1.3/32 removed");
3429 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3430 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3431 "200.200.200.200/32 removed");
3434 * add-remove test. no change.
3436 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3437 fib_path_list_db_size());
3438 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3439 fib_path_list_pool_size());
3440 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3441 fib_entry_pool_size());
3444 * A route whose paths are built up iteratively and then removed
3447 fib_prefix_t pfx_4_4_4_4_s_32 = {
3449 .fp_proto = FIB_PROTOCOL_IP4,
3452 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3456 fib_table_entry_path_add(fib_index,
3459 FIB_ENTRY_FLAG_NONE,
3462 tm->hw[0]->sw_if_index,
3466 FIB_ROUTE_PATH_FLAG_NONE);
3467 fib_table_entry_path_add(fib_index,
3470 FIB_ENTRY_FLAG_NONE,
3473 tm->hw[0]->sw_if_index,
3477 FIB_ROUTE_PATH_FLAG_NONE);
3478 fib_table_entry_path_add(fib_index,
3481 FIB_ENTRY_FLAG_NONE,
3484 tm->hw[0]->sw_if_index,
3488 FIB_ROUTE_PATH_FLAG_NONE);
3489 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3490 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3491 "4.4.4.4/32 present");
3493 fib_table_entry_delete(fib_index,
3496 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3497 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3498 "4.4.4.4/32 removed");
3501 * add-remove test. no change.
3503 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3504 fib_path_list_db_size());
3505 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3506 fib_path_list_pool_size());
3507 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3508 fib_entry_pool_size());
3511 * A route with multiple paths at once
3513 fib_route_path_t *r_paths = NULL;
3515 for (ii = 0; ii < 4; ii++)
3517 fib_route_path_t r_path = {
3518 .frp_proto = DPO_PROTO_IP4,
3520 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3522 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3524 .frp_fib_index = ~0,
3526 vec_add1(r_paths, r_path);
3529 fib_table_entry_update(fib_index,
3532 FIB_ENTRY_FLAG_NONE,
3535 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3536 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3537 dpo = fib_entry_contribute_ip_forwarding(fei);
3539 lb = load_balance_get(dpo->dpoi_index);
3540 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3542 fib_table_entry_delete(fib_index,
3545 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3546 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3547 "4.4.4.4/32 removed");
3551 * add-remove test. no change.
3553 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3554 fib_path_list_db_size());
3555 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3556 fib_path_list_pool_size());
3557 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3558 fib_entry_pool_size());
3561 * A route deag route
3563 fib_table_entry_path_add(fib_index,
3566 FIB_ENTRY_FLAG_NONE,
3573 FIB_ROUTE_PATH_FLAG_NONE);
3575 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3576 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3578 dpo = fib_entry_contribute_ip_forwarding(fei);
3579 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3580 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3582 FIB_TEST((fib_index == lkd->lkd_fib_index),
3583 "4.4.4.4/32 is deag in %d %U",
3585 format_dpo_id, dpo, 0);
3586 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
3587 "4.4.4.4/32 is source deag in %d %U",
3589 format_dpo_id, dpo, 0);
3591 fib_table_entry_delete(fib_index,
3594 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3595 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3596 "4.4.4.4/32 removed");
3600 * A route deag route in a source lookup table
3602 fib_table_entry_path_add(fib_index,
3605 FIB_ENTRY_FLAG_NONE,
3612 FIB_ROUTE_PATH_SOURCE_LOOKUP);
3614 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3615 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3617 dpo = fib_entry_contribute_ip_forwarding(fei);
3618 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3619 lkd = lookup_dpo_get(dpo->dpoi_index);
3621 FIB_TEST((fib_index == lkd->lkd_fib_index),
3622 "4.4.4.4/32 is deag in %d %U",
3624 format_dpo_id, dpo, 0);
3625 FIB_TEST((LOOKUP_INPUT_SRC_ADDR == lkd->lkd_input),
3626 "4.4.4.4/32 is source deag in %d %U",
3628 format_dpo_id, dpo, 0);
3630 fib_table_entry_delete(fib_index,
3633 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3634 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3635 "4.4.4.4/32 removed");
3639 * add-remove test. no change.
3641 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3642 fib_path_list_db_size());
3643 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3644 fib_path_list_pool_size());
3645 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3646 fib_entry_pool_size());
3650 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3652 fib_prefix_t pfx_34_1_1_1_s_32 = {
3654 .fp_proto = FIB_PROTOCOL_IP4,
3656 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3659 fib_prefix_t pfx_34_34_1_1_s_32 = {
3661 .fp_proto = FIB_PROTOCOL_IP4,
3663 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3666 fei = fib_table_entry_path_add(fib_index,
3667 &pfx_34_34_1_1_s_32,
3669 FIB_ENTRY_FLAG_NONE,
3672 tm->hw[0]->sw_if_index,
3676 FIB_ROUTE_PATH_FLAG_NONE);
3677 fei = fib_table_entry_path_add(fib_index,
3680 FIB_ENTRY_FLAG_NONE,
3682 &pfx_34_34_1_1_s_32.fp_addr,
3687 FIB_ROUTE_PATH_FLAG_NONE);
3688 fei = fib_table_entry_path_add(fib_index,
3691 FIB_ENTRY_FLAG_NONE,
3693 &pfx_34_34_1_1_s_32.fp_addr,
3698 FIB_ROUTE_PATH_FLAG_NONE);
3699 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3700 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3701 fib_table_entry_delete(fib_index,
3702 &pfx_34_34_1_1_s_32,
3707 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3708 * all of which are via 10.10.10.1, Itf1
3710 fib_table_entry_path_remove(fib_index,
3715 tm->hw[0]->sw_if_index,
3718 FIB_ROUTE_PATH_FLAG_NONE);
3719 fib_table_entry_path_remove(fib_index,
3724 tm->hw[0]->sw_if_index,
3727 FIB_ROUTE_PATH_FLAG_NONE);
3728 fib_table_entry_path_remove(fib_index,
3733 tm->hw[0]->sw_if_index,
3736 FIB_ROUTE_PATH_FLAG_NONE);
3738 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3739 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3740 "1.1.1.1/32 removed");
3741 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3742 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3743 "1.1.1.2/32 removed");
3744 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3745 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3746 "1.1.2.0/24 removed");
3749 * -3 entries and -1 shared path-list
3751 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3752 fib_path_list_db_size());
3753 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3754 fib_path_list_pool_size());
3755 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3756 fib_entry_pool_size());
3759 * An attached-host route. Expect to link to the incomplete adj
3761 fib_prefix_t pfx_4_1_1_1_s_32 = {
3763 .fp_proto = FIB_PROTOCOL_IP4,
3766 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3769 fib_table_entry_path_add(fib_index,
3772 FIB_ENTRY_FLAG_NONE,
3775 tm->hw[0]->sw_if_index,
3779 FIB_ROUTE_PATH_FLAG_NONE);
3781 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3782 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3783 ai = fib_entry_get_adj(fei);
3785 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3787 &pfx_4_1_1_1_s_32.fp_addr,
3788 tm->hw[0]->sw_if_index);
3789 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3793 * +1 entry and +1 shared path-list
3795 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3796 fib_path_list_db_size());
3797 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3798 fib_path_list_pool_size());
3799 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3800 fib_entry_pool_size());
3802 fib_table_entry_delete(fib_index,
3806 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3807 fib_path_list_db_size());
3808 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3809 fib_path_list_pool_size());
3810 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3811 fib_entry_pool_size());
3814 * add a v6 prefix via v4 next-hops
3816 fib_prefix_t pfx_2001_s_64 = {
3818 .fp_proto = FIB_PROTOCOL_IP6,
3820 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3823 fei = fib_table_entry_path_add(0, //default v6 table
3826 FIB_ENTRY_FLAG_NONE,
3829 tm->hw[0]->sw_if_index,
3833 FIB_ROUTE_PATH_FLAG_NONE);
3835 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3836 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3837 ai = fib_entry_get_adj(fei);
3839 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3840 "2001::/64 via ARP-adj");
3841 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3842 "2001::/64 is link type v6");
3843 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3844 "2001::/64 ADJ-adj is NH proto v4");
3845 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3848 * add a uRPF exempt prefix:
3850 * - it's forwarding is drop
3851 * - it's uRPF list is not empty
3852 * - the uRPF list for the default route (it's cover) is empty
3854 fei = fib_table_entry_special_add(fib_index,
3856 FIB_SOURCE_URPF_EXEMPT,
3857 FIB_ENTRY_FLAG_DROP);
3858 dpo = fib_entry_contribute_ip_forwarding(fei);
3859 FIB_TEST(load_balance_is_drop(dpo),
3860 "uRPF exempt 4.1.1.1/32 DROP");
3861 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3862 "uRPF list for exempt prefix has itf index 0");
3863 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3864 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3865 "uRPF list for 0.0.0.0/0 empty");
3867 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3870 * An adj-fib that fails the refinement criteria - no connected cover
3872 fib_prefix_t pfx_12_10_10_2_s_32 = {
3874 .fp_proto = FIB_PROTOCOL_IP4,
3877 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3881 fib_table_entry_path_add(fib_index,
3882 &pfx_12_10_10_2_s_32,
3884 FIB_ENTRY_FLAG_ATTACHED,
3886 &pfx_12_10_10_2_s_32.fp_addr,
3887 tm->hw[0]->sw_if_index,
3888 ~0, // invalid fib index
3891 FIB_ROUTE_PATH_FLAG_NONE);
3893 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3894 dpo = fib_entry_contribute_ip_forwarding(fei);
3895 FIB_TEST(!dpo_id_is_valid(dpo),
3896 "no connected cover adj-fib fails refinement");
3898 fib_table_entry_delete(fib_index,
3899 &pfx_12_10_10_2_s_32,
3903 * An adj-fib that fails the refinement criteria - cover is connected
3904 * but on a different interface
3906 fib_prefix_t pfx_10_10_10_127_s_32 = {
3908 .fp_proto = FIB_PROTOCOL_IP4,
3911 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3915 fib_table_entry_path_add(fib_index,
3916 &pfx_10_10_10_127_s_32,
3918 FIB_ENTRY_FLAG_ATTACHED,
3920 &pfx_10_10_10_127_s_32.fp_addr,
3921 tm->hw[1]->sw_if_index,
3922 ~0, // invalid fib index
3925 FIB_ROUTE_PATH_FLAG_NONE);
3927 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3928 dpo = fib_entry_contribute_ip_forwarding(fei);
3929 FIB_TEST(!dpo_id_is_valid(dpo),
3930 "wrong interface adj-fib fails refinement");
3932 fib_table_entry_delete(fib_index,
3933 &pfx_10_10_10_127_s_32,
3937 * add a second path to an adj-fib
3938 * this is a sumiluation of another ARP entry created
3939 * on an interface on which the connected prefi does not exist.
3940 * The second path fails refinement. Expect to forward through the
3943 fib_prefix_t pfx_10_10_10_3_s_32 = {
3945 .fp_proto = FIB_PROTOCOL_IP4,
3948 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
3952 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3955 tm->hw[0]->sw_if_index);
3957 fib_test_lb_bucket_t ip_o_10_10_10_3 = {
3963 fei = fib_table_entry_path_add(fib_index,
3964 &pfx_10_10_10_3_s_32,
3966 FIB_ENTRY_FLAG_NONE,
3969 tm->hw[0]->sw_if_index,
3973 FIB_ROUTE_PATH_FLAG_NONE);
3974 fei = fib_table_entry_path_add(fib_index,
3975 &pfx_10_10_10_3_s_32,
3977 FIB_ENTRY_FLAG_NONE,
3980 tm->hw[1]->sw_if_index,
3984 FIB_ROUTE_PATH_FLAG_NONE);
3985 FIB_TEST(fib_test_validate_entry(fei,
3986 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
3989 "10.10.10.3 via 10.10.10.3/Eth0 only");
3992 * remove the path that refines the cover, should go unresolved
3994 fib_table_entry_path_remove(fib_index,
3995 &pfx_10_10_10_3_s_32,
3999 tm->hw[0]->sw_if_index,
4002 FIB_ROUTE_PATH_FLAG_NONE);
4003 dpo = fib_entry_contribute_ip_forwarding(fei);
4004 FIB_TEST(!dpo_id_is_valid(dpo),
4005 "wrong interface adj-fib fails refinement");
4008 * add back the path that refines the cover
4010 fei = fib_table_entry_path_add(fib_index,
4011 &pfx_10_10_10_3_s_32,
4013 FIB_ENTRY_FLAG_NONE,
4016 tm->hw[0]->sw_if_index,
4020 FIB_ROUTE_PATH_FLAG_NONE);
4021 FIB_TEST(fib_test_validate_entry(fei,
4022 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4025 "10.10.10.3 via 10.10.10.3/Eth0 only");
4028 * remove the path that does not refine the cover
4030 fib_table_entry_path_remove(fib_index,
4031 &pfx_10_10_10_3_s_32,
4035 tm->hw[1]->sw_if_index,
4038 FIB_ROUTE_PATH_FLAG_NONE);
4039 FIB_TEST(fib_test_validate_entry(fei,
4040 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4043 "10.10.10.3 via 10.10.10.3/Eth0 only");
4046 * remove the path that does refine, it's the last path, so
4047 * the entry should be gone
4049 fib_table_entry_path_remove(fib_index,
4050 &pfx_10_10_10_3_s_32,
4054 tm->hw[0]->sw_if_index,
4057 FIB_ROUTE_PATH_FLAG_NONE);
4058 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4059 FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
4064 * change the table's flow-hash config - expect the update to propagete to
4065 * the entries' load-balance objects
4067 flow_hash_config_t old_hash_config, new_hash_config;
4069 old_hash_config = fib_table_get_flow_hash_config(fib_index,
4071 new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
4072 IP_FLOW_HASH_DST_ADDR);
4074 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4075 dpo = fib_entry_contribute_ip_forwarding(fei);
4076 lb = load_balance_get(dpo->dpoi_index);
4077 FIB_TEST((lb->lb_hash_config == old_hash_config),
4078 "Table and LB hash config match: %U",
4079 format_ip_flow_hash_config, lb->lb_hash_config);
4081 fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
4083 FIB_TEST((lb->lb_hash_config == new_hash_config),
4084 "Table and LB newhash config match: %U",
4085 format_ip_flow_hash_config, lb->lb_hash_config);
4088 * A route via an L2 Bridge
4090 fei = fib_table_entry_path_add(fib_index,
4091 &pfx_10_10_10_3_s_32,
4093 FIB_ENTRY_FLAG_NONE,
4096 tm->hw[0]->sw_if_index,
4100 FIB_ROUTE_PATH_FLAG_NONE);
4101 dpo_id_t l2_dpo = DPO_INVALID;
4102 l2_bridge_dpo_add_or_lock(tm->hw[0]->sw_if_index, &l2_dpo);
4103 fib_test_lb_bucket_t ip_o_l2 = {
4106 .adj = l2_dpo.dpoi_index,
4110 FIB_TEST(fib_test_validate_entry(fei,
4111 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4114 "10.10.10.3 via L2 on Eth0");
4115 fib_table_entry_path_remove(fib_index,
4116 &pfx_10_10_10_3_s_32,
4120 tm->hw[0]->sw_if_index,
4123 FIB_ROUTE_PATH_FLAG_NONE);
4130 fib_table_entry_delete(fib_index,
4131 &pfx_10_10_10_1_s_32,
4133 fib_table_entry_delete(fib_index,
4134 &pfx_10_10_10_2_s_32,
4136 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4137 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4138 "10.10.10.1/32 adj-fib removed");
4139 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4140 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4141 "10.10.10.2/32 adj-fib removed");
4144 * -2 entries and -2 non-shared path-list
4146 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4147 fib_path_list_db_size());
4148 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4149 fib_path_list_pool_size());
4150 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4151 fib_entry_pool_size());
4154 * unlock the adjacencies for which this test provided a rewrite.
4155 * These are the last locks on these adjs. they should thus go away.
4159 adj_unlock(ai_12_12_12_12);
4161 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4166 * remove the interface prefixes
4168 local_pfx.fp_len = 32;
4169 fib_table_entry_special_remove(fib_index, &local_pfx,
4170 FIB_SOURCE_INTERFACE);
4171 fei = fib_table_lookup(fib_index, &local_pfx);
4173 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4174 fib_table_lookup_exact_match(fib_index, &local_pfx),
4175 "10.10.10.10/32 adj-fib removed");
4177 local_pfx.fp_len = 24;
4178 fib_table_entry_delete(fib_index, &local_pfx,
4179 FIB_SOURCE_INTERFACE);
4181 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4182 fib_table_lookup_exact_match(fib_index, &local_pfx),
4183 "10.10.10.10/24 adj-fib removed");
4186 * -2 entries and -2 non-shared path-list
4188 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4189 fib_path_list_db_size());
4190 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4191 fib_path_list_pool_size());
4192 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4193 fib_entry_pool_size());
4196 * Last but not least, remove the VRF
4198 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4201 "NO API Source'd prefixes");
4202 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4205 "NO RR Source'd prefixes");
4206 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4208 FIB_SOURCE_INTERFACE)),
4209 "NO INterface Source'd prefixes");
4211 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
4213 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4214 fib_path_list_db_size());
4215 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4216 fib_path_list_pool_size());
4217 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4218 fib_entry_pool_size());
4219 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4220 pool_elts(fib_urpf_list_pool));
4221 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4222 pool_elts(load_balance_map_pool));
4223 FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4224 pool_elts(load_balance_pool));
4225 FIB_TEST((0 == pool_elts(l2_bridge_dpo_pool)), "L2 DPO pool size is %d",
4226 pool_elts(l2_bridge_dpo_pool));
4235 * In the default table check for the presence and correct forwarding
4236 * of the special entries
4238 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4239 const dpo_id_t *dpo, *dpo_drop;
4240 const ip_adjacency_t *adj;
4241 const receive_dpo_t *rd;
4246 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4249 /* via 2001:0:0:1::2 */
4250 ip46_address_t nh_2001_2 = {
4253 [0] = clib_host_to_net_u64(0x2001000000000001),
4254 [1] = clib_host_to_net_u64(0x0000000000000002),
4261 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4263 /* Find or create FIB table 11 */
4264 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
4267 for (ii = 0; ii < 4; ii++)
4269 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4272 fib_prefix_t pfx_0_0 = {
4274 .fp_proto = FIB_PROTOCOL_IP6,
4282 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4283 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4284 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4285 "Default route is DROP");
4287 dpo = fib_entry_contribute_ip_forwarding(dfrt);
4288 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4291 &pfx_0_0.fp_addr.ip6)),
4292 "default-route; fwd and non-fwd tables match");
4294 // FIXME - check specials.
4297 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4298 * each with 2 entries and a v6 mfib with 4 path-lists.
4299 * All entries are special so no path-list sharing.
4302 #define PNPS (5+4+4)
4303 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4304 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4305 fib_path_list_pool_size());
4306 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4307 fib_entry_pool_size());
4310 * add interface routes.
4311 * validate presence of /64 attached and /128 recieve.
4312 * test for the presence of the receive address in the glean and local adj
4314 * receive on 2001:0:0:1::1/128
4316 fib_prefix_t local_pfx = {
4318 .fp_proto = FIB_PROTOCOL_IP6,
4322 [0] = clib_host_to_net_u64(0x2001000000000001),
4323 [1] = clib_host_to_net_u64(0x0000000000000001),
4329 fib_table_entry_update_one_path(fib_index, &local_pfx,
4330 FIB_SOURCE_INTERFACE,
4331 (FIB_ENTRY_FLAG_CONNECTED |
4332 FIB_ENTRY_FLAG_ATTACHED),
4335 tm->hw[0]->sw_if_index,
4339 FIB_ROUTE_PATH_FLAG_NONE);
4340 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4342 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4344 ai = fib_entry_get_adj(fei);
4345 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4347 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4348 "attached interface adj is glean");
4349 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4350 &adj->sub_type.glean.receive_addr)),
4351 "attached interface adj is receive ok");
4352 dpo = fib_entry_contribute_ip_forwarding(fei);
4353 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4356 &local_pfx.fp_addr.ip6)),
4357 "attached-route; fwd and non-fwd tables match");
4359 local_pfx.fp_len = 128;
4360 fib_table_entry_update_one_path(fib_index, &local_pfx,
4361 FIB_SOURCE_INTERFACE,
4362 (FIB_ENTRY_FLAG_CONNECTED |
4363 FIB_ENTRY_FLAG_LOCAL),
4366 tm->hw[0]->sw_if_index,
4367 ~0, // invalid fib index
4370 FIB_ROUTE_PATH_FLAG_NONE);
4371 fei = fib_table_lookup(fib_index, &local_pfx);
4373 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4375 dpo = fib_entry_contribute_ip_forwarding(fei);
4376 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4377 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4378 "local interface adj is local");
4379 rd = receive_dpo_get(dpo->dpoi_index);
4381 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4383 "local interface adj is receive ok");
4385 dpo = fib_entry_contribute_ip_forwarding(fei);
4386 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4389 &local_pfx.fp_addr.ip6)),
4390 "local-route; fwd and non-fwd tables match");
4393 * +2 entries. +2 unshared path-lists
4395 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4396 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4397 fib_path_list_pool_size());
4398 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4399 fib_entry_pool_size());
4402 * Modify the default route to be via an adj not yet known.
4403 * this sources the defalut route with the API source, which is
4404 * a higher preference to the DEFAULT_ROUTE source
4406 fib_table_entry_path_add(fib_index, &pfx_0_0,
4408 FIB_ENTRY_FLAG_NONE,
4411 tm->hw[0]->sw_if_index,
4415 FIB_ROUTE_PATH_FLAG_NONE);
4416 fei = fib_table_lookup(fib_index, &pfx_0_0);
4418 FIB_TEST((fei == dfrt), "default route same index");
4419 ai = fib_entry_get_adj(fei);
4420 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4422 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4423 "adj is incomplete");
4424 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4425 "adj nbr next-hop ok");
4428 * find the adj in the shared db
4430 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4433 tm->hw[0]->sw_if_index);
4434 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4435 adj_unlock(locked_ai);
4438 * no more entires. +1 shared path-list
4440 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4441 fib_path_list_db_size());
4442 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4443 fib_path_list_pool_size());
4444 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4445 fib_entry_pool_size());
4448 * remove the API source from the default route. We expected
4449 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4451 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4455 tm->hw[0]->sw_if_index,
4458 FIB_ROUTE_PATH_FLAG_NONE);
4459 fei = fib_table_lookup(fib_index, &pfx_0_0);
4461 FIB_TEST((fei == dfrt), "default route same index");
4462 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4463 "Default route is DROP");
4466 * no more entires. -1 shared path-list
4468 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4469 fib_path_list_db_size());
4470 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4471 fib_path_list_pool_size());
4472 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4473 fib_entry_pool_size());
4476 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4478 fib_prefix_t pfx_2001_1_2_s_128 = {
4480 .fp_proto = FIB_PROTOCOL_IP6,
4484 [0] = clib_host_to_net_u64(0x2001000000000001),
4485 [1] = clib_host_to_net_u64(0x0000000000000002),
4490 fib_prefix_t pfx_2001_1_3_s_128 = {
4492 .fp_proto = FIB_PROTOCOL_IP6,
4496 [0] = clib_host_to_net_u64(0x2001000000000001),
4497 [1] = clib_host_to_net_u64(0x0000000000000003),
4503 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4506 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4508 &pfx_2001_1_2_s_128.fp_addr,
4509 tm->hw[0]->sw_if_index);
4510 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4511 adj = adj_get(ai_01);
4512 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4513 "adj is incomplete");
4514 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4515 &adj->sub_type.nbr.next_hop)),
4516 "adj nbr next-hop ok");
4518 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4519 fib_test_build_rewrite(eth_addr));
4520 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4522 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4523 &adj->sub_type.nbr.next_hop)),
4524 "adj nbr next-hop ok");
4526 fib_table_entry_path_add(fib_index,
4527 &pfx_2001_1_2_s_128,
4529 FIB_ENTRY_FLAG_ATTACHED,
4531 &pfx_2001_1_2_s_128.fp_addr,
4532 tm->hw[0]->sw_if_index,
4536 FIB_ROUTE_PATH_FLAG_NONE);
4538 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4539 ai = fib_entry_get_adj(fei);
4540 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4544 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4546 &pfx_2001_1_3_s_128.fp_addr,
4547 tm->hw[0]->sw_if_index);
4548 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4549 adj = adj_get(ai_02);
4550 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4551 "adj is incomplete");
4552 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4553 &adj->sub_type.nbr.next_hop)),
4554 "adj nbr next-hop ok");
4556 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4557 fib_test_build_rewrite(eth_addr));
4558 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4560 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4561 &adj->sub_type.nbr.next_hop)),
4562 "adj nbr next-hop ok");
4563 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4565 fib_table_entry_path_add(fib_index,
4566 &pfx_2001_1_3_s_128,
4568 FIB_ENTRY_FLAG_ATTACHED,
4570 &pfx_2001_1_3_s_128.fp_addr,
4571 tm->hw[0]->sw_if_index,
4575 FIB_ROUTE_PATH_FLAG_NONE);
4577 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4578 ai = fib_entry_get_adj(fei);
4579 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4582 * +2 entries, +2 unshread path-lists.
4584 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4585 fib_path_list_db_size());
4586 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4587 fib_path_list_pool_size());
4588 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4589 fib_entry_pool_size());
4592 * Add a 2 routes via the first ADJ. ensure path-list sharing
4594 fib_prefix_t pfx_2001_a_s_64 = {
4596 .fp_proto = FIB_PROTOCOL_IP6,
4600 [0] = clib_host_to_net_u64(0x200100000000000a),
4601 [1] = clib_host_to_net_u64(0x0000000000000000),
4606 fib_prefix_t pfx_2001_b_s_64 = {
4608 .fp_proto = FIB_PROTOCOL_IP6,
4612 [0] = clib_host_to_net_u64(0x200100000000000b),
4613 [1] = clib_host_to_net_u64(0x0000000000000000),
4619 fib_table_entry_path_add(fib_index,
4622 FIB_ENTRY_FLAG_NONE,
4625 tm->hw[0]->sw_if_index,
4629 FIB_ROUTE_PATH_FLAG_NONE);
4630 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4631 ai = fib_entry_get_adj(fei);
4632 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4633 fib_table_entry_path_add(fib_index,
4636 FIB_ENTRY_FLAG_NONE,
4639 tm->hw[0]->sw_if_index,
4643 FIB_ROUTE_PATH_FLAG_NONE);
4644 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4645 ai = fib_entry_get_adj(fei);
4646 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4649 * +2 entries, +1 shared path-list.
4651 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4652 fib_path_list_db_size());
4653 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4654 fib_path_list_pool_size());
4655 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4656 fib_entry_pool_size());
4659 * add a v4 prefix via a v6 next-hop
4661 fib_prefix_t pfx_1_1_1_1_s_32 = {
4663 .fp_proto = FIB_PROTOCOL_IP4,
4665 .ip4.as_u32 = 0x01010101,
4668 fei = fib_table_entry_path_add(0, // default table
4671 FIB_ENTRY_FLAG_NONE,
4674 tm->hw[0]->sw_if_index,
4678 FIB_ROUTE_PATH_FLAG_NONE);
4679 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4680 "1.1.1.1/32 o v6 route present");
4681 ai = fib_entry_get_adj(fei);
4683 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4684 "1.1.1.1/32 via ARP-adj");
4685 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4686 "1.1.1.1/32 ADJ-adj is link type v4");
4687 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4688 "1.1.1.1/32 ADJ-adj is NH proto v6");
4689 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4694 fib_prefix_t pfx_2001_c_s_64 = {
4696 .fp_proto = FIB_PROTOCOL_IP6,
4700 [0] = clib_host_to_net_u64(0x200100000000000c),
4701 [1] = clib_host_to_net_u64(0x0000000000000000),
4706 fib_table_entry_path_add(fib_index,
4709 FIB_ENTRY_FLAG_ATTACHED,
4712 tm->hw[0]->sw_if_index,
4716 FIB_ROUTE_PATH_FLAG_NONE);
4717 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4718 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4719 ai = fib_entry_get_adj(fei);
4721 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4722 "2001:0:0:c/64 attached resolves via glean");
4724 fib_table_entry_path_remove(fib_index,
4729 tm->hw[0]->sw_if_index,
4732 FIB_ROUTE_PATH_FLAG_NONE);
4733 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4734 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4737 * Shutdown the interface on which we have a connected and through
4738 * which the routes are reachable.
4739 * This will result in the connected, adj-fibs, and routes linking to drop
4740 * The local/for-us prefix continues to receive.
4742 clib_error_t * error;
4744 error = vnet_sw_interface_set_flags(vnet_get_main(),
4745 tm->hw[0]->sw_if_index,
4746 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4747 FIB_TEST((NULL == error), "Interface shutdown OK");
4749 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4750 dpo = fib_entry_contribute_ip_forwarding(fei);
4751 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4752 "2001::b/64 resolves via drop");
4754 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4755 dpo = fib_entry_contribute_ip_forwarding(fei);
4756 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4757 "2001::a/64 resolves via drop");
4758 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4759 dpo = fib_entry_contribute_ip_forwarding(fei);
4760 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4761 "2001:0:0:1::3/64 resolves via drop");
4762 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4763 dpo = fib_entry_contribute_ip_forwarding(fei);
4764 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4765 "2001:0:0:1::2/64 resolves via drop");
4766 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4767 dpo = fib_entry_contribute_ip_forwarding(fei);
4768 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4769 "2001:0:0:1::1/128 not drop");
4770 local_pfx.fp_len = 64;
4771 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4772 dpo = fib_entry_contribute_ip_forwarding(fei);
4773 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4774 "2001:0:0:1/64 resolves via drop");
4779 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4780 fib_path_list_db_size());
4781 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4782 fib_path_list_pool_size());
4783 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4784 fib_entry_pool_size());
4787 * shutdown one of the other interfaces, then add a connected.
4788 * and swap one of the routes to it.
4790 error = vnet_sw_interface_set_flags(vnet_get_main(),
4791 tm->hw[1]->sw_if_index,
4792 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4793 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4795 fib_prefix_t connected_pfx = {
4797 .fp_proto = FIB_PROTOCOL_IP6,
4800 /* 2001:0:0:2::1/64 */
4802 [0] = clib_host_to_net_u64(0x2001000000000002),
4803 [1] = clib_host_to_net_u64(0x0000000000000001),
4808 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4809 FIB_SOURCE_INTERFACE,
4810 (FIB_ENTRY_FLAG_CONNECTED |
4811 FIB_ENTRY_FLAG_ATTACHED),
4814 tm->hw[1]->sw_if_index,
4818 FIB_ROUTE_PATH_FLAG_NONE);
4819 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4820 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4821 dpo = fib_entry_contribute_ip_forwarding(fei);
4822 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4823 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4824 "2001:0:0:2/64 not resolves via drop");
4826 connected_pfx.fp_len = 128;
4827 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4828 FIB_SOURCE_INTERFACE,
4829 (FIB_ENTRY_FLAG_CONNECTED |
4830 FIB_ENTRY_FLAG_LOCAL),
4833 tm->hw[0]->sw_if_index,
4834 ~0, // invalid fib index
4837 FIB_ROUTE_PATH_FLAG_NONE);
4838 fei = fib_table_lookup(fib_index, &connected_pfx);
4840 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4841 dpo = fib_entry_contribute_ip_forwarding(fei);
4842 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4843 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4844 "local interface adj is local");
4845 rd = receive_dpo_get(dpo->dpoi_index);
4846 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4848 "local interface adj is receive ok");
4851 * +2 entries, +2 unshared path-lists
4853 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4854 fib_path_list_db_size());
4855 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4856 fib_path_list_pool_size());
4857 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4858 fib_entry_pool_size());
4862 * bring the interface back up. we expected the routes to return
4863 * to normal forwarding.
4865 error = vnet_sw_interface_set_flags(vnet_get_main(),
4866 tm->hw[0]->sw_if_index,
4867 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4868 FIB_TEST((NULL == error), "Interface bring-up OK");
4869 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4870 ai = fib_entry_get_adj(fei);
4871 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4872 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4873 ai = fib_entry_get_adj(fei);
4874 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4875 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4876 ai = fib_entry_get_adj(fei);
4877 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4878 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4879 ai = fib_entry_get_adj(fei);
4880 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4881 local_pfx.fp_len = 64;
4882 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4883 ai = fib_entry_get_adj(fei);
4885 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4886 "attached interface adj is glean");
4889 * Same test as above, but this time the HW interface goes down
4891 error = vnet_hw_interface_set_flags(vnet_get_main(),
4892 tm->hw_if_indicies[0],
4893 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4894 FIB_TEST((NULL == error), "Interface shutdown OK");
4896 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4897 dpo = fib_entry_contribute_ip_forwarding(fei);
4898 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4899 "2001::b/64 resolves via drop");
4900 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4901 dpo = fib_entry_contribute_ip_forwarding(fei);
4902 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4903 "2001::a/64 resolves via drop");
4904 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4905 dpo = fib_entry_contribute_ip_forwarding(fei);
4906 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4907 "2001:0:0:1::3/128 resolves via drop");
4908 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4909 dpo = fib_entry_contribute_ip_forwarding(fei);
4910 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4911 "2001:0:0:1::2/128 resolves via drop");
4912 local_pfx.fp_len = 128;
4913 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4914 dpo = fib_entry_contribute_ip_forwarding(fei);
4915 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4916 "2001:0:0:1::1/128 not drop");
4917 local_pfx.fp_len = 64;
4918 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4919 dpo = fib_entry_contribute_ip_forwarding(fei);
4920 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4921 "2001:0:0:1/64 resolves via drop");
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 bring-up OK");
4927 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4928 ai = fib_entry_get_adj(fei);
4929 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4930 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4931 ai = fib_entry_get_adj(fei);
4932 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4933 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4934 ai = fib_entry_get_adj(fei);
4935 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4936 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4937 ai = fib_entry_get_adj(fei);
4938 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4939 local_pfx.fp_len = 64;
4940 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4941 ai = fib_entry_get_adj(fei);
4943 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4944 "attached interface adj is glean");
4947 * Delete the interface that the routes reolve through.
4948 * Again no routes are removed. They all point to drop.
4950 * This is considered an error case. The control plane should
4951 * not remove interfaces through which routes resolve, but
4952 * such things can happen. ALL affected routes will drop.
4954 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4956 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4957 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4958 "2001::b/64 resolves via drop");
4959 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4960 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4961 "2001::b/64 resolves via drop");
4962 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4963 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4964 "2001:0:0:1::3/64 resolves via drop");
4965 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4966 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4967 "2001:0:0:1::2/64 resolves via drop");
4968 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4969 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4970 "2001:0:0:1::1/128 is drop");
4971 local_pfx.fp_len = 64;
4972 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4973 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4974 "2001:0:0:1/64 resolves via drop");
4979 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4980 fib_path_list_db_size());
4981 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4982 fib_path_list_pool_size());
4983 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4984 fib_entry_pool_size());
4987 * Add the interface back. routes stay unresolved.
4989 error = ethernet_register_interface(vnet_get_main(),
4990 test_interface_device_class.index,
4993 &tm->hw_if_indicies[0],
4994 /* flag change */ 0);
4996 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4997 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4998 "2001::b/64 resolves via drop");
4999 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5000 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5001 "2001::b/64 resolves via drop");
5002 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5003 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5004 "2001:0:0:1::3/64 resolves via drop");
5005 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5006 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5007 "2001:0:0:1::2/64 resolves via drop");
5008 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5009 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5010 "2001:0:0:1::1/128 is drop");
5011 local_pfx.fp_len = 64;
5012 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5013 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5014 "2001:0:0:1/64 resolves via drop");
5017 * CLEANUP ALL the routes
5019 fib_table_entry_delete(fib_index,
5022 fib_table_entry_delete(fib_index,
5025 fib_table_entry_delete(fib_index,
5028 fib_table_entry_delete(fib_index,
5029 &pfx_2001_1_3_s_128,
5031 fib_table_entry_delete(fib_index,
5032 &pfx_2001_1_2_s_128,
5034 local_pfx.fp_len = 64;
5035 fib_table_entry_delete(fib_index, &local_pfx,
5036 FIB_SOURCE_INTERFACE);
5037 local_pfx.fp_len = 128;
5038 fib_table_entry_special_remove(fib_index, &local_pfx,
5039 FIB_SOURCE_INTERFACE);
5040 connected_pfx.fp_len = 64;
5041 fib_table_entry_delete(fib_index, &connected_pfx,
5042 FIB_SOURCE_INTERFACE);
5043 connected_pfx.fp_len = 128;
5044 fib_table_entry_special_remove(fib_index, &connected_pfx,
5045 FIB_SOURCE_INTERFACE);
5047 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5048 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
5049 "2001::a/64 removed");
5050 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5051 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
5052 "2001::b/64 removed");
5053 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5054 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
5055 "2001:0:0:1::3/128 removed");
5056 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5057 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
5058 "2001:0:0:1::3/128 removed");
5059 local_pfx.fp_len = 64;
5060 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5061 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5062 "2001:0:0:1/64 removed");
5063 local_pfx.fp_len = 128;
5064 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5065 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5066 "2001:0:0:1::1/128 removed");
5067 connected_pfx.fp_len = 64;
5068 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5069 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5070 "2001:0:0:2/64 removed");
5071 connected_pfx.fp_len = 128;
5072 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5073 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5074 "2001:0:0:2::1/128 removed");
5077 * -8 entries. -7 path-lists (1 was shared).
5079 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5080 fib_path_list_db_size());
5081 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5082 fib_path_list_pool_size());
5083 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5084 fib_entry_pool_size());
5087 * now remove the VRF
5089 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
5091 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5092 fib_path_list_db_size());
5093 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5094 fib_path_list_pool_size());
5095 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5096 fib_entry_pool_size());
5102 * return the interfaces to up state
5104 error = vnet_sw_interface_set_flags(vnet_get_main(),
5105 tm->hw[0]->sw_if_index,
5106 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5107 error = vnet_sw_interface_set_flags(vnet_get_main(),
5108 tm->hw[1]->sw_if_index,
5109 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5111 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5118 * Test Attached Exports
5123 const dpo_id_t *dpo, *dpo_drop;
5124 const u32 fib_index = 0;
5125 fib_node_index_t fei;
5132 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5136 * add interface routes. We'll assume this works. It's more rigorously
5139 fib_prefix_t local_pfx = {
5141 .fp_proto = FIB_PROTOCOL_IP4,
5145 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5150 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5151 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5153 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5155 fib_table_entry_update_one_path(fib_index, &local_pfx,
5156 FIB_SOURCE_INTERFACE,
5157 (FIB_ENTRY_FLAG_CONNECTED |
5158 FIB_ENTRY_FLAG_ATTACHED),
5161 tm->hw[0]->sw_if_index,
5165 FIB_ROUTE_PATH_FLAG_NONE);
5166 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5167 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5168 "attached interface route present");
5170 local_pfx.fp_len = 32;
5171 fib_table_entry_update_one_path(fib_index, &local_pfx,
5172 FIB_SOURCE_INTERFACE,
5173 (FIB_ENTRY_FLAG_CONNECTED |
5174 FIB_ENTRY_FLAG_LOCAL),
5177 tm->hw[0]->sw_if_index,
5178 ~0, // invalid fib index
5181 FIB_ROUTE_PATH_FLAG_NONE);
5182 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5184 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5185 "local interface route present");
5188 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5190 fib_prefix_t pfx_10_10_10_1_s_32 = {
5192 .fp_proto = FIB_PROTOCOL_IP4,
5195 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5198 fib_node_index_t ai;
5200 fib_table_entry_path_add(fib_index,
5201 &pfx_10_10_10_1_s_32,
5203 FIB_ENTRY_FLAG_ATTACHED,
5205 &pfx_10_10_10_1_s_32.fp_addr,
5206 tm->hw[0]->sw_if_index,
5207 ~0, // invalid fib index
5210 FIB_ROUTE_PATH_FLAG_NONE);
5212 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5213 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5214 ai = fib_entry_get_adj(fei);
5217 * create another FIB table into which routes will be imported
5219 u32 import_fib_index1;
5221 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
5226 * Add an attached route in the import FIB
5228 local_pfx.fp_len = 24;
5229 fib_table_entry_update_one_path(import_fib_index1,
5232 FIB_ENTRY_FLAG_NONE,
5235 tm->hw[0]->sw_if_index,
5236 ~0, // invalid fib index
5239 FIB_ROUTE_PATH_FLAG_NONE);
5240 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5241 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5244 * check for the presence of the adj-fibs in the import table
5246 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5247 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5248 FIB_TEST((ai == fib_entry_get_adj(fei)),
5249 "adj-fib1 Import uses same adj as export");
5252 * check for the presence of the local in the import table
5254 local_pfx.fp_len = 32;
5255 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5256 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5259 * Add another adj-fin in the export table. Expect this
5260 * to get magically exported;
5262 fib_prefix_t pfx_10_10_10_2_s_32 = {
5264 .fp_proto = FIB_PROTOCOL_IP4,
5267 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5271 fib_table_entry_path_add(fib_index,
5272 &pfx_10_10_10_2_s_32,
5274 FIB_ENTRY_FLAG_ATTACHED,
5276 &pfx_10_10_10_2_s_32.fp_addr,
5277 tm->hw[0]->sw_if_index,
5278 ~0, // invalid fib index
5281 FIB_ROUTE_PATH_FLAG_NONE);
5282 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5283 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5284 ai = fib_entry_get_adj(fei);
5286 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5287 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5288 FIB_TEST((ai == fib_entry_get_adj(fei)),
5289 "Import uses same adj as export");
5290 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5291 "ADJ-fib2 imported flags %d",
5292 fib_entry_get_flags(fei));
5295 * create a 2nd FIB table into which routes will be imported
5297 u32 import_fib_index2;
5299 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
5303 * Add an attached route in the import FIB
5305 local_pfx.fp_len = 24;
5306 fib_table_entry_update_one_path(import_fib_index2,
5309 FIB_ENTRY_FLAG_NONE,
5312 tm->hw[0]->sw_if_index,
5313 ~0, // invalid fib index
5316 FIB_ROUTE_PATH_FLAG_NONE);
5317 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5318 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5321 * check for the presence of all the adj-fibs and local in the import table
5323 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5324 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5325 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5326 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5327 local_pfx.fp_len = 32;
5328 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5329 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5332 * add a 3rd adj-fib. expect it to be exported to both tables.
5334 fib_prefix_t pfx_10_10_10_3_s_32 = {
5336 .fp_proto = FIB_PROTOCOL_IP4,
5339 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5343 fib_table_entry_path_add(fib_index,
5344 &pfx_10_10_10_3_s_32,
5346 FIB_ENTRY_FLAG_ATTACHED,
5348 &pfx_10_10_10_3_s_32.fp_addr,
5349 tm->hw[0]->sw_if_index,
5350 ~0, // invalid fib index
5353 FIB_ROUTE_PATH_FLAG_NONE);
5354 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5355 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5356 ai = fib_entry_get_adj(fei);
5358 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5359 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5360 FIB_TEST((ai == fib_entry_get_adj(fei)),
5361 "Import uses same adj as export");
5362 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5363 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5364 FIB_TEST((ai == fib_entry_get_adj(fei)),
5365 "Import uses same adj as export");
5368 * remove the 3rd adj fib. we expect it to be removed from both FIBs
5370 fib_table_entry_delete(fib_index,
5371 &pfx_10_10_10_3_s_32,
5374 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5375 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5377 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5378 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5380 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5381 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5384 * remove the attached route from the 2nd FIB. expect the imported
5385 * entires to be removed
5387 local_pfx.fp_len = 24;
5388 fib_table_entry_delete(import_fib_index2,
5391 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5392 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5394 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5395 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5396 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5397 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5398 local_pfx.fp_len = 32;
5399 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5400 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5402 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5403 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5404 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5405 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5406 local_pfx.fp_len = 32;
5407 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5408 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5411 * modify the route in FIB1 so it is no longer attached. expect the imported
5412 * entires to be removed
5414 local_pfx.fp_len = 24;
5415 fib_table_entry_update_one_path(import_fib_index1,
5418 FIB_ENTRY_FLAG_NONE,
5420 &pfx_10_10_10_2_s_32.fp_addr,
5421 tm->hw[0]->sw_if_index,
5422 ~0, // invalid fib index
5425 FIB_ROUTE_PATH_FLAG_NONE);
5426 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5427 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5428 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5429 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5430 local_pfx.fp_len = 32;
5431 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5432 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5435 * modify it back to attached. expect the adj-fibs back
5437 local_pfx.fp_len = 24;
5438 fib_table_entry_update_one_path(import_fib_index1,
5441 FIB_ENTRY_FLAG_NONE,
5444 tm->hw[0]->sw_if_index,
5445 ~0, // invalid fib index
5448 FIB_ROUTE_PATH_FLAG_NONE);
5449 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5450 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5451 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5452 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5453 local_pfx.fp_len = 32;
5454 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5455 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5458 * add a covering attached next-hop for the interface address, so we have
5459 * a valid adj to find when we check the forwarding tables
5461 fib_prefix_t pfx_10_0_0_0_s_8 = {
5463 .fp_proto = FIB_PROTOCOL_IP4,
5466 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5470 fei = fib_table_entry_update_one_path(fib_index,
5473 FIB_ENTRY_FLAG_NONE,
5475 &pfx_10_10_10_3_s_32.fp_addr,
5476 tm->hw[0]->sw_if_index,
5477 ~0, // invalid fib index
5480 FIB_ROUTE_PATH_FLAG_NONE);
5481 dpo = fib_entry_contribute_ip_forwarding(fei);
5484 * remove the route in the export fib. expect the adj-fibs to be removed
5486 local_pfx.fp_len = 24;
5487 fib_table_entry_delete(fib_index,
5489 FIB_SOURCE_INTERFACE);
5491 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5492 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5493 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5494 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5495 local_pfx.fp_len = 32;
5496 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5497 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5500 * the adj-fibs in the export VRF are present in the FIB table,
5501 * but not installed in forwarding, since they have no attached cover.
5502 * Consequently a lookup in the MTRIE gives the adj for the covering
5505 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5506 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5509 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5510 FIB_TEST(lbi == dpo->dpoi_index,
5511 "10.10.10.1 forwards on \n%U not \n%U",
5512 format_load_balance, lbi, 0,
5513 format_dpo_id, dpo, 0);
5514 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5515 FIB_TEST(lbi == dpo->dpoi_index,
5516 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5517 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5518 FIB_TEST(lbi == dpo->dpoi_index,
5519 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5522 * add the export prefix back, but not as attached.
5523 * No adj-fibs in export nor import tables
5525 local_pfx.fp_len = 24;
5526 fei = fib_table_entry_update_one_path(fib_index,
5529 FIB_ENTRY_FLAG_NONE,
5531 &pfx_10_10_10_1_s_32.fp_addr,
5532 tm->hw[0]->sw_if_index,
5533 ~0, // invalid fib index
5536 FIB_ROUTE_PATH_FLAG_NONE);
5537 dpo = fib_entry_contribute_ip_forwarding(fei);
5539 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5540 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: 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 %U", format_dpo_id, dpo, 0);
5544 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5545 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
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);
5550 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5551 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5552 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5553 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5554 local_pfx.fp_len = 32;
5555 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5556 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5559 * modify the export prefix so it is attached. expect all covereds to return
5561 local_pfx.fp_len = 24;
5562 fib_table_entry_update_one_path(fib_index,
5565 FIB_ENTRY_FLAG_NONE,
5568 tm->hw[0]->sw_if_index,
5569 ~0, // invalid fib index
5572 FIB_ROUTE_PATH_FLAG_NONE);
5574 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5575 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5576 dpo = fib_entry_contribute_ip_forwarding(fei);
5577 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5578 "Adj-fib1 is not drop in export");
5579 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5580 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5581 local_pfx.fp_len = 32;
5582 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5583 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5584 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5585 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5586 dpo = fib_entry_contribute_ip_forwarding(fei);
5587 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5588 "Adj-fib1 is not drop in export");
5589 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5590 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5591 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5592 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5593 local_pfx.fp_len = 32;
5594 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5595 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5598 * modify the export prefix so connected. no change.
5600 local_pfx.fp_len = 24;
5601 fib_table_entry_update_one_path(fib_index, &local_pfx,
5602 FIB_SOURCE_INTERFACE,
5603 (FIB_ENTRY_FLAG_CONNECTED |
5604 FIB_ENTRY_FLAG_ATTACHED),
5607 tm->hw[0]->sw_if_index,
5611 FIB_ROUTE_PATH_FLAG_NONE);
5613 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5614 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5615 dpo = fib_entry_contribute_ip_forwarding(fei);
5616 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5617 "Adj-fib1 is not drop in export");
5618 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5619 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5620 local_pfx.fp_len = 32;
5621 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5622 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5623 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5624 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5625 dpo = fib_entry_contribute_ip_forwarding(fei);
5626 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5627 "Adj-fib1 is not drop in export");
5628 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5629 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5630 local_pfx.fp_len = 32;
5631 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5632 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5637 fib_table_entry_delete(fib_index,
5640 fib_table_entry_delete(fib_index,
5641 &pfx_10_10_10_1_s_32,
5643 fib_table_entry_delete(fib_index,
5644 &pfx_10_10_10_2_s_32,
5646 local_pfx.fp_len = 32;
5647 fib_table_entry_delete(fib_index,
5649 FIB_SOURCE_INTERFACE);
5650 local_pfx.fp_len = 24;
5651 fib_table_entry_delete(fib_index,
5654 fib_table_entry_delete(fib_index,
5656 FIB_SOURCE_INTERFACE);
5657 local_pfx.fp_len = 24;
5658 fib_table_entry_delete(import_fib_index1,
5662 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5663 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5665 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5672 * Test Path Preference
5675 fib_test_pref (void)
5677 test_main_t *tm = &test_main;
5679 const fib_prefix_t pfx_1_1_1_1_s_32 = {
5681 .fp_proto = FIB_PROTOCOL_IP4,
5684 .as_u32 = clib_host_to_net_u32(0x01010101),
5690 * 2 high, 2 medium and 2 low preference non-recursive paths
5692 fib_route_path_t nr_path_hi_1 = {
5693 .frp_proto = DPO_PROTO_IP4,
5694 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5695 .frp_fib_index = ~0,
5697 .frp_preference = 0,
5698 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5700 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5703 fib_route_path_t nr_path_hi_2 = {
5704 .frp_proto = DPO_PROTO_IP4,
5705 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5706 .frp_fib_index = ~0,
5708 .frp_preference = 0,
5709 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5711 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5714 fib_route_path_t nr_path_med_1 = {
5715 .frp_proto = DPO_PROTO_IP4,
5716 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5717 .frp_fib_index = ~0,
5719 .frp_preference = 1,
5720 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5722 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5725 fib_route_path_t nr_path_med_2 = {
5726 .frp_proto = DPO_PROTO_IP4,
5727 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5728 .frp_fib_index = ~0,
5730 .frp_preference = 1,
5731 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5733 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5736 fib_route_path_t nr_path_low_1 = {
5737 .frp_proto = DPO_PROTO_IP4,
5738 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5739 .frp_fib_index = ~0,
5741 .frp_preference = 2,
5742 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5744 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5747 fib_route_path_t nr_path_low_2 = {
5748 .frp_proto = DPO_PROTO_IP4,
5749 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5750 .frp_fib_index = ~0,
5752 .frp_preference = 2,
5753 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5755 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5758 fib_route_path_t *nr_paths = NULL;
5760 vec_add1(nr_paths, nr_path_hi_1);
5761 vec_add1(nr_paths, nr_path_hi_2);
5762 vec_add1(nr_paths, nr_path_med_1);
5763 vec_add1(nr_paths, nr_path_med_2);
5764 vec_add1(nr_paths, nr_path_low_1);
5765 vec_add1(nr_paths, nr_path_low_2);
5767 adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5769 &nr_path_hi_1.frp_addr,
5770 nr_path_hi_1.frp_sw_if_index);
5771 adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5773 &nr_path_hi_2.frp_addr,
5774 nr_path_hi_2.frp_sw_if_index);
5775 adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5777 &nr_path_med_1.frp_addr,
5778 nr_path_med_1.frp_sw_if_index);
5779 adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5781 &nr_path_med_2.frp_addr,
5782 nr_path_med_2.frp_sw_if_index);
5783 adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5785 &nr_path_low_1.frp_addr,
5786 nr_path_low_1.frp_sw_if_index);
5787 adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5789 &nr_path_low_2.frp_addr,
5790 nr_path_low_2.frp_sw_if_index);
5792 fib_test_lb_bucket_t ip_hi_1 = {
5798 fib_test_lb_bucket_t ip_hi_2 = {
5804 fib_test_lb_bucket_t ip_med_1 = {
5810 fib_test_lb_bucket_t ip_med_2 = {
5816 fib_test_lb_bucket_t ip_low_1 = {
5822 fib_test_lb_bucket_t ip_low_2 = {
5829 fib_node_index_t fei;
5831 fei = fib_table_entry_path_add2(0,
5834 FIB_ENTRY_FLAG_NONE,
5837 FIB_TEST(fib_test_validate_entry(fei,
5838 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5842 "1.1.1.1/32 via high preference paths");
5845 * bring down the interface on which the high preference path lie
5847 vnet_sw_interface_set_flags(vnet_get_main(),
5848 tm->hw[0]->sw_if_index,
5851 FIB_TEST(fib_test_validate_entry(fei,
5852 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5856 "1.1.1.1/32 via medium preference paths");
5859 * bring down the interface on which the medium preference path lie
5861 vnet_sw_interface_set_flags(vnet_get_main(),
5862 tm->hw[1]->sw_if_index,
5865 FIB_TEST(fib_test_validate_entry(fei,
5866 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5870 "1.1.1.1/32 via low preference paths");
5873 * bring up the interface on which the high preference path lie
5875 vnet_sw_interface_set_flags(vnet_get_main(),
5876 tm->hw[0]->sw_if_index,
5877 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5879 FIB_TEST(fib_test_validate_entry(fei,
5880 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5884 "1.1.1.1/32 via high preference paths");
5887 * bring up the interface on which the medium preference path lie
5889 vnet_sw_interface_set_flags(vnet_get_main(),
5890 tm->hw[1]->sw_if_index,
5891 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5893 FIB_TEST(fib_test_validate_entry(fei,
5894 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5898 "1.1.1.1/32 via high preference paths");
5900 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
5901 fib_entry_contribute_forwarding(fei,
5902 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5906 * 3 recursive paths of different preference
5908 const fib_prefix_t pfx_1_1_1_2_s_32 = {
5910 .fp_proto = FIB_PROTOCOL_IP4,
5913 .as_u32 = clib_host_to_net_u32(0x01010102),
5917 const fib_prefix_t pfx_1_1_1_3_s_32 = {
5919 .fp_proto = FIB_PROTOCOL_IP4,
5922 .as_u32 = clib_host_to_net_u32(0x01010103),
5926 fei = fib_table_entry_path_add2(0,
5929 FIB_ENTRY_FLAG_NONE,
5931 dpo_id_t ip_1_1_1_2 = DPO_INVALID;
5932 fib_entry_contribute_forwarding(fei,
5933 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5935 fei = fib_table_entry_path_add2(0,
5938 FIB_ENTRY_FLAG_NONE,
5940 dpo_id_t ip_1_1_1_3 = DPO_INVALID;
5941 fib_entry_contribute_forwarding(fei,
5942 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5945 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5948 .lb = ip_1_1_1_1.dpoi_index,
5951 fib_test_lb_bucket_t ip_o_1_1_1_2 = {
5954 .lb = ip_1_1_1_2.dpoi_index,
5957 fib_test_lb_bucket_t ip_o_1_1_1_3 = {
5960 .lb = ip_1_1_1_3.dpoi_index,
5963 fib_route_path_t r_path_hi = {
5964 .frp_proto = DPO_PROTO_IP4,
5965 .frp_sw_if_index = ~0,
5968 .frp_preference = 0,
5969 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5970 .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
5972 fib_route_path_t r_path_med = {
5973 .frp_proto = DPO_PROTO_IP4,
5974 .frp_sw_if_index = ~0,
5977 .frp_preference = 10,
5978 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5979 .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
5981 fib_route_path_t r_path_low = {
5982 .frp_proto = DPO_PROTO_IP4,
5983 .frp_sw_if_index = ~0,
5986 .frp_preference = 255,
5987 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5988 .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
5990 fib_route_path_t *r_paths = NULL;
5992 vec_add1(r_paths, r_path_hi);
5993 vec_add1(r_paths, r_path_low);
5994 vec_add1(r_paths, r_path_med);
5997 * add many recursive so we get the LB MAp created
6000 fib_prefix_t pfx_r[N_PFXS];
6001 unsigned int n_pfxs;
6002 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6004 pfx_r[n_pfxs].fp_len = 32;
6005 pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
6006 pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
6007 clib_host_to_net_u32(0x02000000 + n_pfxs);
6009 fei = fib_table_entry_path_add2(0,
6012 FIB_ENTRY_FLAG_NONE,
6015 FIB_TEST(fib_test_validate_entry(fei,
6016 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6019 "recursive via high preference paths");
6022 * withdraw hig pref resolving entry
6024 fib_table_entry_delete(0,
6028 /* suspend so the update walk kicks int */
6029 vlib_process_suspend(vlib_get_main(), 1e-5);
6031 FIB_TEST(fib_test_validate_entry(fei,
6032 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6035 "recursive via medium preference paths");
6038 * withdraw medium pref resolving entry
6040 fib_table_entry_delete(0,
6044 /* suspend so the update walk kicks int */
6045 vlib_process_suspend(vlib_get_main(), 1e-5);
6047 FIB_TEST(fib_test_validate_entry(fei,
6048 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6051 "recursive via low preference paths");
6054 * add back paths for next iteration
6056 fei = fib_table_entry_update(0,
6059 FIB_ENTRY_FLAG_NONE,
6061 fei = fib_table_entry_update(0,
6064 FIB_ENTRY_FLAG_NONE,
6067 /* suspend so the update walk kicks int */
6068 vlib_process_suspend(vlib_get_main(), 1e-5);
6070 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6071 FIB_TEST(fib_test_validate_entry(fei,
6072 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6075 "recursive via high preference paths");
6079 fib_table_entry_delete(0,
6083 /* suspend so the update walk kicks int */
6084 vlib_process_suspend(vlib_get_main(), 1e-5);
6086 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6088 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6090 FIB_TEST(fib_test_validate_entry(fei,
6091 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6094 "recursive via medium preference paths");
6096 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6098 fib_table_entry_delete(0,
6106 fib_table_entry_delete(0,
6109 fib_table_entry_delete(0,
6113 dpo_reset(&ip_1_1_1_1);
6114 dpo_reset(&ip_1_1_1_2);
6115 dpo_reset(&ip_1_1_1_3);
6116 adj_unlock(ai_low_2);
6117 adj_unlock(ai_low_1);
6118 adj_unlock(ai_med_2);
6119 adj_unlock(ai_med_1);
6120 adj_unlock(ai_hi_2);
6121 adj_unlock(ai_hi_1);
6126 * Test the recursive route route handling for GRE tunnels
6129 fib_test_label (void)
6131 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;
6132 const u32 fib_index = 0;
6137 lb_count = pool_elts(load_balance_pool);
6142 * add interface routes. We'll assume this works. It's more rigorously
6145 fib_prefix_t local0_pfx = {
6147 .fp_proto = FIB_PROTOCOL_IP4,
6151 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6156 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6159 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6160 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6162 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6163 FIB_SOURCE_INTERFACE,
6164 (FIB_ENTRY_FLAG_CONNECTED |
6165 FIB_ENTRY_FLAG_ATTACHED),
6168 tm->hw[0]->sw_if_index,
6172 FIB_ROUTE_PATH_FLAG_NONE);
6173 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6174 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6175 "attached interface route present");
6177 local0_pfx.fp_len = 32;
6178 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6179 FIB_SOURCE_INTERFACE,
6180 (FIB_ENTRY_FLAG_CONNECTED |
6181 FIB_ENTRY_FLAG_LOCAL),
6184 tm->hw[0]->sw_if_index,
6185 ~0, // invalid fib index
6188 FIB_ROUTE_PATH_FLAG_NONE);
6189 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6191 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6192 "local interface route present");
6194 fib_prefix_t local1_pfx = {
6196 .fp_proto = FIB_PROTOCOL_IP4,
6200 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6205 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6206 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6208 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6209 FIB_SOURCE_INTERFACE,
6210 (FIB_ENTRY_FLAG_CONNECTED |
6211 FIB_ENTRY_FLAG_ATTACHED),
6214 tm->hw[1]->sw_if_index,
6218 FIB_ROUTE_PATH_FLAG_NONE);
6219 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6220 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6221 "attached interface route present");
6223 local1_pfx.fp_len = 32;
6224 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6225 FIB_SOURCE_INTERFACE,
6226 (FIB_ENTRY_FLAG_CONNECTED |
6227 FIB_ENTRY_FLAG_LOCAL),
6230 tm->hw[1]->sw_if_index,
6231 ~0, // invalid fib index
6234 FIB_ROUTE_PATH_FLAG_NONE);
6235 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6237 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6238 "local interface route present");
6240 ip46_address_t nh_10_10_10_1 = {
6242 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6245 ip46_address_t nh_10_10_11_1 = {
6247 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6250 ip46_address_t nh_10_10_11_2 = {
6252 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6256 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6259 tm->hw[1]->sw_if_index);
6260 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6263 tm->hw[1]->sw_if_index);
6264 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6267 tm->hw[0]->sw_if_index);
6268 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6271 tm->hw[1]->sw_if_index);
6272 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6275 tm->hw[1]->sw_if_index);
6278 * Add an etry with one path with a real out-going label
6280 fib_prefix_t pfx_1_1_1_1_s_32 = {
6282 .fp_proto = FIB_PROTOCOL_IP4,
6284 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6287 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6288 .type = FT_LB_LABEL_O_ADJ,
6290 .adj = ai_mpls_10_10_10_1,
6295 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6296 .type = FT_LB_LABEL_O_ADJ,
6298 .adj = ai_mpls_10_10_10_1,
6300 .eos = MPLS_NON_EOS,
6303 mpls_label_t *l99 = NULL;
6306 fib_table_entry_update_one_path(fib_index,
6309 FIB_ENTRY_FLAG_NONE,
6312 tm->hw[0]->sw_if_index,
6313 ~0, // invalid fib index
6316 FIB_ROUTE_PATH_FLAG_NONE);
6318 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6319 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6321 FIB_TEST(fib_test_validate_entry(fei,
6322 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6324 &l99_eos_o_10_10_10_1),
6325 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6328 * add a path with an implicit NULL label
6330 fib_test_lb_bucket_t a_o_10_10_11_1 = {
6333 .adj = ai_v4_10_10_11_1,
6336 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6339 .adj = ai_mpls_10_10_11_1,
6342 mpls_label_t *l_imp_null = NULL;
6343 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6345 fei = fib_table_entry_path_add(fib_index,
6348 FIB_ENTRY_FLAG_NONE,
6351 tm->hw[1]->sw_if_index,
6352 ~0, // invalid fib index
6355 FIB_ROUTE_PATH_FLAG_NONE);
6357 FIB_TEST(fib_test_validate_entry(fei,
6358 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6360 &l99_eos_o_10_10_10_1,
6362 "1.1.1.1/32 LB 2 buckets via: "
6363 "label 99 over 10.10.10.1, "
6364 "adj over 10.10.11.1");
6367 * assign the route a local label
6369 fib_table_entry_local_label_add(fib_index,
6373 fib_prefix_t pfx_24001_eos = {
6374 .fp_proto = FIB_PROTOCOL_MPLS,
6378 fib_prefix_t pfx_24001_neos = {
6379 .fp_proto = FIB_PROTOCOL_MPLS,
6381 .fp_eos = MPLS_NON_EOS,
6385 * The EOS entry should link to both the paths,
6386 * and use an ip adj for the imp-null
6387 * The NON-EOS entry should link to both the paths,
6388 * and use an mpls adj for the imp-null
6390 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6392 FIB_TEST(fib_test_validate_entry(fei,
6393 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6395 &l99_eos_o_10_10_10_1,
6397 "24001/eos LB 2 buckets via: "
6398 "label 99 over 10.10.10.1, "
6399 "adj over 10.10.11.1");
6402 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6404 FIB_TEST(fib_test_validate_entry(fei,
6405 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6407 &l99_neos_o_10_10_10_1,
6408 &a_mpls_o_10_10_11_1),
6409 "24001/neos LB 1 bucket via: "
6410 "label 99 over 10.10.10.1 ",
6411 "mpls-adj via 10.10.11.1");
6414 * add an unlabelled path, this is excluded from the neos chains,
6416 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6419 .adj = ai_v4_10_10_11_2,
6423 fei = fib_table_entry_path_add(fib_index,
6426 FIB_ENTRY_FLAG_NONE,
6429 tm->hw[1]->sw_if_index,
6430 ~0, // invalid fib index
6433 FIB_ROUTE_PATH_FLAG_NONE);
6435 FIB_TEST(fib_test_validate_entry(fei,
6436 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6437 16, // 3 choices spread over 16 buckets
6438 &l99_eos_o_10_10_10_1,
6439 &l99_eos_o_10_10_10_1,
6440 &l99_eos_o_10_10_10_1,
6441 &l99_eos_o_10_10_10_1,
6442 &l99_eos_o_10_10_10_1,
6443 &l99_eos_o_10_10_10_1,
6454 "1.1.1.1/32 LB 16 buckets via: "
6455 "label 99 over 10.10.10.1, "
6456 "adj over 10.10.11.1",
6457 "adj over 10.10.11.2");
6460 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6462 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6463 fib_entry_contribute_forwarding(fei,
6464 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6468 * n-eos has only the 2 labelled paths
6470 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6473 FIB_TEST(fib_test_validate_entry(fei,
6474 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6476 &l99_neos_o_10_10_10_1,
6477 &a_mpls_o_10_10_11_1),
6478 "24001/neos LB 2 buckets via: "
6479 "label 99 over 10.10.10.1, "
6480 "adj-mpls over 10.10.11.2");
6483 * A labelled recursive
6485 fib_prefix_t pfx_2_2_2_2_s_32 = {
6487 .fp_proto = FIB_PROTOCOL_IP4,
6489 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6492 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6493 .type = FT_LB_LABEL_O_LB,
6495 .lb = non_eos_1_1_1_1.dpoi_index,
6500 mpls_label_t *l1600 = NULL;
6501 vec_add1(l1600, 1600);
6503 fib_table_entry_update_one_path(fib_index,
6506 FIB_ENTRY_FLAG_NONE,
6508 &pfx_1_1_1_1_s_32.fp_addr,
6513 FIB_ROUTE_PATH_FLAG_NONE);
6515 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6516 FIB_TEST(fib_test_validate_entry(fei,
6517 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6519 &l1600_eos_o_1_1_1_1),
6520 "2.2.2.2.2/32 LB 1 buckets via: "
6521 "label 1600 over 1.1.1.1");
6523 dpo_id_t dpo_44 = DPO_INVALID;
6526 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6527 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6529 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6530 "uRPF check for 2.2.2.2/32 on %d OK",
6531 tm->hw[0]->sw_if_index);
6532 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6533 "uRPF check for 2.2.2.2/32 on %d OK",
6534 tm->hw[1]->sw_if_index);
6535 FIB_TEST(!fib_urpf_check(urpfi, 99),
6536 "uRPF check for 2.2.2.2/32 on 99 not-OK",
6539 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6540 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6541 "Shared uRPF on IP and non-EOS chain");
6546 * we are holding a lock on the non-eos LB of the via-entry.
6547 * do a PIC-core failover by shutting the link of the via-entry.
6549 * shut down the link with the valid label
6551 vnet_sw_interface_set_flags(vnet_get_main(),
6552 tm->hw[0]->sw_if_index,
6555 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6556 FIB_TEST(fib_test_validate_entry(fei,
6557 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6561 "1.1.1.1/32 LB 2 buckets via: "
6562 "adj over 10.10.11.1, ",
6563 "adj-v4 over 10.10.11.2");
6565 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6567 FIB_TEST(fib_test_validate_entry(fei,
6568 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6572 "24001/eos LB 2 buckets via: "
6573 "adj over 10.10.11.1, ",
6574 "adj-v4 over 10.10.11.2");
6576 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6578 FIB_TEST(fib_test_validate_entry(fei,
6579 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6581 &a_mpls_o_10_10_11_1),
6582 "24001/neos LB 1 buckets via: "
6583 "adj-mpls over 10.10.11.2");
6586 * test that the pre-failover load-balance has been in-place
6589 dpo_id_t current = DPO_INVALID;
6590 fib_entry_contribute_forwarding(fei,
6591 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6594 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6596 "PIC-core LB inplace modified %U %U",
6597 format_dpo_id, &non_eos_1_1_1_1, 0,
6598 format_dpo_id, ¤t, 0);
6600 dpo_reset(&non_eos_1_1_1_1);
6601 dpo_reset(¤t);
6604 * no-shut the link with the valid label
6606 vnet_sw_interface_set_flags(vnet_get_main(),
6607 tm->hw[0]->sw_if_index,
6608 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6610 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6611 FIB_TEST(fib_test_validate_entry(fei,
6612 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6613 16, // 3 choices spread over 16 buckets
6614 &l99_eos_o_10_10_10_1,
6615 &l99_eos_o_10_10_10_1,
6616 &l99_eos_o_10_10_10_1,
6617 &l99_eos_o_10_10_10_1,
6618 &l99_eos_o_10_10_10_1,
6619 &l99_eos_o_10_10_10_1,
6630 "1.1.1.1/32 LB 16 buckets via: "
6631 "label 99 over 10.10.10.1, "
6632 "adj over 10.10.11.1",
6633 "adj-v4 over 10.10.11.2");
6636 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6638 FIB_TEST(fib_test_validate_entry(fei,
6639 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6640 16, // 3 choices spread over 16 buckets
6641 &l99_eos_o_10_10_10_1,
6642 &l99_eos_o_10_10_10_1,
6643 &l99_eos_o_10_10_10_1,
6644 &l99_eos_o_10_10_10_1,
6645 &l99_eos_o_10_10_10_1,
6646 &l99_eos_o_10_10_10_1,
6657 "24001/eos LB 16 buckets via: "
6658 "label 99 over 10.10.10.1, "
6659 "adj over 10.10.11.1",
6660 "adj-v4 over 10.10.11.2");
6662 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6664 FIB_TEST(fib_test_validate_entry(fei,
6665 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6667 &l99_neos_o_10_10_10_1,
6668 &a_mpls_o_10_10_11_1),
6669 "24001/neos LB 2 buckets via: "
6670 "label 99 over 10.10.10.1, "
6671 "adj-mpls over 10.10.11.2");
6674 * remove the first path with the valid label
6676 fib_table_entry_path_remove(fib_index,
6681 tm->hw[0]->sw_if_index,
6682 ~0, // invalid fib index
6684 FIB_ROUTE_PATH_FLAG_NONE);
6686 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6687 FIB_TEST(fib_test_validate_entry(fei,
6688 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6692 "1.1.1.1/32 LB 2 buckets via: "
6693 "adj over 10.10.11.1, "
6694 "adj-v4 over 10.10.11.2");
6696 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6698 FIB_TEST(fib_test_validate_entry(fei,
6699 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6703 "24001/eos LB 2 buckets via: "
6704 "adj over 10.10.11.1, "
6705 "adj-v4 over 10.10.11.2");
6707 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6710 FIB_TEST(fib_test_validate_entry(fei,
6711 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6713 &a_mpls_o_10_10_11_1),
6714 "24001/neos LB 1 buckets via: "
6715 "adj-mpls over 10.10.11.2");
6718 * remove the other path with a valid label
6720 fib_test_lb_bucket_t bucket_drop = {
6723 fib_test_lb_bucket_t mpls_bucket_drop = {
6726 .adj = DPO_PROTO_MPLS,
6730 fib_table_entry_path_remove(fib_index,
6735 tm->hw[1]->sw_if_index,
6736 ~0, // invalid fib index
6738 FIB_ROUTE_PATH_FLAG_NONE);
6740 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6741 FIB_TEST(fib_test_validate_entry(fei,
6742 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6745 "1.1.1.1/32 LB 1 buckets via: "
6746 "adj over 10.10.11.2");
6748 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6750 FIB_TEST(fib_test_validate_entry(fei,
6751 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6754 "24001/eos LB 1 buckets via: "
6755 "adj over 10.10.11.2");
6757 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6759 FIB_TEST(fib_test_validate_entry(fei,
6760 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6763 "24001/neos LB 1 buckets via: DROP");
6766 * add back the path with the valid label
6771 fib_table_entry_path_add(fib_index,
6774 FIB_ENTRY_FLAG_NONE,
6777 tm->hw[0]->sw_if_index,
6778 ~0, // invalid fib index
6781 FIB_ROUTE_PATH_FLAG_NONE);
6783 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6784 FIB_TEST(fib_test_validate_entry(fei,
6785 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6787 &l99_eos_o_10_10_10_1,
6789 "1.1.1.1/32 LB 2 buckets via: "
6790 "label 99 over 10.10.10.1, "
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 &l99_eos_o_10_10_10_1,
6800 "24001/eos LB 2 buckets via: "
6801 "label 99 over 10.10.10.1, "
6802 "adj over 10.10.11.2");
6804 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6806 FIB_TEST(fib_test_validate_entry(fei,
6807 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6809 &l99_neos_o_10_10_10_1),
6810 "24001/neos LB 1 buckets via: "
6811 "label 99 over 10.10.10.1");
6814 * change the local label
6816 fib_table_entry_local_label_add(fib_index,
6820 fib_prefix_t pfx_25005_eos = {
6821 .fp_proto = FIB_PROTOCOL_MPLS,
6825 fib_prefix_t pfx_25005_neos = {
6826 .fp_proto = FIB_PROTOCOL_MPLS,
6828 .fp_eos = MPLS_NON_EOS,
6831 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6832 fib_table_lookup(fib_index, &pfx_24001_eos)),
6833 "24001/eos removed after label change");
6834 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6835 fib_table_lookup(fib_index, &pfx_24001_neos)),
6836 "24001/eos removed after label change");
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,
6845 "25005/eos LB 2 buckets via: "
6846 "label 99 over 10.10.10.1, "
6847 "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 "25005/neos LB 1 buckets via: "
6856 "label 99 over 10.10.10.1");
6859 * remove the local label.
6860 * the check that the MPLS entries are gone is done by the fact the
6861 * MPLS table is no longer present.
6863 fib_table_entry_local_label_remove(fib_index,
6867 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6868 FIB_TEST(fib_test_validate_entry(fei,
6869 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6871 &l99_eos_o_10_10_10_1,
6873 "24001/eos LB 2 buckets via: "
6874 "label 99 over 10.10.10.1, "
6875 "adj over 10.10.11.2");
6877 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6878 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6879 "No more MPLS FIB entries => table removed");
6882 * add another via-entry for the recursive
6884 fib_prefix_t pfx_1_1_1_2_s_32 = {
6886 .fp_proto = FIB_PROTOCOL_IP4,
6888 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6891 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6892 .type = FT_LB_LABEL_O_ADJ,
6894 .adj = ai_mpls_10_10_10_1,
6899 mpls_label_t *l101 = NULL;
6900 vec_add1(l101, 101);
6902 fei = fib_table_entry_update_one_path(fib_index,
6905 FIB_ENTRY_FLAG_NONE,
6908 tm->hw[0]->sw_if_index,
6909 ~0, // invalid fib index
6912 FIB_ROUTE_PATH_FLAG_NONE);
6914 FIB_TEST(fib_test_validate_entry(fei,
6915 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6917 &l101_eos_o_10_10_10_1),
6918 "1.1.1.2/32 LB 1 buckets via: "
6919 "label 101 over 10.10.10.1");
6921 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6922 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6924 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6926 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6928 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6931 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6932 .type = FT_LB_LABEL_O_LB,
6934 .lb = non_eos_1_1_1_2.dpoi_index,
6939 mpls_label_t *l1601 = NULL;
6940 vec_add1(l1601, 1601);
6942 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6944 fei = fib_table_entry_path_add(fib_index,
6947 FIB_ENTRY_FLAG_NONE,
6949 &pfx_1_1_1_2_s_32.fp_addr,
6954 FIB_ROUTE_PATH_FLAG_NONE);
6956 FIB_TEST(fib_test_validate_entry(fei,
6957 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6959 &l1600_eos_o_1_1_1_1,
6960 &l1601_eos_o_1_1_1_2),
6961 "2.2.2.2/32 LB 2 buckets via: "
6962 "label 1600 via 1.1,1.1, "
6963 "label 16001 via 1.1.1.2");
6966 * update the via-entry so it no longer has an imp-null path.
6967 * the LB for the recursive can use an imp-null
6970 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6972 fei = fib_table_entry_update_one_path(fib_index,
6975 FIB_ENTRY_FLAG_NONE,
6978 tm->hw[1]->sw_if_index,
6979 ~0, // invalid fib index
6982 FIB_ROUTE_PATH_FLAG_NONE);
6984 FIB_TEST(fib_test_validate_entry(fei,
6985 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6988 "1.1.1.2/32 LB 1 buckets via: "
6991 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6992 FIB_TEST(fib_test_validate_entry(fei,
6993 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6995 &l1600_eos_o_1_1_1_1,
6996 &l1601_eos_o_1_1_1_2),
6997 "2.2.2.2/32 LB 2 buckets via: "
6998 "label 1600 via 1.1,1.1, "
6999 "label 16001 via 1.1.1.2");
7002 * update the via-entry so it no longer has labelled paths.
7003 * the LB for the recursive should exclue this via form its LB
7005 fei = fib_table_entry_update_one_path(fib_index,
7008 FIB_ENTRY_FLAG_NONE,
7011 tm->hw[1]->sw_if_index,
7012 ~0, // invalid fib index
7015 FIB_ROUTE_PATH_FLAG_NONE);
7017 FIB_TEST(fib_test_validate_entry(fei,
7018 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7021 "1.1.1.2/32 LB 1 buckets via: "
7024 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7025 FIB_TEST(fib_test_validate_entry(fei,
7026 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7028 &l1600_eos_o_1_1_1_1),
7029 "2.2.2.2/32 LB 1 buckets via: "
7030 "label 1600 via 1.1,1.1");
7032 dpo_reset(&non_eos_1_1_1_1);
7033 dpo_reset(&non_eos_1_1_1_2);
7036 * Add a recursive with no out-labels. We expect to use the IP of the via
7038 fib_prefix_t pfx_2_2_2_3_s_32 = {
7040 .fp_proto = FIB_PROTOCOL_IP4,
7042 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7045 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
7047 fib_table_entry_update_one_path(fib_index,
7050 FIB_ENTRY_FLAG_NONE,
7052 &pfx_1_1_1_1_s_32.fp_addr,
7057 FIB_ROUTE_PATH_FLAG_NONE);
7059 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7061 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7064 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7067 .lb = ip_1_1_1_1.dpoi_index,
7071 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7072 FIB_TEST(fib_test_validate_entry(fei,
7073 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7076 "2.2.2.2.3/32 LB 1 buckets via: "
7080 * Add a recursive with an imp-null out-label.
7081 * We expect to use the IP of the via
7083 fib_prefix_t pfx_2_2_2_4_s_32 = {
7085 .fp_proto = FIB_PROTOCOL_IP4,
7087 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7091 fib_table_entry_update_one_path(fib_index,
7094 FIB_ENTRY_FLAG_NONE,
7096 &pfx_1_1_1_1_s_32.fp_addr,
7101 FIB_ROUTE_PATH_FLAG_NONE);
7103 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7104 FIB_TEST(fib_test_validate_entry(fei,
7105 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7108 "2.2.2.2.4/32 LB 1 buckets via: "
7111 dpo_reset(&ip_1_1_1_1);
7114 * Create an entry with a deep label stack
7116 fib_prefix_t pfx_2_2_5_5_s_32 = {
7118 .fp_proto = FIB_PROTOCOL_IP4,
7120 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7123 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7124 .type = FT_LB_LABEL_STACK_O_ADJ,
7125 .label_stack_o_adj = {
7126 .adj = ai_mpls_10_10_11_1,
7127 .label_stack_size = 8,
7129 200, 201, 202, 203, 204, 205, 206, 207
7134 mpls_label_t *label_stack = NULL;
7135 vec_validate(label_stack, 7);
7136 for (ii = 0; ii < 8; ii++)
7138 label_stack[ii] = ii + 200;
7141 fei = fib_table_entry_update_one_path(fib_index,
7144 FIB_ENTRY_FLAG_NONE,
7147 tm->hw[1]->sw_if_index,
7148 ~0, // invalid fib index
7151 FIB_ROUTE_PATH_FLAG_NONE);
7153 FIB_TEST(fib_test_validate_entry(fei,
7154 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7156 &ls_eos_o_10_10_10_1),
7157 "2.2.5.5/32 LB 1 buckets via: "
7159 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7164 fib_table_entry_delete(fib_index,
7168 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7169 FIB_TEST(fib_test_validate_entry(fei,
7170 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7172 &l1600_eos_o_1_1_1_1),
7173 "2.2.2.2/32 LB 1 buckets via: "
7174 "label 1600 via 1.1,1.1");
7176 fib_table_entry_delete(fib_index,
7180 FIB_TEST(fib_test_validate_entry(fei,
7181 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7184 "2.2.2.2/32 LB 1 buckets via: DROP");
7186 fib_table_entry_delete(fib_index,
7189 fib_table_entry_delete(fib_index,
7192 fib_table_entry_delete(fib_index,
7196 adj_unlock(ai_mpls_10_10_10_1);
7197 adj_unlock(ai_mpls_10_10_11_2);
7198 adj_unlock(ai_v4_10_10_11_1);
7199 adj_unlock(ai_v4_10_10_11_2);
7200 adj_unlock(ai_mpls_10_10_11_1);
7202 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7205 local0_pfx.fp_len = 32;
7206 fib_table_entry_delete(fib_index,
7208 FIB_SOURCE_INTERFACE);
7209 local0_pfx.fp_len = 24;
7210 fib_table_entry_delete(fib_index,
7212 FIB_SOURCE_INTERFACE);
7213 local1_pfx.fp_len = 32;
7214 fib_table_entry_delete(fib_index,
7216 FIB_SOURCE_INTERFACE);
7217 local1_pfx.fp_len = 24;
7218 fib_table_entry_delete(fib_index,
7220 FIB_SOURCE_INTERFACE);
7223 * +1 for the drop LB in the MPLS tables.
7225 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7226 "Load-balance resources freed %d of %d",
7227 lb_count+1, pool_elts(load_balance_pool));
7232 #define N_TEST_CHILDREN 4
7233 #define PARENT_INDEX 0
7235 typedef struct fib_node_test_t_
7240 fib_node_back_walk_ctx_t *ctxs;
7244 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7246 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7248 #define FOR_EACH_TEST_CHILD(_tc) \
7249 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
7250 ii < N_TEST_CHILDREN+1; \
7251 ii++, (_tc) = &fib_test_nodes[ii])
7254 fib_test_child_get_node (fib_node_index_t index)
7256 return (&fib_test_nodes[index].node);
7259 static int fib_test_walk_spawns_walks;
7261 static fib_node_back_walk_rc_t
7262 fib_test_child_back_walk_notify (fib_node_t *node,
7263 fib_node_back_walk_ctx_t *ctx)
7265 fib_node_test_t *tc = (fib_node_test_t*) node;
7267 vec_add1(tc->ctxs, *ctx);
7269 if (1 == fib_test_walk_spawns_walks)
7270 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7271 if (2 == fib_test_walk_spawns_walks)
7272 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7273 FIB_WALK_PRIORITY_HIGH, ctx);
7275 return (FIB_NODE_BACK_WALK_CONTINUE);
7279 fib_test_child_last_lock_gone (fib_node_t *node)
7281 fib_node_test_t *tc = (fib_node_test_t *)node;
7287 * The FIB walk's graph node virtual function table
7289 static const fib_node_vft_t fib_test_child_vft = {
7290 .fnv_get = fib_test_child_get_node,
7291 .fnv_last_lock = fib_test_child_last_lock_gone,
7292 .fnv_back_walk = fib_test_child_back_walk_notify,
7296 * the function (that should have been static but isn't so I can do this)
7297 * that processes the walk from the async queue,
7299 f64 fib_walk_process_queues(vlib_main_t * vm,
7301 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7304 fib_test_walk (void)
7306 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7307 fib_node_test_t *tc;
7311 vm = vlib_get_main();
7312 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7315 * init a fake node on which we will add children
7317 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7318 FIB_NODE_TYPE_TEST);
7320 FOR_EACH_TEST_CHILD(tc)
7322 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7323 fib_node_lock(&tc->node);
7326 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7328 FIB_NODE_TYPE_TEST, ii);
7332 * enqueue a walk across the parents children.
7334 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7336 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7337 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7338 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7339 "Parent has %d children pre-walk",
7340 fib_node_list_get_size(PARENT()->fn_children));
7343 * give the walk a large amount of time so it gets to the end
7345 fib_walk_process_queues(vm, 1);
7347 FOR_EACH_TEST_CHILD(tc)
7349 FIB_TEST(1 == vec_len(tc->ctxs),
7350 "%d child visitsed %d times",
7351 ii, vec_len(tc->ctxs));
7354 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7355 "Queue is empty post walk");
7356 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7357 "Parent has %d children post walk",
7358 fib_node_list_get_size(PARENT()->fn_children));
7361 * walk again. should be no increase in the number of visits, since
7362 * the walk will have terminated.
7364 fib_walk_process_queues(vm, 1);
7366 FOR_EACH_TEST_CHILD(tc)
7368 FIB_TEST(0 == vec_len(tc->ctxs),
7369 "%d child visitsed %d times",
7370 ii, vec_len(tc->ctxs));
7374 * schedule a low and hig priority walk. expect the high to be performed
7376 * schedule the high prio walk first so that it is further from the head
7377 * of the dependency list. that way it won't merge with the low one.
7379 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7380 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7382 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7383 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7384 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7385 FIB_WALK_PRIORITY_LOW, &low_ctx);
7387 fib_walk_process_queues(vm, 1);
7389 FOR_EACH_TEST_CHILD(tc)
7391 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7392 "%d child visitsed by high prio walk", ii);
7393 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7394 "%d child visitsed by low prio walk", ii);
7397 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7398 "Queue is empty post prio walk");
7399 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7400 "Parent has %d children post prio walk",
7401 fib_node_list_get_size(PARENT()->fn_children));
7404 * schedule 2 walks of the same priority that can be megred.
7405 * expect that each child is thus visited only once.
7407 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7408 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7410 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7411 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7412 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7413 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7415 fib_walk_process_queues(vm, 1);
7417 FOR_EACH_TEST_CHILD(tc)
7419 FIB_TEST(1 == vec_len(tc->ctxs),
7420 "%d child visitsed %d times during merge walk",
7421 ii, vec_len(tc->ctxs));
7424 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7425 "Queue is empty post merge walk");
7426 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7427 "Parent has %d children post merge walk",
7428 fib_node_list_get_size(PARENT()->fn_children));
7431 * schedule 2 walks of the same priority that cannot be megred.
7432 * expect that each child is thus visited twice and in the order
7433 * in which the walks were scheduled.
7435 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7436 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7438 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7439 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7440 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7441 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7443 fib_walk_process_queues(vm, 1);
7445 FOR_EACH_TEST_CHILD(tc)
7447 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7448 "%d child visitsed by high prio walk", ii);
7449 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7450 "%d child visitsed by low prio walk", ii);
7453 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7454 "Queue is empty post no-merge walk");
7455 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7456 "Parent has %d children post no-merge walk",
7457 fib_node_list_get_size(PARENT()->fn_children));
7460 * schedule a walk that makes one one child progress.
7461 * we do this by giving the queue draining process zero
7462 * time quanta. it's a do..while loop, so it does something.
7464 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7466 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7467 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7468 fib_walk_process_queues(vm, 0);
7470 FOR_EACH_TEST_CHILD(tc)
7472 if (ii == N_TEST_CHILDREN)
7474 FIB_TEST(1 == vec_len(tc->ctxs),
7475 "%d child visitsed %d times in zero quanta walk",
7476 ii, vec_len(tc->ctxs));
7480 FIB_TEST(0 == vec_len(tc->ctxs),
7481 "%d child visitsed %d times in 0 quanta walk",
7482 ii, vec_len(tc->ctxs));
7485 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7486 "Queue is not empty post zero quanta walk");
7487 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7488 "Parent has %d children post zero qunta walk",
7489 fib_node_list_get_size(PARENT()->fn_children));
7494 fib_walk_process_queues(vm, 0);
7496 FOR_EACH_TEST_CHILD(tc)
7498 if (ii >= N_TEST_CHILDREN-1)
7500 FIB_TEST(1 == vec_len(tc->ctxs),
7501 "%d child visitsed %d times in 2nd zero quanta walk",
7502 ii, vec_len(tc->ctxs));
7506 FIB_TEST(0 == vec_len(tc->ctxs),
7507 "%d child visitsed %d times in 2nd 0 quanta walk",
7508 ii, vec_len(tc->ctxs));
7511 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7512 "Queue is not empty post zero quanta walk");
7513 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7514 "Parent has %d children post zero qunta walk",
7515 fib_node_list_get_size(PARENT()->fn_children));
7518 * schedule another walk that will catch-up and merge.
7520 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7521 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7522 fib_walk_process_queues(vm, 1);
7524 FOR_EACH_TEST_CHILD(tc)
7526 if (ii >= N_TEST_CHILDREN-1)
7528 FIB_TEST(2 == vec_len(tc->ctxs),
7529 "%d child visitsed %d times in 2nd zero quanta merge walk",
7530 ii, vec_len(tc->ctxs));
7535 FIB_TEST(1 == vec_len(tc->ctxs),
7536 "%d child visitsed %d times in 2nd 0 quanta merge walk",
7537 ii, vec_len(tc->ctxs));
7541 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7542 "Queue is not empty post 2nd zero quanta merge walk");
7543 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7544 "Parent has %d children post 2nd zero qunta merge walk",
7545 fib_node_list_get_size(PARENT()->fn_children));
7548 * park a async walk in the middle of the list, then have an sync walk catch
7549 * it. same expectations as async catches async.
7551 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7553 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7554 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7556 fib_walk_process_queues(vm, 0);
7557 fib_walk_process_queues(vm, 0);
7559 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7561 FOR_EACH_TEST_CHILD(tc)
7563 if (ii >= N_TEST_CHILDREN-1)
7565 FIB_TEST(2 == vec_len(tc->ctxs),
7566 "%d child visitsed %d times in sync catches async walk",
7567 ii, vec_len(tc->ctxs));
7572 FIB_TEST(1 == vec_len(tc->ctxs),
7573 "%d child visitsed %d times in sync catches async walk",
7574 ii, vec_len(tc->ctxs));
7578 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7579 "Queue is not empty post 2nd zero quanta merge walk");
7580 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7581 "Parent has %d children post 2nd zero qunta merge walk",
7582 fib_node_list_get_size(PARENT()->fn_children));
7585 * make the parent a child of one of its children, thus inducing a routing loop.
7587 fib_test_nodes[PARENT_INDEX].sibling =
7588 fib_node_child_add(FIB_NODE_TYPE_TEST,
7589 1, // the first child
7594 * execute a sync walk from the parent. each child visited spawns more sync
7595 * walks. we expect the walk to terminate.
7597 fib_test_walk_spawns_walks = 1;
7599 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7601 FOR_EACH_TEST_CHILD(tc)
7604 * child 1 - which is last in the list - has the loop.
7605 * the other children a re thus visitsed first. the we meet
7606 * child 1. we go round the loop again, visting the other children.
7607 * then we meet the walk in the dep list and bail. child 1 is not visitsed
7612 FIB_TEST(1 == vec_len(tc->ctxs),
7613 "child %d visitsed %d times during looped sync walk",
7614 ii, vec_len(tc->ctxs));
7618 FIB_TEST(2 == vec_len(tc->ctxs),
7619 "child %d visitsed %d times during looped sync walk",
7620 ii, vec_len(tc->ctxs));
7624 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7625 "Parent has %d children post sync loop walk",
7626 fib_node_list_get_size(PARENT()->fn_children));
7629 * the walk doesn't reach the max depth because the infra knows that sync
7630 * meets sync implies a loop and bails early.
7632 FIB_TEST(high_ctx.fnbw_depth == 9,
7633 "Walk context depth %d post sync loop walk",
7634 high_ctx.fnbw_depth);
7637 * execute an async walk of the graph loop, with each child spawns sync walks
7639 high_ctx.fnbw_depth = 0;
7640 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7641 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7643 fib_walk_process_queues(vm, 1);
7645 FOR_EACH_TEST_CHILD(tc)
7648 * we don't really care how many times the children are visisted, as long as
7649 * it is more than once.
7651 FIB_TEST(1 <= vec_len(tc->ctxs),
7652 "child %d visitsed %d times during looped aync spawns sync walk",
7653 ii, vec_len(tc->ctxs));
7658 * execute an async walk of the graph loop, with each child spawns async walks
7660 fib_test_walk_spawns_walks = 2;
7661 high_ctx.fnbw_depth = 0;
7662 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7663 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7665 fib_walk_process_queues(vm, 1);
7667 FOR_EACH_TEST_CHILD(tc)
7670 * we don't really care how many times the children are visisted, as long as
7671 * it is more than once.
7673 FIB_TEST(1 <= vec_len(tc->ctxs),
7674 "child %d visitsed %d times during looped async spawns async walk",
7675 ii, vec_len(tc->ctxs));
7680 fib_node_child_remove(FIB_NODE_TYPE_TEST,
7681 1, // the first child
7682 fib_test_nodes[PARENT_INDEX].sibling);
7687 FOR_EACH_TEST_CHILD(tc)
7689 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7691 fib_node_deinit(&tc->node);
7692 fib_node_unlock(&tc->node);
7694 fib_node_deinit(PARENT());
7697 * The parent will be destroyed when the last lock on it goes.
7698 * this test ensures all the walk objects are unlocking it.
7700 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7701 "Parent was destroyed");
7707 * declaration of the otherwise static callback functions
7709 void fib_bfd_notify (bfd_listen_event_e event,
7710 const bfd_session_t *session);
7711 void adj_bfd_notify (bfd_listen_event_e event,
7712 const bfd_session_t *session);
7715 * Test BFD session interaction with FIB
7720 fib_node_index_t fei;
7724 /* via 10.10.10.1 */
7725 ip46_address_t nh_10_10_10_1 = {
7726 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7728 /* via 10.10.10.2 */
7729 ip46_address_t nh_10_10_10_2 = {
7730 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7732 /* via 10.10.10.10 */
7733 ip46_address_t nh_10_10_10_10 = {
7734 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7736 n_feis = fib_entry_pool_size();
7741 * add interface routes. we'll assume this works. it's tested elsewhere
7743 fib_prefix_t pfx_10_10_10_10_s_24 = {
7745 .fp_proto = FIB_PROTOCOL_IP4,
7746 .fp_addr = nh_10_10_10_10,
7749 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7750 FIB_SOURCE_INTERFACE,
7751 (FIB_ENTRY_FLAG_CONNECTED |
7752 FIB_ENTRY_FLAG_ATTACHED),
7755 tm->hw[0]->sw_if_index,
7756 ~0, // invalid fib index
7759 FIB_ROUTE_PATH_FLAG_NONE);
7761 fib_prefix_t pfx_10_10_10_10_s_32 = {
7763 .fp_proto = FIB_PROTOCOL_IP4,
7764 .fp_addr = nh_10_10_10_10,
7766 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7767 FIB_SOURCE_INTERFACE,
7768 (FIB_ENTRY_FLAG_CONNECTED |
7769 FIB_ENTRY_FLAG_LOCAL),
7772 tm->hw[0]->sw_if_index,
7773 ~0, // invalid fib index
7776 FIB_ROUTE_PATH_FLAG_NONE);
7779 * A BFD session via a neighbour we do not yet know
7781 bfd_session_t bfd_10_10_10_1 = {
7785 .peer_addr = nh_10_10_10_1,
7788 .hop_type = BFD_HOP_TYPE_MULTI,
7789 .local_state = BFD_STATE_init,
7792 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7795 * A new entry will be created that forwards via the adj
7797 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7800 tm->hw[0]->sw_if_index);
7801 fib_prefix_t pfx_10_10_10_1_s_32 = {
7802 .fp_addr = nh_10_10_10_1,
7804 .fp_proto = FIB_PROTOCOL_IP4,
7806 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7809 .adj = ai_10_10_10_1,
7813 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7814 FIB_TEST(fib_test_validate_entry(fei,
7815 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7818 "BFD sourced %U via %U",
7819 format_fib_prefix, &pfx_10_10_10_1_s_32,
7820 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7823 * Delete the BFD session. Expect the fib_entry to be removed
7825 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7827 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7828 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7829 "BFD sourced %U removed",
7830 format_fib_prefix, &pfx_10_10_10_1_s_32);
7833 * Add the BFD source back
7835 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7838 * source the entry via the ADJ fib
7840 fei = fib_table_entry_path_add(0,
7841 &pfx_10_10_10_1_s_32,
7843 FIB_ENTRY_FLAG_ATTACHED,
7846 tm->hw[0]->sw_if_index,
7847 ~0, // invalid fib index
7850 FIB_ROUTE_PATH_FLAG_NONE);
7853 * Delete the BFD session. Expect the fib_entry to remain
7855 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7857 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7858 FIB_TEST(fib_test_validate_entry(fei,
7859 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7862 "BFD sourced %U remains via %U",
7863 format_fib_prefix, &pfx_10_10_10_1_s_32,
7864 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7867 * Add the BFD source back
7869 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7872 * Create another ADJ FIB
7874 fib_prefix_t pfx_10_10_10_2_s_32 = {
7875 .fp_addr = nh_10_10_10_2,
7877 .fp_proto = FIB_PROTOCOL_IP4,
7879 fib_table_entry_path_add(0,
7880 &pfx_10_10_10_2_s_32,
7882 FIB_ENTRY_FLAG_ATTACHED,
7885 tm->hw[0]->sw_if_index,
7886 ~0, // invalid fib index
7889 FIB_ROUTE_PATH_FLAG_NONE);
7891 * A BFD session for the new ADJ FIB
7893 bfd_session_t bfd_10_10_10_2 = {
7897 .peer_addr = nh_10_10_10_2,
7900 .hop_type = BFD_HOP_TYPE_MULTI,
7901 .local_state = BFD_STATE_init,
7904 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7907 * remove the adj-fib source whilst the session is present
7910 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7911 fib_table_entry_path_add(0,
7912 &pfx_10_10_10_2_s_32,
7914 FIB_ENTRY_FLAG_ATTACHED,
7917 tm->hw[0]->sw_if_index,
7918 ~0, // invalid fib index
7921 FIB_ROUTE_PATH_FLAG_NONE);
7924 * Before adding a recursive via the BFD tracked ADJ-FIBs,
7925 * bring one of the sessions UP, leave the other down
7927 bfd_10_10_10_1.local_state = BFD_STATE_up;
7928 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7929 bfd_10_10_10_2.local_state = BFD_STATE_down;
7930 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7933 * A recursive prefix via both of the ADJ FIBs
7935 fib_prefix_t pfx_200_0_0_0_s_24 = {
7936 .fp_proto = FIB_PROTOCOL_IP4,
7939 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7942 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7945 fib_entry_contribute_ip_forwarding(
7946 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7948 fib_entry_contribute_ip_forwarding(
7949 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7951 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7954 .lb = dpo_10_10_10_1->dpoi_index,
7957 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7960 .lb = dpo_10_10_10_2->dpoi_index,
7965 * A prefix via the adj-fib that is BFD down => DROP
7967 fei = fib_table_entry_path_add(0,
7968 &pfx_200_0_0_0_s_24,
7970 FIB_ENTRY_FLAG_NONE,
7974 0, // default fib index
7977 FIB_ROUTE_PATH_FLAG_NONE);
7978 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7979 "%U resolves via drop",
7980 format_fib_prefix, &pfx_200_0_0_0_s_24);
7983 * add a path via the UP BFD adj-fib.
7984 * we expect that the DOWN BFD ADJ FIB is not used.
7986 fei = fib_table_entry_path_add(0,
7987 &pfx_200_0_0_0_s_24,
7989 FIB_ENTRY_FLAG_NONE,
7993 0, // default fib index
7996 FIB_ROUTE_PATH_FLAG_NONE);
7998 FIB_TEST(fib_test_validate_entry(fei,
7999 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8002 "Recursive %U only UP BFD adj-fibs",
8003 format_fib_prefix, &pfx_200_0_0_0_s_24);
8006 * Send a BFD state change to UP - both sessions are now up
8007 * the recursive prefix should LB over both
8009 bfd_10_10_10_2.local_state = BFD_STATE_up;
8010 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8013 FIB_TEST(fib_test_validate_entry(fei,
8014 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8018 "Recursive %U via both UP BFD adj-fibs",
8019 format_fib_prefix, &pfx_200_0_0_0_s_24);
8022 * Send a BFD state change to DOWN
8023 * the recursive prefix should exclude the down
8025 bfd_10_10_10_2.local_state = BFD_STATE_down;
8026 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8029 FIB_TEST(fib_test_validate_entry(fei,
8030 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8033 "Recursive %U via only UP",
8034 format_fib_prefix, &pfx_200_0_0_0_s_24);
8037 * Delete the BFD session while it is in the DOWN state.
8038 * FIB should consider the entry's state as back up
8040 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
8042 FIB_TEST(fib_test_validate_entry(fei,
8043 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8047 "Recursive %U via both UP BFD adj-fibs post down session delete",
8048 format_fib_prefix, &pfx_200_0_0_0_s_24);
8051 * Delete the BFD other session while it is in the UP state.
8053 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8055 FIB_TEST(fib_test_validate_entry(fei,
8056 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8060 "Recursive %U via both UP BFD adj-fibs post up session delete",
8061 format_fib_prefix, &pfx_200_0_0_0_s_24);
8066 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8067 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8068 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8070 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8071 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8073 adj_unlock(ai_10_10_10_1);
8075 * test no-one left behind
8077 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8078 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8081 * Single-hop BFD tests
8083 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8084 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8086 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8088 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8091 tm->hw[0]->sw_if_index);
8093 * whilst the BFD session is not signalled, the adj is up
8095 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
8098 * bring the BFD session up
8100 bfd_10_10_10_1.local_state = BFD_STATE_up;
8101 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8102 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8105 * bring the BFD session down
8107 bfd_10_10_10_1.local_state = BFD_STATE_down;
8108 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8109 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8113 * add an attached next hop FIB entry via the down adj
8115 fib_prefix_t pfx_5_5_5_5_s_32 = {
8118 .as_u32 = clib_host_to_net_u32(0x05050505),
8122 .fp_proto = FIB_PROTOCOL_IP4,
8125 fei = fib_table_entry_path_add(0,
8128 FIB_ENTRY_FLAG_NONE,
8131 tm->hw[0]->sw_if_index,
8132 ~0, // invalid fib index
8135 FIB_ROUTE_PATH_FLAG_NONE);
8136 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8137 "%U resolves via drop",
8138 format_fib_prefix, &pfx_5_5_5_5_s_32);
8141 * Add a path via an ADJ that is up
8143 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8146 tm->hw[0]->sw_if_index);
8148 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8151 .adj = ai_10_10_10_2,
8154 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8156 fei = fib_table_entry_path_add(0,
8159 FIB_ENTRY_FLAG_NONE,
8162 tm->hw[0]->sw_if_index,
8163 ~0, // invalid fib index
8166 FIB_ROUTE_PATH_FLAG_NONE);
8168 FIB_TEST(fib_test_validate_entry(fei,
8169 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8172 "BFD sourced %U via %U",
8173 format_fib_prefix, &pfx_5_5_5_5_s_32,
8174 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8177 * Bring up the down session - should now LB
8179 bfd_10_10_10_1.local_state = BFD_STATE_up;
8180 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8181 FIB_TEST(fib_test_validate_entry(fei,
8182 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8186 "BFD sourced %U via noth adjs",
8187 format_fib_prefix, &pfx_5_5_5_5_s_32);
8190 * remove the BFD session state from the adj
8192 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8197 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8198 adj_unlock(ai_10_10_10_1);
8199 adj_unlock(ai_10_10_10_2);
8202 * test no-one left behind
8204 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8205 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8212 const mpls_label_t deag_label = 50;
8213 const u32 lfib_index = 0;
8214 const u32 fib_index = 0;
8215 dpo_id_t dpo = DPO_INVALID;
8216 const dpo_id_t *dpo1;
8217 fib_node_index_t lfe;
8221 adj_index_t ai_mpls_10_10_10_1;
8224 lb_count = pool_elts(load_balance_pool);
8226 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8230 * MPLS enable an interface so we get the MPLS table created
8232 mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8233 mpls_sw_interface_enable_disable(&mpls_main,
8234 tm->hw[0]->sw_if_index,
8237 ip46_address_t nh_10_10_10_1 = {
8238 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8240 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8243 tm->hw[0]->sw_if_index);
8246 * Test the specials stack properly.
8248 fib_prefix_t exp_null_v6_pfx = {
8249 .fp_proto = FIB_PROTOCOL_MPLS,
8251 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8252 .fp_payload_proto = DPO_PROTO_IP6,
8254 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8255 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8257 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8258 format_mpls_eos_bit, MPLS_EOS);
8259 fib_entry_contribute_forwarding(lfe,
8260 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8262 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8263 lkd = lookup_dpo_get(dpo1->dpoi_index);
8265 FIB_TEST((fib_index == lkd->lkd_fib_index),
8266 "%U/%U is deag in %d %U",
8267 format_mpls_unicast_label, deag_label,
8268 format_mpls_eos_bit, MPLS_EOS,
8270 format_dpo_id, &dpo, 0);
8271 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8272 "%U/%U is dst deag",
8273 format_mpls_unicast_label, deag_label,
8274 format_mpls_eos_bit, MPLS_EOS);
8275 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8276 "%U/%U is lookup in interface's table",
8277 format_mpls_unicast_label, deag_label,
8278 format_mpls_eos_bit, MPLS_EOS);
8279 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8280 "%U/%U is %U dst deag",
8281 format_mpls_unicast_label, deag_label,
8282 format_mpls_eos_bit, MPLS_EOS,
8283 format_dpo_proto, lkd->lkd_proto);
8287 * A route deag route for EOS
8289 fib_prefix_t pfx = {
8290 .fp_proto = FIB_PROTOCOL_MPLS,
8292 .fp_label = deag_label,
8293 .fp_payload_proto = DPO_PROTO_IP4,
8295 lfe = fib_table_entry_path_add(lfib_index,
8298 FIB_ENTRY_FLAG_NONE,
8305 FIB_ROUTE_PATH_FLAG_NONE);
8307 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8309 format_mpls_unicast_label, deag_label,
8310 format_mpls_eos_bit, MPLS_EOS);
8312 fib_entry_contribute_forwarding(lfe,
8313 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8315 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8316 lkd = lookup_dpo_get(dpo1->dpoi_index);
8318 FIB_TEST((fib_index == lkd->lkd_fib_index),
8319 "%U/%U is deag in %d %U",
8320 format_mpls_unicast_label, deag_label,
8321 format_mpls_eos_bit, MPLS_EOS,
8323 format_dpo_id, &dpo, 0);
8324 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8325 "%U/%U is dst deag",
8326 format_mpls_unicast_label, deag_label,
8327 format_mpls_eos_bit, MPLS_EOS);
8328 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8329 "%U/%U is %U dst deag",
8330 format_mpls_unicast_label, deag_label,
8331 format_mpls_eos_bit, MPLS_EOS,
8332 format_dpo_proto, lkd->lkd_proto);
8334 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8336 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8338 "%U/%U not present",
8339 format_mpls_unicast_label, deag_label,
8340 format_mpls_eos_bit, MPLS_EOS);
8343 * A route deag route for non-EOS
8345 pfx.fp_eos = MPLS_NON_EOS;
8346 lfe = fib_table_entry_path_add(lfib_index,
8349 FIB_ENTRY_FLAG_NONE,
8356 FIB_ROUTE_PATH_FLAG_NONE);
8358 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8360 format_mpls_unicast_label, deag_label,
8361 format_mpls_eos_bit, MPLS_NON_EOS);
8363 fib_entry_contribute_forwarding(lfe,
8364 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8366 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8367 lkd = lookup_dpo_get(dpo1->dpoi_index);
8369 FIB_TEST((fib_index == lkd->lkd_fib_index),
8370 "%U/%U is deag in %d %U",
8371 format_mpls_unicast_label, deag_label,
8372 format_mpls_eos_bit, MPLS_NON_EOS,
8374 format_dpo_id, &dpo, 0);
8375 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8376 "%U/%U is dst deag",
8377 format_mpls_unicast_label, deag_label,
8378 format_mpls_eos_bit, MPLS_NON_EOS);
8380 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8381 "%U/%U is %U dst deag",
8382 format_mpls_unicast_label, deag_label,
8383 format_mpls_eos_bit, MPLS_NON_EOS,
8384 format_dpo_proto, lkd->lkd_proto);
8386 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8388 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8390 "%U/%U not present",
8391 format_mpls_unicast_label, deag_label,
8392 format_mpls_eos_bit, MPLS_EOS);
8399 fib_prefix_t pfx_1200 = {
8401 .fp_proto = FIB_PROTOCOL_MPLS,
8403 .fp_eos = MPLS_NON_EOS,
8405 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8406 .type = FT_LB_LABEL_STACK_O_ADJ,
8407 .label_stack_o_adj = {
8408 .adj = ai_mpls_10_10_10_1,
8409 .label_stack_size = 4,
8413 .eos = MPLS_NON_EOS,
8416 dpo_id_t neos_1200 = DPO_INVALID;
8417 dpo_id_t ip_1200 = DPO_INVALID;
8418 mpls_label_t *l200 = NULL;
8419 vec_add1(l200, 200);
8420 vec_add1(l200, 300);
8421 vec_add1(l200, 400);
8422 vec_add1(l200, 500);
8424 lfe = fib_table_entry_update_one_path(fib_index,
8427 FIB_ENTRY_FLAG_NONE,
8430 tm->hw[0]->sw_if_index,
8431 ~0, // invalid fib index
8434 FIB_ROUTE_PATH_FLAG_NONE);
8436 FIB_TEST(fib_test_validate_entry(lfe,
8437 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8439 &neos_o_10_10_10_1),
8440 "1200/0 LB 1 buckets via: "
8444 * A recursive route via the MPLS x-connect
8446 fib_prefix_t pfx_2_2_2_3_s_32 = {
8448 .fp_proto = FIB_PROTOCOL_IP4,
8450 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8453 fib_route_path_t *rpaths = NULL, rpath = {
8454 .frp_proto = DPO_PROTO_MPLS,
8455 .frp_local_label = 1200,
8456 .frp_eos = MPLS_NON_EOS,
8457 .frp_sw_if_index = ~0, // recurive
8458 .frp_fib_index = 0, // Default MPLS fib
8460 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8461 .frp_label_stack = NULL,
8463 vec_add1(rpaths, rpath);
8465 fib_table_entry_path_add2(fib_index,
8468 FIB_ENTRY_FLAG_NONE,
8472 * A labelled recursive route via the MPLS x-connect
8474 fib_prefix_t pfx_2_2_2_4_s_32 = {
8476 .fp_proto = FIB_PROTOCOL_IP4,
8478 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8481 mpls_label_t *l999 = NULL;
8482 vec_add1(l999, 999);
8483 rpaths[0].frp_label_stack = l999,
8485 fib_table_entry_path_add2(fib_index,
8488 FIB_ENTRY_FLAG_NONE,
8491 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8492 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8494 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8495 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8498 fib_test_lb_bucket_t ip_o_1200 = {
8501 .lb = ip_1200.dpoi_index,
8504 fib_test_lb_bucket_t mpls_o_1200 = {
8505 .type = FT_LB_LABEL_O_LB,
8507 .lb = neos_1200.dpoi_index,
8513 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8514 FIB_TEST(fib_test_validate_entry(lfe,
8515 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8518 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8519 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8520 FIB_TEST(fib_test_validate_entry(lfe,
8521 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8524 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8526 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8527 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8528 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8530 dpo_reset(&neos_1200);
8531 dpo_reset(&ip_1200);
8534 * A recursive via a label that does not exist
8536 fib_test_lb_bucket_t bucket_drop = {
8539 .adj = DPO_PROTO_IP4,
8542 fib_test_lb_bucket_t mpls_bucket_drop = {
8545 .adj = DPO_PROTO_MPLS,
8549 rpaths[0].frp_label_stack = NULL;
8550 lfe = fib_table_entry_path_add2(fib_index,
8553 FIB_ENTRY_FLAG_NONE,
8556 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8557 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8559 ip_o_1200.lb.lb = ip_1200.dpoi_index;
8561 FIB_TEST(fib_test_validate_entry(lfe,
8562 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8565 "2.2.2.2.4/32 LB 1 buckets via: drop");
8566 lfe = fib_table_lookup(fib_index, &pfx_1200);
8567 FIB_TEST(fib_test_validate_entry(lfe,
8568 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8571 "1200/neos LB 1 buckets via: ip4-DROP");
8572 FIB_TEST(fib_test_validate_entry(lfe,
8573 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8576 "1200/neos LB 1 buckets via: mpls-DROP");
8578 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8580 dpo_reset(&ip_1200);
8583 * An rx-interface route.
8584 * like the tail of an mcast LSP
8586 dpo_id_t idpo = DPO_INVALID;
8588 interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8589 tm->hw[0]->sw_if_index,
8592 fib_prefix_t pfx_2500 = {
8594 .fp_proto = FIB_PROTOCOL_MPLS,
8597 .fp_payload_proto = DPO_PROTO_IP4,
8599 fib_test_lb_bucket_t rx_intf_0 = {
8602 .adj = idpo.dpoi_index,
8606 lfe = fib_table_entry_update_one_path(fib_index,
8609 FIB_ENTRY_FLAG_NONE,
8612 tm->hw[0]->sw_if_index,
8613 ~0, // invalid fib index
8616 FIB_ROUTE_PATH_INTF_RX);
8617 FIB_TEST(fib_test_validate_entry(lfe,
8618 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8621 "2500 rx-interface 0");
8622 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8625 * An MPLS mulicast entry
8627 fib_prefix_t pfx_3500 = {
8629 .fp_proto = FIB_PROTOCOL_MPLS,
8632 .fp_payload_proto = DPO_PROTO_IP4,
8634 fib_test_rep_bucket_t mc_0 = {
8635 .type = FT_REP_LABEL_O_ADJ,
8637 .adj = ai_mpls_10_10_10_1,
8642 fib_test_rep_bucket_t mc_intf_0 = {
8643 .type = FT_REP_INTF,
8645 .adj = idpo.dpoi_index,
8648 mpls_label_t *l3300 = NULL;
8649 vec_add1(l3300, 3300);
8651 lfe = fib_table_entry_update_one_path(lfib_index,
8654 FIB_ENTRY_FLAG_MULTICAST,
8657 tm->hw[0]->sw_if_index,
8658 ~0, // invalid fib index
8661 FIB_ROUTE_PATH_FLAG_NONE);
8662 FIB_TEST(fib_test_validate_entry(lfe,
8663 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8666 "3500 via replicate over 10.10.10.1");
8669 * MPLS Bud-node. Add a replication via an interface-receieve path
8671 lfe = fib_table_entry_path_add(lfib_index,
8674 FIB_ENTRY_FLAG_MULTICAST,
8677 tm->hw[0]->sw_if_index,
8678 ~0, // invalid fib index
8681 FIB_ROUTE_PATH_INTF_RX);
8682 FIB_TEST(fib_test_validate_entry(lfe,
8683 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8687 "3500 via replicate over 10.10.10.1 and interface-rx");
8690 * Add a replication via an interface-free for-us path
8692 fib_test_rep_bucket_t mc_disp = {
8693 .type = FT_REP_DISP_MFIB_LOOKUP,
8695 .adj = idpo.dpoi_index,
8698 lfe = fib_table_entry_path_add(lfib_index,
8701 FIB_ENTRY_FLAG_MULTICAST,
8708 FIB_ROUTE_PATH_RPF_ID);
8709 FIB_TEST(fib_test_validate_entry(lfe,
8710 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8715 "3500 via replicate over 10.10.10.1 and interface-rx");
8719 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8725 mpls_sw_interface_enable_disable(&mpls_main,
8726 tm->hw[0]->sw_if_index,
8728 mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
8730 FIB_TEST(lb_count == pool_elts(load_balance_pool),
8731 "Load-balance resources freed %d of %d",
8732 lb_count, pool_elts(load_balance_pool));
8733 FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
8734 "interface_rx_dpo resources freed %d of %d",
8735 0, pool_elts(interface_rx_dpo_pool));
8740 static clib_error_t *
8741 fib_test (vlib_main_t * vm,
8742 unformat_input_t * input,
8743 vlib_cli_command_t * cmd_arg)
8748 fib_test_mk_intf(4);
8750 if (unformat (input, "debug"))
8752 fib_test_do_debug = 1;
8755 if (unformat (input, "ip"))
8757 res += fib_test_v4();
8758 res += fib_test_v6();
8760 else if (unformat (input, "label"))
8762 res += fib_test_label();
8764 else if (unformat (input, "ae"))
8766 res += fib_test_ae();
8768 else if (unformat (input, "pref"))
8770 res += fib_test_pref();
8772 else if (unformat (input, "lfib"))
8776 else if (unformat (input, "walk"))
8778 res += fib_test_walk();
8780 else if (unformat (input, "bfd"))
8782 res += fib_test_bfd();
8786 res += fib_test_v4();
8787 res += fib_test_v6();
8788 res += fib_test_ae();
8789 res += fib_test_bfd();
8790 res += fib_test_pref();
8791 res += fib_test_label();
8795 * fib-walk process must be disabled in order for the walk tests to work
8797 fib_walk_process_disable();
8798 res += fib_test_walk();
8799 fib_walk_process_enable();
8804 return clib_error_return(0, "FIB Unit Test Failed");
8812 VLIB_CLI_COMMAND (test_fib_command, static) = {
8814 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
8815 .function = fib_test,
8819 fib_test_init (vlib_main_t *vm)
8824 VLIB_INIT_FUNCTION (fib_test_init);