2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/fib/fib_test.h>
17 #include <vnet/fib/ip6_fib.h>
18 #include <vnet/fib/ip4_fib.h>
19 #include <vnet/fib/mpls_fib.h>
20 #include <vnet/adj/adj.h>
21 #include <vnet/dpo/load_balance.h>
22 #include <vnet/dpo/load_balance_map.h>
23 #include <vnet/dpo/mpls_label_dpo.h>
24 #include <vnet/dpo/lookup_dpo.h>
25 #include <vnet/dpo/drop_dpo.h>
26 #include <vnet/dpo/receive_dpo.h>
27 #include <vnet/dpo/ip_null_dpo.h>
28 #include <vnet/bfd/bfd_main.h>
29 #include <vnet/dpo/interface_rx_dpo.h>
30 #include <vnet/dpo/replicate_dpo.h>
31 #include <vnet/dpo/dvr_dpo.h>
32 #include <vnet/dpo/mpls_disposition.h>
33 #include <vnet/dpo/punt_dpo.h>
35 #include <vnet/mpls/mpls.h>
37 #include <vnet/fib/fib_test.h>
38 #include <vnet/fib/fib_path_list.h>
39 #include <vnet/fib/fib_entry_src.h>
40 #include <vnet/fib/fib_walk.h>
41 #include <vnet/fib/fib_node_list.h>
42 #include <vnet/fib/fib_urpf_list.h>
44 #include <vlib/unix/plugin.h>
49 * Add debugs for passing tests
51 static int fib_test_do_debug;
53 #define FIB_TEST_I(_cond, _comment, _args...) \
55 int _evald = (_cond); \
57 fformat(stderr, "FAIL:%d: " _comment "\n", \
61 if (fib_test_do_debug) \
62 fformat(stderr, "PASS:%d: " _comment "\n", \
67 #define FIB_TEST(_cond, _comment, _args...) \
69 if (FIB_TEST_I(_cond, _comment, ##_args)) { \
71 ASSERT(!("FAIL: " _comment)); \
76 * A 'i'm not fussed is this is not efficient' store of test data
78 typedef struct test_main_t_ {
82 u32 hw_if_indicies[4];
86 vnet_hw_interface_t * hw[4];
89 static test_main_t test_main;
91 /* fake ethernet device class, distinct from "fake-ethX" */
92 static u8 * format_test_interface_name (u8 * s, va_list * args)
94 u32 dev_instance = va_arg (*args, u32);
95 return format (s, "test-eth%d", dev_instance);
98 static uword placeholder_interface_tx (vlib_main_t * vm,
99 vlib_node_runtime_t * node,
100 vlib_frame_t * frame)
102 clib_warning ("you shouldn't be here, leaking buffers...");
103 return frame->n_vectors;
106 static clib_error_t *
107 test_interface_admin_up_down (vnet_main_t * vnm,
111 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
112 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
113 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
117 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
118 .name = "Test interface",
119 .format_device_name = format_test_interface_name,
120 .tx_function = placeholder_interface_tx,
121 .admin_up_down_function = test_interface_admin_up_down,
124 static u8 *hw_address;
127 fib_test_mk_intf (u32 ninterfaces)
129 clib_error_t * error = NULL;
130 test_main_t *tm = &test_main;
135 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
140 vec_add1(hw_address, byte);
143 for (i = 0; i < ninterfaces; i++)
147 error = ethernet_register_interface(vnet_get_main(),
148 test_interface_device_class.index,
151 &tm->hw_if_indicies[i],
152 /* flag change */ 0);
154 FIB_TEST((NULL == error), "ADD interface %d", i);
156 error = vnet_hw_interface_set_flags(vnet_get_main(),
157 tm->hw_if_indicies[i],
158 VNET_HW_INTERFACE_FLAG_LINK_UP);
159 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
160 tm->hw_if_indicies[i]);
161 vec_validate (ip4_main.fib_index_by_sw_if_index,
162 tm->hw[i]->sw_if_index);
163 vec_validate (ip6_main.fib_index_by_sw_if_index,
164 tm->hw[i]->sw_if_index);
165 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
166 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
168 error = vnet_sw_interface_set_flags(vnet_get_main(),
169 tm->hw[i]->sw_if_index,
170 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
171 FIB_TEST((NULL == error), "UP interface %d", i);
174 * re-eval after the inevitable realloc
176 for (i = 0; i < ninterfaces; i++)
178 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
179 tm->hw_if_indicies[i]);
185 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
187 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
188 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
189 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
190 fib_table_lookup(fib_index, (_via_prefix))); \
191 FIB_TEST(!dpo_cmp(_via_dpo, \
192 load_balance_get_bucket(_rec_dpo->dpoi_index, \
194 "%U is recursive via %U", \
195 format_fib_prefix, (_rec_prefix), \
196 format_fib_prefix, _via_prefix); \
199 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
201 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
202 fib_table_lookup_exact_match(fib_index, (_prefix))); \
203 const dpo_id_t *_dpo1 = \
204 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
205 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
206 format_dpo_type, _dpo1->dpoi_type); \
207 FIB_TEST((_ai == _dpo1->dpoi_index), \
208 "%U bucket %d resolves via %U", \
209 format_fib_prefix, (_prefix), \
211 format_dpo_id, _dpo1, 0); \
214 #define FIB_TEST_RPF(_cond, _comment, _args...) \
216 if (FIB_TEST_I(_cond, _comment, ##_args)) { \
223 fib_test_urpf_is_equal (fib_node_index_t fei,
224 fib_forward_chain_type_t fct,
227 dpo_id_t dpo = DPO_INVALID;
228 fib_urpf_list_t *urpf;
236 fib_entry_contribute_forwarding(fei, fct, &dpo);
237 ui = load_balance_get_urpf(dpo.dpoi_index);
239 urpf = fib_urpf_list_get(ui);
241 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
242 "RPF:%U len %d == %d",
243 format_fib_urpf_list, ui,
244 num, vec_len(urpf->furpf_itfs));
245 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
246 "RPF:%U check-size %d == %d",
247 format_fib_urpf_list, ui,
248 num, vec_len(urpf->furpf_itfs));
250 for (ii = 0; ii < num; ii++)
252 adj_index_t ai = va_arg(ap, adj_index_t);
254 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
255 "RPF:%d item:%d - %d == %d",
256 ui, ii, ai, urpf->furpf_itfs[ii]);
257 FIB_TEST_RPF(fib_urpf_check(ui, ai),
271 fib_test_build_rewrite (u8 *eth_addr)
275 vec_validate(rewrite, 13);
277 memcpy(rewrite, eth_addr, 6);
278 memcpy(rewrite+6, eth_addr, 6);
283 #define FIB_TEST_LB(_cond, _comment, _args...) \
285 if (FIB_TEST_I(_cond, _comment, ##_args)) { \
291 fib_test_validate_rep_v (const replicate_t *rep,
295 const fib_test_rep_bucket_t *exp;
300 FIB_TEST_LB((n_buckets == rep->rep_n_buckets),
301 "n_buckets = %d", rep->rep_n_buckets);
303 for (bucket = 0; bucket < n_buckets; bucket++)
305 exp = va_arg(*ap, fib_test_rep_bucket_t*);
307 dpo = replicate_get_bucket_i(rep, bucket);
311 case FT_REP_LABEL_O_ADJ:
313 const mpls_label_dpo_t *mld;
316 FIB_TEST_LB((mpls_label_dpo_get_type(MPLS_LABEL_DPO_FLAG_NONE)
318 "bucket %d stacks on %U",
320 format_dpo_type, dpo->dpoi_type);
322 mld = mpls_label_dpo_get(dpo->dpoi_index);
323 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
325 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
326 exp->label_o_adj.label),
327 "bucket %d stacks on label %d",
329 exp->label_o_adj.label);
331 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
332 exp->label_o_adj.eos),
333 "bucket %d stacks on label %d %U",
335 exp->label_o_adj.label,
336 format_mpls_eos_bit, exp->label_o_adj.eos);
338 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
339 "bucket %d label stacks on %U",
341 format_dpo_type, mld->mld_dpo.dpoi_type);
343 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
344 "bucket %d label stacks on adj %d",
346 exp->label_o_adj.adj);
350 FIB_TEST_LB((DPO_INTERFACE_RX == dpo->dpoi_type),
351 "bucket %d stacks on %U",
353 format_dpo_type, dpo->dpoi_type);
355 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
356 "bucket %d stacks on adj %d",
360 case FT_REP_DISP_MFIB_LOOKUP:
370 fib_test_validate_lb_v (const load_balance_t *lb,
378 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
380 for (bucket = 0; bucket < n_buckets; bucket++)
382 const fib_test_lb_bucket_t *exp;
384 exp = va_arg(*ap, fib_test_lb_bucket_t*);
385 dpo = load_balance_get_bucket_i(lb, bucket);
389 case FT_LB_LABEL_STACK_O_ADJ:
391 const mpls_label_dpo_t *mld;
392 mpls_label_dpo_flags_t mf;
396 mf = ((exp->label_stack_o_adj.mode ==
397 FIB_MPLS_LSP_MODE_UNIFORM) ?
398 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE :
399 MPLS_LABEL_DPO_FLAG_NONE);
400 FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type),
401 "bucket %d stacks on %U",
403 format_dpo_type, dpo->dpoi_type);
405 mld = mpls_label_dpo_get(dpo->dpoi_index);
407 FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
411 for (ii = 0; ii < mld->mld_n_labels; ii++)
413 hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
414 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
415 exp->label_stack_o_adj.label_stack[ii]),
416 "bucket %d stacks on label %d",
418 exp->label_stack_o_adj.label_stack[ii]);
420 if (ii == mld->mld_n_labels-1)
422 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
423 exp->label_o_adj.eos),
424 "bucket %d stacks on label %d %U!=%U",
426 exp->label_stack_o_adj.label_stack[ii],
427 format_mpls_eos_bit, exp->label_o_adj.eos,
428 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
432 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
433 "bucket %d stacks on label %d %U",
435 exp->label_stack_o_adj.label_stack[ii],
436 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
440 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
441 "bucket %d label stacks on %U",
443 format_dpo_type, mld->mld_dpo.dpoi_type);
445 FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
446 "bucket %d label stacks on adj %d",
448 exp->label_stack_o_adj.adj);
451 case FT_LB_LABEL_CHAIN_O_ADJ:
453 const mpls_label_dpo_t *mld = NULL;
454 mpls_label_dpo_flags_t mf;
458 mf = ((exp->label_chain_o_adj.mode ==
459 FIB_MPLS_LSP_MODE_UNIFORM) ?
460 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE :
461 MPLS_LABEL_DPO_FLAG_NONE);
463 for (ii = 0; ii < exp->label_chain_o_adj.label_chain_size; ii++)
465 FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type),
466 "bucket %d stacks on %U",
468 format_dpo_type, dpo->dpoi_type);
469 mld = mpls_label_dpo_get(dpo->dpoi_index);
471 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
472 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
473 exp->label_chain_o_adj.label_chain[ii]),
474 "bucket %d stacks on label %d",
476 exp->label_chain_o_adj.label_chain[ii]);
480 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
481 "bucket %d label stacks on %U",
483 format_dpo_type, mld->mld_dpo.dpoi_type);
485 FIB_TEST_LB((exp->label_chain_o_adj.adj == mld->mld_dpo.dpoi_index),
486 "bucket %d label stacks on adj %d",
488 exp->label_chain_o_adj.adj);
491 case FT_LB_LABEL_O_ADJ:
493 const mpls_label_dpo_t *mld;
495 FIB_TEST_LB((mpls_label_dpo_get_type(MPLS_LABEL_DPO_FLAG_NONE)
497 "bucket %d stacks on %U",
499 format_dpo_type, dpo->dpoi_type);
501 mld = mpls_label_dpo_get(dpo->dpoi_index);
502 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
504 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
505 exp->label_o_adj.label),
506 "bucket %d stacks on label %d",
508 exp->label_o_adj.label);
510 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
511 exp->label_o_adj.eos),
512 "bucket %d stacks on label %d %U",
514 exp->label_o_adj.label,
515 format_mpls_eos_bit, exp->label_o_adj.eos);
517 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
518 "bucket %d label stacks on %U",
520 format_dpo_type, mld->mld_dpo.dpoi_type);
522 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
523 "bucket %d label stacks on adj %d",
525 exp->label_o_adj.adj);
528 case FT_LB_LABEL_O_LB:
530 const mpls_label_dpo_t *mld;
531 mpls_label_dpo_flags_t mf;
534 mf = ((exp->label_o_lb.mode ==
535 FIB_MPLS_LSP_MODE_UNIFORM) ?
536 MPLS_LABEL_DPO_FLAG_UNIFORM_MODE :
537 MPLS_LABEL_DPO_FLAG_NONE);
538 FIB_TEST_LB((mpls_label_dpo_get_type(mf) == dpo->dpoi_type),
539 "bucket %d stacks on %U",
541 format_dpo_type, dpo->dpoi_type);
543 mld = mpls_label_dpo_get(dpo->dpoi_index);
544 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
546 FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
548 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
549 exp->label_o_lb.label),
550 "bucket %d stacks on label %d",
552 exp->label_o_lb.label);
554 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
555 exp->label_o_lb.eos),
556 "bucket %d stacks on label %d %U",
558 exp->label_o_lb.label,
559 format_mpls_eos_bit, exp->label_o_lb.eos);
561 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
562 "bucket %d label stacks on %U",
564 format_dpo_type, mld->mld_dpo.dpoi_type);
566 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
567 "bucket %d label stacks on LB %d",
573 res = FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
574 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
575 "bucket %d stacks on %U",
577 format_dpo_type, dpo->dpoi_type);
578 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
579 "bucket %d stacks on adj %d",
583 case FT_LB_MPLS_DISP_PIPE_O_ADJ:
585 const mpls_disp_dpo_t *mdd;
587 res = FIB_TEST_I((DPO_MPLS_DISPOSITION_PIPE == dpo->dpoi_type),
588 "bucket %d stacks on %U",
590 format_dpo_type, dpo->dpoi_type);
592 mdd = mpls_disp_dpo_get(dpo->dpoi_index);
596 res = FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
597 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
598 "bucket %d stacks on %U",
600 format_dpo_type, dpo->dpoi_type);
601 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
602 "bucket %d stacks on adj %d",
608 res = FIB_TEST_I((DPO_INTERFACE_RX == dpo->dpoi_type),
609 "bucket %d stacks on %U",
611 format_dpo_type, dpo->dpoi_type);
612 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
613 "bucket %d stacks on adj %d",
618 res = FIB_TEST_I((DPO_DVR == dpo->dpoi_type),
619 "bucket %d stacks on %U",
621 format_dpo_type, dpo->dpoi_type);
622 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
623 "bucket %d stacks on adj %d",
628 res = FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
629 "bucket %d stacks on %U",
631 format_dpo_type, dpo->dpoi_type);
632 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
633 "bucket %d stacks on lb %d not %d",
638 case FT_LB_BIER_TABLE:
639 FIB_TEST_LB((DPO_BIER_TABLE == dpo->dpoi_type),
640 "bucket %d stacks on %U",
642 format_dpo_type, dpo->dpoi_type);
643 FIB_TEST_LB((exp->bier.table == dpo->dpoi_index),
644 "bucket %d stacks on lb %d",
648 case FT_LB_BIER_FMASK:
649 FIB_TEST_LB((DPO_BIER_FMASK == dpo->dpoi_type),
650 "bucket %d stacks on %U",
652 format_dpo_type, dpo->dpoi_type);
653 FIB_TEST_LB((exp->bier.fmask == dpo->dpoi_index),
654 "bucket %d stacks on lb %d",
659 FIB_TEST_LB((DPO_DROP == dpo->dpoi_type),
660 "bucket %d stacks on %U",
662 format_dpo_type, dpo->dpoi_type);
665 FIB_TEST_LB((DPO_PUNT == dpo->dpoi_type),
666 "bucket %d stacks on %U",
668 format_dpo_type, dpo->dpoi_type);
676 fib_test_validate_lb (const dpo_id_t *dpo,
680 const load_balance_t *lb;
685 va_start(ap, n_buckets);
687 if (!FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
689 format_dpo_type, dpo->dpoi_type))
691 lb = load_balance_get(dpo->dpoi_index);
693 res = fib_test_validate_lb_v(lb, n_buckets, &ap);
706 fib_test_validate_entry (fib_node_index_t fei,
707 fib_forward_chain_type_t fct,
711 dpo_id_t dpo = DPO_INVALID;
712 const fib_prefix_t *pfx;
720 pfx = fib_entry_get_prefix(fei);
721 fib_index = fib_entry_get_fib_index(fei);
722 fib_entry_contribute_forwarding(fei, fct, &dpo);
724 if (DPO_REPLICATE == dpo.dpoi_type)
726 const replicate_t *rep;
728 va_start(ap, n_buckets);
729 rep = replicate_get(dpo.dpoi_index);
730 res = fib_test_validate_rep_v(rep, n_buckets, &ap);
735 const load_balance_t *lb;
737 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
738 "%U Entry links to %U",
739 format_fib_prefix, pfx,
740 format_dpo_type, dpo.dpoi_type);
742 va_start(ap, n_buckets);
743 lb = load_balance_get(dpo.dpoi_index);
744 res = fib_test_validate_lb_v(lb, n_buckets, &ap);
748 * ensure that the LB contributed by the entry is the
749 * same as the LB in the forwarding tables
751 if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
753 switch (pfx->fp_proto)
755 case FIB_PROTOCOL_IP4:
756 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx->fp_addr.ip4);
758 case FIB_PROTOCOL_IP6:
759 fw_lbi = ip6_fib_table_fwding_lookup(fib_index, &pfx->fp_addr.ip6);
761 case FIB_PROTOCOL_MPLS:
763 mpls_unicast_header_t hdr = {
764 .label_exp_s_ttl = 0,
767 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx->fp_label);
768 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx->fp_eos);
769 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
771 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
777 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
778 "Contributed LB = FW LB:\n fwd:%U\n cont:%U",
779 format_load_balance, fw_lbi, 0,
780 format_load_balance, dpo.dpoi_index, 0);
793 * In the default table check for the presence and correct forwarding
794 * of the special entries
796 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
797 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
798 const ip_adjacency_t *adj;
799 const load_balance_t *lb;
807 ip46_address_t nh_10_10_10_1 = {
808 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
811 ip46_address_t nh_10_10_10_2 = {
812 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
815 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
816 pool_elts(load_balance_map_pool));
820 /* record the nubmer of load-balances in use before we start */
821 lb_count = pool_elts(load_balance_pool);
823 /* Find or create FIB table 11 */
824 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11,
827 for (ii = 0; ii < 4; ii++)
829 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
832 fib_prefix_t pfx_0_0_0_0_s_0 = {
834 .fp_proto = FIB_PROTOCOL_IP4,
844 .fp_proto = FIB_PROTOCOL_IP4,
852 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
854 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
855 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
856 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
857 "Default route is DROP");
860 fei = fib_table_lookup(fib_index, &pfx);
861 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
862 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
863 "all 0s route is DROP");
865 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
867 fei = fib_table_lookup(fib_index, &pfx);
868 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
869 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
870 "all 1s route is DROP");
872 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
874 fei = fib_table_lookup(fib_index, &pfx);
875 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
876 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
877 "all-mcast route is DROP");
879 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
881 fei = fib_table_lookup(fib_index, &pfx);
882 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
883 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
884 "class-e route is DROP");
887 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
888 * all of which are special sourced and so none of which share path-lists.
889 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
890 * table, and 4 path-lists in the v6 MFIB table and 2 in v4.
894 u32 PNBR = 5+5+2+4+2;
897 * if the IGMP plugin is loaded this adds two more entries to the v4 MFIB
899 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
900 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
901 fib_path_list_pool_size());
902 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
903 fib_entry_pool_size());
906 * add interface routes.
907 * validate presence of /24 attached and /32 recieve.
908 * test for the presence of the receive address in the glean and local adj
910 fib_prefix_t local_pfx = {
912 .fp_proto = FIB_PROTOCOL_IP4,
915 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
920 fib_table_entry_update_one_path(fib_index, &local_pfx,
921 FIB_SOURCE_INTERFACE,
922 (FIB_ENTRY_FLAG_CONNECTED |
923 FIB_ENTRY_FLAG_ATTACHED),
926 tm->hw[0]->sw_if_index,
927 ~0, // invalid fib index
930 FIB_ROUTE_PATH_FLAG_NONE);
931 fei = fib_table_lookup(fib_index, &local_pfx);
932 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
933 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
934 fib_entry_get_flags(fei)),
935 "Flags set on attached interface");
937 ai = fib_entry_get_adj(fei);
938 FIB_TEST((FIB_NODE_INDEX_INVALID != ai),
939 "attached interface route adj present %d", ai);
941 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
942 "attached interface adj is glean");
944 local_pfx.fp_len = 32;
945 fib_table_entry_update_one_path(fib_index, &local_pfx,
946 FIB_SOURCE_INTERFACE,
947 (FIB_ENTRY_FLAG_CONNECTED |
948 FIB_ENTRY_FLAG_LOCAL),
951 tm->hw[0]->sw_if_index,
952 ~0, // invalid fib index
955 FIB_ROUTE_PATH_FLAG_NONE);
956 fei = fib_table_lookup(fib_index, &local_pfx);
957 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
958 fib_entry_get_flags(fei)),
959 "Flags set on local interface");
961 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
963 dpo = fib_entry_contribute_ip_forwarding(fei);
964 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
965 "RPF list for local length 0");
966 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
967 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
968 "local interface adj is local");
969 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
971 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
973 "local interface adj is receive ok");
975 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
977 FIB_SOURCE_INTERFACE)),
978 "2 Interface Source'd prefixes");
979 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
980 &adj->sub_type.glean.rx_pfx.fp_addr)),
981 "attached interface adj is receive ok");
984 * +2 interface routes +2 non-shared path-lists
986 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
987 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
988 fib_path_list_pool_size());
989 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
990 fib_entry_pool_size());
993 * Modify the default route to be via an adj not yet known.
994 * this sources the defalut route with the API source, which is
995 * a higher preference to the DEFAULT_ROUTE source
997 pfx.fp_addr.ip4.as_u32 = 0;
999 fib_table_entry_path_add(fib_index, &pfx,
1001 FIB_ENTRY_FLAG_NONE,
1004 tm->hw[0]->sw_if_index,
1005 ~0, // invalid fib index
1008 FIB_ROUTE_PATH_FLAG_NONE);
1009 fei = fib_table_lookup(fib_index, &pfx);
1010 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
1011 "Flags set on API route");
1013 FIB_TEST((fei == dfrt), "default route same index");
1014 ai = fib_entry_get_adj(fei);
1015 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
1017 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1018 "adj is incomplete");
1019 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
1020 "adj nbr next-hop ok");
1021 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
1024 "1 API Source'd prefixes");
1027 * find the adj in the shared db
1029 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1032 tm->hw[0]->sw_if_index);
1033 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
1034 adj_unlock(locked_ai);
1037 * +1 shared path-list
1039 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
1040 fib_path_list_db_size());
1041 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
1042 fib_path_list_pool_size());
1043 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
1044 fib_entry_pool_size());
1047 * remove the API source from the default route. We expected
1048 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
1050 pfx.fp_addr.ip4.as_u32 = 0;
1052 fib_table_entry_path_remove(fib_index, &pfx,
1056 tm->hw[0]->sw_if_index,
1057 ~0, // non-recursive path, so no FIB index
1059 FIB_ROUTE_PATH_FLAG_NONE);
1061 fei = fib_table_lookup(fib_index, &pfx);
1063 FIB_TEST((fei == dfrt), "default route same index");
1064 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1065 "Default route is DROP");
1068 * -1 shared-path-list
1070 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1071 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
1072 fib_path_list_pool_size());
1073 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
1074 fib_entry_pool_size());
1077 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
1079 fib_prefix_t pfx_10_10_10_1_s_32 = {
1081 .fp_proto = FIB_PROTOCOL_IP4,
1084 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
1087 fib_prefix_t pfx_10_10_10_2_s_32 = {
1089 .fp_proto = FIB_PROTOCOL_IP4,
1092 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
1095 fib_prefix_t pfx_11_11_11_11_s_32 = {
1097 .fp_proto = FIB_PROTOCOL_IP4,
1100 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
1104 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
1107 ip46_address_t nh_12_12_12_12 = {
1108 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
1110 adj_index_t ai_12_12_12_12;
1113 * Add a route via an incomplete ADJ. then complete the ADJ
1114 * Expect the route LB is updated to use complete adj type.
1116 fei = fib_table_entry_update_one_path(fib_index,
1117 &pfx_11_11_11_11_s_32,
1119 FIB_ENTRY_FLAG_ATTACHED,
1121 &pfx_10_10_10_1_s_32.fp_addr,
1122 tm->hw[0]->sw_if_index,
1123 ~0, // invalid fib index
1126 FIB_ROUTE_PATH_FLAG_NONE);
1128 dpo = fib_entry_contribute_ip_forwarding(fei);
1129 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1130 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
1131 "11.11.11.11/32 via incomplete adj");
1133 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1135 &pfx_10_10_10_1_s_32.fp_addr,
1136 tm->hw[0]->sw_if_index);
1137 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
1138 adj = adj_get(ai_01);
1139 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1140 "adj is incomplete");
1141 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1142 &adj->sub_type.nbr.next_hop)),
1143 "adj nbr next-hop ok");
1145 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1146 fib_test_build_rewrite(eth_addr));
1147 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1149 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
1150 &adj->sub_type.nbr.next_hop)),
1151 "adj nbr next-hop ok");
1152 ai = fib_entry_get_adj(fei);
1153 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1155 dpo = fib_entry_contribute_ip_forwarding(fei);
1156 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1157 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1158 "11.11.11.11/32 via complete adj");
1159 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1160 tm->hw[0]->sw_if_index),
1161 "RPF list for adj-fib contains adj");
1163 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1166 tm->hw[1]->sw_if_index);
1167 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1168 adj = adj_get(ai_12_12_12_12);
1169 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1170 "adj is incomplete");
1171 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1172 &adj->sub_type.nbr.next_hop)),
1173 "adj nbr next-hop ok");
1174 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1175 fib_test_build_rewrite(eth_addr));
1176 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1182 fei = fib_table_entry_path_add(fib_index,
1183 &pfx_10_10_10_1_s_32,
1185 FIB_ENTRY_FLAG_ATTACHED,
1187 &pfx_10_10_10_1_s_32.fp_addr,
1188 tm->hw[0]->sw_if_index,
1189 ~0, // invalid fib index
1192 FIB_ROUTE_PATH_FLAG_NONE);
1193 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1194 "Flags set on adj-fib");
1195 ai = fib_entry_get_adj(fei);
1196 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
1198 fib_table_entry_path_remove(fib_index,
1199 &pfx_11_11_11_11_s_32,
1202 &pfx_10_10_10_1_s_32.fp_addr,
1203 tm->hw[0]->sw_if_index,
1204 ~0, // invalid fib index
1206 FIB_ROUTE_PATH_FLAG_NONE);
1210 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1212 &pfx_10_10_10_2_s_32.fp_addr,
1213 tm->hw[0]->sw_if_index);
1214 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1215 adj = adj_get(ai_02);
1216 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1217 "adj is incomplete");
1218 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1219 &adj->sub_type.nbr.next_hop)),
1220 "adj nbr next-hop ok");
1222 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1223 fib_test_build_rewrite(eth_addr));
1224 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1226 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1227 &adj->sub_type.nbr.next_hop)),
1228 "adj nbr next-hop ok");
1229 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1231 fib_table_entry_path_add(fib_index,
1232 &pfx_10_10_10_2_s_32,
1234 FIB_ENTRY_FLAG_ATTACHED,
1236 &pfx_10_10_10_2_s_32.fp_addr,
1237 tm->hw[0]->sw_if_index,
1238 ~0, // invalid fib index
1241 FIB_ROUTE_PATH_FLAG_NONE);
1243 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1244 ai = fib_entry_get_adj(fei);
1245 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1248 * +2 adj-fibs, and their non-shared path-lists
1250 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1251 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1252 fib_path_list_pool_size());
1253 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1254 fib_entry_pool_size());
1257 * Add 2 routes via the first ADJ. ensure path-list sharing
1259 fib_prefix_t pfx_1_1_1_1_s_32 = {
1261 .fp_proto = FIB_PROTOCOL_IP4,
1264 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1268 fib_table_entry_path_add(fib_index,
1271 FIB_ENTRY_FLAG_NONE,
1274 tm->hw[0]->sw_if_index,
1275 ~0, // invalid fib index
1278 FIB_ROUTE_PATH_FLAG_NONE);
1279 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1280 ai = fib_entry_get_adj(fei);
1281 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1284 * +1 entry and a shared path-list
1286 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1287 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1288 fib_path_list_pool_size());
1289 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1290 fib_entry_pool_size());
1293 fib_prefix_t pfx_1_1_2_0_s_24 = {
1295 .fp_proto = FIB_PROTOCOL_IP4,
1297 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1301 fib_table_entry_path_add(fib_index,
1304 FIB_ENTRY_FLAG_NONE,
1307 tm->hw[0]->sw_if_index,
1308 ~0, // invalid fib index
1311 FIB_ROUTE_PATH_FLAG_NONE);
1312 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1313 ai = fib_entry_get_adj(fei);
1314 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1319 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1320 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1321 fib_path_list_pool_size());
1322 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1323 fib_entry_pool_size());
1326 * modify 1.1.2.0/24 to use multipath.
1328 fib_table_entry_path_add(fib_index,
1331 FIB_ENTRY_FLAG_NONE,
1334 tm->hw[0]->sw_if_index,
1335 ~0, // invalid fib index
1338 FIB_ROUTE_PATH_FLAG_NONE);
1339 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1340 dpo = fib_entry_contribute_ip_forwarding(fei);
1341 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1342 1, tm->hw[0]->sw_if_index),
1343 "RPF list for 1.1.2.0/24 contains both adjs");
1345 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1346 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1347 FIB_TEST((ai_01 == dpo1->dpoi_index),
1348 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1349 ai_01, dpo1->dpoi_index);
1351 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1352 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1353 FIB_TEST((ai_02 == dpo1->dpoi_index),
1354 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1357 * +1 shared-pathlist
1359 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
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+6 == fib_entry_pool_size()), "entry pool size is %d",
1363 fib_entry_pool_size());
1368 fib_table_entry_path_remove(fib_index,
1373 tm->hw[0]->sw_if_index,
1376 FIB_ROUTE_PATH_FLAG_NONE);
1377 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1378 dpo = fib_entry_contribute_ip_forwarding(fei);
1379 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1380 1, tm->hw[0]->sw_if_index),
1381 "RPF list for 1.1.2.0/24 contains one adj");
1383 ai = fib_entry_get_adj(fei);
1384 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1387 * +1 shared-pathlist
1389 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1390 fib_path_list_db_size());
1391 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1392 fib_path_list_pool_size());
1393 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1394 fib_entry_pool_size());
1397 * Add 2 recursive routes:
1398 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1399 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1401 fib_prefix_t bgp_100_pfx = {
1403 .fp_proto = FIB_PROTOCOL_IP4,
1405 /* 100.100.100.100/32 */
1406 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1410 ip46_address_t nh_1_1_1_1 = {
1411 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1414 fei = fib_table_entry_path_add(fib_index,
1417 FIB_ENTRY_FLAG_NONE,
1420 ~0, // no index provided.
1421 fib_index, // nexthop in same fib as route
1424 FIB_ROUTE_PATH_FLAG_NONE);
1426 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1427 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1428 tm->hw[0]->sw_if_index),
1429 "RPF list for adj-fib contains adj");
1432 * +1 entry and +1 shared-path-list
1434 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1435 fib_path_list_db_size());
1436 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1437 fib_path_list_pool_size());
1438 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1439 fib_entry_pool_size());
1441 fib_prefix_t bgp_101_pfx = {
1443 .fp_proto = FIB_PROTOCOL_IP4,
1445 /* 100.100.100.101/32 */
1446 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1450 fib_table_entry_path_add(fib_index,
1453 FIB_ENTRY_FLAG_NONE,
1456 ~0, // no index provided.
1457 fib_index, // nexthop in same fib as route
1460 FIB_ROUTE_PATH_FLAG_NONE);
1462 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1463 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1464 tm->hw[0]->sw_if_index),
1465 "RPF list for adj-fib contains adj");
1468 * +1 entry, but the recursive path-list is shared.
1470 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1471 fib_path_list_db_size());
1472 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1473 fib_path_list_pool_size());
1474 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1475 fib_entry_pool_size());
1478 * An special route; one where the user (me) provides the
1479 * adjacency through which the route will resovle by setting the flags
1481 fib_prefix_t ex_pfx = {
1483 .fp_proto = FIB_PROTOCOL_IP4,
1486 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1490 fib_table_entry_special_add(fib_index,
1493 FIB_ENTRY_FLAG_LOCAL);
1494 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1495 dpo = fib_entry_contribute_ip_forwarding(fei);
1496 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1497 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1498 "local interface adj is local");
1500 fib_table_entry_special_remove(fib_index,
1502 FIB_SOURCE_SPECIAL);
1503 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1504 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1505 "Exclusive reoute removed");
1508 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1509 * adjacency through which the route will resovle
1511 dpo_id_t ex_dpo = DPO_INVALID;
1513 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1516 LOOKUP_INPUT_DST_ADDR,
1517 LOOKUP_TABLE_FROM_CONFIG,
1520 fib_table_entry_special_dpo_add(fib_index,
1523 FIB_ENTRY_FLAG_EXCLUSIVE,
1525 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1526 dpo = fib_entry_contribute_ip_forwarding(fei);
1527 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1528 "exclusive remote uses lookup DPO");
1531 * update the exclusive to use a different DPO
1533 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1534 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1536 fib_table_entry_special_dpo_update(fib_index,
1539 FIB_ENTRY_FLAG_EXCLUSIVE,
1541 dpo = fib_entry_contribute_ip_forwarding(fei);
1542 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1543 "exclusive remote uses now uses NULL DPO");
1545 fib_table_entry_special_remove(fib_index,
1547 FIB_SOURCE_SPECIAL);
1548 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1549 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1550 "Exclusive reoute removed");
1554 * Add a recursive route:
1555 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1557 fib_prefix_t bgp_200_pfx = {
1559 .fp_proto = FIB_PROTOCOL_IP4,
1561 /* 200.200.200.200/32 */
1562 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1566 fib_prefix_t pfx_1_1_1_2_s_32 = {
1568 .fp_proto = FIB_PROTOCOL_IP4,
1570 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1574 fei = fib_table_entry_path_add(fib_index,
1577 FIB_ENTRY_FLAG_NONE,
1579 &pfx_1_1_1_2_s_32.fp_addr,
1580 ~0, // no index provided.
1581 fib_index, // nexthop in same fib as route
1584 FIB_ROUTE_PATH_FLAG_NONE);
1586 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1587 "Recursive via unresolved is drop");
1590 * the adj should be recursive via drop, since the route resolves via
1591 * the default route, which is itself a DROP
1593 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1594 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1595 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1596 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1597 "RPF list for 1.1.1.2/32 contains 0 adjs");
1600 * +2 entry and +1 shared-path-list
1602 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1603 fib_path_list_db_size());
1604 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1605 fib_path_list_pool_size());
1606 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1607 fib_entry_pool_size());
1610 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1611 * The paths are sort by NH first. in this case the the path with greater
1612 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1614 fib_prefix_t pfx_1_2_3_4_s_32 = {
1616 .fp_proto = FIB_PROTOCOL_IP4,
1618 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1621 fib_table_entry_path_add(fib_index,
1624 FIB_ENTRY_FLAG_NONE,
1627 tm->hw[0]->sw_if_index,
1631 FIB_ROUTE_PATH_FLAG_NONE);
1632 fei = fib_table_entry_path_add(fib_index,
1635 FIB_ENTRY_FLAG_NONE,
1638 tm->hw[1]->sw_if_index,
1642 FIB_ROUTE_PATH_FLAG_NONE);
1644 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1645 dpo = fib_entry_contribute_ip_forwarding(fei);
1646 lb = load_balance_get(dpo->dpoi_index);
1647 FIB_TEST((lb->lb_n_buckets == 4),
1648 "1.2.3.4/32 LB has %d bucket",
1651 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1652 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1653 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1654 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1656 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1657 tm->hw[0]->sw_if_index,
1658 tm->hw[1]->sw_if_index),
1659 "RPF list for 1.2.3.4/32 contains both adjs");
1663 * Unequal Cost load-balance. 4:1 ratio.
1664 * fits in a 16 bucket LB with ratio 13:3
1666 fib_prefix_t pfx_1_2_3_5_s_32 = {
1668 .fp_proto = FIB_PROTOCOL_IP4,
1670 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1673 fib_table_entry_path_add(fib_index,
1676 FIB_ENTRY_FLAG_NONE,
1679 tm->hw[1]->sw_if_index,
1683 FIB_ROUTE_PATH_FLAG_NONE);
1684 fei = fib_table_entry_path_add(fib_index,
1687 FIB_ENTRY_FLAG_NONE,
1690 tm->hw[0]->sw_if_index,
1694 FIB_ROUTE_PATH_FLAG_NONE);
1696 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1697 dpo = fib_entry_contribute_ip_forwarding(fei);
1698 lb = load_balance_get(dpo->dpoi_index);
1699 FIB_TEST((lb->lb_n_buckets == 16),
1700 "1.2.3.5/32 LB has %d bucket",
1703 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1704 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1705 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1706 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1707 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1708 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1709 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1710 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1711 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1712 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1713 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1714 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1715 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1716 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1717 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1718 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1720 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1721 tm->hw[0]->sw_if_index,
1722 tm->hw[1]->sw_if_index),
1723 "RPF list for 1.2.3.4/32 contains both adjs");
1726 * Test UCMP with a large weight skew - this produces load-balance objects with large
1727 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1728 * laso testing the LB in placce modify code when number of buckets is large.
1730 fib_prefix_t pfx_6_6_6_6_s_32 = {
1732 .fp_proto = FIB_PROTOCOL_IP4,
1735 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1738 fib_test_lb_bucket_t ip_o_10_10_10_1 = {
1744 fib_test_lb_bucket_t ip_o_10_10_10_2 = {
1750 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1753 .adj = ai_12_12_12_12,
1756 fib_table_entry_update_one_path(fib_index,
1759 FIB_ENTRY_FLAG_NONE,
1762 tm->hw[0]->sw_if_index,
1763 ~0, // invalid fib index
1766 FIB_ROUTE_PATH_FLAG_NONE);
1768 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1769 FIB_TEST(!fib_test_validate_entry(fei,
1770 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1773 "6.6.6.6/32 via 10.10.10.1");
1775 fib_table_entry_path_add(fib_index,
1778 FIB_ENTRY_FLAG_NONE,
1781 tm->hw[0]->sw_if_index,
1782 ~0, // invalid fib index
1785 FIB_ROUTE_PATH_FLAG_NONE);
1787 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1788 FIB_TEST(!fib_test_validate_entry(fei,
1789 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1855 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1857 fib_table_entry_path_add(fib_index,
1860 FIB_ENTRY_FLAG_NONE,
1863 tm->hw[1]->sw_if_index,
1864 ~0, // invalid fib index
1867 FIB_ROUTE_PATH_FLAG_NONE);
1869 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1870 FIB_TEST(!fib_test_validate_entry(fei,
1871 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1938 &ip_6_6_6_6_o_12_12_12_12,
1939 &ip_6_6_6_6_o_12_12_12_12,
1940 &ip_6_6_6_6_o_12_12_12_12,
1941 &ip_6_6_6_6_o_12_12_12_12,
1942 &ip_6_6_6_6_o_12_12_12_12,
1943 &ip_6_6_6_6_o_12_12_12_12,
1944 &ip_6_6_6_6_o_12_12_12_12,
1945 &ip_6_6_6_6_o_12_12_12_12,
1946 &ip_6_6_6_6_o_12_12_12_12,
1947 &ip_6_6_6_6_o_12_12_12_12,
1948 &ip_6_6_6_6_o_12_12_12_12,
1949 &ip_6_6_6_6_o_12_12_12_12,
1950 &ip_6_6_6_6_o_12_12_12_12,
1951 &ip_6_6_6_6_o_12_12_12_12,
1952 &ip_6_6_6_6_o_12_12_12_12,
1953 &ip_6_6_6_6_o_12_12_12_12,
1954 &ip_6_6_6_6_o_12_12_12_12,
1955 &ip_6_6_6_6_o_12_12_12_12,
1956 &ip_6_6_6_6_o_12_12_12_12,
1957 &ip_6_6_6_6_o_12_12_12_12,
1958 &ip_6_6_6_6_o_12_12_12_12,
1959 &ip_6_6_6_6_o_12_12_12_12,
1960 &ip_6_6_6_6_o_12_12_12_12,
1961 &ip_6_6_6_6_o_12_12_12_12,
1962 &ip_6_6_6_6_o_12_12_12_12,
1963 &ip_6_6_6_6_o_12_12_12_12,
1964 &ip_6_6_6_6_o_12_12_12_12,
1965 &ip_6_6_6_6_o_12_12_12_12,
1966 &ip_6_6_6_6_o_12_12_12_12,
1967 &ip_6_6_6_6_o_12_12_12_12,
1968 &ip_6_6_6_6_o_12_12_12_12,
1969 &ip_6_6_6_6_o_12_12_12_12,
1970 &ip_6_6_6_6_o_12_12_12_12,
1971 &ip_6_6_6_6_o_12_12_12_12,
1972 &ip_6_6_6_6_o_12_12_12_12,
1973 &ip_6_6_6_6_o_12_12_12_12,
1974 &ip_6_6_6_6_o_12_12_12_12,
1975 &ip_6_6_6_6_o_12_12_12_12,
1976 &ip_6_6_6_6_o_12_12_12_12,
1977 &ip_6_6_6_6_o_12_12_12_12,
1978 &ip_6_6_6_6_o_12_12_12_12,
1979 &ip_6_6_6_6_o_12_12_12_12,
1980 &ip_6_6_6_6_o_12_12_12_12,
1981 &ip_6_6_6_6_o_12_12_12_12,
1982 &ip_6_6_6_6_o_12_12_12_12,
1983 &ip_6_6_6_6_o_12_12_12_12,
1984 &ip_6_6_6_6_o_12_12_12_12,
1985 &ip_6_6_6_6_o_12_12_12_12,
1986 &ip_6_6_6_6_o_12_12_12_12,
1987 &ip_6_6_6_6_o_12_12_12_12,
1988 &ip_6_6_6_6_o_12_12_12_12,
1989 &ip_6_6_6_6_o_12_12_12_12,
1990 &ip_6_6_6_6_o_12_12_12_12,
1991 &ip_6_6_6_6_o_12_12_12_12,
1992 &ip_6_6_6_6_o_12_12_12_12,
1993 &ip_6_6_6_6_o_12_12_12_12,
1994 &ip_6_6_6_6_o_12_12_12_12,
1995 &ip_6_6_6_6_o_12_12_12_12,
1996 &ip_6_6_6_6_o_12_12_12_12,
1997 &ip_6_6_6_6_o_12_12_12_12,
1998 &ip_6_6_6_6_o_12_12_12_12,
1999 &ip_6_6_6_6_o_12_12_12_12,
2000 &ip_6_6_6_6_o_12_12_12_12),
2001 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
2003 fib_table_entry_path_remove(fib_index,
2008 tm->hw[1]->sw_if_index,
2009 ~0, // invalid fib index
2011 FIB_ROUTE_PATH_FLAG_NONE);
2013 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2014 FIB_TEST(!fib_test_validate_entry(fei,
2015 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2081 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
2083 fib_table_entry_path_remove(fib_index,
2088 tm->hw[0]->sw_if_index,
2089 ~0, // invalid fib index
2091 FIB_ROUTE_PATH_FLAG_NONE);
2093 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
2094 FIB_TEST(!fib_test_validate_entry(fei,
2095 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
2098 "6.6.6.6/32 via 10.10.10.1");
2100 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
2103 * A recursive via the two unequal cost entries
2105 fib_prefix_t bgp_44_s_32 = {
2107 .fp_proto = FIB_PROTOCOL_IP4,
2109 /* 200.200.200.201/32 */
2110 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
2113 fei = fib_table_entry_path_add(fib_index,
2116 FIB_ENTRY_FLAG_NONE,
2118 &pfx_1_2_3_4_s_32.fp_addr,
2123 FIB_ROUTE_PATH_FLAG_NONE);
2124 fei = fib_table_entry_path_add(fib_index,
2127 FIB_ENTRY_FLAG_NONE,
2129 &pfx_1_2_3_5_s_32.fp_addr,
2134 FIB_ROUTE_PATH_FLAG_NONE);
2136 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
2137 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
2138 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
2139 tm->hw[0]->sw_if_index,
2140 tm->hw[1]->sw_if_index),
2141 "RPF list for 1.2.3.4/32 contains both adjs");
2144 * test the uRPF check functions
2146 dpo_id_t dpo_44 = DPO_INVALID;
2149 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
2150 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2152 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2153 "uRPF check for 68.68.68.68/32 on %d OK",
2154 tm->hw[0]->sw_if_index);
2155 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2156 "uRPF check for 68.68.68.68/32 on %d OK",
2157 tm->hw[1]->sw_if_index);
2158 FIB_TEST(!fib_urpf_check(urpfi, 99),
2159 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2163 fib_table_entry_delete(fib_index,
2166 fib_table_entry_delete(fib_index,
2169 fib_table_entry_delete(fib_index,
2174 * Add a recursive route:
2175 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2177 fib_prefix_t bgp_201_pfx = {
2179 .fp_proto = FIB_PROTOCOL_IP4,
2181 /* 200.200.200.201/32 */
2182 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2186 fib_prefix_t pfx_1_1_1_200_s_32 = {
2188 .fp_proto = FIB_PROTOCOL_IP4,
2190 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2194 fei = fib_table_entry_path_add(fib_index,
2197 FIB_ENTRY_FLAG_NONE,
2199 &pfx_1_1_1_200_s_32.fp_addr,
2200 ~0, // no index provided.
2201 fib_index, // nexthop in same fib as route
2204 FIB_ROUTE_PATH_FLAG_NONE);
2206 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2207 "Recursive via unresolved is drop");
2209 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2210 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2211 "Flags set on RR via non-attached");
2212 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2213 "RPF list for BGP route empty");
2216 * +2 entry (BGP & RR) and +1 shared-path-list
2218 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2219 fib_path_list_db_size());
2220 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2221 fib_path_list_pool_size());
2222 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2223 fib_entry_pool_size());
2226 * insert a route that covers the missing 1.1.1.2/32. we epxect
2227 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2229 fib_prefix_t pfx_1_1_1_0_s_24 = {
2231 .fp_proto = FIB_PROTOCOL_IP4,
2234 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2238 fib_table_entry_path_add(fib_index,
2241 FIB_ENTRY_FLAG_NONE,
2244 tm->hw[0]->sw_if_index,
2245 ~0, // invalid fib index
2248 FIB_ROUTE_PATH_FLAG_NONE);
2249 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2250 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2251 ai = fib_entry_get_adj(fei);
2252 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2253 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2254 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2255 ai = fib_entry_get_adj(fei);
2256 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2257 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2258 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2259 ai = fib_entry_get_adj(fei);
2260 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2263 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2265 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2266 fib_path_list_db_size());
2267 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2268 fib_path_list_pool_size());
2269 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2270 fib_entry_pool_size());
2273 * the recursive adj for 200.200.200.200 should be updated.
2275 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2276 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2277 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2278 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2279 tm->hw[0]->sw_if_index),
2280 "RPF list for BGP route has itf index 0");
2283 * insert a more specific route than 1.1.1.0/24 that also covers the
2284 * missing 1.1.1.2/32, but not 1.1.1.200/32. we expect
2285 * 200.200.200.200 to resolve through it.
2287 fib_prefix_t pfx_1_1_1_0_s_28 = {
2289 .fp_proto = FIB_PROTOCOL_IP4,
2292 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2296 fib_table_entry_path_add(fib_index,
2299 FIB_ENTRY_FLAG_NONE,
2302 tm->hw[0]->sw_if_index,
2303 ~0, // invalid fib index
2306 FIB_ROUTE_PATH_FLAG_NONE);
2307 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2308 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2309 ai = fib_entry_get_adj(fei);
2310 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2313 * +1 entry. +1 shared path-list
2315 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2316 fib_path_list_db_size());
2317 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2318 fib_path_list_pool_size());
2319 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2320 fib_entry_pool_size());
2323 * the recursive adj for 200.200.200.200 should be updated.
2324 * 200.200.200.201 remains unchanged.
2326 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2327 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2330 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2332 fib_table_entry_path_remove(fib_index,
2337 tm->hw[0]->sw_if_index,
2340 FIB_ROUTE_PATH_FLAG_NONE);
2341 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2342 FIB_NODE_INDEX_INVALID),
2343 "1.1.1.0/28 removed");
2344 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2345 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2346 "1.1.1.0/28 lookup via /24");
2347 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2348 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2351 * -1 entry. -1 shared path-list
2353 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2354 fib_path_list_db_size());
2355 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2356 fib_path_list_pool_size());
2357 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2358 fib_entry_pool_size());
2361 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2363 fib_table_entry_path_remove(fib_index,
2368 tm->hw[0]->sw_if_index,
2371 FIB_ROUTE_PATH_FLAG_NONE);
2372 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2373 FIB_NODE_INDEX_INVALID),
2374 "1.1.1.0/24 removed");
2376 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2377 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2378 "1.1.1.2/32 route is DROP");
2379 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2380 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2381 "1.1.1.200/32 route is DROP");
2383 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2384 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2386 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2387 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2393 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2394 fib_path_list_db_size());
2395 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2396 fib_path_list_pool_size());
2397 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2398 fib_entry_pool_size());
2401 * insert the missing 1.1.1.2/32
2403 fei = fib_table_entry_path_add(fib_index,
2406 FIB_ENTRY_FLAG_NONE,
2409 tm->hw[0]->sw_if_index,
2410 ~0, // invalid fib index
2413 FIB_ROUTE_PATH_FLAG_NONE);
2414 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2415 ai = fib_entry_get_adj(fei);
2416 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2418 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2419 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2421 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2424 * no change. 1.1.1.2/32 was already there RR sourced.
2426 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2427 fib_path_list_db_size());
2428 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2429 fib_path_list_pool_size());
2430 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2431 fib_entry_pool_size());
2434 * give 201 a resolved path.
2435 * it now has the unresolved 1.1.1.200 and the resolved 1.1.1.2,
2436 * only the latter contributes forwarding.
2438 fei = fib_table_entry_path_add(fib_index,
2441 FIB_ENTRY_FLAG_NONE,
2443 &pfx_1_1_1_2_s_32.fp_addr,
2448 FIB_ROUTE_PATH_FLAG_NONE);
2449 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_2_s_32, 0);
2450 fib_table_entry_path_remove(fib_index,
2454 &pfx_1_1_1_2_s_32.fp_addr,
2458 FIB_ROUTE_PATH_FLAG_NONE);
2461 * remove 200.200.200.201/32 which does not have a valid via FIB
2463 fib_table_entry_path_remove(fib_index,
2467 &pfx_1_1_1_200_s_32.fp_addr,
2468 ~0, // no index provided.
2471 FIB_ROUTE_PATH_FLAG_NONE);
2474 * -2 entries (BGP and RR). -1 shared path-list;
2476 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2477 FIB_NODE_INDEX_INVALID),
2478 "200.200.200.201/32 removed");
2479 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2480 FIB_NODE_INDEX_INVALID),
2481 "1.1.1.200/32 removed");
2483 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2484 fib_path_list_db_size());
2485 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2486 fib_path_list_pool_size());
2487 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2488 fib_entry_pool_size());
2491 * remove 200.200.200.200/32 which does have a valid via FIB
2493 fib_table_entry_path_remove(fib_index,
2497 &pfx_1_1_1_2_s_32.fp_addr,
2498 ~0, // no index provided.
2501 FIB_ROUTE_PATH_FLAG_NONE);
2503 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2504 FIB_NODE_INDEX_INVALID),
2505 "200.200.200.200/32 removed");
2506 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2507 FIB_NODE_INDEX_INVALID),
2508 "1.1.1.2/32 still present");
2511 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2513 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2514 fib_path_list_db_size());
2515 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2516 fib_path_list_pool_size());
2517 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2518 fib_entry_pool_size());
2521 * A recursive prefix that has a 2 path load-balance.
2522 * It also shares a next-hop with other BGP prefixes and hence
2523 * test the ref counting of RR sourced prefixes and 2 level LB.
2525 const fib_prefix_t bgp_102 = {
2527 .fp_proto = FIB_PROTOCOL_IP4,
2529 /* 100.100.100.101/32 */
2530 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2533 fib_table_entry_path_add(fib_index,
2536 FIB_ENTRY_FLAG_NONE,
2538 &pfx_1_1_1_1_s_32.fp_addr,
2539 ~0, // no index provided.
2540 fib_index, // same as route
2543 FIB_ROUTE_PATH_FLAG_NONE);
2544 fib_table_entry_path_add(fib_index,
2547 FIB_ENTRY_FLAG_NONE,
2549 &pfx_1_1_1_2_s_32.fp_addr,
2550 ~0, // no index provided.
2551 fib_index, // same as route's FIB
2554 FIB_ROUTE_PATH_FLAG_NONE);
2555 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2556 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2557 dpo = fib_entry_contribute_ip_forwarding(fei);
2559 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2560 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2561 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2562 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2564 lb = load_balance_get(dpo->dpoi_index);
2565 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2566 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2567 "First via 10.10.10.1");
2568 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2569 "Second via 10.10.10.1");
2571 fib_table_entry_path_remove(fib_index,
2575 &pfx_1_1_1_1_s_32.fp_addr,
2576 ~0, // no index provided.
2577 fib_index, // same as route's FIB
2579 FIB_ROUTE_PATH_FLAG_NONE);
2580 fib_table_entry_path_remove(fib_index,
2584 &pfx_1_1_1_2_s_32.fp_addr,
2585 ~0, // no index provided.
2586 fib_index, // same as route's FIB
2588 FIB_ROUTE_PATH_FLAG_NONE);
2589 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2590 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2593 * remove the remaining recursives
2595 fib_table_entry_path_remove(fib_index,
2599 &pfx_1_1_1_1_s_32.fp_addr,
2600 ~0, // no index provided.
2601 fib_index, // same as route's FIB
2603 FIB_ROUTE_PATH_FLAG_NONE);
2604 fib_table_entry_path_remove(fib_index,
2608 &pfx_1_1_1_1_s_32.fp_addr,
2609 ~0, // no index provided.
2610 fib_index, // same as route's FIB
2612 FIB_ROUTE_PATH_FLAG_NONE);
2613 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2614 FIB_NODE_INDEX_INVALID),
2615 "100.100.100.100/32 removed");
2616 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2617 FIB_NODE_INDEX_INVALID),
2618 "100.100.100.101/32 removed");
2621 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2623 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2624 fib_path_list_db_size());
2625 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2626 fib_path_list_pool_size());
2627 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2628 fib_entry_pool_size());
2631 * Add a recursive route via a connected cover, using an adj-fib that does exist
2633 fib_table_entry_path_add(fib_index,
2636 FIB_ENTRY_FLAG_NONE,
2639 ~0, // no index provided.
2640 fib_index, // Same as route's FIB
2643 FIB_ROUTE_PATH_FLAG_NONE);
2646 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2648 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2649 fib_path_list_db_size());
2650 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2651 fib_path_list_pool_size());
2652 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2653 fib_entry_pool_size());
2655 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2656 dpo = fib_entry_contribute_ip_forwarding(fei);
2658 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2659 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2661 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2662 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2664 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2665 "Flags set on RR via existing attached");
2668 * Add a recursive route via a connected cover, using and adj-fib that does
2671 ip46_address_t nh_10_10_10_3 = {
2672 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2674 fib_prefix_t pfx_10_10_10_3 = {
2676 .fp_proto = FIB_PROTOCOL_IP4,
2677 .fp_addr = nh_10_10_10_3,
2680 fib_table_entry_path_add(fib_index,
2683 FIB_ENTRY_FLAG_NONE,
2686 ~0, // no index provided.
2690 FIB_ROUTE_PATH_FLAG_NONE);
2693 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2694 * one unshared non-recursive via 10.10.10.3
2696 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2697 fib_path_list_db_size());
2698 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2699 fib_path_list_pool_size());
2700 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2701 fib_entry_pool_size());
2703 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2706 tm->hw[0]->sw_if_index);
2708 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2709 dpo = fib_entry_contribute_ip_forwarding(fei);
2710 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2711 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2713 ai = fib_entry_get_adj(fei);
2714 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2715 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2716 fib_entry_get_flags(fei)),
2717 "Flags set on RR via non-existing attached");
2719 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2720 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2725 * remove the recursives
2727 fib_table_entry_path_remove(fib_index,
2732 ~0, // no index provided.
2733 fib_index, // same as route's FIB
2735 FIB_ROUTE_PATH_FLAG_NONE);
2736 fib_table_entry_path_remove(fib_index,
2741 ~0, // no index provided.
2742 fib_index, // same as route's FIB
2744 FIB_ROUTE_PATH_FLAG_NONE);
2746 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2747 FIB_NODE_INDEX_INVALID),
2748 "200.200.200.201/32 removed");
2749 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2750 FIB_NODE_INDEX_INVALID),
2751 "200.200.200.200/32 removed");
2752 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2753 FIB_NODE_INDEX_INVALID),
2754 "10.10.10.3/32 removed");
2757 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2758 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2760 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2761 fib_path_list_db_size());
2762 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2763 fib_path_list_pool_size());
2764 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2765 fib_entry_pool_size());
2770 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2772 fib_prefix_t pfx_5_5_5_5_s_32 = {
2774 .fp_proto = FIB_PROTOCOL_IP4,
2776 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2779 fib_prefix_t pfx_5_5_5_6_s_32 = {
2781 .fp_proto = FIB_PROTOCOL_IP4,
2783 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2786 fib_prefix_t pfx_5_5_5_7_s_32 = {
2788 .fp_proto = FIB_PROTOCOL_IP4,
2790 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2794 fib_table_entry_path_add(fib_index,
2797 FIB_ENTRY_FLAG_NONE,
2799 &pfx_5_5_5_6_s_32.fp_addr,
2800 ~0, // no index provided.
2804 FIB_ROUTE_PATH_FLAG_NONE);
2805 fib_table_entry_path_add(fib_index,
2808 FIB_ENTRY_FLAG_NONE,
2810 &pfx_5_5_5_7_s_32.fp_addr,
2811 ~0, // no index provided.
2815 FIB_ROUTE_PATH_FLAG_NONE);
2816 fib_table_entry_path_add(fib_index,
2819 FIB_ENTRY_FLAG_NONE,
2821 &pfx_5_5_5_5_s_32.fp_addr,
2822 ~0, // no index provided.
2826 FIB_ROUTE_PATH_FLAG_NONE);
2828 * +3 entries, +3 shared path-list
2830 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2831 fib_path_list_db_size());
2832 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2833 fib_path_list_pool_size());
2834 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2835 fib_entry_pool_size());
2838 * All the entries have only looped paths, so they are all drop
2840 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2841 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2842 "LB for 5.5.5.7/32 is via adj for DROP");
2843 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2844 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2845 "LB for 5.5.5.5/32 is via adj for DROP");
2846 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2847 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2848 "LB for 5.5.5.6/32 is via adj for DROP");
2851 * provide 5.5.5.6/32 with alternate path.
2852 * this will allow only 5.5.5.6/32 to forward with this path, the others
2853 * are still drop since the loop is still present.
2855 fib_table_entry_path_add(fib_index,
2858 FIB_ENTRY_FLAG_NONE,
2861 tm->hw[0]->sw_if_index,
2865 FIB_ROUTE_PATH_FLAG_NONE);
2867 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2868 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2870 lb = load_balance_get(dpo1->dpoi_index);
2871 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2873 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2874 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2875 FIB_TEST((ai_01 == dpo2->dpoi_index),
2876 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2878 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2879 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2880 "LB for 5.5.5.7/32 is via adj for DROP");
2881 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2882 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2883 "LB for 5.5.5.5/32 is via adj for DROP");
2886 * remove the alternate path for 5.5.5.6/32
2889 fib_table_entry_path_remove(fib_index,
2894 tm->hw[0]->sw_if_index,
2897 FIB_ROUTE_PATH_FLAG_NONE);
2899 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2900 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2901 "LB for 5.5.5.7/32 is via adj for DROP");
2902 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2903 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2904 "LB for 5.5.5.5/32 is via adj for DROP");
2905 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2906 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2907 "LB for 5.5.5.6/32 is via adj for DROP");
2910 * break the loop by giving 5.5.5.5/32 a new set of paths
2911 * expect all to forward via this new path.
2913 fib_table_entry_update_one_path(fib_index,
2916 FIB_ENTRY_FLAG_NONE,
2919 tm->hw[0]->sw_if_index,
2920 ~0, // invalid fib index
2923 FIB_ROUTE_PATH_FLAG_NONE);
2925 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2926 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2927 lb = load_balance_get(dpo1->dpoi_index);
2928 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2930 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2931 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2932 FIB_TEST((ai_01 == dpo2->dpoi_index),
2933 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2935 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2936 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2938 lb = load_balance_get(dpo2->dpoi_index);
2939 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2940 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2941 "5.5.5.5.7 via 5.5.5.5");
2943 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2944 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2946 lb = load_balance_get(dpo1->dpoi_index);
2947 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2948 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2949 "5.5.5.5.6 via 5.5.5.7");
2952 * revert back to the loop. so we can remove the prefixes with
2955 fib_table_entry_update_one_path(fib_index,
2958 FIB_ENTRY_FLAG_NONE,
2960 &pfx_5_5_5_6_s_32.fp_addr,
2961 ~0, // no index provided.
2965 FIB_ROUTE_PATH_FLAG_NONE);
2967 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2968 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2969 "LB for 5.5.5.7/32 is via adj for DROP");
2970 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2971 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2972 "LB for 5.5.5.5/32 is via adj for DROP");
2973 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2974 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2975 "LB for 5.5.5.6/32 is via adj for DROP");
2978 * remove all the 5.5.5.x/32 prefixes
2980 fib_table_entry_path_remove(fib_index,
2984 &pfx_5_5_5_6_s_32.fp_addr,
2985 ~0, // no index provided.
2986 fib_index, // same as route's FIB
2988 FIB_ROUTE_PATH_FLAG_NONE);
2989 fib_table_entry_path_remove(fib_index,
2993 &pfx_5_5_5_7_s_32.fp_addr,
2994 ~0, // no index provided.
2995 fib_index, // same as route's FIB
2997 FIB_ROUTE_PATH_FLAG_NONE);
2998 fib_table_entry_path_remove(fib_index,
3002 &pfx_5_5_5_5_s_32.fp_addr,
3003 ~0, // no index provided.
3004 fib_index, // same as route's FIB
3006 FIB_ROUTE_PATH_FLAG_NONE);
3007 fib_table_entry_path_remove(fib_index,
3012 ~0, // no index provided.
3013 fib_index, // same as route's FIB
3015 FIB_ROUTE_PATH_FLAG_NONE);
3018 * -3 entries, -3 shared path-list
3020 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3021 fib_path_list_db_size());
3022 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3023 fib_path_list_pool_size());
3024 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3025 fib_entry_pool_size());
3028 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
3030 fib_table_entry_path_add(fib_index,
3033 FIB_ENTRY_FLAG_NONE,
3035 &pfx_5_5_5_6_s_32.fp_addr,
3036 ~0, // no index provided.
3040 FIB_ROUTE_PATH_FLAG_NONE);
3041 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
3042 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
3043 "1-level 5.5.5.6/32 loop is via adj for DROP");
3045 fib_table_entry_path_remove(fib_index,
3049 &pfx_5_5_5_6_s_32.fp_addr,
3050 ~0, // no index provided.
3051 fib_index, // same as route's FIB
3053 FIB_ROUTE_PATH_FLAG_NONE);
3054 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3055 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
3056 "1-level 5.5.5.6/32 loop is removed");
3059 * A recursive route whose next-hop is covered by the prefix.
3060 * This would mean the via-fib, which inherits forwarding from its
3061 * cover, thus picks up forwarding from the prfix, which is via the
3062 * via-fib, and we have a loop.
3064 fib_prefix_t pfx_23_23_23_0_s_24 = {
3066 .fp_proto = FIB_PROTOCOL_IP4,
3068 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
3071 fib_prefix_t pfx_23_23_23_23_s_32 = {
3073 .fp_proto = FIB_PROTOCOL_IP4,
3075 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
3078 fei = fib_table_entry_path_add(fib_index,
3079 &pfx_23_23_23_0_s_24,
3081 FIB_ENTRY_FLAG_NONE,
3083 &pfx_23_23_23_23_s_32.fp_addr,
3088 FIB_ROUTE_PATH_FLAG_NONE);
3089 dpo = fib_entry_contribute_ip_forwarding(fei);
3090 FIB_TEST(load_balance_is_drop(dpo),
3091 "23.23.23.0/24 via covered is DROP");
3092 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3095 * add-remove test. no change.
3097 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3098 fib_path_list_db_size());
3099 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3100 fib_path_list_pool_size());
3101 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3102 fib_entry_pool_size());
3105 * Make the default route recursive via a unknown next-hop. Thus the
3106 * next hop's cover would be the default route
3108 fei = fib_table_entry_path_add(fib_index,
3111 FIB_ENTRY_FLAG_NONE,
3113 &pfx_23_23_23_23_s_32.fp_addr,
3118 FIB_ROUTE_PATH_FLAG_NONE);
3119 dpo = fib_entry_contribute_ip_forwarding(fei);
3120 FIB_TEST(load_balance_is_drop(dpo),
3121 "0.0.0.0.0/0 via is DROP");
3122 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3123 "no resolving interface for looped 0.0.0.0/0");
3125 fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
3126 dpo = fib_entry_contribute_ip_forwarding(fei);
3127 FIB_TEST(load_balance_is_drop(dpo),
3128 "23.23.23.23/32 via is DROP");
3129 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
3130 "no resolving interface for looped 23.23.23.23/32");
3132 fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
3135 * A recursive route with recursion constraints.
3136 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
3138 fib_table_entry_path_add(fib_index,
3141 FIB_ENTRY_FLAG_NONE,
3148 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3150 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3151 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3153 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3154 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3156 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3157 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3160 * save the load-balance. we expect it to be inplace modified
3162 lb = load_balance_get(dpo1->dpoi_index);
3165 * add a covering prefix for the via fib that would otherwise serve
3166 * as the resolving route when the host is removed
3168 fib_table_entry_path_add(fib_index,
3171 FIB_ENTRY_FLAG_NONE,
3174 tm->hw[0]->sw_if_index,
3175 ~0, // invalid fib index
3178 FIB_ROUTE_PATH_FLAG_NONE);
3179 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3180 ai = fib_entry_get_adj(fei);
3181 FIB_TEST((ai == ai_01),
3182 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3185 * remove the host via FIB - expect the BGP prefix to be drop
3187 fib_table_entry_path_remove(fib_index,
3192 tm->hw[0]->sw_if_index,
3193 ~0, // invalid fib index
3195 FIB_ROUTE_PATH_FLAG_NONE);
3197 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3198 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3201 * add the via-entry host reoute back. expect to resolve again
3203 fib_table_entry_path_add(fib_index,
3206 FIB_ENTRY_FLAG_NONE,
3209 tm->hw[0]->sw_if_index,
3210 ~0, // invalid fib index
3213 FIB_ROUTE_PATH_FLAG_NONE);
3214 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3215 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3218 * add another path for the recursive. it will then have 2.
3220 fib_prefix_t pfx_1_1_1_3_s_32 = {
3222 .fp_proto = FIB_PROTOCOL_IP4,
3224 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3227 fib_table_entry_path_add(fib_index,
3230 FIB_ENTRY_FLAG_NONE,
3233 tm->hw[0]->sw_if_index,
3234 ~0, // invalid fib index
3237 FIB_ROUTE_PATH_FLAG_NONE);
3239 fib_table_entry_path_add(fib_index,
3242 FIB_ENTRY_FLAG_NONE,
3244 &pfx_1_1_1_3_s_32.fp_addr,
3249 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3252 * add a bunch load more entries using this path combo so that we get
3253 * an LB-map created.
3256 fib_prefix_t bgp_78s[N_P];
3257 for (ii = 0; ii < N_P; ii++)
3259 bgp_78s[ii].fp_len = 32;
3260 bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3261 bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3264 fib_table_entry_path_add(fib_index,
3267 FIB_ENTRY_FLAG_NONE,
3269 &pfx_1_1_1_3_s_32.fp_addr,
3274 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3275 fib_table_entry_path_add(fib_index,
3278 FIB_ENTRY_FLAG_NONE,
3285 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3288 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3289 dpo = fib_entry_contribute_ip_forwarding(fei);
3291 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3292 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3293 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3294 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3295 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3296 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3297 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3298 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3301 * expect the lb-map used by the recursive's load-balance is using both buckets
3303 load_balance_map_t *lbm;
3306 lb = load_balance_get(dpo->dpoi_index);
3308 load_balance_map_lock(lbmi);
3309 lbm = load_balance_map_get(lbmi);
3311 FIB_TEST(lbm->lbm_buckets[0] == 0,
3312 "LB maps's bucket 0 is %d",
3313 lbm->lbm_buckets[0]);
3314 FIB_TEST(lbm->lbm_buckets[1] == 1,
3315 "LB maps's bucket 1 is %d",
3316 lbm->lbm_buckets[1]);
3319 * withdraw one of the /32 via-entrys.
3320 * that ECMP path will be unresolved and forwarding should continue on the
3321 * other available path. this is an iBGP PIC edge failover.
3322 * Test the forwarding changes without re-fetching the adj from the
3323 * recursive entry. this ensures its the same one that is updated; i.e. an
3326 fib_table_entry_path_remove(fib_index,
3331 tm->hw[0]->sw_if_index,
3332 ~0, // invalid fib index
3334 FIB_ROUTE_PATH_FLAG_NONE);
3336 /* suspend so the update walk kicks int */
3337 vlib_process_suspend(vlib_get_main(), 1e-5);
3339 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3340 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3341 "post PIC 200.200.200.200/32 was inplace modified");
3343 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3344 "post PIC adj for 200.200.200.200/32 is recursive"
3345 " via adj for 1.1.1.3");
3348 * the LB maps that was locked above should have been modified to remove
3349 * the path that was down, and thus its bucket points to a path that is
3352 FIB_TEST(lbm->lbm_buckets[0] == 1,
3353 "LB maps's bucket 0 is %d",
3354 lbm->lbm_buckets[0]);
3355 FIB_TEST(lbm->lbm_buckets[1] == 1,
3356 "LB maps's bucket 1 is %d",
3357 lbm->lbm_buckets[1]);
3359 load_balance_map_unlock(lbmi);
3362 * add it back. again
3364 fib_table_entry_path_add(fib_index,
3367 FIB_ENTRY_FLAG_NONE,
3370 tm->hw[0]->sw_if_index,
3371 ~0, // invalid fib index
3374 FIB_ROUTE_PATH_FLAG_NONE);
3376 /* suspend so the update walk kicks in */
3377 vlib_process_suspend(vlib_get_main(), 1e-5);
3379 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3380 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3381 "via adj for 1.1.1.1");
3382 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3383 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3384 "via adj for 1.1.1.3");
3386 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3387 dpo = fib_entry_contribute_ip_forwarding(fei);
3388 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3389 "post PIC 200.200.200.200/32 was inplace modified");
3392 * add a 3rd path. this makes the LB 16 buckets.
3394 fib_table_entry_path_add(fib_index,
3397 FIB_ENTRY_FLAG_NONE,
3399 &pfx_1_1_1_2_s_32.fp_addr,
3404 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3405 for (ii = 0; ii < N_P; ii++)
3407 fib_table_entry_path_add(fib_index,
3410 FIB_ENTRY_FLAG_NONE,
3412 &pfx_1_1_1_2_s_32.fp_addr,
3417 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3420 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3421 dpo = fib_entry_contribute_ip_forwarding(fei);
3422 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3423 "200.200.200.200/32 was inplace modified for 3rd path");
3424 FIB_TEST(16 == lb->lb_n_buckets,
3425 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3428 load_balance_map_lock(lbmi);
3429 lbm = load_balance_map_get(lbmi);
3431 for (ii = 0; ii < 16; ii++)
3433 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3434 "LB Map for 200.200.200.200/32 at %d is %d",
3435 ii, lbm->lbm_buckets[ii]);
3439 * trigger PIC by removing the first via-entry
3440 * the first 6 buckets of the map should map to the next 6
3442 fib_table_entry_path_remove(fib_index,
3447 tm->hw[0]->sw_if_index,
3450 FIB_ROUTE_PATH_FLAG_NONE);
3451 /* suspend so the update walk kicks int */
3452 vlib_process_suspend(vlib_get_main(), 1e-5);
3454 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3455 dpo = fib_entry_contribute_ip_forwarding(fei);
3456 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3457 "200.200.200.200/32 was inplace modified for 3rd path");
3458 FIB_TEST(2 == lb->lb_n_buckets,
3459 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3461 for (ii = 0; ii < 6; ii++)
3463 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3464 "LB Map for 200.200.200.200/32 at %d is %d",
3465 ii, lbm->lbm_buckets[ii]);
3467 for (ii = 6; ii < 16; ii++)
3469 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3470 "LB Map for 200.200.200.200/32 at %d is %d",
3471 ii, lbm->lbm_buckets[ii]);
3473 load_balance_map_unlock(lbmi);
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);
3490 for (ii = 0; ii < N_P; ii++)
3492 fib_table_entry_delete(fib_index,
3495 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3496 fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3498 format_fib_prefix, &bgp_78s[ii]);
3500 fib_table_entry_path_remove(fib_index,
3504 &pfx_1_1_1_2_s_32.fp_addr,
3508 MPLS_LABEL_INVALID);
3509 fib_table_entry_path_remove(fib_index,
3517 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3518 fib_table_entry_path_remove(fib_index,
3522 &pfx_1_1_1_3_s_32.fp_addr,
3526 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3527 fib_table_entry_delete(fib_index,
3530 fib_table_entry_delete(fib_index,
3533 /* suspend so the update walk kicks int */
3534 vlib_process_suspend(vlib_get_main(), 1e-5);
3535 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3536 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3537 "1.1.1.1/28 removed");
3538 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3539 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3540 "1.1.1.3/32 removed");
3541 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3542 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3543 "200.200.200.200/32 removed");
3546 * add-remove test. no change.
3548 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3549 fib_path_list_db_size());
3550 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3551 fib_path_list_pool_size());
3552 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3553 fib_entry_pool_size());
3556 * A route whose paths are built up iteratively and then removed
3559 fib_prefix_t pfx_4_4_4_4_s_32 = {
3561 .fp_proto = FIB_PROTOCOL_IP4,
3564 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3568 fib_table_entry_path_add(fib_index,
3571 FIB_ENTRY_FLAG_NONE,
3574 tm->hw[0]->sw_if_index,
3578 FIB_ROUTE_PATH_FLAG_NONE);
3579 fib_table_entry_path_add(fib_index,
3582 FIB_ENTRY_FLAG_NONE,
3585 tm->hw[0]->sw_if_index,
3589 FIB_ROUTE_PATH_FLAG_NONE);
3590 fib_table_entry_path_add(fib_index,
3593 FIB_ENTRY_FLAG_NONE,
3596 tm->hw[0]->sw_if_index,
3600 FIB_ROUTE_PATH_FLAG_NONE);
3601 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3602 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3603 "4.4.4.4/32 present");
3605 fib_table_entry_delete(fib_index,
3608 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3609 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3610 "4.4.4.4/32 removed");
3613 * add-remove test. no change.
3615 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3616 fib_path_list_db_size());
3617 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3618 fib_path_list_pool_size());
3619 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3620 fib_entry_pool_size());
3623 * A route with multiple paths at once
3625 fib_route_path_t *r_paths = NULL;
3627 for (ii = 0; ii < 4; ii++)
3629 fib_route_path_t r_path = {
3630 .frp_proto = DPO_PROTO_IP4,
3632 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3634 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3636 .frp_fib_index = ~0,
3638 vec_add1(r_paths, r_path);
3641 fib_table_entry_update(fib_index,
3644 FIB_ENTRY_FLAG_NONE,
3647 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3648 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3649 dpo = fib_entry_contribute_ip_forwarding(fei);
3651 lb = load_balance_get(dpo->dpoi_index);
3652 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3654 fib_table_entry_delete(fib_index,
3657 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3658 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3659 "4.4.4.4/32 removed");
3663 * add-remove test. no change.
3665 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3666 fib_path_list_db_size());
3667 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3668 fib_path_list_pool_size());
3669 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3670 fib_entry_pool_size());
3673 * A route deag route
3675 fib_table_entry_path_add(fib_index,
3678 FIB_ENTRY_FLAG_NONE,
3685 FIB_ROUTE_PATH_FLAG_NONE);
3687 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3688 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3690 dpo = fib_entry_contribute_ip_forwarding(fei);
3691 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3692 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3694 FIB_TEST((fib_index == lkd->lkd_fib_index),
3695 "4.4.4.4/32 is deag in %d %U",
3697 format_dpo_id, dpo, 0);
3698 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
3699 "4.4.4.4/32 is source deag in %d %U",
3701 format_dpo_id, dpo, 0);
3703 fib_table_entry_delete(fib_index,
3706 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3707 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3708 "4.4.4.4/32 removed");
3712 * A route deag route in a source lookup table
3714 fib_table_entry_path_add(fib_index,
3717 FIB_ENTRY_FLAG_NONE,
3724 FIB_ROUTE_PATH_SOURCE_LOOKUP);
3726 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3727 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3729 dpo = fib_entry_contribute_ip_forwarding(fei);
3730 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3731 lkd = lookup_dpo_get(dpo->dpoi_index);
3733 FIB_TEST((fib_index == lkd->lkd_fib_index),
3734 "4.4.4.4/32 is deag in %d %U",
3736 format_dpo_id, dpo, 0);
3737 FIB_TEST((LOOKUP_INPUT_SRC_ADDR == lkd->lkd_input),
3738 "4.4.4.4/32 is source deag in %d %U",
3740 format_dpo_id, dpo, 0);
3742 fib_table_entry_delete(fib_index,
3745 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3746 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3747 "4.4.4.4/32 removed");
3751 * add-remove test. no change.
3753 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3754 fib_path_list_db_size());
3755 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3756 fib_path_list_pool_size());
3757 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3758 fib_entry_pool_size());
3762 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3764 fib_prefix_t pfx_34_1_1_1_s_32 = {
3766 .fp_proto = FIB_PROTOCOL_IP4,
3768 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3771 fib_prefix_t pfx_34_34_1_1_s_32 = {
3773 .fp_proto = FIB_PROTOCOL_IP4,
3775 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3778 fei = fib_table_entry_path_add(fib_index,
3779 &pfx_34_34_1_1_s_32,
3781 FIB_ENTRY_FLAG_NONE,
3784 tm->hw[0]->sw_if_index,
3788 FIB_ROUTE_PATH_FLAG_NONE);
3789 fei = fib_table_entry_path_add(fib_index,
3792 FIB_ENTRY_FLAG_NONE,
3794 &pfx_34_34_1_1_s_32.fp_addr,
3799 FIB_ROUTE_PATH_FLAG_NONE);
3800 fei = fib_table_entry_path_add(fib_index,
3803 FIB_ENTRY_FLAG_NONE,
3805 &pfx_34_34_1_1_s_32.fp_addr,
3810 FIB_ROUTE_PATH_FLAG_NONE);
3811 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3812 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3813 fib_table_entry_delete(fib_index,
3814 &pfx_34_34_1_1_s_32,
3819 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3820 * all of which are via 10.10.10.1, Itf1
3822 fib_table_entry_path_remove(fib_index,
3827 tm->hw[0]->sw_if_index,
3830 FIB_ROUTE_PATH_FLAG_NONE);
3831 fib_table_entry_path_remove(fib_index,
3836 tm->hw[0]->sw_if_index,
3839 FIB_ROUTE_PATH_FLAG_NONE);
3840 fib_table_entry_path_remove(fib_index,
3845 tm->hw[0]->sw_if_index,
3848 FIB_ROUTE_PATH_FLAG_NONE);
3850 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3851 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3852 "1.1.1.1/32 removed");
3853 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3854 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3855 "1.1.1.2/32 removed");
3856 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3857 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3858 "1.1.2.0/24 removed");
3861 * -3 entries and -1 shared path-list
3863 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3864 fib_path_list_db_size());
3865 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3866 fib_path_list_pool_size());
3867 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3868 fib_entry_pool_size());
3871 * An attached-host route. Expect to link to the incomplete adj
3873 fib_prefix_t pfx_4_1_1_1_s_32 = {
3875 .fp_proto = FIB_PROTOCOL_IP4,
3878 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3881 fib_table_entry_path_add(fib_index,
3884 FIB_ENTRY_FLAG_NONE,
3887 tm->hw[0]->sw_if_index,
3891 FIB_ROUTE_PATH_FLAG_NONE);
3893 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3894 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3895 ai = fib_entry_get_adj(fei);
3897 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3899 &pfx_4_1_1_1_s_32.fp_addr,
3900 tm->hw[0]->sw_if_index);
3901 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3905 * +1 entry and +1 shared path-list
3907 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3908 fib_path_list_db_size());
3909 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3910 fib_path_list_pool_size());
3911 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3912 fib_entry_pool_size());
3914 fib_table_entry_delete(fib_index,
3918 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3919 fib_path_list_db_size());
3920 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3921 fib_path_list_pool_size());
3922 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3923 fib_entry_pool_size());
3926 * add a v6 prefix via v4 next-hops
3928 fib_prefix_t pfx_2001_s_64 = {
3930 .fp_proto = FIB_PROTOCOL_IP6,
3932 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3935 fei = fib_table_entry_path_add(0, //default v6 table
3938 FIB_ENTRY_FLAG_NONE,
3941 tm->hw[0]->sw_if_index,
3945 FIB_ROUTE_PATH_FLAG_NONE);
3947 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3948 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3949 ai = fib_entry_get_adj(fei);
3951 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3952 "2001::/64 via ARP-adj");
3953 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3954 "2001::/64 is link type v6");
3955 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3956 "2001::/64 ADJ-adj is NH proto v4");
3957 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3960 * add a uRPF exempt prefix:
3962 * - it's forwarding is drop
3963 * - it's uRPF list is not empty
3964 * - the uRPF list for the default route (it's cover) is empty
3966 fei = fib_table_entry_special_add(fib_index,
3968 FIB_SOURCE_URPF_EXEMPT,
3969 FIB_ENTRY_FLAG_DROP);
3970 dpo = fib_entry_contribute_ip_forwarding(fei);
3971 FIB_TEST(load_balance_is_drop(dpo),
3972 "uRPF exempt 4.1.1.1/32 DROP");
3973 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3974 "uRPF list for exempt prefix has itf index 0");
3975 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3976 FIB_TEST(!fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3977 "uRPF list for 0.0.0.0/0 empty");
3979 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3982 * An adj-fib that fails the refinement criteria - no connected cover
3984 fib_prefix_t pfx_12_10_10_2_s_32 = {
3986 .fp_proto = FIB_PROTOCOL_IP4,
3989 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3993 fib_table_entry_path_add(fib_index,
3994 &pfx_12_10_10_2_s_32,
3996 FIB_ENTRY_FLAG_ATTACHED,
3998 &pfx_12_10_10_2_s_32.fp_addr,
3999 tm->hw[0]->sw_if_index,
4000 ~0, // invalid fib index
4003 FIB_ROUTE_PATH_FLAG_NONE);
4005 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
4006 dpo = fib_entry_contribute_ip_forwarding(fei);
4007 FIB_TEST(dpo_is_drop(dpo),
4008 "no connected cover adj-fib fails refinement: %U",
4009 format_dpo_id, dpo, 0);
4011 fib_table_entry_delete(fib_index,
4012 &pfx_12_10_10_2_s_32,
4016 * An adj-fib that fails the refinement criteria - cover is connected
4017 * but on a different interface
4019 fib_prefix_t pfx_10_10_10_127_s_32 = {
4021 .fp_proto = FIB_PROTOCOL_IP4,
4024 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
4028 fib_table_entry_path_add(fib_index,
4029 &pfx_10_10_10_127_s_32,
4031 FIB_ENTRY_FLAG_ATTACHED,
4033 &pfx_10_10_10_127_s_32.fp_addr,
4034 tm->hw[1]->sw_if_index,
4035 ~0, // invalid fib index
4038 FIB_ROUTE_PATH_FLAG_NONE);
4040 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
4041 dpo = fib_entry_contribute_ip_forwarding(fei);
4042 FIB_TEST(dpo_is_drop(dpo),
4043 "wrong interface adj-fib fails refinement");
4045 fib_table_entry_delete(fib_index,
4046 &pfx_10_10_10_127_s_32,
4050 * add a second path to an adj-fib
4051 * this is a sumiluation of another ARP entry created
4052 * on an interface on which the connected prefix does not exist.
4053 * The second path fails refinement. Expect to forward through the
4056 fib_prefix_t pfx_10_10_10_3_s_32 = {
4058 .fp_proto = FIB_PROTOCOL_IP4,
4061 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
4065 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
4068 tm->hw[0]->sw_if_index);
4070 fib_test_lb_bucket_t ip_o_10_10_10_3 = {
4076 fei = fib_table_entry_path_add(fib_index,
4077 &pfx_10_10_10_3_s_32,
4079 FIB_ENTRY_FLAG_NONE,
4082 tm->hw[0]->sw_if_index,
4086 FIB_ROUTE_PATH_FLAG_NONE);
4087 fei = fib_table_entry_path_add(fib_index,
4088 &pfx_10_10_10_3_s_32,
4090 FIB_ENTRY_FLAG_NONE,
4093 tm->hw[1]->sw_if_index,
4097 FIB_ROUTE_PATH_FLAG_NONE);
4098 FIB_TEST(!fib_test_validate_entry(fei,
4099 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4102 "10.10.10.3 via 10.10.10.3/Eth0 only");
4105 * remove the path that refines the cover, should go unresolved
4107 fib_table_entry_path_remove(fib_index,
4108 &pfx_10_10_10_3_s_32,
4112 tm->hw[0]->sw_if_index,
4115 FIB_ROUTE_PATH_FLAG_NONE);
4116 dpo = fib_entry_contribute_ip_forwarding(fei);
4117 FIB_TEST(dpo_is_drop(dpo),
4118 "wrong interface adj-fib fails refinement");
4121 * add back the path that refines the cover
4123 fei = fib_table_entry_path_add(fib_index,
4124 &pfx_10_10_10_3_s_32,
4126 FIB_ENTRY_FLAG_NONE,
4129 tm->hw[0]->sw_if_index,
4133 FIB_ROUTE_PATH_FLAG_NONE);
4134 FIB_TEST(!fib_test_validate_entry(fei,
4135 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4138 "10.10.10.3 via 10.10.10.3/Eth0 only");
4141 * remove the path that does not refine the cover
4143 fib_table_entry_path_remove(fib_index,
4144 &pfx_10_10_10_3_s_32,
4148 tm->hw[1]->sw_if_index,
4151 FIB_ROUTE_PATH_FLAG_NONE);
4152 FIB_TEST(!fib_test_validate_entry(fei,
4153 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4156 "10.10.10.3 via 10.10.10.3/Eth0 only");
4159 * remove the path that does refine, it's the last path, so
4160 * the entry should be gone
4162 fib_table_entry_path_remove(fib_index,
4163 &pfx_10_10_10_3_s_32,
4167 tm->hw[0]->sw_if_index,
4170 FIB_ROUTE_PATH_FLAG_NONE);
4171 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4172 FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
4177 * change the table's flow-hash config - expect the update to propagete to
4178 * the entries' load-balance objects
4180 flow_hash_config_t old_hash_config, new_hash_config;
4182 old_hash_config = fib_table_get_flow_hash_config(fib_index,
4184 new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
4185 IP_FLOW_HASH_DST_ADDR);
4187 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4188 dpo = fib_entry_contribute_ip_forwarding(fei);
4189 lb = load_balance_get(dpo->dpoi_index);
4190 FIB_TEST((lb->lb_hash_config == old_hash_config),
4191 "Table and LB hash config match: %U",
4192 format_ip_flow_hash_config, lb->lb_hash_config);
4194 fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
4196 FIB_TEST((lb->lb_hash_config == new_hash_config),
4197 "Table and LB newhash config match: %U",
4198 format_ip_flow_hash_config, lb->lb_hash_config);
4201 * A route via DVR DPO
4203 fei = fib_table_entry_path_add(fib_index,
4204 &pfx_10_10_10_3_s_32,
4206 FIB_ENTRY_FLAG_NONE,
4209 tm->hw[0]->sw_if_index,
4213 FIB_ROUTE_PATH_DVR);
4214 dpo_id_t dvr_dpo = DPO_INVALID;
4215 dvr_dpo_add_or_lock(tm->hw[0]->sw_if_index, DPO_PROTO_IP4, &dvr_dpo);
4216 fib_test_lb_bucket_t ip_o_l2 = {
4219 .adj = dvr_dpo.dpoi_index,
4223 FIB_TEST(!fib_test_validate_entry(fei,
4224 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4227 "10.10.10.3 via L2 on Eth0");
4228 fib_table_entry_path_remove(fib_index,
4229 &pfx_10_10_10_3_s_32,
4233 tm->hw[0]->sw_if_index,
4236 FIB_ROUTE_PATH_DVR);
4237 dpo_reset(&dvr_dpo);
4240 * add the default route via a next-hop that will form a loop
4242 fib_prefix_t pfx_conn = {
4244 .fp_proto = FIB_PROTOCOL_IP4,
4247 .ip4.as_u32 = clib_host_to_net_u32(0x1e1e1e1e),
4251 dfrt = fib_table_entry_path_add(fib_index,
4254 FIB_ENTRY_FLAG_NONE,
4261 FIB_ROUTE_PATH_FLAG_NONE);
4263 * the default route is a drop, since it's looped
4265 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4266 "Default route is DROP");
4269 * add a connected cover for the next-hop, this breaks the recursion loop
4270 * for the default route
4272 fib_table_entry_path_add(fib_index,
4275 (FIB_ENTRY_FLAG_CONNECTED |
4276 FIB_ENTRY_FLAG_ATTACHED),
4279 tm->hw[0]->sw_if_index,
4283 FIB_ROUTE_PATH_FLAG_NONE);
4284 pfx_conn.fp_len = 32;
4285 fei = fib_table_lookup_exact_match(fib_index, &pfx_conn);
4287 u32 ai_30 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
4290 tm->hw[0]->sw_if_index);
4292 fib_test_lb_bucket_t ip_o_30_30_30_30 = {
4298 FIB_TEST(!fib_test_validate_entry(fei,
4299 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4302 "30.30.30.30 via adj");
4303 FIB_TEST_REC_FORW(&pfx_0_0_0_0_s_0, &pfx_conn, 0);
4305 pfx_conn.fp_len = 24;
4306 fib_table_entry_delete(fib_index,
4309 fib_table_entry_delete(fib_index,
4318 fib_table_entry_delete(fib_index,
4319 &pfx_10_10_10_1_s_32,
4321 fib_table_entry_delete(fib_index,
4322 &pfx_10_10_10_2_s_32,
4324 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4325 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4326 "10.10.10.1/32 adj-fib removed");
4327 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4328 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4329 "10.10.10.2/32 adj-fib removed");
4332 * -2 entries and -2 non-shared path-list
4334 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4335 fib_path_list_db_size());
4336 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4337 fib_path_list_pool_size());
4338 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4339 fib_entry_pool_size());
4342 * unlock the adjacencies for which this test provided a rewrite.
4343 * These are the last locks on these adjs. they should thus go away.
4347 adj_unlock(ai_12_12_12_12);
4349 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4354 * remove the interface prefixes
4356 local_pfx.fp_len = 32;
4357 fib_table_entry_special_remove(fib_index, &local_pfx,
4358 FIB_SOURCE_INTERFACE);
4359 fei = fib_table_lookup(fib_index, &local_pfx);
4361 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4362 fib_table_lookup_exact_match(fib_index, &local_pfx),
4363 "10.10.10.10/32 adj-fib removed");
4365 local_pfx.fp_len = 24;
4366 fib_table_entry_delete(fib_index, &local_pfx,
4367 FIB_SOURCE_INTERFACE);
4369 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4370 fib_table_lookup_exact_match(fib_index, &local_pfx),
4371 "10.10.10.10/24 adj-fib removed");
4374 * -2 entries and -2 non-shared path-list
4376 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4377 fib_path_list_db_size());
4378 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4379 fib_path_list_pool_size());
4380 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4381 fib_entry_pool_size());
4384 * Last but not least, remove the VRF
4386 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4389 "NO API Source'd prefixes");
4390 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4393 "NO RR Source'd prefixes");
4394 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4396 FIB_SOURCE_INTERFACE)),
4397 "NO INterface Source'd prefixes");
4399 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
4401 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4402 fib_path_list_db_size());
4403 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4404 fib_path_list_pool_size());
4405 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4406 fib_entry_pool_size());
4407 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4408 pool_elts(fib_urpf_list_pool));
4409 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4410 pool_elts(load_balance_map_pool));
4411 FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4412 pool_elts(load_balance_pool));
4413 FIB_TEST((0 == pool_elts(dvr_dpo_pool)), "L2 DPO pool size is %d",
4414 pool_elts(dvr_dpo_pool));
4423 * In the default table check for the presence and correct forwarding
4424 * of the special entries
4426 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4427 const dpo_id_t *dpo, *dpo_drop;
4428 const ip_adjacency_t *adj;
4429 const receive_dpo_t *rd;
4435 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4438 /* via 2001:0:0:1::2 */
4439 ip46_address_t nh_2001_2 = {
4442 [0] = clib_host_to_net_u64(0x2001000000000001),
4443 [1] = clib_host_to_net_u64(0x0000000000000002),
4450 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4452 /* Find or create FIB table 11 */
4453 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
4456 for (ii = 0; ii < 4; ii++)
4458 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4461 fib_prefix_t pfx_0_0 = {
4463 .fp_proto = FIB_PROTOCOL_IP6,
4471 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4472 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4473 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4474 "Default route is DROP");
4476 dpo = fib_entry_contribute_ip_forwarding(dfrt);
4477 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4479 &pfx_0_0.fp_addr.ip6)),
4480 "default-route; fwd and non-fwd tables match");
4482 // FIXME - check specials.
4485 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4486 * each with 2 entries and a v6 mfib with 4 path-lists and v4 mfib with 2.
4487 * All entries are special so no path-list sharing.
4490 u32 PNPS = (5+4+4+2);
4492 * if the IGMP plugin is loaded this adds two more entries to the v4 MFIB
4494 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4495 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4496 fib_path_list_pool_size());
4497 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4498 fib_entry_pool_size());
4501 * add interface routes.
4502 * validate presence of /64 attached and /128 recieve.
4503 * test for the presence of the receive address in the glean and local adj
4505 * receive on 2001:0:0:1::1/128
4507 fib_prefix_t local_pfx = {
4509 .fp_proto = FIB_PROTOCOL_IP6,
4513 [0] = clib_host_to_net_u64(0x2001000000000001),
4514 [1] = clib_host_to_net_u64(0x0000000000000001),
4520 fib_table_entry_update_one_path(fib_index, &local_pfx,
4521 FIB_SOURCE_INTERFACE,
4522 (FIB_ENTRY_FLAG_CONNECTED |
4523 FIB_ENTRY_FLAG_ATTACHED),
4526 tm->hw[0]->sw_if_index,
4530 FIB_ROUTE_PATH_FLAG_NONE);
4531 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4533 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4535 ai = fib_entry_get_adj(fei);
4536 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4538 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4539 "attached interface adj is glean");
4540 dpo = fib_entry_contribute_ip_forwarding(fei);
4541 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4543 &local_pfx.fp_addr.ip6)),
4544 "attached-route; fwd and non-fwd tables match");
4546 local_pfx.fp_len = 128;
4547 fib_table_entry_update_one_path(fib_index, &local_pfx,
4548 FIB_SOURCE_INTERFACE,
4549 (FIB_ENTRY_FLAG_CONNECTED |
4550 FIB_ENTRY_FLAG_LOCAL),
4553 tm->hw[0]->sw_if_index,
4554 ~0, // invalid fib index
4557 FIB_ROUTE_PATH_FLAG_NONE);
4558 fei = fib_table_lookup(fib_index, &local_pfx);
4560 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4562 dpo = fib_entry_contribute_ip_forwarding(fei);
4563 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4564 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4565 "local interface adj is local");
4566 rd = receive_dpo_get(dpo->dpoi_index);
4568 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4570 "local interface adj is receive ok");
4572 dpo = fib_entry_contribute_ip_forwarding(fei);
4573 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4575 &local_pfx.fp_addr.ip6)),
4576 "local-route; fwd and non-fwd tables match");
4577 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4578 &adj->sub_type.glean.rx_pfx.fp_addr)),
4579 "attached interface adj is receive ok");
4582 * +2 entries. +2 unshared path-lists
4584 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4585 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4586 fib_path_list_pool_size());
4587 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4588 fib_entry_pool_size());
4591 * Modify the default route to be via an adj not yet known.
4592 * this sources the defalut route with the API source, which is
4593 * a higher preference to the DEFAULT_ROUTE source
4595 fib_table_entry_path_add(fib_index, &pfx_0_0,
4597 FIB_ENTRY_FLAG_NONE,
4600 tm->hw[0]->sw_if_index,
4604 FIB_ROUTE_PATH_FLAG_NONE);
4605 fei = fib_table_lookup(fib_index, &pfx_0_0);
4607 FIB_TEST((fei == dfrt), "default route same index");
4608 ai = fib_entry_get_adj(fei);
4609 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4611 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4612 "adj is incomplete");
4613 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4614 "adj nbr next-hop ok");
4617 * find the adj in the shared db
4619 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4622 tm->hw[0]->sw_if_index);
4623 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4624 adj_unlock(locked_ai);
4627 * no more entries. +1 shared path-list
4629 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4630 fib_path_list_db_size());
4631 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4632 fib_path_list_pool_size());
4633 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4634 fib_entry_pool_size());
4637 * remove the API source from the default route. We expected
4638 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4640 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4644 tm->hw[0]->sw_if_index,
4647 FIB_ROUTE_PATH_FLAG_NONE);
4648 fei = fib_table_lookup(fib_index, &pfx_0_0);
4650 FIB_TEST((fei == dfrt), "default route same index");
4651 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4652 "Default route is DROP");
4655 * no more entries. -1 shared path-list
4657 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4658 fib_path_list_db_size());
4659 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4660 fib_path_list_pool_size());
4661 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4662 fib_entry_pool_size());
4665 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4667 fib_prefix_t pfx_2001_1_2_s_128 = {
4669 .fp_proto = FIB_PROTOCOL_IP6,
4673 [0] = clib_host_to_net_u64(0x2001000000000001),
4674 [1] = clib_host_to_net_u64(0x0000000000000002),
4679 fib_prefix_t pfx_2001_1_3_s_128 = {
4681 .fp_proto = FIB_PROTOCOL_IP6,
4685 [0] = clib_host_to_net_u64(0x2001000000000001),
4686 [1] = clib_host_to_net_u64(0x0000000000000003),
4692 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4695 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4697 &pfx_2001_1_2_s_128.fp_addr,
4698 tm->hw[0]->sw_if_index);
4699 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4700 adj = adj_get(ai_01);
4701 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4702 "adj is incomplete");
4703 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4704 &adj->sub_type.nbr.next_hop)),
4705 "adj nbr next-hop ok");
4707 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4708 fib_test_build_rewrite(eth_addr));
4709 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4711 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4712 &adj->sub_type.nbr.next_hop)),
4713 "adj nbr next-hop ok");
4715 fib_table_entry_path_add(fib_index,
4716 &pfx_2001_1_2_s_128,
4718 FIB_ENTRY_FLAG_ATTACHED,
4720 &pfx_2001_1_2_s_128.fp_addr,
4721 tm->hw[0]->sw_if_index,
4725 FIB_ROUTE_PATH_FLAG_NONE);
4727 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4728 ai = fib_entry_get_adj(fei);
4729 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4733 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4735 &pfx_2001_1_3_s_128.fp_addr,
4736 tm->hw[0]->sw_if_index);
4737 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4738 adj = adj_get(ai_02);
4739 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4740 "adj is incomplete");
4741 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4742 &adj->sub_type.nbr.next_hop)),
4743 "adj nbr next-hop ok");
4745 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4746 fib_test_build_rewrite(eth_addr));
4747 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4749 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4750 &adj->sub_type.nbr.next_hop)),
4751 "adj nbr next-hop ok");
4752 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4754 fib_table_entry_path_add(fib_index,
4755 &pfx_2001_1_3_s_128,
4757 FIB_ENTRY_FLAG_ATTACHED,
4759 &pfx_2001_1_3_s_128.fp_addr,
4760 tm->hw[0]->sw_if_index,
4764 FIB_ROUTE_PATH_FLAG_NONE);
4766 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4767 ai = fib_entry_get_adj(fei);
4768 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4771 * +2 entries, +2 unshread path-lists.
4773 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4774 fib_path_list_db_size());
4775 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4776 fib_path_list_pool_size());
4777 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4778 fib_entry_pool_size());
4781 * Add a 2 routes via the first ADJ. ensure path-list sharing
4783 fib_prefix_t pfx_2001_a_s_64 = {
4785 .fp_proto = FIB_PROTOCOL_IP6,
4789 [0] = clib_host_to_net_u64(0x200100000000000a),
4790 [1] = clib_host_to_net_u64(0x0000000000000000),
4795 fib_prefix_t pfx_2001_b_s_64 = {
4797 .fp_proto = FIB_PROTOCOL_IP6,
4801 [0] = clib_host_to_net_u64(0x200100000000000b),
4802 [1] = clib_host_to_net_u64(0x0000000000000000),
4808 fib_table_entry_path_add(fib_index,
4811 FIB_ENTRY_FLAG_NONE,
4814 tm->hw[0]->sw_if_index,
4818 FIB_ROUTE_PATH_FLAG_NONE);
4819 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4820 ai = fib_entry_get_adj(fei);
4821 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4822 fib_table_entry_path_add(fib_index,
4825 FIB_ENTRY_FLAG_NONE,
4828 tm->hw[0]->sw_if_index,
4832 FIB_ROUTE_PATH_FLAG_NONE);
4833 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4834 ai = fib_entry_get_adj(fei);
4835 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4838 * +2 entries, +1 shared path-list.
4840 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4841 fib_path_list_db_size());
4842 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4843 fib_path_list_pool_size());
4844 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4845 fib_entry_pool_size());
4848 * add a v4 prefix via a v6 next-hop
4850 fib_prefix_t pfx_1_1_1_1_s_32 = {
4852 .fp_proto = FIB_PROTOCOL_IP4,
4854 .ip4.as_u32 = 0x01010101,
4857 fei = fib_table_entry_path_add(0, // default table
4860 FIB_ENTRY_FLAG_NONE,
4863 tm->hw[0]->sw_if_index,
4867 FIB_ROUTE_PATH_FLAG_NONE);
4868 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4869 "1.1.1.1/32 o v6 route present");
4870 ai = fib_entry_get_adj(fei);
4872 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4873 "1.1.1.1/32 via ARP-adj");
4874 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4875 "1.1.1.1/32 ADJ-adj is link type v4");
4876 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4877 "1.1.1.1/32 ADJ-adj is NH proto v6");
4878 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4883 fib_prefix_t pfx_2001_c_s_64 = {
4885 .fp_proto = FIB_PROTOCOL_IP6,
4889 [0] = clib_host_to_net_u64(0x200100000000000c),
4890 [1] = clib_host_to_net_u64(0x0000000000000000),
4895 fib_table_entry_path_add(fib_index,
4898 FIB_ENTRY_FLAG_ATTACHED,
4901 tm->hw[0]->sw_if_index,
4905 FIB_ROUTE_PATH_FLAG_NONE);
4906 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4907 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4908 ai = fib_entry_get_adj(fei);
4910 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4911 "2001:0:0:c/64 attached resolves via glean");
4913 fib_table_entry_path_remove(fib_index,
4918 tm->hw[0]->sw_if_index,
4921 FIB_ROUTE_PATH_FLAG_NONE);
4922 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4923 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4926 * Shutdown the interface on which we have a connected and through
4927 * which the routes are reachable.
4928 * This will result in the connected, adj-fibs, and routes linking to drop
4929 * The local/for-us prefix continues to receive.
4931 clib_error_t * error;
4933 error = vnet_sw_interface_set_flags(vnet_get_main(),
4934 tm->hw[0]->sw_if_index,
4935 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4936 FIB_TEST((NULL == error), "Interface shutdown OK");
4938 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4939 dpo = fib_entry_contribute_ip_forwarding(fei);
4940 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4941 "2001::b/64 resolves via drop");
4943 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4944 dpo = fib_entry_contribute_ip_forwarding(fei);
4945 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4946 "2001::a/64 resolves via drop");
4947 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4948 dpo = fib_entry_contribute_ip_forwarding(fei);
4949 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4950 "2001:0:0:1::3/64 resolves via drop");
4951 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4952 dpo = fib_entry_contribute_ip_forwarding(fei);
4953 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4954 "2001:0:0:1::2/64 resolves via drop");
4955 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4956 dpo = fib_entry_contribute_ip_forwarding(fei);
4957 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4958 "2001:0:0:1::1/128 not drop");
4959 local_pfx.fp_len = 64;
4960 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4961 dpo = fib_entry_contribute_ip_forwarding(fei);
4962 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4963 "2001:0:0:1/64 resolves via drop");
4968 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4969 fib_path_list_db_size());
4970 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4971 fib_path_list_pool_size());
4972 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4973 fib_entry_pool_size());
4976 * shutdown one of the other interfaces, then add a connected.
4977 * and swap one of the routes to it.
4979 error = vnet_sw_interface_set_flags(vnet_get_main(),
4980 tm->hw[1]->sw_if_index,
4981 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4982 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4984 fib_prefix_t connected_pfx = {
4986 .fp_proto = FIB_PROTOCOL_IP6,
4989 /* 2001:0:0:2::1/64 */
4991 [0] = clib_host_to_net_u64(0x2001000000000002),
4992 [1] = clib_host_to_net_u64(0x0000000000000001),
4997 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4998 FIB_SOURCE_INTERFACE,
4999 (FIB_ENTRY_FLAG_CONNECTED |
5000 FIB_ENTRY_FLAG_ATTACHED),
5003 tm->hw[1]->sw_if_index,
5007 FIB_ROUTE_PATH_FLAG_NONE);
5008 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
5009 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
5010 dpo = fib_entry_contribute_ip_forwarding(fei);
5011 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
5012 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
5013 "2001:0:0:2/64 not resolves via drop");
5015 connected_pfx.fp_len = 128;
5016 fib_table_entry_update_one_path(fib_index, &connected_pfx,
5017 FIB_SOURCE_INTERFACE,
5018 (FIB_ENTRY_FLAG_CONNECTED |
5019 FIB_ENTRY_FLAG_LOCAL),
5022 tm->hw[0]->sw_if_index,
5023 ~0, // invalid fib index
5026 FIB_ROUTE_PATH_FLAG_NONE);
5027 fei = fib_table_lookup(fib_index, &connected_pfx);
5029 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
5030 dpo = fib_entry_contribute_ip_forwarding(fei);
5031 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
5032 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
5033 "local interface adj is local");
5034 rd = receive_dpo_get(dpo->dpoi_index);
5035 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
5037 "local interface adj is receive ok");
5040 * +2 entries, +2 unshared path-lists
5042 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
5043 fib_path_list_db_size());
5044 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
5045 fib_path_list_pool_size());
5046 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
5047 fib_entry_pool_size());
5051 * bring the interface back up. we expected the routes to return
5052 * to normal forwarding.
5054 error = vnet_sw_interface_set_flags(vnet_get_main(),
5055 tm->hw[0]->sw_if_index,
5056 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5057 FIB_TEST((NULL == error), "Interface bring-up OK");
5058 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5059 ai = fib_entry_get_adj(fei);
5060 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
5061 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5062 ai = fib_entry_get_adj(fei);
5063 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
5064 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5065 ai = fib_entry_get_adj(fei);
5066 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
5067 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5068 ai = fib_entry_get_adj(fei);
5069 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
5070 local_pfx.fp_len = 64;
5071 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5072 ai = fib_entry_get_adj(fei);
5074 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
5075 "attached interface adj is glean");
5078 * Same test as above, but this time the HW interface goes down
5080 error = vnet_hw_interface_set_flags(vnet_get_main(),
5081 tm->hw_if_indicies[0],
5082 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
5083 FIB_TEST((NULL == error), "Interface shutdown OK");
5085 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5086 dpo = fib_entry_contribute_ip_forwarding(fei);
5087 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5088 "2001::b/64 resolves via drop");
5089 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5090 dpo = fib_entry_contribute_ip_forwarding(fei);
5091 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5092 "2001::a/64 resolves via drop");
5093 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5094 dpo = fib_entry_contribute_ip_forwarding(fei);
5095 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5096 "2001:0:0:1::3/128 resolves via drop");
5097 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5098 dpo = fib_entry_contribute_ip_forwarding(fei);
5099 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5100 "2001:0:0:1::2/128 resolves via drop");
5101 local_pfx.fp_len = 128;
5102 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5103 dpo = fib_entry_contribute_ip_forwarding(fei);
5104 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5105 "2001:0:0:1::1/128 not drop");
5106 local_pfx.fp_len = 64;
5107 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5108 dpo = fib_entry_contribute_ip_forwarding(fei);
5109 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5110 "2001:0:0:1/64 resolves via drop");
5112 error = vnet_hw_interface_set_flags(vnet_get_main(),
5113 tm->hw_if_indicies[0],
5114 VNET_HW_INTERFACE_FLAG_LINK_UP);
5115 FIB_TEST((NULL == error), "Interface bring-up OK");
5116 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5117 ai = fib_entry_get_adj(fei);
5118 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
5119 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5120 ai = fib_entry_get_adj(fei);
5121 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
5122 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5123 ai = fib_entry_get_adj(fei);
5124 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
5125 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5126 ai = fib_entry_get_adj(fei);
5127 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
5128 local_pfx.fp_len = 64;
5129 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5130 ai = fib_entry_get_adj(fei);
5132 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
5133 "attached interface adj is glean");
5136 * Delete the interface that the routes reolve through.
5137 * Again no routes are removed. They all point to drop.
5139 * This is considered an error case. The control plane should
5140 * not remove interfaces through which routes resolve, but
5141 * such things can happen. ALL affected routes will drop.
5143 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
5145 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5146 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5147 "2001::b/64 resolves via drop");
5148 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5149 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5150 "2001::b/64 resolves via drop");
5151 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5152 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5153 "2001:0:0:1::3/64 resolves via drop");
5154 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5155 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5156 "2001:0:0:1::2/64 resolves via drop");
5157 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5158 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5159 "2001:0:0:1::1/128 is drop");
5160 local_pfx.fp_len = 64;
5161 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5162 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5163 "2001:0:0:1/64 resolves via drop");
5168 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
5169 fib_path_list_db_size());
5170 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
5171 fib_path_list_pool_size());
5172 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
5173 fib_entry_pool_size());
5176 * Add the interface back. routes stay unresolved.
5178 error = ethernet_register_interface(vnet_get_main(),
5179 test_interface_device_class.index,
5182 &tm->hw_if_indicies[0],
5183 /* flag change */ 0);
5185 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
5186 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5187 "2001::b/64 resolves via drop");
5188 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
5189 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5190 "2001::b/64 resolves via drop");
5191 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
5192 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5193 "2001:0:0:1::3/64 resolves via drop");
5194 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
5195 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5196 "2001:0:0:1::2/64 resolves via drop");
5197 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5198 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5199 "2001:0:0:1::1/128 is drop");
5200 local_pfx.fp_len = 64;
5201 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5202 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
5203 "2001:0:0:1/64 resolves via drop");
5206 * CLEANUP ALL the routes
5208 fib_table_entry_delete(fib_index,
5211 fib_table_entry_delete(fib_index,
5214 fib_table_entry_delete(fib_index,
5217 fib_table_entry_delete(fib_index,
5218 &pfx_2001_1_3_s_128,
5220 fib_table_entry_delete(fib_index,
5221 &pfx_2001_1_2_s_128,
5223 local_pfx.fp_len = 64;
5224 fib_table_entry_delete(fib_index, &local_pfx,
5225 FIB_SOURCE_INTERFACE);
5226 local_pfx.fp_len = 128;
5227 fib_table_entry_special_remove(fib_index, &local_pfx,
5228 FIB_SOURCE_INTERFACE);
5229 connected_pfx.fp_len = 64;
5230 fib_table_entry_delete(fib_index, &connected_pfx,
5231 FIB_SOURCE_INTERFACE);
5232 connected_pfx.fp_len = 128;
5233 fib_table_entry_special_remove(fib_index, &connected_pfx,
5234 FIB_SOURCE_INTERFACE);
5236 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5237 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
5238 "2001::a/64 removed");
5239 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5240 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
5241 "2001::b/64 removed");
5242 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5243 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
5244 "2001:0:0:1::3/128 removed");
5245 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5246 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
5247 "2001:0:0:1::3/128 removed");
5248 local_pfx.fp_len = 64;
5249 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5250 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5251 "2001:0:0:1/64 removed");
5252 local_pfx.fp_len = 128;
5253 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5254 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5255 "2001:0:0:1::1/128 removed");
5256 connected_pfx.fp_len = 64;
5257 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5258 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5259 "2001:0:0:2/64 removed");
5260 connected_pfx.fp_len = 128;
5261 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5262 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5263 "2001:0:0:2::1/128 removed");
5266 * -8 entries. -7 path-lists (1 was shared).
5268 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5269 fib_path_list_db_size());
5270 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5271 fib_path_list_pool_size());
5272 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5273 fib_entry_pool_size());
5276 * now remove the VRF
5278 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
5280 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5281 fib_path_list_db_size());
5282 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5283 fib_path_list_pool_size());
5284 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5285 fib_entry_pool_size());
5291 * return the interfaces to up state
5293 error = vnet_sw_interface_set_flags(vnet_get_main(),
5294 tm->hw[0]->sw_if_index,
5295 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5296 error = vnet_sw_interface_set_flags(vnet_get_main(),
5297 tm->hw[1]->sw_if_index,
5298 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5300 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5302 FIB_TEST((0 == adj_glean_db_size()), "ADJ DB size is %d",
5303 adj_glean_db_size());
5309 * Test Attached Exports
5314 const dpo_id_t *dpo, *dpo_drop;
5315 const u32 fib_index = 0;
5316 fib_node_index_t fei;
5325 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5329 * add interface routes. We'll assume this works. It's more rigorously
5332 fib_prefix_t local_pfx = {
5334 .fp_proto = FIB_PROTOCOL_IP4,
5338 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5343 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5344 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5346 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5348 fib_table_entry_update_one_path(fib_index, &local_pfx,
5349 FIB_SOURCE_INTERFACE,
5350 (FIB_ENTRY_FLAG_CONNECTED |
5351 FIB_ENTRY_FLAG_ATTACHED),
5354 tm->hw[0]->sw_if_index,
5358 FIB_ROUTE_PATH_FLAG_NONE);
5359 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5360 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5361 "attached interface route present");
5363 local_pfx.fp_len = 32;
5364 fib_table_entry_update_one_path(fib_index, &local_pfx,
5365 FIB_SOURCE_INTERFACE,
5366 (FIB_ENTRY_FLAG_CONNECTED |
5367 FIB_ENTRY_FLAG_LOCAL),
5370 tm->hw[0]->sw_if_index,
5371 ~0, // invalid fib index
5374 FIB_ROUTE_PATH_FLAG_NONE);
5375 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5377 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5378 "local interface route present");
5381 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5383 fib_prefix_t pfx_10_10_10_1_s_32 = {
5385 .fp_proto = FIB_PROTOCOL_IP4,
5388 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5391 fib_node_index_t ai;
5393 fib_table_entry_path_add(fib_index,
5394 &pfx_10_10_10_1_s_32,
5396 FIB_ENTRY_FLAG_ATTACHED,
5398 &pfx_10_10_10_1_s_32.fp_addr,
5399 tm->hw[0]->sw_if_index,
5400 ~0, // invalid fib index
5403 FIB_ROUTE_PATH_FLAG_NONE);
5405 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5406 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5407 ai = fib_entry_get_adj(fei);
5410 * create another FIB table into which routes will be imported
5412 u32 import_fib_index1;
5414 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
5419 * Add an attached route in the import FIB
5421 local_pfx.fp_len = 24;
5422 fib_table_entry_update_one_path(import_fib_index1,
5425 FIB_ENTRY_FLAG_NONE,
5428 tm->hw[0]->sw_if_index,
5429 ~0, // invalid fib index
5432 FIB_ROUTE_PATH_FLAG_NONE);
5433 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5434 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5437 * check for the presence of the adj-fibs in the import table
5439 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5440 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5441 FIB_TEST((ai == fib_entry_get_adj(fei)),
5442 "adj-fib1 Import uses same adj as export");
5445 * check for the presence of the local in the import table
5447 local_pfx.fp_len = 32;
5448 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5449 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5452 * Add another adj-fin in the export table. Expect this
5453 * to get magically exported;
5455 fib_prefix_t pfx_10_10_10_2_s_32 = {
5457 .fp_proto = FIB_PROTOCOL_IP4,
5460 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5464 fib_table_entry_path_add(fib_index,
5465 &pfx_10_10_10_2_s_32,
5467 FIB_ENTRY_FLAG_ATTACHED,
5469 &pfx_10_10_10_2_s_32.fp_addr,
5470 tm->hw[0]->sw_if_index,
5471 ~0, // invalid fib index
5474 FIB_ROUTE_PATH_FLAG_NONE);
5475 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5476 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5477 ai = fib_entry_get_adj(fei);
5479 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5480 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5481 FIB_TEST((ai == fib_entry_get_adj(fei)),
5482 "Import uses same adj as export");
5483 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5484 "ADJ-fib2 imported flags %d",
5485 fib_entry_get_flags(fei));
5488 * create a 2nd FIB table into which routes will be imported
5490 u32 import_fib_index2;
5492 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
5496 * Add an attached route in the import FIB
5498 local_pfx.fp_len = 24;
5499 fib_table_entry_update_one_path(import_fib_index2,
5502 FIB_ENTRY_FLAG_NONE,
5505 tm->hw[0]->sw_if_index,
5506 ~0, // invalid fib index
5509 FIB_ROUTE_PATH_FLAG_NONE);
5510 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5511 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5514 * check for the presence of all the adj-fibs and local in the import table
5516 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5517 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5518 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5519 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5520 local_pfx.fp_len = 32;
5521 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5522 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5525 * add a 3rd adj-fib. expect it to be exported to both tables.
5527 fib_prefix_t pfx_10_10_10_3_s_32 = {
5529 .fp_proto = FIB_PROTOCOL_IP4,
5532 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5536 fib_table_entry_path_add(fib_index,
5537 &pfx_10_10_10_3_s_32,
5539 FIB_ENTRY_FLAG_ATTACHED,
5541 &pfx_10_10_10_3_s_32.fp_addr,
5542 tm->hw[0]->sw_if_index,
5543 ~0, // invalid fib index
5546 FIB_ROUTE_PATH_FLAG_NONE);
5547 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5548 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5549 ai = fib_entry_get_adj(fei);
5551 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5552 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5553 FIB_TEST((ai == fib_entry_get_adj(fei)),
5554 "Import uses same adj as export");
5555 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5556 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5557 FIB_TEST((ai == fib_entry_get_adj(fei)),
5558 "Import uses same adj as export");
5561 * remove the 3rd adj fib. we expect it to be removed from both FIBs
5563 fib_table_entry_delete(fib_index,
5564 &pfx_10_10_10_3_s_32,
5567 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5568 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5570 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5571 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5573 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5574 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5577 * remove the attached route from the 2nd FIB. expect the imported
5578 * entries to be removed
5580 local_pfx.fp_len = 24;
5581 fib_table_entry_delete(import_fib_index2,
5584 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5585 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5587 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5588 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5589 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5590 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5591 local_pfx.fp_len = 32;
5592 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5593 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5595 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5596 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5597 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5598 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5599 local_pfx.fp_len = 32;
5600 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5601 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5604 * modify the route in FIB1 so it is no longer attached. expect the imported
5605 * entries to be removed
5607 local_pfx.fp_len = 24;
5608 fib_table_entry_update_one_path(import_fib_index1,
5611 FIB_ENTRY_FLAG_NONE,
5613 &pfx_10_10_10_2_s_32.fp_addr,
5614 tm->hw[0]->sw_if_index,
5615 ~0, // invalid fib index
5618 FIB_ROUTE_PATH_FLAG_NONE);
5619 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5620 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5621 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5622 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5623 local_pfx.fp_len = 32;
5624 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5625 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5628 * modify it back to attached. expect the adj-fibs back
5630 local_pfx.fp_len = 24;
5631 fib_table_entry_update_one_path(import_fib_index1,
5634 FIB_ENTRY_FLAG_NONE,
5637 tm->hw[0]->sw_if_index,
5638 ~0, // invalid fib index
5641 FIB_ROUTE_PATH_FLAG_NONE);
5642 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5643 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5644 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5645 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5646 local_pfx.fp_len = 32;
5647 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5648 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5651 * add a covering attached next-hop for the interface address, so we have
5652 * a valid adj to find when we check the forwarding tables
5654 fib_prefix_t pfx_10_0_0_0_s_8 = {
5656 .fp_proto = FIB_PROTOCOL_IP4,
5659 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5663 fei = fib_table_entry_update_one_path(fib_index,
5666 FIB_ENTRY_FLAG_NONE,
5668 &pfx_10_10_10_3_s_32.fp_addr,
5669 tm->hw[0]->sw_if_index,
5670 ~0, // invalid fib index
5673 FIB_ROUTE_PATH_FLAG_NONE);
5674 dpo = fib_entry_contribute_ip_forwarding(fei);
5677 * remove the route in the export fib. expect the adj-fibs to be removed
5679 local_pfx.fp_len = 24;
5680 fib_table_entry_delete(fib_index,
5682 FIB_SOURCE_INTERFACE);
5684 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5685 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5686 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5687 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5688 local_pfx.fp_len = 32;
5689 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5690 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5693 * the adj-fibs in the export VRF are present in the FIB table,
5694 * but not installed in forwarding, since they have no attached cover.
5695 * Consequently a lookup in the MTRIE gives the adj for the covering
5698 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5699 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5702 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5703 FIB_TEST(lbi == dpo->dpoi_index,
5704 "10.10.10.1 forwards on \n%U not \n%U",
5705 format_load_balance, lbi, 0,
5706 format_dpo_id, dpo, 0);
5707 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5708 FIB_TEST(lbi == dpo->dpoi_index,
5709 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5710 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5711 FIB_TEST(lbi == dpo->dpoi_index,
5712 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5715 * add the export prefix back, but not as attached.
5716 * No adj-fibs in export nor import tables
5718 local_pfx.fp_len = 24;
5719 fei = fib_table_entry_update_one_path(fib_index,
5722 FIB_ENTRY_FLAG_NONE,
5724 &pfx_10_10_10_1_s_32.fp_addr,
5725 tm->hw[0]->sw_if_index,
5726 ~0, // invalid fib index
5729 FIB_ROUTE_PATH_FLAG_NONE);
5730 dpo = fib_entry_contribute_ip_forwarding(fei);
5732 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5733 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5734 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5735 FIB_TEST(lbi == dpo->dpoi_index,
5736 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5737 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5738 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5739 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5740 FIB_TEST(lbi == dpo->dpoi_index,
5741 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5743 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5744 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5745 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5746 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5747 local_pfx.fp_len = 32;
5748 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5749 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5752 * modify the export prefix so it is attached. expect all covereds to return
5754 local_pfx.fp_len = 24;
5755 fib_table_entry_update_one_path(fib_index,
5758 FIB_ENTRY_FLAG_NONE,
5761 tm->hw[0]->sw_if_index,
5762 ~0, // invalid fib index
5765 FIB_ROUTE_PATH_FLAG_NONE);
5767 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5768 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5769 dpo = fib_entry_contribute_ip_forwarding(fei);
5770 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5771 "Adj-fib1 is not drop in export");
5772 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5773 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5774 local_pfx.fp_len = 32;
5775 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5776 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5777 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5778 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5779 dpo = fib_entry_contribute_ip_forwarding(fei);
5780 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5781 "Adj-fib1 is not drop in export: %U %U",
5782 format_dpo_id, dpo, 0,
5783 format_dpo_id, load_balance_get_bucket(dpo->dpoi_index, 0), 0);
5784 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5785 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5786 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5787 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5788 local_pfx.fp_len = 32;
5789 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5790 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5793 * modify the export prefix so connected. no change.
5795 local_pfx.fp_len = 24;
5796 fib_table_entry_update_one_path(fib_index, &local_pfx,
5797 FIB_SOURCE_INTERFACE,
5798 (FIB_ENTRY_FLAG_CONNECTED |
5799 FIB_ENTRY_FLAG_ATTACHED),
5802 tm->hw[0]->sw_if_index,
5806 FIB_ROUTE_PATH_FLAG_NONE);
5808 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5809 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5810 dpo = fib_entry_contribute_ip_forwarding(fei);
5811 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5812 "Adj-fib1 is not drop in export");
5813 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5814 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5815 local_pfx.fp_len = 32;
5816 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5817 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5818 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5819 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5820 dpo = fib_entry_contribute_ip_forwarding(fei);
5821 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5822 "Adj-fib1 is not drop in export");
5823 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5824 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5825 local_pfx.fp_len = 32;
5826 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5827 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5832 fib_table_entry_delete(fib_index,
5835 fib_table_entry_delete(fib_index,
5836 &pfx_10_10_10_1_s_32,
5838 fib_table_entry_delete(fib_index,
5839 &pfx_10_10_10_2_s_32,
5841 local_pfx.fp_len = 32;
5842 fib_table_entry_delete(fib_index,
5844 FIB_SOURCE_INTERFACE);
5845 local_pfx.fp_len = 24;
5846 fib_table_entry_delete(fib_index,
5849 fib_table_entry_delete(fib_index,
5851 FIB_SOURCE_INTERFACE);
5852 local_pfx.fp_len = 24;
5853 fib_table_entry_delete(import_fib_index1,
5857 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5858 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5860 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5867 * Test Path Preference
5870 fib_test_pref (void)
5872 test_main_t *tm = &test_main;
5876 const fib_prefix_t pfx_1_1_1_1_s_32 = {
5878 .fp_proto = FIB_PROTOCOL_IP4,
5881 .as_u32 = clib_host_to_net_u32(0x01010101),
5887 * 2 high, 2 medium and 2 low preference non-recursive paths
5889 fib_route_path_t nr_path_hi_1 = {
5890 .frp_proto = DPO_PROTO_IP4,
5891 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5892 .frp_fib_index = ~0,
5894 .frp_preference = 0,
5895 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5897 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5900 fib_route_path_t nr_path_hi_2 = {
5901 .frp_proto = DPO_PROTO_IP4,
5902 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5903 .frp_fib_index = ~0,
5905 .frp_preference = 0,
5906 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5908 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5911 fib_route_path_t nr_path_med_1 = {
5912 .frp_proto = DPO_PROTO_IP4,
5913 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5914 .frp_fib_index = ~0,
5916 .frp_preference = 1,
5917 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5919 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5922 fib_route_path_t nr_path_med_2 = {
5923 .frp_proto = DPO_PROTO_IP4,
5924 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5925 .frp_fib_index = ~0,
5927 .frp_preference = 1,
5928 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5930 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5933 fib_route_path_t nr_path_low_1 = {
5934 .frp_proto = DPO_PROTO_IP4,
5935 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5936 .frp_fib_index = ~0,
5938 .frp_preference = 2,
5939 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5941 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5944 fib_route_path_t nr_path_low_2 = {
5945 .frp_proto = DPO_PROTO_IP4,
5946 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5947 .frp_fib_index = ~0,
5949 .frp_preference = 2,
5950 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5952 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5955 fib_route_path_t *nr_paths = NULL;
5957 vec_add1(nr_paths, nr_path_hi_1);
5958 vec_add1(nr_paths, nr_path_hi_2);
5959 vec_add1(nr_paths, nr_path_med_1);
5960 vec_add1(nr_paths, nr_path_med_2);
5961 vec_add1(nr_paths, nr_path_low_1);
5962 vec_add1(nr_paths, nr_path_low_2);
5964 adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5966 &nr_path_hi_1.frp_addr,
5967 nr_path_hi_1.frp_sw_if_index);
5968 adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5970 &nr_path_hi_2.frp_addr,
5971 nr_path_hi_2.frp_sw_if_index);
5972 adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5974 &nr_path_med_1.frp_addr,
5975 nr_path_med_1.frp_sw_if_index);
5976 adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5978 &nr_path_med_2.frp_addr,
5979 nr_path_med_2.frp_sw_if_index);
5980 adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5982 &nr_path_low_1.frp_addr,
5983 nr_path_low_1.frp_sw_if_index);
5984 adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5986 &nr_path_low_2.frp_addr,
5987 nr_path_low_2.frp_sw_if_index);
5989 fib_test_lb_bucket_t ip_hi_1 = {
5995 fib_test_lb_bucket_t ip_hi_2 = {
6001 fib_test_lb_bucket_t ip_med_1 = {
6007 fib_test_lb_bucket_t ip_med_2 = {
6013 fib_test_lb_bucket_t ip_low_1 = {
6019 fib_test_lb_bucket_t ip_low_2 = {
6026 fib_node_index_t fei;
6028 fei = fib_table_entry_path_add2(0,
6031 FIB_ENTRY_FLAG_NONE,
6034 FIB_TEST(!fib_test_validate_entry(fei,
6035 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6039 "1.1.1.1/32 via high preference paths");
6042 * bring down the interface on which the high preference path lie
6044 vnet_sw_interface_set_flags(vnet_get_main(),
6045 tm->hw[0]->sw_if_index,
6048 FIB_TEST(!fib_test_validate_entry(fei,
6049 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6053 "1.1.1.1/32 via medium preference paths");
6056 * bring down the interface on which the medium preference path lie
6058 vnet_sw_interface_set_flags(vnet_get_main(),
6059 tm->hw[1]->sw_if_index,
6062 FIB_TEST(!fib_test_validate_entry(fei,
6063 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6067 "1.1.1.1/32 via low preference paths");
6070 * bring up the interface on which the high preference path lie
6072 vnet_sw_interface_set_flags(vnet_get_main(),
6073 tm->hw[0]->sw_if_index,
6074 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6076 FIB_TEST(!fib_test_validate_entry(fei,
6077 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6081 "1.1.1.1/32 via high preference paths");
6084 * bring up the interface on which the medium preference path lie
6086 vnet_sw_interface_set_flags(vnet_get_main(),
6087 tm->hw[1]->sw_if_index,
6088 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6090 FIB_TEST(!fib_test_validate_entry(fei,
6091 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6095 "1.1.1.1/32 via high preference paths");
6097 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
6098 fib_entry_contribute_forwarding(fei,
6099 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6103 * 3 recursive paths of different preference
6105 const fib_prefix_t pfx_1_1_1_2_s_32 = {
6107 .fp_proto = FIB_PROTOCOL_IP4,
6110 .as_u32 = clib_host_to_net_u32(0x01010102),
6114 const fib_prefix_t pfx_1_1_1_3_s_32 = {
6116 .fp_proto = FIB_PROTOCOL_IP4,
6119 .as_u32 = clib_host_to_net_u32(0x01010103),
6123 fei = fib_table_entry_path_add2(0,
6126 FIB_ENTRY_FLAG_NONE,
6128 dpo_id_t ip_1_1_1_2 = DPO_INVALID;
6129 fib_entry_contribute_forwarding(fei,
6130 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6132 fei = fib_table_entry_path_add2(0,
6135 FIB_ENTRY_FLAG_NONE,
6137 dpo_id_t ip_1_1_1_3 = DPO_INVALID;
6138 fib_entry_contribute_forwarding(fei,
6139 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6142 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
6145 .lb = ip_1_1_1_1.dpoi_index,
6148 fib_test_lb_bucket_t ip_o_1_1_1_2 = {
6151 .lb = ip_1_1_1_2.dpoi_index,
6154 fib_test_lb_bucket_t ip_o_1_1_1_3 = {
6157 .lb = ip_1_1_1_3.dpoi_index,
6160 fib_route_path_t r_path_hi = {
6161 .frp_proto = DPO_PROTO_IP4,
6162 .frp_sw_if_index = ~0,
6165 .frp_preference = 0,
6166 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6167 .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
6169 fib_route_path_t r_path_med = {
6170 .frp_proto = DPO_PROTO_IP4,
6171 .frp_sw_if_index = ~0,
6174 .frp_preference = 10,
6175 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
6176 .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
6178 fib_route_path_t r_path_low = {
6179 .frp_proto = DPO_PROTO_IP4,
6180 .frp_sw_if_index = ~0,
6183 .frp_preference = 255,
6184 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
6185 .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
6187 fib_route_path_t *r_paths = NULL;
6189 vec_add1(r_paths, r_path_hi);
6190 vec_add1(r_paths, r_path_low);
6191 vec_add1(r_paths, r_path_med);
6194 * add many recursive so we get the LB MAp created
6197 fib_prefix_t pfx_r[N_PFXS];
6198 unsigned int n_pfxs;
6199 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6201 pfx_r[n_pfxs].fp_len = 32;
6202 pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
6203 pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
6204 clib_host_to_net_u32(0x02000000 + n_pfxs);
6206 fei = fib_table_entry_path_add2(0,
6209 FIB_ENTRY_FLAG_NONE,
6212 FIB_TEST(!fib_test_validate_entry(fei,
6213 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6216 "recursive via high preference paths");
6219 * withdraw hig pref resolving entry
6221 fib_table_entry_delete(0,
6225 /* suspend so the update walk kicks int */
6226 vlib_process_suspend(vlib_get_main(), 1e-5);
6228 FIB_TEST(!fib_test_validate_entry(fei,
6229 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6232 "recursive via medium preference paths");
6235 * withdraw medium pref resolving entry
6237 fib_table_entry_delete(0,
6241 /* suspend so the update walk kicks int */
6242 vlib_process_suspend(vlib_get_main(), 1e-5);
6244 FIB_TEST(!fib_test_validate_entry(fei,
6245 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6248 "recursive via low preference paths");
6251 * add back paths for next iteration
6253 fei = fib_table_entry_update(0,
6256 FIB_ENTRY_FLAG_NONE,
6258 fei = fib_table_entry_update(0,
6261 FIB_ENTRY_FLAG_NONE,
6264 /* suspend so the update walk kicks int */
6265 vlib_process_suspend(vlib_get_main(), 1e-5);
6267 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6268 FIB_TEST(!fib_test_validate_entry(fei,
6269 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6272 "recursive via high preference paths");
6276 fib_table_entry_delete(0,
6280 /* suspend so the update walk kicks int */
6281 vlib_process_suspend(vlib_get_main(), 1e-5);
6283 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6285 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6287 FIB_TEST(!fib_test_validate_entry(fei,
6288 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6291 "recursive via medium preference paths");
6293 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6295 fib_table_entry_delete(0,
6303 fib_table_entry_delete(0,
6306 fib_table_entry_delete(0,
6310 dpo_reset(&ip_1_1_1_1);
6311 dpo_reset(&ip_1_1_1_2);
6312 dpo_reset(&ip_1_1_1_3);
6313 adj_unlock(ai_low_2);
6314 adj_unlock(ai_low_1);
6315 adj_unlock(ai_med_2);
6316 adj_unlock(ai_med_1);
6317 adj_unlock(ai_hi_2);
6318 adj_unlock(ai_hi_1);
6324 * Test the recursive route route handling for GRE tunnels
6327 fib_test_label (void)
6329 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;
6330 const u32 fib_index = 0;
6331 int lb_count, ii, res;
6336 lb_count = pool_elts(load_balance_pool);
6341 * add interface routes. We'll assume this works. It's more rigorously
6344 fib_prefix_t local0_pfx = {
6346 .fp_proto = FIB_PROTOCOL_IP4,
6350 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6355 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6358 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6359 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6361 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6362 FIB_SOURCE_INTERFACE,
6363 (FIB_ENTRY_FLAG_CONNECTED |
6364 FIB_ENTRY_FLAG_ATTACHED),
6367 tm->hw[0]->sw_if_index,
6371 FIB_ROUTE_PATH_FLAG_NONE);
6372 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6373 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6374 "attached interface route present");
6376 local0_pfx.fp_len = 32;
6377 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6378 FIB_SOURCE_INTERFACE,
6379 (FIB_ENTRY_FLAG_CONNECTED |
6380 FIB_ENTRY_FLAG_LOCAL),
6383 tm->hw[0]->sw_if_index,
6384 ~0, // invalid fib index
6387 FIB_ROUTE_PATH_FLAG_NONE);
6388 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6390 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6391 "local interface route present");
6393 fib_prefix_t local1_pfx = {
6395 .fp_proto = FIB_PROTOCOL_IP4,
6399 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6404 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6405 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6407 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6408 FIB_SOURCE_INTERFACE,
6409 (FIB_ENTRY_FLAG_CONNECTED |
6410 FIB_ENTRY_FLAG_ATTACHED),
6413 tm->hw[1]->sw_if_index,
6417 FIB_ROUTE_PATH_FLAG_NONE);
6418 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6419 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6420 "attached interface route present");
6422 local1_pfx.fp_len = 32;
6423 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6424 FIB_SOURCE_INTERFACE,
6425 (FIB_ENTRY_FLAG_CONNECTED |
6426 FIB_ENTRY_FLAG_LOCAL),
6429 tm->hw[1]->sw_if_index,
6430 ~0, // invalid fib index
6433 FIB_ROUTE_PATH_FLAG_NONE);
6434 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6436 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6437 "local interface route present");
6439 ip46_address_t nh_10_10_10_1 = {
6441 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6444 ip46_address_t nh_10_10_11_1 = {
6446 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6449 ip46_address_t nh_10_10_11_2 = {
6451 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6455 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6458 tm->hw[1]->sw_if_index);
6459 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6462 tm->hw[1]->sw_if_index);
6463 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6466 tm->hw[0]->sw_if_index);
6467 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6470 tm->hw[1]->sw_if_index);
6471 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6474 tm->hw[1]->sw_if_index);
6477 * Add an etry with one path with a real out-going label
6479 fib_prefix_t pfx_1_1_1_1_s_32 = {
6481 .fp_proto = FIB_PROTOCOL_IP4,
6483 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6486 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6487 .type = FT_LB_LABEL_O_ADJ,
6489 .adj = ai_mpls_10_10_10_1,
6494 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6495 .type = FT_LB_LABEL_O_ADJ,
6497 .adj = ai_mpls_10_10_10_1,
6499 .eos = MPLS_NON_EOS,
6502 fib_mpls_label_t *l99 = NULL, fml99 = {
6505 vec_add1(l99, fml99);
6507 fib_table_entry_update_one_path(fib_index,
6510 FIB_ENTRY_FLAG_NONE,
6513 tm->hw[0]->sw_if_index,
6514 ~0, // invalid fib index
6517 FIB_ROUTE_PATH_FLAG_NONE);
6519 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6520 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6522 FIB_TEST(!fib_test_validate_entry(fei,
6523 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6525 &l99_eos_o_10_10_10_1),
6526 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6529 * add a path with an implicit NULL label
6531 fib_test_lb_bucket_t a_o_10_10_11_1 = {
6534 .adj = ai_v4_10_10_11_1,
6537 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6540 .adj = ai_mpls_10_10_11_1,
6543 fib_mpls_label_t *l_imp_null = NULL, fml_imp_null = {
6544 .fml_value = MPLS_IETF_IMPLICIT_NULL_LABEL,
6546 vec_add1(l_imp_null, fml_imp_null);
6548 fei = fib_table_entry_path_add(fib_index,
6551 FIB_ENTRY_FLAG_NONE,
6554 tm->hw[1]->sw_if_index,
6555 ~0, // invalid fib index
6558 FIB_ROUTE_PATH_FLAG_NONE);
6560 FIB_TEST(!fib_test_validate_entry(fei,
6561 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6563 &l99_eos_o_10_10_10_1,
6565 "1.1.1.1/32 LB 2 buckets via: "
6566 "label 99 over 10.10.10.1, "
6567 "adj over 10.10.11.1");
6570 * assign the route a local label
6572 fib_table_entry_local_label_add(fib_index,
6576 fib_prefix_t pfx_24001_eos = {
6577 .fp_proto = FIB_PROTOCOL_MPLS,
6581 fib_prefix_t pfx_24001_neos = {
6582 .fp_proto = FIB_PROTOCOL_MPLS,
6584 .fp_eos = MPLS_NON_EOS,
6586 fib_test_lb_bucket_t disp_o_10_10_11_1 = {
6587 .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
6589 .adj = ai_v4_10_10_11_1,
6594 * The EOS entry should link to both the paths,
6595 * and use an ip adj for the imp-null
6596 * The NON-EOS entry should link to both the paths,
6597 * and use an mpls adj for the imp-null
6599 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6601 FIB_TEST(!fib_test_validate_entry(fei,
6602 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6604 &l99_eos_o_10_10_10_1,
6605 &disp_o_10_10_11_1),
6606 "24001/eos LB 2 buckets via: "
6607 "label 99 over 10.10.10.1, "
6608 "mpls disp adj over 10.10.11.1");
6611 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6613 FIB_TEST(!fib_test_validate_entry(fei,
6614 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6616 &l99_neos_o_10_10_10_1,
6617 &a_mpls_o_10_10_11_1),
6618 "24001/neos LB 1 bucket via: "
6619 "label 99 over 10.10.10.1 ",
6620 "mpls-adj via 10.10.11.1");
6623 * add an unlabelled path, this is excluded from the neos chains,
6625 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6628 .adj = ai_v4_10_10_11_2,
6631 fib_test_lb_bucket_t disp_o_10_10_11_2 = {
6632 .type = FT_LB_MPLS_DISP_PIPE_O_ADJ,
6634 .adj = ai_v4_10_10_11_2,
6639 fei = fib_table_entry_path_add(fib_index,
6642 FIB_ENTRY_FLAG_NONE,
6645 tm->hw[1]->sw_if_index,
6646 ~0, // invalid fib index
6649 FIB_ROUTE_PATH_FLAG_NONE);
6651 FIB_TEST(!fib_test_validate_entry(fei,
6652 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6653 16, // 3 choices spread over 16 buckets
6654 &l99_eos_o_10_10_10_1,
6655 &l99_eos_o_10_10_10_1,
6656 &l99_eos_o_10_10_10_1,
6657 &l99_eos_o_10_10_10_1,
6658 &l99_eos_o_10_10_10_1,
6659 &l99_eos_o_10_10_10_1,
6670 "1.1.1.1/32 LB 16 buckets via: "
6671 "label 99 over 10.10.10.1, "
6672 "adj over 10.10.11.1",
6673 "adj over 10.10.11.2");
6676 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6678 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6679 fib_entry_contribute_forwarding(fei,
6680 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6684 * n-eos has only the 2 labelled paths
6686 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6689 FIB_TEST(!fib_test_validate_entry(fei,
6690 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6692 &l99_neos_o_10_10_10_1,
6693 &a_mpls_o_10_10_11_1),
6694 "24001/neos LB 2 buckets via: "
6695 "label 99 over 10.10.10.1, "
6696 "adj-mpls over 10.10.11.2");
6699 * A labelled recursive
6701 fib_prefix_t pfx_2_2_2_2_s_32 = {
6703 .fp_proto = FIB_PROTOCOL_IP4,
6705 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6708 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6709 .type = FT_LB_LABEL_O_LB,
6711 .lb = non_eos_1_1_1_1.dpoi_index,
6714 .mode = FIB_MPLS_LSP_MODE_UNIFORM,
6717 fib_mpls_label_t *l1600 = NULL, fml1600 = {
6719 .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
6721 vec_add1(l1600, fml1600);
6723 fei = fib_table_entry_update_one_path(fib_index,
6726 FIB_ENTRY_FLAG_NONE,
6728 &pfx_1_1_1_1_s_32.fp_addr,
6733 FIB_ROUTE_PATH_FLAG_NONE);
6735 FIB_TEST(!fib_test_validate_entry(fei,
6736 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6738 &l1600_eos_o_1_1_1_1),
6739 "2.2.2.2.2/32 LB 1 buckets via: "
6740 "label 1600 over 1.1.1.1");
6742 dpo_id_t dpo_44 = DPO_INVALID;
6745 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6746 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6748 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6749 "uRPF check for 2.2.2.2/32 on %d OK",
6750 tm->hw[0]->sw_if_index);
6751 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6752 "uRPF check for 2.2.2.2/32 on %d OK",
6753 tm->hw[1]->sw_if_index);
6754 FIB_TEST(!fib_urpf_check(urpfi, 99),
6755 "uRPF check for 2.2.2.2/32 on 99 not-OK",
6758 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6759 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6760 "Shared uRPF on IP and non-EOS chain");
6765 * we are holding a lock on the non-eos LB of the via-entry.
6766 * do a PIC-core failover by shutting the link of the via-entry.
6768 * shut down the link with the valid label
6770 vnet_sw_interface_set_flags(vnet_get_main(),
6771 tm->hw[0]->sw_if_index,
6774 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6775 FIB_TEST(!fib_test_validate_entry(fei,
6776 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6780 "1.1.1.1/32 LB 2 buckets via: "
6781 "adj over 10.10.11.1, ",
6782 "adj-v4 over 10.10.11.2");
6784 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6786 FIB_TEST(!fib_test_validate_entry(fei,
6787 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6790 &disp_o_10_10_11_2),
6791 "24001/eos LB 2 buckets via: "
6792 "mpls-disp adj over 10.10.11.1, ",
6793 "mpls-disp adj-v4 over 10.10.11.2");
6795 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6797 FIB_TEST(!fib_test_validate_entry(fei,
6798 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6800 &a_mpls_o_10_10_11_1),
6801 "24001/neos LB 1 buckets via: "
6802 "adj-mpls over 10.10.11.2");
6805 * test that the pre-failover load-balance has been in-place
6808 dpo_id_t current = DPO_INVALID;
6809 fib_entry_contribute_forwarding(fei,
6810 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6813 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6815 "PIC-core LB inplace modified %U %U",
6816 format_dpo_id, &non_eos_1_1_1_1, 0,
6817 format_dpo_id, ¤t, 0);
6819 dpo_reset(&non_eos_1_1_1_1);
6820 dpo_reset(¤t);
6823 * no-shut the link with the valid label
6825 vnet_sw_interface_set_flags(vnet_get_main(),
6826 tm->hw[0]->sw_if_index,
6827 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6829 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6830 FIB_TEST(!fib_test_validate_entry(fei,
6831 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6832 16, // 3 choices spread over 16 buckets
6833 &l99_eos_o_10_10_10_1,
6834 &l99_eos_o_10_10_10_1,
6835 &l99_eos_o_10_10_10_1,
6836 &l99_eos_o_10_10_10_1,
6837 &l99_eos_o_10_10_10_1,
6838 &l99_eos_o_10_10_10_1,
6849 "1.1.1.1/32 LB 16 buckets via: "
6850 "label 99 over 10.10.10.1, "
6851 "adj over 10.10.11.1",
6852 "adj-v4 over 10.10.11.2");
6855 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6857 FIB_TEST(!fib_test_validate_entry(fei,
6858 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6859 16, // 3 choices spread over 16 buckets
6860 &l99_eos_o_10_10_10_1,
6861 &l99_eos_o_10_10_10_1,
6862 &l99_eos_o_10_10_10_1,
6863 &l99_eos_o_10_10_10_1,
6864 &l99_eos_o_10_10_10_1,
6865 &l99_eos_o_10_10_10_1,
6875 &disp_o_10_10_11_2),
6876 "24001/eos LB 16 buckets via: "
6877 "label 99 over 10.10.10.1, "
6878 "MPLS disp adj over 10.10.11.1",
6879 "MPLS disp adj-v4 over 10.10.11.2");
6881 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6883 FIB_TEST(!fib_test_validate_entry(fei,
6884 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6886 &l99_neos_o_10_10_10_1,
6887 &a_mpls_o_10_10_11_1),
6888 "24001/neos LB 2 buckets via: "
6889 "label 99 over 10.10.10.1, "
6890 "adj-mpls over 10.10.11.2");
6893 * remove the first path with the valid label
6895 fib_table_entry_path_remove(fib_index,
6900 tm->hw[0]->sw_if_index,
6901 ~0, // invalid fib index
6903 FIB_ROUTE_PATH_FLAG_NONE);
6905 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6906 FIB_TEST(!fib_test_validate_entry(fei,
6907 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6911 "1.1.1.1/32 LB 2 buckets via: "
6912 "adj over 10.10.11.1, "
6913 "adj-v4 over 10.10.11.2");
6915 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6917 FIB_TEST(!fib_test_validate_entry(fei,
6918 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6921 &disp_o_10_10_11_2),
6922 "24001/eos LB 2 buckets via: "
6923 "MPLS disp adj over 10.10.11.1, "
6924 "MPLS disp adj-v4 over 10.10.11.2");
6926 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6929 FIB_TEST(!fib_test_validate_entry(fei,
6930 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6932 &a_mpls_o_10_10_11_1),
6933 "24001/neos LB 1 buckets via: "
6934 "adj-mpls over 10.10.11.2");
6937 * remove the other path with a valid label
6939 fib_test_lb_bucket_t bucket_drop = {
6942 fib_test_lb_bucket_t mpls_bucket_drop = {
6945 .adj = DPO_PROTO_MPLS,
6949 fib_table_entry_path_remove(fib_index,
6954 tm->hw[1]->sw_if_index,
6955 ~0, // invalid fib index
6957 FIB_ROUTE_PATH_FLAG_NONE);
6959 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6960 FIB_TEST(!fib_test_validate_entry(fei,
6961 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6964 "1.1.1.1/32 LB 1 buckets via: "
6965 "adj over 10.10.11.2");
6967 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6969 FIB_TEST(!fib_test_validate_entry(fei,
6970 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6972 &disp_o_10_10_11_2),
6973 "24001/eos LB 1 buckets via: "
6974 "MPLS disp adj over 10.10.11.2");
6976 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6978 FIB_TEST(!fib_test_validate_entry(fei,
6979 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6982 "24001/neos LB 1 buckets via: DROP");
6985 * add back the path with the valid label
6988 vec_add1(l99, fml99);
6990 fib_table_entry_path_add(fib_index,
6993 FIB_ENTRY_FLAG_NONE,
6996 tm->hw[0]->sw_if_index,
6997 ~0, // invalid fib index
7000 FIB_ROUTE_PATH_FLAG_NONE);
7002 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
7003 FIB_TEST(!fib_test_validate_entry(fei,
7004 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7006 &l99_eos_o_10_10_10_1,
7008 "1.1.1.1/32 LB 2 buckets via: "
7009 "label 99 over 10.10.10.1, "
7010 "adj over 10.10.11.2");
7012 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7014 FIB_TEST(!fib_test_validate_entry(fei,
7015 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7017 &l99_eos_o_10_10_10_1,
7018 &disp_o_10_10_11_2),
7019 "24001/eos LB 2 buckets via: "
7020 "label 99 over 10.10.10.1, "
7021 "MPLS disp adj over 10.10.11.2");
7023 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7025 FIB_TEST(!fib_test_validate_entry(fei,
7026 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7028 &l99_neos_o_10_10_10_1),
7029 "24001/neos LB 1 buckets via: "
7030 "label 99 over 10.10.10.1");
7033 * change the local label
7035 fib_table_entry_local_label_add(fib_index,
7039 fib_prefix_t pfx_25005_eos = {
7040 .fp_proto = FIB_PROTOCOL_MPLS,
7044 fib_prefix_t pfx_25005_neos = {
7045 .fp_proto = FIB_PROTOCOL_MPLS,
7047 .fp_eos = MPLS_NON_EOS,
7050 FIB_TEST((FIB_NODE_INDEX_INVALID ==
7051 fib_table_lookup(fib_index, &pfx_24001_eos)),
7052 "24001/eos removed after label change");
7053 FIB_TEST((FIB_NODE_INDEX_INVALID ==
7054 fib_table_lookup(fib_index, &pfx_24001_neos)),
7055 "24001/eos removed after label change");
7057 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7059 FIB_TEST(!fib_test_validate_entry(fei,
7060 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
7062 &l99_eos_o_10_10_10_1,
7063 &disp_o_10_10_11_2),
7064 "25005/eos LB 2 buckets via: "
7065 "label 99 over 10.10.10.1, "
7066 "MPLS disp adj over 10.10.11.2");
7068 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
7070 FIB_TEST(!fib_test_validate_entry(fei,
7071 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7073 &l99_neos_o_10_10_10_1),
7074 "25005/neos LB 1 buckets via: "
7075 "label 99 over 10.10.10.1");
7078 * remove the local label.
7079 * the check that the MPLS entries are gone is done by the fact the
7080 * MPLS table is no longer present.
7082 fib_table_entry_local_label_remove(fib_index,
7086 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
7087 FIB_TEST(!fib_test_validate_entry(fei,
7088 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7090 &l99_eos_o_10_10_10_1,
7092 "24001/eos LB 2 buckets via: "
7093 "label 99 over 10.10.10.1, "
7094 "adj over 10.10.11.2");
7096 FIB_TEST((FIB_NODE_INDEX_INVALID ==
7097 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
7098 "No more MPLS FIB entries => table removed");
7101 * add another via-entry for the recursive
7103 fib_prefix_t pfx_1_1_1_2_s_32 = {
7105 .fp_proto = FIB_PROTOCOL_IP4,
7107 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
7110 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
7111 .type = FT_LB_LABEL_O_ADJ,
7113 .adj = ai_mpls_10_10_10_1,
7118 fib_mpls_label_t *l101 = NULL, fml101 = {
7121 vec_add1(l101, fml101);
7123 fei = fib_table_entry_update_one_path(fib_index,
7126 FIB_ENTRY_FLAG_NONE,
7129 tm->hw[0]->sw_if_index,
7130 ~0, // invalid fib index
7133 FIB_ROUTE_PATH_FLAG_NONE);
7135 FIB_TEST(!fib_test_validate_entry(fei,
7136 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7138 &l101_eos_o_10_10_10_1),
7139 "1.1.1.2/32 LB 1 buckets via: "
7140 "label 101 over 10.10.10.1");
7142 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
7143 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7145 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7147 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7149 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
7152 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
7153 .type = FT_LB_LABEL_O_LB,
7155 .lb = non_eos_1_1_1_2.dpoi_index,
7160 fib_mpls_label_t *l1601 = NULL, fml1601 = {
7163 vec_add1(l1601, fml1601);
7165 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
7167 fei = fib_table_entry_path_add(fib_index,
7170 FIB_ENTRY_FLAG_NONE,
7172 &pfx_1_1_1_2_s_32.fp_addr,
7177 FIB_ROUTE_PATH_FLAG_NONE);
7179 FIB_TEST(!fib_test_validate_entry(fei,
7180 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7182 &l1600_eos_o_1_1_1_1,
7183 &l1601_eos_o_1_1_1_2),
7184 "2.2.2.2/32 LB 2 buckets via: "
7185 "label 1600 via 1.1,1.1, "
7186 "label 16001 via 1.1.1.2");
7189 * update the via-entry so it no longer has an imp-null path.
7190 * the LB for the recursive can use an imp-null
7193 vec_add1(l_imp_null, fml_imp_null);
7195 fei = fib_table_entry_update_one_path(fib_index,
7198 FIB_ENTRY_FLAG_NONE,
7201 tm->hw[1]->sw_if_index,
7202 ~0, // invalid fib index
7205 FIB_ROUTE_PATH_FLAG_NONE);
7207 FIB_TEST(!fib_test_validate_entry(fei,
7208 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7211 "1.1.1.2/32 LB 1 buckets via: "
7214 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7215 FIB_TEST(!fib_test_validate_entry(fei,
7216 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7218 &l1600_eos_o_1_1_1_1,
7219 &l1601_eos_o_1_1_1_2),
7220 "2.2.2.2/32 LB 2 buckets via: "
7221 "label 1600 via 1.1,1.1, "
7222 "label 16001 via 1.1.1.2");
7225 * update the via-entry so it no longer has labelled paths.
7226 * the LB for the recursive should exclue this via form its LB
7228 fei = fib_table_entry_update_one_path(fib_index,
7231 FIB_ENTRY_FLAG_NONE,
7234 tm->hw[1]->sw_if_index,
7235 ~0, // invalid fib index
7238 FIB_ROUTE_PATH_FLAG_NONE);
7240 FIB_TEST(!fib_test_validate_entry(fei,
7241 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7244 "1.1.1.2/32 LB 1 buckets via: "
7247 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7248 FIB_TEST(!fib_test_validate_entry(fei,
7249 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7251 &l1600_eos_o_1_1_1_1),
7252 "2.2.2.2/32 LB 1 buckets via: "
7253 "label 1600 via 1.1,1.1");
7255 dpo_reset(&non_eos_1_1_1_1);
7256 dpo_reset(&non_eos_1_1_1_2);
7259 * Add a recursive with no out-labels. We expect to use the IP of the via
7261 fib_prefix_t pfx_2_2_2_3_s_32 = {
7263 .fp_proto = FIB_PROTOCOL_IP4,
7265 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7268 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
7270 fib_table_entry_update_one_path(fib_index,
7273 FIB_ENTRY_FLAG_NONE,
7275 &pfx_1_1_1_1_s_32.fp_addr,
7280 FIB_ROUTE_PATH_FLAG_NONE);
7282 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7284 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7287 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7290 .lb = ip_1_1_1_1.dpoi_index,
7294 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7295 FIB_TEST(!fib_test_validate_entry(fei,
7296 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7299 "2.2.2.2.3/32 LB 1 buckets via: "
7303 * Add a recursive with an imp-null out-label.
7304 * We expect to use the IP of the via
7306 fib_prefix_t pfx_2_2_2_4_s_32 = {
7308 .fp_proto = FIB_PROTOCOL_IP4,
7310 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7314 fib_table_entry_update_one_path(fib_index,
7317 FIB_ENTRY_FLAG_NONE,
7319 &pfx_1_1_1_1_s_32.fp_addr,
7324 FIB_ROUTE_PATH_FLAG_NONE);
7326 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7327 FIB_TEST(!fib_test_validate_entry(fei,
7328 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7331 "2.2.2.2.4/32 LB 1 buckets via: "
7334 dpo_reset(&ip_1_1_1_1);
7337 * Create an entry with a deep label stack
7339 fib_prefix_t pfx_2_2_5_5_s_32 = {
7341 .fp_proto = FIB_PROTOCOL_IP4,
7343 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7346 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7347 .type = FT_LB_LABEL_STACK_O_ADJ,
7348 .label_stack_o_adj = {
7349 .adj = ai_mpls_10_10_11_1,
7350 .label_stack_size = 8,
7352 200, 201, 202, 203, 204, 205, 206, 207
7357 fib_mpls_label_t *label_stack = NULL;
7358 vec_validate(label_stack, 7);
7359 for (ii = 0; ii < 8; ii++)
7361 label_stack[ii].fml_value = ii + 200;
7364 fei = fib_table_entry_update_one_path(fib_index,
7367 FIB_ENTRY_FLAG_NONE,
7370 tm->hw[1]->sw_if_index,
7371 ~0, // invalid fib index
7374 FIB_ROUTE_PATH_FLAG_NONE);
7376 FIB_TEST(!fib_test_validate_entry(fei,
7377 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7379 &ls_eos_o_10_10_10_1),
7380 "2.2.5.5/32 LB 1 buckets via: "
7382 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7387 fib_table_entry_delete(fib_index,
7391 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7392 FIB_TEST(!fib_test_validate_entry(fei,
7393 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7395 &l1600_eos_o_1_1_1_1),
7396 "2.2.2.2/32 LB 1 buckets via: "
7397 "label 1600 via 1.1,1.1");
7399 fib_table_entry_delete(fib_index,
7403 FIB_TEST(!fib_test_validate_entry(fei,
7404 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7407 "2.2.2.2/32 LB 1 buckets via: DROP");
7409 fib_table_entry_delete(fib_index,
7412 fib_table_entry_delete(fib_index,
7415 fib_table_entry_delete(fib_index,
7419 adj_unlock(ai_mpls_10_10_10_1);
7420 adj_unlock(ai_mpls_10_10_11_2);
7421 adj_unlock(ai_v4_10_10_11_1);
7422 adj_unlock(ai_v4_10_10_11_2);
7423 adj_unlock(ai_mpls_10_10_11_1);
7425 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7428 local0_pfx.fp_len = 32;
7429 fib_table_entry_delete(fib_index,
7431 FIB_SOURCE_INTERFACE);
7432 local0_pfx.fp_len = 24;
7433 fib_table_entry_delete(fib_index,
7435 FIB_SOURCE_INTERFACE);
7436 local1_pfx.fp_len = 32;
7437 fib_table_entry_delete(fib_index,
7439 FIB_SOURCE_INTERFACE);
7440 local1_pfx.fp_len = 24;
7441 fib_table_entry_delete(fib_index,
7443 FIB_SOURCE_INTERFACE);
7446 * +1 for the drop LB in the MPLS tables.
7448 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7449 "Load-balance resources freed %d of %d",
7450 lb_count+1, pool_elts(load_balance_pool));
7455 #define N_TEST_CHILDREN 4
7456 #define PARENT_INDEX 0
7458 typedef struct fib_node_test_t_
7463 fib_node_back_walk_ctx_t *ctxs;
7467 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7469 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7471 #define FOR_EACH_TEST_CHILD(_tc) \
7472 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
7473 ii < N_TEST_CHILDREN+1; \
7474 ii++, (_tc) = &fib_test_nodes[ii])
7477 fib_test_child_get_node (fib_node_index_t index)
7479 return (&fib_test_nodes[index].node);
7482 static int fib_test_walk_spawns_walks;
7484 static fib_node_back_walk_rc_t
7485 fib_test_child_back_walk_notify (fib_node_t *node,
7486 fib_node_back_walk_ctx_t *ctx)
7488 fib_node_test_t *tc = (fib_node_test_t*) node;
7490 vec_add1(tc->ctxs, *ctx);
7492 if (1 == fib_test_walk_spawns_walks)
7493 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7494 if (2 == fib_test_walk_spawns_walks)
7495 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7496 FIB_WALK_PRIORITY_HIGH, ctx);
7498 return (FIB_NODE_BACK_WALK_CONTINUE);
7502 fib_test_child_last_lock_gone (fib_node_t *node)
7504 fib_node_test_t *tc = (fib_node_test_t *)node;
7510 * The FIB walk's graph node virtual function table
7512 static const fib_node_vft_t fib_test_child_vft = {
7513 .fnv_get = fib_test_child_get_node,
7514 .fnv_last_lock = fib_test_child_last_lock_gone,
7515 .fnv_back_walk = fib_test_child_back_walk_notify,
7519 * the function (that should have been static but isn't so I can do this)
7520 * that processes the walk from the async queue,
7522 f64 fib_walk_process_queues(vlib_main_t * vm,
7524 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7527 fib_test_walk (void)
7529 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7530 fib_node_test_t *tc;
7535 vm = vlib_get_main();
7536 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7539 * init a fake node on which we will add children
7541 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7542 FIB_NODE_TYPE_TEST);
7544 FOR_EACH_TEST_CHILD(tc)
7546 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7547 fib_node_lock(&tc->node);
7550 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7552 FIB_NODE_TYPE_TEST, ii);
7556 * enqueue a walk across the parents children.
7558 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7560 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7561 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7562 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7563 "Parent has %d children pre-walk",
7564 fib_node_list_get_size(PARENT()->fn_children));
7567 * give the walk a large amount of time so it gets to the end
7569 fib_walk_process_queues(vm, 1);
7571 FOR_EACH_TEST_CHILD(tc)
7573 FIB_TEST(1 == vec_len(tc->ctxs),
7574 "%d child visitsed %d times",
7575 ii, vec_len(tc->ctxs));
7578 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7579 "Queue is empty post walk");
7580 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7581 "Parent has %d children post walk",
7582 fib_node_list_get_size(PARENT()->fn_children));
7585 * walk again. should be no increase in the number of visits, since
7586 * the walk will have terminated.
7588 fib_walk_process_queues(vm, 1);
7590 FOR_EACH_TEST_CHILD(tc)
7592 FIB_TEST(0 == vec_len(tc->ctxs),
7593 "%d child visitsed %d times",
7594 ii, vec_len(tc->ctxs));
7598 * schedule a low and hig priority walk. expect the high to be performed
7600 * schedule the high prio walk first so that it is further from the head
7601 * of the dependency list. that way it won't merge with the low one.
7603 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7604 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7606 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7607 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7608 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7609 FIB_WALK_PRIORITY_LOW, &low_ctx);
7611 fib_walk_process_queues(vm, 1);
7613 FOR_EACH_TEST_CHILD(tc)
7615 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7616 "%d child visitsed by high prio walk", ii);
7617 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7618 "%d child visitsed by low prio walk", ii);
7621 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7622 "Queue is empty post prio walk");
7623 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7624 "Parent has %d children post prio walk",
7625 fib_node_list_get_size(PARENT()->fn_children));
7628 * schedule 2 walks of the same priority that can be megred.
7629 * expect that each child is thus visited only once.
7631 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7632 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7634 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7635 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7636 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7637 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7639 fib_walk_process_queues(vm, 1);
7641 FOR_EACH_TEST_CHILD(tc)
7643 FIB_TEST(1 == vec_len(tc->ctxs),
7644 "%d child visitsed %d times during merge walk",
7645 ii, vec_len(tc->ctxs));
7648 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7649 "Queue is empty post merge walk");
7650 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7651 "Parent has %d children post merge walk",
7652 fib_node_list_get_size(PARENT()->fn_children));
7655 * schedule 2 walks of the same priority that cannot be megred.
7656 * expect that each child is thus visited twice and in the order
7657 * in which the walks were scheduled.
7659 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7660 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7662 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7663 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7664 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7665 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7667 fib_walk_process_queues(vm, 1);
7669 FOR_EACH_TEST_CHILD(tc)
7671 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7672 "%d child visitsed by high prio walk", ii);
7673 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7674 "%d child visitsed by low prio walk", ii);
7677 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7678 "Queue is empty post no-merge walk");
7679 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7680 "Parent has %d children post no-merge walk",
7681 fib_node_list_get_size(PARENT()->fn_children));
7684 * schedule a walk that makes one one child progress.
7685 * we do this by giving the queue draining process zero
7686 * time quanta. it's a do..while loop, so it does something.
7688 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7690 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7691 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7692 fib_walk_process_queues(vm, 0);
7694 FOR_EACH_TEST_CHILD(tc)
7696 if (ii == N_TEST_CHILDREN)
7698 FIB_TEST(1 == vec_len(tc->ctxs),
7699 "%d child visitsed %d times in zero quanta walk",
7700 ii, vec_len(tc->ctxs));
7704 FIB_TEST(0 == vec_len(tc->ctxs),
7705 "%d child visitsed %d times in 0 quanta walk",
7706 ii, vec_len(tc->ctxs));
7709 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7710 "Queue is not empty post zero quanta walk");
7711 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7712 "Parent has %d children post zero qunta walk",
7713 fib_node_list_get_size(PARENT()->fn_children));
7718 fib_walk_process_queues(vm, 0);
7720 FOR_EACH_TEST_CHILD(tc)
7722 if (ii >= N_TEST_CHILDREN-1)
7724 FIB_TEST(1 == vec_len(tc->ctxs),
7725 "%d child visitsed %d times in 2nd zero quanta walk",
7726 ii, vec_len(tc->ctxs));
7730 FIB_TEST(0 == vec_len(tc->ctxs),
7731 "%d child visitsed %d times in 2nd 0 quanta walk",
7732 ii, vec_len(tc->ctxs));
7735 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7736 "Queue is not empty post zero quanta walk");
7737 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7738 "Parent has %d children post zero qunta walk",
7739 fib_node_list_get_size(PARENT()->fn_children));
7742 * schedule another walk that will catch-up and merge.
7744 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7745 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7746 fib_walk_process_queues(vm, 1);
7748 FOR_EACH_TEST_CHILD(tc)
7750 if (ii >= N_TEST_CHILDREN-1)
7752 FIB_TEST(2 == vec_len(tc->ctxs),
7753 "%d child visitsed %d times in 2nd zero quanta merge walk",
7754 ii, vec_len(tc->ctxs));
7759 FIB_TEST(1 == vec_len(tc->ctxs),
7760 "%d child visitsed %d times in 2nd 0 quanta merge walk",
7761 ii, vec_len(tc->ctxs));
7765 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7766 "Queue is not empty post 2nd zero quanta merge walk");
7767 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7768 "Parent has %d children post 2nd zero qunta merge walk",
7769 fib_node_list_get_size(PARENT()->fn_children));
7772 * park a async walk in the middle of the list, then have an sync walk catch
7773 * it. same expectations as async catches async.
7775 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7777 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7778 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7780 fib_walk_process_queues(vm, 0);
7781 fib_walk_process_queues(vm, 0);
7783 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7785 FOR_EACH_TEST_CHILD(tc)
7787 if (ii >= N_TEST_CHILDREN-1)
7789 FIB_TEST(2 == vec_len(tc->ctxs),
7790 "%d child visitsed %d times in sync catches async walk",
7791 ii, vec_len(tc->ctxs));
7796 FIB_TEST(1 == vec_len(tc->ctxs),
7797 "%d child visitsed %d times in sync catches async walk",
7798 ii, vec_len(tc->ctxs));
7802 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7803 "Queue is not empty post 2nd zero quanta merge walk");
7804 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7805 "Parent has %d children post 2nd zero qunta merge walk",
7806 fib_node_list_get_size(PARENT()->fn_children));
7809 * make the parent a child of one of its children, thus inducing a routing loop.
7811 fib_test_nodes[PARENT_INDEX].sibling =
7812 fib_node_child_add(FIB_NODE_TYPE_TEST,
7813 1, // the first child
7818 * execute a sync walk from the parent. each child visited spawns more sync
7819 * walks. we expect the walk to terminate.
7821 fib_test_walk_spawns_walks = 1;
7823 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7825 FOR_EACH_TEST_CHILD(tc)
7828 * child 1 - which is last in the list - has the loop.
7829 * the other children a re thus visitsed first. the we meet
7830 * child 1. we go round the loop again, visting the other children.
7831 * then we meet the walk in the dep list and bail. child 1 is not visitsed
7836 FIB_TEST(1 == vec_len(tc->ctxs),
7837 "child %d visitsed %d times during looped sync walk",
7838 ii, vec_len(tc->ctxs));
7842 FIB_TEST(2 == vec_len(tc->ctxs),
7843 "child %d visitsed %d times during looped sync walk",
7844 ii, vec_len(tc->ctxs));
7848 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7849 "Parent has %d children post sync loop walk",
7850 fib_node_list_get_size(PARENT()->fn_children));
7853 * the walk doesn't reach the max depth because the infra knows that sync
7854 * meets sync implies a loop and bails early.
7856 FIB_TEST(high_ctx.fnbw_depth == 9,
7857 "Walk context depth %d post sync loop walk",
7858 high_ctx.fnbw_depth);
7861 * execute an async walk of the graph loop, with each child spawns sync walks
7863 high_ctx.fnbw_depth = 0;
7864 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7865 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7867 fib_walk_process_queues(vm, 1);
7869 FOR_EACH_TEST_CHILD(tc)
7872 * we don't really care how many times the children are visited, as long as
7873 * it is more than once.
7875 FIB_TEST(1 <= vec_len(tc->ctxs),
7876 "child %d visitsed %d times during looped aync spawns sync walk",
7877 ii, vec_len(tc->ctxs));
7882 * execute an async walk of the graph loop, with each child spawns async walks
7884 fib_test_walk_spawns_walks = 2;
7885 high_ctx.fnbw_depth = 0;
7886 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7887 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7889 fib_walk_process_queues(vm, 1);
7891 FOR_EACH_TEST_CHILD(tc)
7894 * we don't really care how many times the children are visited, as long as
7895 * it is more than once.
7897 FIB_TEST(1 <= vec_len(tc->ctxs),
7898 "child %d visitsed %d times during looped async spawns async walk",
7899 ii, vec_len(tc->ctxs));
7904 fib_node_child_remove(FIB_NODE_TYPE_TEST,
7905 1, // the first child
7906 fib_test_nodes[PARENT_INDEX].sibling);
7911 FOR_EACH_TEST_CHILD(tc)
7913 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7915 fib_node_deinit(&tc->node);
7916 fib_node_unlock(&tc->node);
7918 fib_node_deinit(PARENT());
7921 * The parent will be destroyed when the last lock on it goes.
7922 * this test ensures all the walk objects are unlocking it.
7924 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7925 "Parent was destroyed");
7931 * declaration of the otherwise static callback functions
7933 void fib_bfd_notify (bfd_listen_event_e event,
7934 const bfd_session_t *session);
7935 void adj_bfd_notify (bfd_listen_event_e event,
7936 const bfd_session_t *session);
7939 * Test BFD session interaction with FIB
7944 fib_node_index_t fei;
7949 /* via 10.10.10.1 */
7950 ip46_address_t nh_10_10_10_1 = {
7951 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7953 /* via 10.10.10.2 */
7954 ip46_address_t nh_10_10_10_2 = {
7955 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7957 /* via 10.10.10.10 */
7958 ip46_address_t nh_10_10_10_10 = {
7959 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7961 n_feis = fib_entry_pool_size();
7966 * add interface routes. we'll assume this works. it's tested elsewhere
7968 fib_prefix_t pfx_10_10_10_10_s_24 = {
7970 .fp_proto = FIB_PROTOCOL_IP4,
7971 .fp_addr = nh_10_10_10_10,
7974 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7975 FIB_SOURCE_INTERFACE,
7976 (FIB_ENTRY_FLAG_CONNECTED |
7977 FIB_ENTRY_FLAG_ATTACHED),
7980 tm->hw[0]->sw_if_index,
7981 ~0, // invalid fib index
7984 FIB_ROUTE_PATH_FLAG_NONE);
7986 fib_prefix_t pfx_10_10_10_10_s_32 = {
7988 .fp_proto = FIB_PROTOCOL_IP4,
7989 .fp_addr = nh_10_10_10_10,
7991 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7992 FIB_SOURCE_INTERFACE,
7993 (FIB_ENTRY_FLAG_CONNECTED |
7994 FIB_ENTRY_FLAG_LOCAL),
7997 tm->hw[0]->sw_if_index,
7998 ~0, // invalid fib index
8001 FIB_ROUTE_PATH_FLAG_NONE);
8004 * A BFD session via a neighbour we do not yet know
8006 bfd_session_t bfd_10_10_10_1 = {
8010 .peer_addr = nh_10_10_10_1,
8013 .hop_type = BFD_HOP_TYPE_MULTI,
8014 .local_state = BFD_STATE_init,
8017 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8020 * A new entry will be created that forwards via the adj
8022 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8025 tm->hw[0]->sw_if_index);
8026 fib_prefix_t pfx_10_10_10_1_s_32 = {
8027 .fp_addr = nh_10_10_10_1,
8029 .fp_proto = FIB_PROTOCOL_IP4,
8031 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
8034 .adj = ai_10_10_10_1,
8038 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8039 FIB_TEST(!fib_test_validate_entry(fei,
8040 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8043 "BFD sourced %U via %U",
8044 format_fib_prefix, &pfx_10_10_10_1_s_32,
8045 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
8048 * Delete the BFD session. Expect the fib_entry to be removed
8050 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8052 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8053 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
8054 "BFD sourced %U removed",
8055 format_fib_prefix, &pfx_10_10_10_1_s_32);
8058 * Add the BFD source back
8060 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8063 * source the entry via the ADJ fib
8065 fei = fib_table_entry_path_add(0,
8066 &pfx_10_10_10_1_s_32,
8068 FIB_ENTRY_FLAG_ATTACHED,
8071 tm->hw[0]->sw_if_index,
8072 ~0, // invalid fib index
8075 FIB_ROUTE_PATH_FLAG_NONE);
8078 * Delete the BFD session. Expect the fib_entry to remain
8080 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8082 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
8083 FIB_TEST(!fib_test_validate_entry(fei,
8084 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8087 "BFD sourced %U remains via %U",
8088 format_fib_prefix, &pfx_10_10_10_1_s_32,
8089 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
8092 * Add the BFD source back
8094 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8097 * Create another ADJ FIB
8099 fib_prefix_t pfx_10_10_10_2_s_32 = {
8100 .fp_addr = nh_10_10_10_2,
8102 .fp_proto = FIB_PROTOCOL_IP4,
8104 fib_table_entry_path_add(0,
8105 &pfx_10_10_10_2_s_32,
8107 FIB_ENTRY_FLAG_ATTACHED,
8110 tm->hw[0]->sw_if_index,
8111 ~0, // invalid fib index
8114 FIB_ROUTE_PATH_FLAG_NONE);
8116 * A BFD session for the new ADJ FIB
8118 bfd_session_t bfd_10_10_10_2 = {
8122 .peer_addr = nh_10_10_10_2,
8125 .hop_type = BFD_HOP_TYPE_MULTI,
8126 .local_state = BFD_STATE_init,
8129 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
8132 * remove the adj-fib source whilst the session is present
8135 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8136 fib_table_entry_path_add(0,
8137 &pfx_10_10_10_2_s_32,
8139 FIB_ENTRY_FLAG_ATTACHED,
8142 tm->hw[0]->sw_if_index,
8143 ~0, // invalid fib index
8146 FIB_ROUTE_PATH_FLAG_NONE);
8149 * Before adding a recursive via the BFD tracked ADJ-FIBs,
8150 * bring one of the sessions UP, leave the other down
8152 bfd_10_10_10_1.local_state = BFD_STATE_up;
8153 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8154 bfd_10_10_10_2.local_state = BFD_STATE_down;
8155 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8158 * A recursive prefix via both of the ADJ FIBs
8160 fib_prefix_t pfx_200_0_0_0_s_24 = {
8161 .fp_proto = FIB_PROTOCOL_IP4,
8164 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
8167 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
8170 fib_entry_contribute_ip_forwarding(
8171 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
8173 fib_entry_contribute_ip_forwarding(
8174 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
8176 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
8179 .lb = dpo_10_10_10_1->dpoi_index,
8182 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
8185 .lb = dpo_10_10_10_2->dpoi_index,
8190 * A prefix via the adj-fib that is BFD down => DROP
8192 fei = fib_table_entry_path_add(0,
8193 &pfx_200_0_0_0_s_24,
8195 FIB_ENTRY_FLAG_NONE,
8199 0, // default fib index
8202 FIB_ROUTE_PATH_FLAG_NONE);
8203 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8204 "%U resolves via drop",
8205 format_fib_prefix, &pfx_200_0_0_0_s_24);
8208 * add a path via the UP BFD adj-fib.
8209 * we expect that the DOWN BFD ADJ FIB is not used.
8211 fei = fib_table_entry_path_add(0,
8212 &pfx_200_0_0_0_s_24,
8214 FIB_ENTRY_FLAG_NONE,
8218 0, // default fib index
8221 FIB_ROUTE_PATH_FLAG_NONE);
8223 FIB_TEST(!fib_test_validate_entry(fei,
8224 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8227 "Recursive %U only UP BFD adj-fibs",
8228 format_fib_prefix, &pfx_200_0_0_0_s_24);
8231 * Send a BFD state change to UP - both sessions are now up
8232 * the recursive prefix should LB over both
8234 bfd_10_10_10_2.local_state = BFD_STATE_up;
8235 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8238 FIB_TEST(!fib_test_validate_entry(fei,
8239 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8243 "Recursive %U via both UP BFD adj-fibs",
8244 format_fib_prefix, &pfx_200_0_0_0_s_24);
8247 * Send a BFD state change to DOWN
8248 * the recursive prefix should exclude the down
8250 bfd_10_10_10_2.local_state = BFD_STATE_down;
8251 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
8254 FIB_TEST(!fib_test_validate_entry(fei,
8255 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8258 "Recursive %U via only UP",
8259 format_fib_prefix, &pfx_200_0_0_0_s_24);
8262 * Delete the BFD session while it is in the DOWN state.
8263 * FIB should consider the entry's state as back up
8265 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
8267 FIB_TEST(!fib_test_validate_entry(fei,
8268 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8272 "Recursive %U via both UP BFD adj-fibs post down session delete",
8273 format_fib_prefix, &pfx_200_0_0_0_s_24);
8276 * Delete the BFD other session while it is in the UP state.
8278 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8280 FIB_TEST(!fib_test_validate_entry(fei,
8281 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8285 "Recursive %U via both UP BFD adj-fibs post up session delete",
8286 format_fib_prefix, &pfx_200_0_0_0_s_24);
8291 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8292 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8293 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8295 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8296 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8298 adj_unlock(ai_10_10_10_1);
8300 * test no-one left behind
8302 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8303 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8306 * Single-hop BFD tests
8308 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8309 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8311 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8313 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8316 tm->hw[0]->sw_if_index);
8318 * whilst the BFD session is not signalled, the adj is up
8320 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on uninit session");
8323 * bring the BFD session up
8325 bfd_10_10_10_1.local_state = BFD_STATE_up;
8326 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8327 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8330 * bring the BFD session down
8332 bfd_10_10_10_1.local_state = BFD_STATE_down;
8333 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8334 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8337 * add an attached next hop FIB entry via the down adj
8339 fib_prefix_t pfx_5_5_5_5_s_32 = {
8342 .as_u32 = clib_host_to_net_u32(0x05050505),
8346 .fp_proto = FIB_PROTOCOL_IP4,
8349 fei = fib_table_entry_path_add(0,
8352 FIB_ENTRY_FLAG_NONE,
8355 tm->hw[0]->sw_if_index,
8356 ~0, // invalid fib index
8359 FIB_ROUTE_PATH_FLAG_NONE);
8360 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8361 "%U resolves via drop",
8362 format_fib_prefix, &pfx_5_5_5_5_s_32);
8365 * Add a path via an ADJ that is up
8367 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8370 tm->hw[0]->sw_if_index);
8372 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8375 .adj = ai_10_10_10_2,
8378 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8380 fei = fib_table_entry_path_add(0,
8383 FIB_ENTRY_FLAG_NONE,
8386 tm->hw[0]->sw_if_index,
8387 ~0, // invalid fib index
8390 FIB_ROUTE_PATH_FLAG_NONE);
8392 FIB_TEST(!fib_test_validate_entry(fei,
8393 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8396 "BFD sourced %U via %U",
8397 format_fib_prefix, &pfx_5_5_5_5_s_32,
8398 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8401 * Bring up the down session - should now LB
8403 bfd_10_10_10_1.local_state = BFD_STATE_up;
8404 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8405 FIB_TEST(!fib_test_validate_entry(fei,
8406 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8410 "BFD sourced %U via noth adjs",
8411 format_fib_prefix, &pfx_5_5_5_5_s_32);
8414 * remove the BFD session state from the adj
8416 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8421 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8422 adj_unlock(ai_10_10_10_1);
8423 adj_unlock(ai_10_10_10_2);
8426 * test no-one left behind
8428 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8429 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8437 const mpls_label_t deag_label = 50;
8438 adj_index_t ai_mpls_10_10_10_1;
8439 dpo_id_t dpo = DPO_INVALID;
8440 const u32 lfib_index = 0;
8441 const u32 fib_index = 0;
8442 const dpo_id_t *dpo1;
8443 fib_node_index_t lfe;
8450 lb_count = pool_elts(load_balance_pool);
8452 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8456 * MPLS enable an interface so we get the MPLS table created
8458 mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8459 mpls_sw_interface_enable_disable(&mpls_main,
8460 tm->hw[0]->sw_if_index,
8463 ip46_address_t nh_10_10_10_1 = {
8464 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8466 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8469 tm->hw[0]->sw_if_index);
8472 * Test the specials stack properly.
8474 fib_prefix_t exp_null_v6_pfx = {
8475 .fp_proto = FIB_PROTOCOL_MPLS,
8477 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8478 .fp_payload_proto = DPO_PROTO_IP6,
8480 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8481 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8483 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8484 format_mpls_eos_bit, MPLS_EOS);
8485 fib_entry_contribute_forwarding(lfe,
8486 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8488 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8489 lkd = lookup_dpo_get(dpo1->dpoi_index);
8491 FIB_TEST((fib_index == lkd->lkd_fib_index),
8492 "%U/%U is deag in %d %U",
8493 format_mpls_unicast_label, deag_label,
8494 format_mpls_eos_bit, MPLS_EOS,
8496 format_dpo_id, &dpo, 0);
8497 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8498 "%U/%U is dst deag",
8499 format_mpls_unicast_label, deag_label,
8500 format_mpls_eos_bit, MPLS_EOS);
8501 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8502 "%U/%U is lookup in interface's table",
8503 format_mpls_unicast_label, deag_label,
8504 format_mpls_eos_bit, MPLS_EOS);
8505 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8506 "%U/%U is %U dst deag",
8507 format_mpls_unicast_label, deag_label,
8508 format_mpls_eos_bit, MPLS_EOS,
8509 format_dpo_proto, lkd->lkd_proto);
8512 * A route deag route for EOS
8514 fib_prefix_t pfx = {
8515 .fp_proto = FIB_PROTOCOL_MPLS,
8517 .fp_label = deag_label,
8518 .fp_payload_proto = DPO_PROTO_IP4,
8520 mpls_disp_dpo_t *mdd;
8521 lfe = fib_table_entry_path_add(lfib_index,
8524 FIB_ENTRY_FLAG_NONE,
8531 FIB_ROUTE_PATH_FLAG_NONE);
8533 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8535 format_mpls_unicast_label, deag_label,
8536 format_mpls_eos_bit, MPLS_EOS);
8538 fib_entry_contribute_forwarding(lfe,
8539 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8541 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8542 mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
8544 FIB_TEST((FIB_MPLS_LSP_MODE_PIPE == mdd->mdd_mode),
8545 "%U/%U disp is pipe mode",
8546 format_mpls_unicast_label, deag_label,
8547 format_mpls_eos_bit, MPLS_EOS);
8549 lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
8551 FIB_TEST((fib_index == lkd->lkd_fib_index),
8552 "%U/%U is deag in %d %U",
8553 format_mpls_unicast_label, deag_label,
8554 format_mpls_eos_bit, MPLS_EOS,
8556 format_dpo_id, &dpo, 0);
8557 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8558 "%U/%U is dst deag",
8559 format_mpls_unicast_label, deag_label,
8560 format_mpls_eos_bit, MPLS_EOS);
8561 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8562 "%U/%U is %U dst deag",
8563 format_mpls_unicast_label, deag_label,
8564 format_mpls_eos_bit, MPLS_EOS,
8565 format_dpo_proto, lkd->lkd_proto);
8567 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8569 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8571 "%U/%U not present",
8572 format_mpls_unicast_label, deag_label,
8573 format_mpls_eos_bit, MPLS_EOS);
8577 * A route deag route for EOS with LSP mode uniform
8579 fib_mpls_label_t *l_pops = NULL, l_pop = {
8580 .fml_value = MPLS_LABEL_POP,
8581 .fml_mode = FIB_MPLS_LSP_MODE_UNIFORM,
8583 vec_add1(l_pops, l_pop);
8584 lfe = fib_table_entry_path_add(lfib_index,
8587 FIB_ENTRY_FLAG_NONE,
8594 FIB_ROUTE_PATH_FLAG_NONE);
8596 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8598 format_mpls_unicast_label, deag_label,
8599 format_mpls_eos_bit, MPLS_EOS);
8601 fib_entry_contribute_forwarding(lfe,
8602 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8604 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8605 mdd = mpls_disp_dpo_get(dpo1->dpoi_index);
8607 FIB_TEST((FIB_MPLS_LSP_MODE_UNIFORM == mdd->mdd_mode),
8608 "%U/%U disp is uniform mode",
8609 format_mpls_unicast_label, deag_label,
8610 format_mpls_eos_bit, MPLS_EOS);
8612 lkd = lookup_dpo_get(mdd->mdd_dpo.dpoi_index);
8614 FIB_TEST((fib_index == lkd->lkd_fib_index),
8615 "%U/%U is deag in %d %U",
8616 format_mpls_unicast_label, deag_label,
8617 format_mpls_eos_bit, MPLS_EOS,
8619 format_dpo_id, &dpo, 0);
8620 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8621 "%U/%U is dst deag",
8622 format_mpls_unicast_label, deag_label,
8623 format_mpls_eos_bit, MPLS_EOS);
8624 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8625 "%U/%U is %U dst deag",
8626 format_mpls_unicast_label, deag_label,
8627 format_mpls_eos_bit, MPLS_EOS,
8628 format_dpo_proto, lkd->lkd_proto);
8630 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8632 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8634 "%U/%U not present",
8635 format_mpls_unicast_label, deag_label,
8636 format_mpls_eos_bit, MPLS_EOS);
8640 * A route deag route for non-EOS
8642 pfx.fp_eos = MPLS_NON_EOS;
8643 lfe = fib_table_entry_path_add(lfib_index,
8646 FIB_ENTRY_FLAG_NONE,
8653 FIB_ROUTE_PATH_FLAG_NONE);
8655 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8657 format_mpls_unicast_label, deag_label,
8658 format_mpls_eos_bit, MPLS_NON_EOS);
8660 fib_entry_contribute_forwarding(lfe,
8661 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8663 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8664 lkd = lookup_dpo_get(dpo1->dpoi_index);
8666 FIB_TEST((fib_index == lkd->lkd_fib_index),
8667 "%U/%U is deag in %d %U",
8668 format_mpls_unicast_label, deag_label,
8669 format_mpls_eos_bit, MPLS_NON_EOS,
8671 format_dpo_id, &dpo, 0);
8672 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8673 "%U/%U is dst deag",
8674 format_mpls_unicast_label, deag_label,
8675 format_mpls_eos_bit, MPLS_NON_EOS);
8677 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8678 "%U/%U is %U dst deag",
8679 format_mpls_unicast_label, deag_label,
8680 format_mpls_eos_bit, MPLS_NON_EOS,
8681 format_dpo_proto, lkd->lkd_proto);
8683 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8685 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8687 "%U/%U not present",
8688 format_mpls_unicast_label, deag_label,
8689 format_mpls_eos_bit, MPLS_EOS);
8696 fib_prefix_t pfx_1200 = {
8698 .fp_proto = FIB_PROTOCOL_MPLS,
8700 .fp_eos = MPLS_NON_EOS,
8702 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8703 .type = FT_LB_LABEL_STACK_O_ADJ,
8704 .label_stack_o_adj = {
8705 .adj = ai_mpls_10_10_10_1,
8706 .label_stack_size = 4,
8710 .eos = MPLS_NON_EOS,
8713 dpo_id_t neos_1200 = DPO_INVALID;
8714 dpo_id_t ip_1200 = DPO_INVALID;
8715 fib_mpls_label_t *l200 = NULL;
8717 for (ii = 0; ii < 4; ii++)
8719 fib_mpls_label_t fml = {
8720 .fml_value = 200 + (ii * 100),
8722 vec_add1(l200, fml);
8725 lfe = fib_table_entry_update_one_path(fib_index,
8728 FIB_ENTRY_FLAG_NONE,
8731 tm->hw[0]->sw_if_index,
8732 ~0, // invalid fib index
8735 FIB_ROUTE_PATH_FLAG_NONE);
8737 FIB_TEST(!fib_test_validate_entry(lfe,
8738 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8740 &neos_o_10_10_10_1),
8741 "1200/0 LB 1 buckets via: "
8745 * A recursive route via the MPLS x-connect
8747 fib_prefix_t pfx_2_2_2_3_s_32 = {
8749 .fp_proto = FIB_PROTOCOL_IP4,
8751 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8754 fib_route_path_t *rpaths = NULL, rpath = {
8755 .frp_proto = DPO_PROTO_MPLS,
8756 .frp_local_label = 1200,
8757 .frp_eos = MPLS_NON_EOS,
8758 .frp_sw_if_index = ~0, // recurive
8759 .frp_fib_index = 0, // Default MPLS fib
8761 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8762 .frp_label_stack = NULL,
8764 vec_add1(rpaths, rpath);
8766 fib_table_entry_path_add2(fib_index,
8769 FIB_ENTRY_FLAG_NONE,
8773 * A labelled recursive route via the MPLS x-connect
8775 fib_prefix_t pfx_2_2_2_4_s_32 = {
8777 .fp_proto = FIB_PROTOCOL_IP4,
8779 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8782 fib_mpls_label_t *l999 = NULL, fml_999 = {
8785 vec_add1(l999, fml_999);
8786 rpaths[0].frp_label_stack = l999,
8788 fib_table_entry_path_add2(fib_index,
8791 FIB_ENTRY_FLAG_NONE,
8794 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8795 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8797 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8798 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8801 fib_test_lb_bucket_t ip_o_1200 = {
8804 .lb = ip_1200.dpoi_index,
8807 fib_test_lb_bucket_t mpls_o_1200 = {
8808 .type = FT_LB_LABEL_O_LB,
8810 .lb = neos_1200.dpoi_index,
8816 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8817 FIB_TEST(!fib_test_validate_entry(lfe,
8818 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8821 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8822 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8823 FIB_TEST(!fib_test_validate_entry(lfe,
8824 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8827 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8829 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8830 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8831 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8833 dpo_reset(&neos_1200);
8834 dpo_reset(&ip_1200);
8837 * A recursive via a label that does not exist
8839 fib_test_lb_bucket_t bucket_drop = {
8842 .adj = DPO_PROTO_IP4,
8845 fib_test_lb_bucket_t mpls_bucket_drop = {
8848 .adj = DPO_PROTO_MPLS,
8852 rpaths[0].frp_label_stack = NULL;
8853 lfe = fib_table_entry_path_add2(fib_index,
8856 FIB_ENTRY_FLAG_NONE,
8859 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8860 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8862 ip_o_1200.lb.lb = ip_1200.dpoi_index;
8864 FIB_TEST(!fib_test_validate_entry(lfe,
8865 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8868 "2.2.2.2.4/32 LB 1 buckets via: drop");
8869 lfe = fib_table_lookup(fib_index, &pfx_1200);
8870 FIB_TEST(!fib_test_validate_entry(lfe,
8871 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8874 "1200/neos LB 1 buckets via: ip4-DROP");
8875 FIB_TEST(!fib_test_validate_entry(lfe,
8876 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8879 "1200/neos LB 1 buckets via: mpls-DROP");
8881 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8883 dpo_reset(&ip_1200);
8886 * An rx-interface route.
8887 * like the tail of an mcast LSP
8889 dpo_id_t idpo = DPO_INVALID;
8891 interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8892 tm->hw[0]->sw_if_index,
8895 fib_prefix_t pfx_2500 = {
8897 .fp_proto = FIB_PROTOCOL_MPLS,
8900 .fp_payload_proto = DPO_PROTO_IP4,
8902 fib_test_lb_bucket_t rx_intf_0 = {
8905 .adj = idpo.dpoi_index,
8909 lfe = fib_table_entry_update_one_path(fib_index,
8912 FIB_ENTRY_FLAG_NONE,
8915 tm->hw[0]->sw_if_index,
8916 ~0, // invalid fib index
8919 FIB_ROUTE_PATH_INTF_RX);
8920 FIB_TEST(!fib_test_validate_entry(lfe,
8921 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8924 "2500 rx-interface 0");
8925 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8928 * An MPLS mulicast entry
8930 fib_prefix_t pfx_3500 = {
8932 .fp_proto = FIB_PROTOCOL_MPLS,
8935 .fp_payload_proto = DPO_PROTO_IP4,
8937 fib_test_rep_bucket_t mc_0 = {
8938 .type = FT_REP_LABEL_O_ADJ,
8940 .adj = ai_mpls_10_10_10_1,
8945 fib_test_rep_bucket_t mc_intf_0 = {
8946 .type = FT_REP_INTF,
8948 .adj = idpo.dpoi_index,
8951 fib_mpls_label_t *l3300 = NULL, fml_3300 = {
8954 vec_add1(l3300, fml_3300);
8956 lfe = fib_table_entry_update_one_path(lfib_index,
8959 FIB_ENTRY_FLAG_MULTICAST,
8962 tm->hw[0]->sw_if_index,
8963 ~0, // invalid fib index
8966 FIB_ROUTE_PATH_FLAG_NONE);
8967 FIB_TEST(!fib_test_validate_entry(lfe,
8968 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8971 "3500 via replicate over 10.10.10.1");
8974 * MPLS Bud-node. Add a replication via an interface-receieve path
8976 lfe = fib_table_entry_path_add(lfib_index,
8979 FIB_ENTRY_FLAG_MULTICAST,
8982 tm->hw[0]->sw_if_index,
8983 ~0, // invalid fib index
8986 FIB_ROUTE_PATH_INTF_RX);
8987 FIB_TEST(!fib_test_validate_entry(lfe,
8988 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8992 "3500 via replicate over 10.10.10.1 and interface-rx");
8995 * Add a replication via an interface-free for-us path
8997 fib_test_rep_bucket_t mc_disp = {
8998 .type = FT_REP_DISP_MFIB_LOOKUP,
9000 .adj = idpo.dpoi_index,
9003 lfe = fib_table_entry_path_add(lfib_index,
9006 FIB_ENTRY_FLAG_MULTICAST,
9013 FIB_ROUTE_PATH_RPF_ID);
9014 FIB_TEST(!fib_test_validate_entry(lfe,
9015 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
9020 "3500 via replicate over 10.10.10.1 and interface-rx");
9024 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
9030 mpls_sw_interface_enable_disable(&mpls_main,
9031 tm->hw[0]->sw_if_index,
9033 mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
9035 FIB_TEST(0 == pool_elts(mpls_disp_dpo_pool),
9036 "mpls_disp_dpo resources freed %d of %d",
9037 0, pool_elts(mpls_disp_dpo_pool));
9038 FIB_TEST(lb_count == pool_elts(load_balance_pool),
9039 "Load-balance resources freed %d of %d",
9040 lb_count, pool_elts(load_balance_pool));
9041 FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
9042 "interface_rx_dpo resources freed %d of %d",
9043 0, pool_elts(interface_rx_dpo_pool));
9049 fib_test_inherit (void)
9051 fib_node_index_t fei;
9056 n_feis = fib_entry_pool_size();
9059 const ip46_address_t nh_10_10_10_1 = {
9060 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
9062 const ip46_address_t nh_10_10_10_2 = {
9063 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
9065 const ip46_address_t nh_10_10_10_3 = {
9066 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
9068 const ip46_address_t nh_10_10_10_16 = {
9069 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a10),
9071 const ip46_address_t nh_10_10_10_20 = {
9072 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a14),
9074 const ip46_address_t nh_10_10_10_21 = {
9075 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a15),
9077 const ip46_address_t nh_10_10_10_22 = {
9078 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a16),
9080 const ip46_address_t nh_10_10_10_255 = {
9081 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0aff),
9083 const ip46_address_t nh_10_10_10_0 = {
9084 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a00),
9086 const ip46_address_t nh_10_10_0_0 = {
9087 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0000),
9089 const ip46_address_t nh_11_11_11_11 = {
9090 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
9092 const ip46_address_t nh_11_11_11_0 = {
9093 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b00),
9097 * prefixes at the base of a sub-tree
9099 const fib_prefix_t pfx_10_10_10_21_s_32 = {
9101 .fp_proto = FIB_PROTOCOL_IP4,
9102 .fp_addr = nh_10_10_10_21,
9104 const fib_prefix_t pfx_10_10_10_22_s_32 = {
9106 .fp_proto = FIB_PROTOCOL_IP4,
9107 .fp_addr = nh_10_10_10_22,
9109 const fib_prefix_t pfx_10_10_10_255_s_32 = {
9111 .fp_proto = FIB_PROTOCOL_IP4,
9112 .fp_addr = nh_10_10_10_255,
9114 const u32 N_PLS = fib_path_list_pool_size();
9116 fib_table_entry_special_add(0,
9117 &pfx_10_10_10_21_s_32,
9119 FIB_ENTRY_FLAG_DROP);
9120 fib_table_entry_special_add(0,
9121 &pfx_10_10_10_22_s_32,
9123 FIB_ENTRY_FLAG_DROP);
9124 fib_table_entry_special_add(0,
9125 &pfx_10_10_10_255_s_32,
9127 FIB_ENTRY_FLAG_DROP);
9130 * source an entry that pushes its state down the sub-tree
9132 const fib_prefix_t pfx_10_10_10_16_s_28 = {
9134 .fp_proto = FIB_PROTOCOL_IP4,
9135 .fp_addr = nh_10_10_10_16,
9137 fib_table_entry_update_one_path(0,
9138 &pfx_10_10_10_16_s_28,
9140 FIB_ENTRY_FLAG_COVERED_INHERIT,
9143 tm->hw[0]->sw_if_index,
9147 FIB_ROUTE_PATH_FLAG_NONE);
9150 * this covering entry and all those below it should have
9151 * the same forwarding information.
9153 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9156 tm->hw[0]->sw_if_index);
9157 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
9160 .adj = ai_10_10_10_1,
9164 fei = fib_table_lookup(0, &pfx_10_10_10_16_s_28);
9165 FIB_TEST(!fib_test_validate_entry(fei,
9166 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9169 "%U via 10.10.10.1",
9170 format_fib_prefix, &pfx_10_10_10_16_s_28);
9171 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9172 FIB_TEST(!fib_test_validate_entry(fei,
9173 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9176 "%U via 10.10.10.1",
9177 format_fib_prefix, &pfx_10_10_10_21_s_32);
9178 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9179 FIB_TEST(!fib_test_validate_entry(fei,
9180 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9183 "%U via 10.10.10.1",
9184 format_fib_prefix, &pfx_10_10_10_22_s_32);
9185 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9186 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9187 "%U resolves via drop",
9188 format_fib_prefix, &pfx_10_10_10_255_s_32);
9191 * remove the inherting cover - covereds go back to drop
9193 fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
9195 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9196 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9197 "%U resolves via drop",
9198 format_fib_prefix, &pfx_10_10_10_21_s_32);
9201 * source an entry that pushes its state down the sub-tree
9203 const fib_prefix_t pfx_10_10_10_0_s_24 = {
9205 .fp_proto = FIB_PROTOCOL_IP4,
9206 .fp_addr = nh_10_10_10_0,
9208 fib_table_entry_update_one_path(0,
9209 &pfx_10_10_10_0_s_24,
9211 FIB_ENTRY_FLAG_COVERED_INHERIT,
9214 tm->hw[0]->sw_if_index,
9218 FIB_ROUTE_PATH_FLAG_NONE);
9221 * whole sub-tree now covered
9223 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9224 FIB_TEST(!fib_test_validate_entry(fei,
9225 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9228 "%U via 10.10.10.1",
9229 format_fib_prefix, &pfx_10_10_10_0_s_24);
9230 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9231 FIB_TEST(!fib_test_validate_entry(fei,
9232 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9235 "%U via 10.10.10.1",
9236 format_fib_prefix, &pfx_10_10_10_21_s_32);
9237 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9238 FIB_TEST(!fib_test_validate_entry(fei,
9239 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9242 "%U via 10.10.10.1",
9243 format_fib_prefix, &pfx_10_10_10_22_s_32);
9244 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9245 FIB_TEST(!fib_test_validate_entry(fei,
9246 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9249 "%U via 10.10.10.1",
9250 format_fib_prefix, &pfx_10_10_10_255_s_32);
9253 * insert a more specific into the sub-tree - expect inheritance
9254 * this one is directly covered by the root
9256 fib_table_entry_special_add(0,
9257 &pfx_10_10_10_16_s_28,
9259 FIB_ENTRY_FLAG_DROP);
9260 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9261 FIB_TEST(!fib_test_validate_entry(fei,
9262 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9265 "%U via 10.10.10.1",
9266 format_fib_prefix, &pfx_10_10_10_16_s_28);
9269 * insert a more specific into the sub-tree - expect inheritance
9270 * this one is indirectly covered by the root
9272 const fib_prefix_t pfx_10_10_10_20_s_30 = {
9274 .fp_proto = FIB_PROTOCOL_IP4,
9275 .fp_addr = nh_10_10_10_20,
9277 fib_table_entry_special_add(0,
9278 &pfx_10_10_10_20_s_30,
9280 FIB_ENTRY_FLAG_DROP);
9281 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9282 FIB_TEST(!fib_test_validate_entry(fei,
9283 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9286 "%U via 10.10.10.1",
9287 format_fib_prefix, &pfx_10_10_10_20_s_30);
9290 * remove the prefix from the middle of the sub-tree
9291 * the inherited source will be the only one remaining - expect
9292 * it to be withdrawn and hence the prefix is removed.
9294 fib_table_entry_special_remove(0,
9295 &pfx_10_10_10_20_s_30,
9297 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_20_s_30);
9298 FIB_TEST((FIB_NODE_INDEX_INVALID == fei),
9300 format_fib_prefix, &pfx_10_10_10_20_s_30);
9303 * inheriting source is modifed - expect the modification to be present
9304 * throughout the sub-tree
9306 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9309 tm->hw[0]->sw_if_index);
9310 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
9313 .adj = ai_10_10_10_2,
9317 fib_table_entry_update_one_path(0,
9318 &pfx_10_10_10_0_s_24,
9320 FIB_ENTRY_FLAG_COVERED_INHERIT,
9323 tm->hw[0]->sw_if_index,
9327 FIB_ROUTE_PATH_FLAG_NONE);
9328 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9329 FIB_TEST(!fib_test_validate_entry(fei,
9330 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9333 "%U via 10.10.10.2",
9334 format_fib_prefix, &pfx_10_10_10_21_s_32);
9335 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9336 FIB_TEST(!fib_test_validate_entry(fei,
9337 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9340 "%U via 10.10.10.2",
9341 format_fib_prefix, &pfx_10_10_10_22_s_32);
9342 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9343 FIB_TEST(!fib_test_validate_entry(fei,
9344 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9347 "%U via 10.10.10.2",
9348 format_fib_prefix, &pfx_10_10_10_255_s_32);
9349 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9350 FIB_TEST(!fib_test_validate_entry(fei,
9351 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9354 "%U via 10.10.10.2",
9355 format_fib_prefix, &pfx_10_10_10_0_s_24);
9357 fib_source_t hi_src = fib_source_allocate("test", 0x50,
9358 FIB_SOURCE_BH_SIMPLE);
9361 * add the source that replaces inherited state.
9362 * inheriting source is not the best, so it doesn't push state.
9364 fib_table_entry_update_one_path(0,
9365 &pfx_10_10_10_0_s_24,
9367 FIB_ENTRY_FLAG_NONE,
9370 tm->hw[0]->sw_if_index,
9374 FIB_ROUTE_PATH_FLAG_NONE);
9375 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9376 FIB_TEST(!fib_test_validate_entry(fei,
9377 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9380 "%U via 10.10.10.1",
9381 format_fib_prefix, &pfx_10_10_10_0_s_24);
9383 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9384 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9385 "%U resolves via drop",
9386 format_fib_prefix, &pfx_10_10_10_21_s_32);
9387 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9388 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9389 "%U resolves via drop",
9390 format_fib_prefix, &pfx_10_10_10_22_s_32);
9391 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9392 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9393 "%U resolves via drop",
9394 format_fib_prefix, &pfx_10_10_10_255_s_32);
9395 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9396 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
9397 "%U resolves via drop",
9398 format_fib_prefix, &pfx_10_10_10_16_s_28);
9401 * withdraw the higher priority source and expect the inherited to return
9402 * throughout the sub-tree
9404 fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, hi_src);
9406 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9407 FIB_TEST(!fib_test_validate_entry(fei,
9408 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9411 "%U via 10.10.10.2",
9412 format_fib_prefix, &pfx_10_10_10_21_s_32);
9413 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9414 FIB_TEST(!fib_test_validate_entry(fei,
9415 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9418 "%U via 10.10.10.2",
9419 format_fib_prefix, &pfx_10_10_10_22_s_32);
9420 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9421 FIB_TEST(!fib_test_validate_entry(fei,
9422 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9425 "%U via 10.10.10.2",
9426 format_fib_prefix, &pfx_10_10_10_255_s_32);
9427 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9428 FIB_TEST(!fib_test_validate_entry(fei,
9429 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9432 "%U via 10.10.10.2",
9433 format_fib_prefix, &pfx_10_10_10_0_s_24);
9434 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9435 FIB_TEST(!fib_test_validate_entry(fei,
9436 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9439 "%U via 10.10.10.2",
9440 format_fib_prefix, &pfx_10_10_10_16_s_28);
9443 * source a covered entry in the sub-tree with the same inherting source
9444 * - expect that it now owns the sub-tree and thus over-rides its cover
9446 fib_table_entry_update_one_path(0,
9447 &pfx_10_10_10_16_s_28,
9449 FIB_ENTRY_FLAG_COVERED_INHERIT,
9452 tm->hw[0]->sw_if_index,
9456 FIB_ROUTE_PATH_FLAG_NONE);
9457 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_16_s_28);
9458 FIB_TEST(!fib_test_validate_entry(fei,
9459 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9462 "%U via 10.10.10.1",
9463 format_fib_prefix, &pfx_10_10_10_16_s_28);
9464 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9465 FIB_TEST(!fib_test_validate_entry(fei,
9466 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9469 "%U via 10.10.10.2",
9470 format_fib_prefix, &pfx_10_10_10_22_s_32);
9471 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9472 FIB_TEST(!fib_test_validate_entry(fei,
9473 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9476 "%U via 10.10.10.2",
9477 format_fib_prefix, &pfx_10_10_10_21_s_32);
9479 /* these two unaffected by the sub-tree change */
9480 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9481 FIB_TEST(!fib_test_validate_entry(fei,
9482 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9485 "%U via 10.10.10.2",
9486 format_fib_prefix, &pfx_10_10_10_255_s_32);
9487 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9488 FIB_TEST(!fib_test_validate_entry(fei,
9489 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9492 "%U via 10.10.10.2",
9493 format_fib_prefix, &pfx_10_10_10_0_s_24);
9496 * removes the more specific, expect the /24 to now re-owns the sub-tree
9498 fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_API);
9500 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9501 FIB_TEST(!fib_test_validate_entry(fei,
9502 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9505 "%U via 10.10.10.2",
9506 format_fib_prefix, &pfx_10_10_10_16_s_28);
9507 FIB_TEST(!fib_test_validate_entry(fei,
9508 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9511 "%U via 10.10.10.2",
9512 format_fib_prefix, &pfx_10_10_10_21_s_32);
9513 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9514 FIB_TEST(!fib_test_validate_entry(fei,
9515 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9518 "%U via 10.10.10.2",
9519 format_fib_prefix, &pfx_10_10_10_22_s_32);
9520 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9521 FIB_TEST(!fib_test_validate_entry(fei,
9522 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9525 "%U via 10.10.10.2",
9526 format_fib_prefix, &pfx_10_10_10_255_s_32);
9527 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9528 FIB_TEST(!fib_test_validate_entry(fei,
9529 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9532 "%U via 10.10.10.2",
9533 format_fib_prefix, &pfx_10_10_10_0_s_24);
9535 * modify the /24. expect the new forwarding to be pushed down
9537 fib_table_entry_update_one_path(0,
9538 &pfx_10_10_10_0_s_24,
9540 FIB_ENTRY_FLAG_COVERED_INHERIT,
9543 tm->hw[0]->sw_if_index,
9547 FIB_ROUTE_PATH_FLAG_NONE);
9548 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9549 FIB_TEST(!fib_test_validate_entry(fei,
9550 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9553 "%U via 10.10.10.1",
9554 format_fib_prefix, &pfx_10_10_10_16_s_28);
9555 FIB_TEST(!fib_test_validate_entry(fei,
9556 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9559 "%U via 10.10.10.1",
9560 format_fib_prefix, &pfx_10_10_10_21_s_32);
9561 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9562 FIB_TEST(!fib_test_validate_entry(fei,
9563 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9566 "%U via 10.10.10.1",
9567 format_fib_prefix, &pfx_10_10_10_22_s_32);
9568 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9569 FIB_TEST(!fib_test_validate_entry(fei,
9570 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9573 "%U via 10.10.10.1",
9574 format_fib_prefix, &pfx_10_10_10_255_s_32);
9575 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9576 FIB_TEST(!fib_test_validate_entry(fei,
9577 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9580 "%U via 10.10.10.1",
9581 format_fib_prefix, &pfx_10_10_10_0_s_24);
9584 * add an entry less specific to /24. it should not own the /24's tree
9586 const fib_prefix_t pfx_10_10_0_0_s_16 = {
9588 .fp_proto = FIB_PROTOCOL_IP4,
9589 .fp_addr = nh_10_10_0_0,
9591 fib_table_entry_update_one_path(0,
9592 &pfx_10_10_0_0_s_16,
9594 FIB_ENTRY_FLAG_COVERED_INHERIT,
9597 tm->hw[0]->sw_if_index,
9601 FIB_ROUTE_PATH_FLAG_NONE);
9602 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
9603 FIB_TEST(!fib_test_validate_entry(fei,
9604 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9607 "%U via 10.10.10.1",
9608 format_fib_prefix, &pfx_10_10_10_16_s_28);
9609 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_22_s_32);
9610 FIB_TEST(!fib_test_validate_entry(fei,
9611 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9614 "%U via 10.10.10.1",
9615 format_fib_prefix, &pfx_10_10_10_22_s_32);
9616 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_255_s_32);
9617 FIB_TEST(!fib_test_validate_entry(fei,
9618 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9621 "%U via 10.10.10.1",
9622 format_fib_prefix, &pfx_10_10_10_255_s_32);
9623 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
9624 FIB_TEST(!fib_test_validate_entry(fei,
9625 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9628 "%U via 10.10.10.1",
9629 format_fib_prefix, &pfx_10_10_10_0_s_24);
9630 fei = fib_table_lookup_exact_match(0, &pfx_10_10_0_0_s_16);
9631 FIB_TEST(!fib_test_validate_entry(fei,
9632 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9635 "%U via 10.10.10.2",
9636 format_fib_prefix, &pfx_10_10_0_0_s_16);
9639 * Add/remove an interposer source to a new /32
9641 const fib_prefix_t pfx_11_11_11_11_s_32 = {
9643 .fp_proto = FIB_PROTOCOL_IP4,
9644 .fp_addr = nh_11_11_11_11,
9647 fib_table_entry_update_one_path(0,
9648 &pfx_11_11_11_11_s_32,
9650 FIB_ENTRY_FLAG_NONE,
9653 tm->hw[0]->sw_if_index,
9657 FIB_ROUTE_PATH_FLAG_NONE);
9659 dpo_id_t interposer = DPO_INVALID;
9660 fib_mpls_label_t *l99 = NULL, fml_99 = {
9663 vec_add1(l99, fml_99);
9665 mpls_label_dpo_create(l99,
9668 MPLS_LABEL_DPO_FLAG_NONE,
9669 punt_dpo_get(DPO_PROTO_MPLS),
9672 adj_index_t ai_10_10_10_3 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9675 tm->hw[0]->sw_if_index);
9676 fib_test_lb_bucket_t adj_o_10_10_10_3 = {
9679 .adj = ai_10_10_10_3,
9682 fib_test_lb_bucket_t l99_o_10_10_10_3 = {
9683 .type = FT_LB_LABEL_O_ADJ,
9685 .adj = ai_10_10_10_3,
9691 fei = fib_table_entry_special_dpo_add(0,
9692 &pfx_11_11_11_11_s_32,
9694 FIB_ENTRY_FLAG_INTERPOSE,
9696 FIB_TEST(!fib_test_validate_entry(fei,
9697 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9700 "%U via interposer adj",
9701 format_fib_prefix,&pfx_11_11_11_11_s_32);
9703 fib_table_entry_special_remove(0,
9704 &pfx_11_11_11_11_s_32,
9705 FIB_SOURCE_SPECIAL);
9706 FIB_TEST(!fib_test_validate_entry(fei,
9707 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9710 "%U via 10.10.10.1",
9711 format_fib_prefix, &pfx_11_11_11_11_s_32);
9712 dpo_reset(&interposer);
9713 fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9716 * add an interposer to a source with path-extensions
9718 fib_mpls_label_t *l3300 = NULL, fml_3300 = {
9721 vec_add1(l3300, fml_3300);
9722 fib_table_entry_update_one_path(0,
9723 &pfx_11_11_11_11_s_32,
9725 FIB_ENTRY_FLAG_NONE,
9728 tm->hw[0]->sw_if_index,
9732 FIB_ROUTE_PATH_FLAG_NONE);
9734 mpls_label_dpo_create(l99,
9737 MPLS_LABEL_DPO_FLAG_NONE,
9738 punt_dpo_get(DPO_PROTO_MPLS),
9741 adj_index_t ai_mpls_10_10_10_3 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
9744 tm->hw[0]->sw_if_index);
9745 fib_test_lb_bucket_t l3300_o_10_10_10_3 = {
9746 .type = FT_LB_LABEL_O_ADJ,
9748 .adj = ai_mpls_10_10_10_3,
9753 fib_test_lb_bucket_t lchain_o_10_10_10_3 = {
9754 .type = FT_LB_LABEL_CHAIN_O_ADJ,
9755 .label_chain_o_adj = {
9756 .adj = ai_mpls_10_10_10_3,
9757 .label_chain_size = 2,
9765 fei = fib_table_entry_special_dpo_add(0,
9766 &pfx_11_11_11_11_s_32,
9768 FIB_ENTRY_FLAG_INTERPOSE,
9771 FIB_TEST(!fib_test_validate_entry(fei,
9772 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9774 &lchain_o_10_10_10_3),
9775 "%U via interposer & mpls on adj",
9776 format_fib_prefix, &pfx_11_11_11_11_s_32);
9778 fib_table_entry_special_remove(0,
9779 &pfx_11_11_11_11_s_32,
9780 FIB_SOURCE_SPECIAL);
9781 FIB_TEST(!fib_test_validate_entry(fei,
9782 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9784 &l3300_o_10_10_10_3),
9785 "%U via 10.10.10.1",
9786 format_fib_prefix, &pfx_11_11_11_11_s_32);
9787 adj_unlock(ai_mpls_10_10_10_3);
9790 * remove and re-add the second best API source while the interpose
9793 fei = fib_table_entry_special_dpo_add(0,
9794 &pfx_11_11_11_11_s_32,
9796 FIB_ENTRY_FLAG_INTERPOSE,
9798 FIB_TEST(!fib_test_validate_entry(fei,
9799 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9801 &lchain_o_10_10_10_3),
9802 "%U via interposer adj",
9803 format_fib_prefix,&pfx_11_11_11_11_s_32);
9805 FIB_TEST(3 == pool_elts(mpls_label_dpo_pool),
9806 "MPLS label pool: %d",
9807 pool_elts(mpls_label_dpo_pool));
9809 fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9812 * the interpose does not get stacked when there are not valid paths
9814 fib_test_lb_bucket_t bucket_drop = {
9817 .adj = DPO_PROTO_IP4,
9820 FIB_TEST(!fib_test_validate_entry(fei,
9821 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9825 format_fib_prefix,&pfx_11_11_11_11_s_32);
9827 fib_table_entry_update_one_path(0,
9828 &pfx_11_11_11_11_s_32,
9830 FIB_ENTRY_FLAG_NONE,
9833 tm->hw[0]->sw_if_index,
9837 FIB_ROUTE_PATH_FLAG_NONE);
9838 FIB_TEST(!fib_test_validate_entry(fei,
9839 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9842 "%U via interposer adj",
9843 format_fib_prefix,&pfx_11_11_11_11_s_32);
9844 fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9847 * add a cover for the interposed entry, so that we test it selects
9848 * the covers forwarding.
9850 const fib_prefix_t pfx_11_11_11_0_s_24 = {
9852 .fp_proto = FIB_PROTOCOL_IP4,
9853 .fp_addr = nh_11_11_11_0,
9855 fib_table_entry_update_one_path(0,
9856 &pfx_11_11_11_0_s_24,
9858 FIB_ENTRY_FLAG_NONE,
9861 tm->hw[0]->sw_if_index,
9865 FIB_ROUTE_PATH_FLAG_NONE);
9866 FIB_TEST(!fib_test_validate_entry(fei,
9867 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9870 "%U via interposer adj",
9871 format_fib_prefix,&pfx_11_11_11_11_s_32);
9874 * multiple interpose sources on the same entry. Only the high
9875 * priority source gets to add the interpose.
9877 fib_table_entry_update_one_path(0,
9878 &pfx_11_11_11_11_s_32,
9880 FIB_ENTRY_FLAG_NONE,
9883 tm->hw[0]->sw_if_index,
9887 FIB_ROUTE_PATH_FLAG_NONE);
9889 dpo_id_t interposer2 = DPO_INVALID;
9890 fib_mpls_label_t *l100 = NULL, fml_100 = {
9893 vec_add1(l100, fml_100);
9895 mpls_label_dpo_create(l100,
9898 MPLS_LABEL_DPO_FLAG_NONE,
9899 punt_dpo_get(DPO_PROTO_MPLS),
9902 fei = fib_table_entry_special_dpo_add(0,
9903 &pfx_11_11_11_11_s_32,
9904 FIB_SOURCE_CLASSIFY,
9905 FIB_ENTRY_FLAG_INTERPOSE,
9908 fib_test_lb_bucket_t lc100_o_10_10_10_3 = {
9909 .type = FT_LB_LABEL_CHAIN_O_ADJ,
9910 .label_chain_o_adj = {
9911 .adj = ai_10_10_10_3,
9912 .label_chain_size = 2,
9920 FIB_TEST(!fib_test_validate_entry(fei,
9921 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9923 &lc100_o_10_10_10_3),
9924 "%U via interposer label 99",
9925 format_fib_prefix,&pfx_11_11_11_11_s_32);
9927 fib_test_lb_bucket_t l100_o_10_10_10_3 = {
9928 .type = FT_LB_LABEL_O_ADJ,
9930 .adj = ai_10_10_10_3,
9936 fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_SPECIAL);
9938 FIB_TEST(!fib_test_validate_entry(fei,
9939 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9941 &l100_o_10_10_10_3),
9942 "%U via interposer label 99",
9943 format_fib_prefix,&pfx_11_11_11_11_s_32);
9945 fib_table_entry_delete(0, &pfx_11_11_11_0_s_24, FIB_SOURCE_API);
9946 fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API);
9947 FIB_TEST(!fib_test_validate_entry(fei,
9948 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
9952 format_fib_prefix,&pfx_11_11_11_11_s_32);
9953 fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_CLASSIFY);
9956 * update a source to/from interpose.
9958 /* fib_table_entry_update_one_path(0, */
9959 /* &pfx_11_11_11_0_s_24, */
9960 /* FIB_SOURCE_API, */
9961 /* FIB_ENTRY_FLAG_NONE, */
9962 /* DPO_PROTO_IP4, */
9963 /* &nh_10_10_10_3, */
9964 /* tm->hw[0]->sw_if_index, */
9968 /* FIB_ROUTE_PATH_FLAG_NONE); */
9969 /* fei = fib_table_entry_special_dpo_add(0, */
9970 /* &pfx_11_11_11_11_s_32, */
9971 /* FIB_SOURCE_API, */
9972 /* FIB_ENTRY_FLAG_INTERPOSE, */
9974 /* FIB_TEST(!fib_test_validate_entry(fei, */
9975 /* FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
9977 /* &l99_o_10_10_10_3), */
9978 /* "%U via interposer label 99", */
9979 /* format_fib_prefix,&pfx_11_11_11_11_s_32); */
9981 /* FIB_TEST(3 == pool_elts(mpls_label_dpo_pool), */
9982 /* "MPLS label pool: %d", */
9983 /* pool_elts(mpls_label_dpo_pool)); */
9984 /* FIB_TEST((2 == mpls_label_dpo_get(interposer.dpoi_index)->mld_locks), */
9985 /* "Interposer %d locks", */
9986 /* mpls_label_dpo_get(interposer.dpoi_index)->mld_locks); */
9988 /* fib_table_entry_update_one_path(0, */
9989 /* &pfx_11_11_11_11_s_32, */
9990 /* FIB_SOURCE_API, */
9991 /* FIB_ENTRY_FLAG_NONE, */
9992 /* DPO_PROTO_IP4, */
9993 /* &nh_10_10_10_2, */
9994 /* tm->hw[0]->sw_if_index, */
9998 /* FIB_ROUTE_PATH_FLAG_NONE); */
9999 /* FIB_TEST(!fib_test_validate_entry(fei, */
10000 /* FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
10002 /* &adj_o_10_10_10_2), */
10003 /* "%U via 10.10.10.2", */
10004 /* format_fib_prefix,&pfx_11_11_11_11_s_32); */
10006 /* FIB_TEST((1 == mpls_label_dpo_get(interposer.dpoi_index)->mld_locks), */
10007 /* "Interposer %d locks", */
10008 /* mpls_label_dpo_get(interposer.dpoi_index)->mld_locks); */
10009 /* FIB_TEST(2 == pool_elts(mpls_label_dpo_pool), */
10010 /* "MPLS label pool: %d", */
10011 /* pool_elts(mpls_label_dpo_pool)); */
10013 /* fei = fib_table_entry_special_dpo_add(0, */
10014 /* &pfx_11_11_11_11_s_32, */
10015 /* FIB_SOURCE_API, */
10016 /* FIB_ENTRY_FLAG_INTERPOSE, */
10017 /* &interposer); */
10018 /* FIB_TEST(!fib_test_validate_entry(fei, */
10019 /* FIB_FORW_CHAIN_TYPE_UNICAST_IP4, */
10021 /* &l99_o_10_10_10_3), */
10022 /* "%U via interposer label 99", */
10023 /* format_fib_prefix,&pfx_11_11_11_11_s_32); */
10025 /* fib_table_entry_delete(0, &pfx_11_11_11_11_s_32, FIB_SOURCE_API); */
10028 * Add/remove an interposer source from the top of the subtrie. The
10029 * interposer source is not inherited.
10031 fib_table_entry_update_one_path(0,
10032 &pfx_10_10_10_0_s_24,
10034 FIB_ENTRY_FLAG_COVERED_INHERIT,
10037 tm->hw[0]->sw_if_index,
10041 FIB_ROUTE_PATH_FLAG_NONE);
10042 fei = fib_table_entry_special_dpo_add(0,
10043 &pfx_10_10_10_0_s_24,
10044 FIB_SOURCE_SPECIAL,
10045 FIB_ENTRY_FLAG_INTERPOSE,
10047 FIB_TEST(!fib_test_validate_entry(fei,
10048 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10050 &l99_o_10_10_10_3),
10051 "%U via interposer label",
10052 format_fib_prefix,&pfx_10_10_10_0_s_24);
10053 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
10054 FIB_TEST(!fib_test_validate_entry(fei,
10055 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10059 format_fib_prefix, &pfx_10_10_10_21_s_32);
10061 fib_table_entry_special_remove(0,
10062 &pfx_10_10_10_0_s_24,
10063 FIB_SOURCE_SPECIAL);
10064 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_0_s_24);
10065 FIB_TEST(!fib_test_validate_entry(fei,
10066 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10068 &adj_o_10_10_10_3),
10069 "%U via 10.10.10.1",
10070 format_fib_prefix, &pfx_10_10_10_0_s_24);
10071 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
10072 FIB_TEST(!fib_test_validate_entry(fei,
10073 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10075 &adj_o_10_10_10_3),
10076 "%U via via 10.10.10.1",
10077 format_fib_prefix, &pfx_10_10_10_21_s_32);
10080 * Add/remove an interposer source from the top of the subtrie. The
10081 * interposer source is inherited.
10083 fei = fib_table_entry_special_dpo_add(0,
10084 &pfx_10_10_10_0_s_24,
10085 FIB_SOURCE_SPECIAL,
10086 (FIB_ENTRY_FLAG_COVERED_INHERIT |
10087 FIB_ENTRY_FLAG_INTERPOSE),
10089 FIB_TEST(!fib_test_validate_entry(fei,
10090 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10092 &l99_o_10_10_10_3),
10093 "%U via interposer label",
10094 format_fib_prefix,&pfx_10_10_10_0_s_24);
10096 /* interposer gets forwarding from the drop cli source */
10097 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_21_s_32);
10098 FIB_TEST(!fib_test_validate_entry(fei,
10099 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10103 format_fib_prefix,&pfx_10_10_10_21_s_32);
10105 fib_table_entry_update_one_path(0,
10106 &pfx_10_10_10_21_s_32,
10108 FIB_ENTRY_FLAG_NONE,
10111 tm->hw[0]->sw_if_index,
10115 FIB_ROUTE_PATH_FLAG_NONE);
10116 fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_CLI);
10117 /* interposer gets forwarding from the API source */
10118 FIB_TEST(!fib_test_validate_entry(fei,
10119 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10121 &l99_o_10_10_10_3),
10122 "%U via interposer label",
10123 format_fib_prefix,&pfx_10_10_10_21_s_32);
10128 fib_table_entry_delete(0, &pfx_10_10_10_22_s_32, FIB_SOURCE_CLI);
10129 fib_table_entry_delete(0, &pfx_10_10_10_21_s_32, FIB_SOURCE_API);
10130 fib_table_entry_delete(0, &pfx_10_10_10_16_s_28, FIB_SOURCE_CLI);
10131 fib_table_entry_delete(0, &pfx_10_10_10_255_s_32, FIB_SOURCE_CLI);
10132 fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_API);
10133 fib_table_entry_delete(0, &pfx_10_10_0_0_s_16, FIB_SOURCE_API);
10134 fib_table_entry_delete(0, &pfx_10_10_10_0_s_24, FIB_SOURCE_SPECIAL);
10135 adj_unlock(ai_10_10_10_1);
10136 adj_unlock(ai_10_10_10_2);
10137 adj_unlock(ai_10_10_10_3);
10138 dpo_reset(&interposer);
10139 dpo_reset(&interposer2);
10140 FIB_TEST(0 == pool_elts(mpls_label_dpo_pool),
10141 "MPLS label pool empty: %d",
10142 pool_elts(mpls_label_dpo_pool));
10143 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
10144 FIB_TEST(N_PLS == fib_path_list_pool_size(),
10145 "number of path-lists: %d = %d",
10146 N_PLS, fib_path_list_pool_size());
10149 * test the v6 tree walk.
10150 * a /64 that covers everything. a /96 that covers one /128
10151 * a second /128 covered only by the /64.
10153 const fib_prefix_t pfx_2001_s_64 = {
10155 .fp_proto = FIB_PROTOCOL_IP6,
10159 [0] = clib_host_to_net_u64(0x2001000000000000),
10160 [1] = clib_host_to_net_u64(0x0000000000000000),
10165 const fib_prefix_t pfx_2001_1_s_96 = {
10167 .fp_proto = FIB_PROTOCOL_IP6,
10171 [0] = clib_host_to_net_u64(0x2001000000000000),
10172 [1] = clib_host_to_net_u64(0x1000000000000000),
10177 const fib_prefix_t pfx_2001_1_1_s_128 = {
10179 .fp_proto = FIB_PROTOCOL_IP6,
10183 [0] = clib_host_to_net_u64(0x2001000000000000),
10184 [1] = clib_host_to_net_u64(0x1000000000000001),
10189 const fib_prefix_t pfx_2001_0_1_s_128 = {
10191 .fp_proto = FIB_PROTOCOL_IP6,
10195 [0] = clib_host_to_net_u64(0x2001000000000000),
10196 [1] = clib_host_to_net_u64(0x0000000000000001),
10201 const ip46_address_t nh_3000_1 = {
10204 [0] = clib_host_to_net_u64(0x3000000000000000),
10205 [1] = clib_host_to_net_u64(0x0000000000000001),
10209 const ip46_address_t nh_3000_2 = {
10212 [0] = clib_host_to_net_u64(0x3000000000000000),
10213 [1] = clib_host_to_net_u64(0x0000000000000002),
10217 adj_index_t ai_3000_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
10220 tm->hw[0]->sw_if_index);
10221 adj_index_t ai_3000_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
10224 tm->hw[0]->sw_if_index);
10225 fib_test_lb_bucket_t adj_o_3000_1 = {
10231 fib_test_lb_bucket_t adj_o_3000_2 = {
10238 fib_table_entry_special_add(0,
10239 &pfx_2001_0_1_s_128,
10241 FIB_ENTRY_FLAG_DROP);
10242 fib_table_entry_special_add(0,
10243 &pfx_2001_1_1_s_128,
10245 FIB_ENTRY_FLAG_DROP);
10248 * /96 has inherited forwarding pushed down to its covered /128
10250 fib_table_entry_update_one_path(0,
10253 FIB_ENTRY_FLAG_COVERED_INHERIT,
10256 tm->hw[0]->sw_if_index,
10260 FIB_ROUTE_PATH_FLAG_NONE);
10261 fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
10262 FIB_TEST(!fib_test_validate_entry(fei,
10263 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10267 format_fib_prefix, &pfx_2001_1_s_96);
10268 fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
10269 FIB_TEST(!fib_test_validate_entry(fei,
10270 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10274 format_fib_prefix, &pfx_2001_1_1_s_128);
10275 fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
10276 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
10277 "%U resolves via drop",
10278 format_fib_prefix, &pfx_2001_0_1_s_128);
10281 * /64 has inherited forwarding pushed down to all, but the /96
10282 * and its sub-tree remain unaffected.
10284 fib_table_entry_update_one_path(0,
10287 FIB_ENTRY_FLAG_COVERED_INHERIT,
10290 tm->hw[0]->sw_if_index,
10294 FIB_ROUTE_PATH_FLAG_NONE);
10296 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
10297 FIB_TEST(!fib_test_validate_entry(fei,
10298 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10302 format_fib_prefix, &pfx_2001_s_64);
10303 fei = fib_table_lookup_exact_match(0, &pfx_2001_0_1_s_128);
10304 FIB_TEST(!fib_test_validate_entry(fei,
10305 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10309 format_fib_prefix, &pfx_2001_0_1_s_128);
10311 fei = fib_table_lookup_exact_match(0, &pfx_2001_1_s_96);
10312 FIB_TEST(!fib_test_validate_entry(fei,
10313 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10317 format_fib_prefix, &pfx_2001_1_s_96);
10318 fei = fib_table_lookup_exact_match(0, &pfx_2001_1_1_s_128);
10319 FIB_TEST(!fib_test_validate_entry(fei,
10320 FIB_FORW_CHAIN_TYPE_UNICAST_IP6,
10324 format_fib_prefix, &pfx_2001_1_1_s_128);
10329 fib_table_entry_delete(0, &pfx_2001_0_1_s_128, FIB_SOURCE_CLI);
10330 fib_table_entry_delete(0, &pfx_2001_1_1_s_128, FIB_SOURCE_CLI);
10331 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
10332 fib_table_entry_delete(0, &pfx_2001_1_s_96, FIB_SOURCE_API);
10333 adj_unlock(ai_3000_1);
10334 adj_unlock(ai_3000_2);
10337 * test no-one left behind
10339 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
10340 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
10346 fib_test_sticky (void)
10348 fib_route_path_t *r_paths = NULL;
10349 test_main_t *tm = &test_main;
10350 u32 ii, lb_count, pl_count;
10351 dpo_id_t dpo = DPO_INVALID;
10352 fib_node_index_t pl_index;
10356 fib_test_lb_bucket_t buckets[N_PATHS];
10357 bfd_session_t bfds[N_PATHS] = {{0}};
10359 lb_count = pool_elts(load_balance_pool);
10360 pl_count = fib_path_list_pool_size();
10362 for (ii = 0; ii < N_PATHS; ii++)
10364 ip46_address_t nh = {
10365 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
10369 ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
10371 &nh, tm->hw[0]->sw_if_index);
10373 buckets[ii].type = FT_LB_ADJ;
10374 buckets[ii].adj.adj = ai;
10376 bfds[ii].udp.key.peer_addr = nh;
10377 bfds[ii].udp.key.sw_if_index = tm->hw[0]->sw_if_index;
10378 bfds[ii].hop_type = BFD_HOP_TYPE_SINGLE;
10379 bfds[ii].local_state = BFD_STATE_init;
10380 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfds[ii]);
10381 bfds[ii].local_state = BFD_STATE_up;
10382 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[ii]);
10385 for (ii = 0; ii < N_PATHS; ii++)
10387 fib_route_path_t r_path = {
10388 .frp_proto = DPO_PROTO_IP4,
10390 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
10392 .frp_sw_if_index = tm->hw[0]->sw_if_index,
10394 .frp_fib_index = ~0,
10396 vec_add1(r_paths, r_path);
10399 pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths);
10400 fib_path_list_lock(pl_index);
10402 fib_path_list_contribute_forwarding(pl_index,
10403 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10404 FIB_PATH_LIST_FWD_FLAG_STICKY,
10407 FIB_TEST(!fib_test_validate_lb(&dpo,
10427 /* take down paths */
10428 bfds[0].local_state = BFD_STATE_down;
10429 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[0]);
10431 fib_path_list_contribute_forwarding(pl_index,
10432 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10433 FIB_PATH_LIST_FWD_FLAG_STICKY,
10436 FIB_TEST(!fib_test_validate_lb(&dpo,
10454 "Failed at shut-down path 0");
10456 bfds[7].local_state = BFD_STATE_down;
10457 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[7]);
10459 fib_path_list_contribute_forwarding(pl_index,
10460 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10461 FIB_PATH_LIST_FWD_FLAG_STICKY,
10464 FIB_TEST(!fib_test_validate_lb(&dpo,
10482 "Failed at shut-down path 7");
10484 /* paths back up */
10485 bfds[0].local_state = BFD_STATE_up;
10486 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[0]);
10487 bfds[7].local_state = BFD_STATE_up;
10488 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[7]);
10490 fib_path_list_contribute_forwarding(pl_index,
10491 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10492 FIB_PATH_LIST_FWD_FLAG_STICKY,
10495 FIB_TEST(!fib_test_validate_lb(&dpo,
10515 fib_path_list_unlock(pl_index);
10518 * non-power of 2 number of buckets
10520 fib_route_path_t *r_paths2 = NULL;
10522 r_paths2 = vec_dup(r_paths);
10523 _vec_len(r_paths2) = 3;
10525 pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths2);
10526 fib_path_list_lock(pl_index);
10528 fib_path_list_contribute_forwarding(pl_index,
10529 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10530 FIB_PATH_LIST_FWD_FLAG_STICKY,
10533 FIB_TEST(!fib_test_validate_lb(&dpo,
10553 bfds[1].local_state = BFD_STATE_down;
10554 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10556 fib_path_list_contribute_forwarding(pl_index,
10557 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10558 FIB_PATH_LIST_FWD_FLAG_STICKY,
10562 * path 1's buckets alternate between path 0 and 2
10564 FIB_TEST(!fib_test_validate_lb(&dpo,
10583 bfds[1].local_state = BFD_STATE_up;
10584 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10586 fib_path_list_unlock(pl_index);
10591 fib_route_path_t *r_paths3 = NULL;
10593 r_paths3 = vec_dup(r_paths);
10594 _vec_len(r_paths3) = 3;
10596 r_paths3[0].frp_weight = 3;
10598 pl_index = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, r_paths3);
10599 fib_path_list_lock(pl_index);
10601 fib_path_list_contribute_forwarding(pl_index,
10602 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10603 FIB_PATH_LIST_FWD_FLAG_STICKY,
10606 FIB_TEST(!fib_test_validate_lb(&dpo,
10626 bfds[1].local_state = BFD_STATE_down;
10627 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10629 fib_path_list_contribute_forwarding(pl_index,
10630 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
10631 FIB_PATH_LIST_FWD_FLAG_STICKY,
10633 /* No attempt to Un-equal distribute the down path's buckets */
10634 FIB_TEST(!fib_test_validate_lb(&dpo,
10653 bfds[1].local_state = BFD_STATE_up;
10654 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfds[1]);
10657 fib_path_list_unlock(pl_index);
10660 vec_free(r_paths2);
10661 vec_free(r_paths3);
10663 FIB_TEST(lb_count == pool_elts(load_balance_pool), "no leaked LBs");
10664 FIB_TEST(pl_count == fib_path_list_pool_size(), "no leaked PLs");
10669 static clib_error_t *
10670 fib_test (vlib_main_t * vm,
10671 unformat_input_t * input,
10672 vlib_cli_command_t * cmd_arg)
10678 fib_test_mk_intf(4);
10680 if (unformat (input, "debug"))
10682 fib_test_do_debug = 1;
10685 if (unformat (input, "ip4"))
10687 res += fib_test_v4();
10689 else if (unformat (input, "ip6"))
10691 res += fib_test_v6();
10693 else if (unformat (input, "ip"))
10695 res += fib_test_v4();
10696 res += fib_test_v6();
10698 else if (unformat (input, "label"))
10700 res += fib_test_label();
10702 else if (unformat (input, "ae"))
10704 res += fib_test_ae();
10706 else if (unformat (input, "pref"))
10708 res += fib_test_pref();
10710 else if (unformat (input, "lfib"))
10712 res += lfib_test();
10714 else if (unformat (input, "walk"))
10716 res += fib_test_walk();
10718 else if (unformat (input, "bfd"))
10720 res += fib_test_bfd();
10722 else if (unformat (input, "inherit"))
10724 res += fib_test_inherit();
10726 else if (unformat (input, "sticky"))
10728 res += fib_test_sticky();
10732 res += fib_test_v4();
10733 res += fib_test_v6();
10734 res += fib_test_ae();
10735 res += fib_test_bfd();
10736 res += fib_test_pref();
10737 res += fib_test_label();
10738 res += fib_test_inherit();
10739 res += lfib_test();
10742 * fib-walk process must be disabled in order for the walk tests to work
10744 fib_walk_process_disable();
10745 res += fib_test_walk();
10746 fib_walk_process_enable();
10752 return clib_error_return(0, "FIB Unit Test Failed");
10760 VLIB_CLI_COMMAND (test_fib_command, static) = {
10761 .path = "test fib",
10762 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
10763 .function = fib_test,
10767 fib_test_init (vlib_main_t *vm)
10772 VLIB_INIT_FUNCTION (fib_test_init);