2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vnet/fib/ip6_fib.h>
17 #include <vnet/fib/ip4_fib.h>
18 #include <vnet/fib/mpls_fib.h>
19 #include <vnet/adj/adj.h>
20 #include <vnet/dpo/load_balance.h>
21 #include <vnet/dpo/load_balance_map.h>
22 #include <vnet/dpo/mpls_label_dpo.h>
23 #include <vnet/dpo/lookup_dpo.h>
24 #include <vnet/dpo/drop_dpo.h>
25 #include <vnet/dpo/receive_dpo.h>
26 #include <vnet/dpo/ip_null_dpo.h>
27 #include <vnet/bfd/bfd_main.h>
28 #include <vnet/dpo/interface_rx_dpo.h>
29 #include <vnet/dpo/replicate_dpo.h>
30 #include <vnet/dpo/l2_bridge_dpo.h>
32 #include <vnet/mpls/mpls.h>
34 #include <vnet/fib/fib_test.h>
35 #include <vnet/fib/fib_path_list.h>
36 #include <vnet/fib/fib_entry_src.h>
37 #include <vnet/fib/fib_walk.h>
38 #include <vnet/fib/fib_node_list.h>
39 #include <vnet/fib/fib_urpf_list.h>
42 * Add debugs for passing tests
44 static int fib_test_do_debug;
46 #define FIB_TEST_I(_cond, _comment, _args...) \
48 int _evald = (_cond); \
50 fformat(stderr, "FAIL:%d: " _comment "\n", \
53 if (fib_test_do_debug) \
54 fformat(stderr, "PASS:%d: " _comment "\n", \
59 #define FIB_TEST(_cond, _comment, _args...) \
61 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
63 ASSERT(!("FAIL: " _comment)); \
68 * A 'i'm not fussed is this is not efficient' store of test data
70 typedef struct test_main_t_ {
74 u32 hw_if_indicies[4];
78 vnet_hw_interface_t * hw[4];
81 static test_main_t test_main;
83 /* fake ethernet device class, distinct from "fake-ethX" */
84 static u8 * format_test_interface_name (u8 * s, va_list * args)
86 u32 dev_instance = va_arg (*args, u32);
87 return format (s, "test-eth%d", dev_instance);
90 static uword dummy_interface_tx (vlib_main_t * vm,
91 vlib_node_runtime_t * node,
94 clib_warning ("you shouldn't be here, leaking buffers...");
95 return frame->n_vectors;
99 test_interface_admin_up_down (vnet_main_t * vnm,
103 u32 hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
104 VNET_HW_INTERFACE_FLAG_LINK_UP : 0;
105 vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
109 VNET_DEVICE_CLASS (test_interface_device_class,static) = {
110 .name = "Test interface",
111 .format_device_name = format_test_interface_name,
112 .tx_function = dummy_interface_tx,
113 .admin_up_down_function = test_interface_admin_up_down,
116 static u8 *hw_address;
119 fib_test_mk_intf (u32 ninterfaces)
121 clib_error_t * error = NULL;
122 test_main_t *tm = &test_main;
126 ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
131 vec_add1(hw_address, byte);
134 for (i = 0; i < ninterfaces; i++)
138 error = ethernet_register_interface(vnet_get_main(),
139 test_interface_device_class.index,
142 &tm->hw_if_indicies[i],
143 /* flag change */ 0);
145 FIB_TEST((NULL == error), "ADD interface %d", i);
147 error = vnet_hw_interface_set_flags(vnet_get_main(),
148 tm->hw_if_indicies[i],
149 VNET_HW_INTERFACE_FLAG_LINK_UP);
150 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
151 tm->hw_if_indicies[i]);
152 vec_validate (ip4_main.fib_index_by_sw_if_index,
153 tm->hw[i]->sw_if_index);
154 vec_validate (ip6_main.fib_index_by_sw_if_index,
155 tm->hw[i]->sw_if_index);
156 ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
157 ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
159 error = vnet_sw_interface_set_flags(vnet_get_main(),
160 tm->hw[i]->sw_if_index,
161 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
162 FIB_TEST((NULL == error), "UP interface %d", i);
165 * re-eval after the inevitable realloc
167 for (i = 0; i < ninterfaces; i++)
169 tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
170 tm->hw_if_indicies[i]);
176 #define FIB_TEST_REC_FORW(_rec_prefix, _via_prefix, _bucket) \
178 const dpo_id_t *_rec_dpo = fib_entry_contribute_ip_forwarding( \
179 fib_table_lookup_exact_match(fib_index, (_rec_prefix))); \
180 const dpo_id_t *_via_dpo = fib_entry_contribute_ip_forwarding( \
181 fib_table_lookup(fib_index, (_via_prefix))); \
182 FIB_TEST(!dpo_cmp(_via_dpo, \
183 load_balance_get_bucket(_rec_dpo->dpoi_index, \
185 "%U is recursive via %U", \
186 format_fib_prefix, (_rec_prefix), \
187 format_fib_prefix, _via_prefix); \
190 #define FIB_TEST_LB_BUCKET_VIA_ADJ(_prefix, _bucket, _ai) \
192 const dpo_id_t *_dpo = fib_entry_contribute_ip_forwarding( \
193 fib_table_lookup_exact_match(fib_index, (_prefix))); \
194 const dpo_id_t *_dpo1 = \
195 load_balance_get_bucket(_dpo->dpoi_index, _bucket); \
196 FIB_TEST(DPO_ADJACENCY == _dpo1->dpoi_type, "type is %U", \
197 format_dpo_type, _dpo1->dpoi_type); \
198 FIB_TEST((_ai == _dpo1->dpoi_index), \
199 "%U bucket %d resolves via %U", \
200 format_fib_prefix, (_prefix), \
202 format_dpo_id, _dpo1, 0); \
205 #define FIB_TEST_RPF(_cond, _comment, _args...) \
207 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
213 fib_test_urpf_is_equal (fib_node_index_t fei,
214 fib_forward_chain_type_t fct,
217 dpo_id_t dpo = DPO_INVALID;
218 fib_urpf_list_t *urpf;
225 fib_entry_contribute_forwarding(fei, fct, &dpo);
226 ui = load_balance_get_urpf(dpo.dpoi_index);
228 urpf = fib_urpf_list_get(ui);
230 FIB_TEST_RPF(num == vec_len(urpf->furpf_itfs),
231 "RPF:%U len %d == %d",
232 format_fib_urpf_list, ui,
233 num, vec_len(urpf->furpf_itfs));
234 FIB_TEST_RPF(num == fib_urpf_check_size(ui),
235 "RPF:%U check-size %d == %d",
236 format_fib_urpf_list, ui,
237 num, vec_len(urpf->furpf_itfs));
239 for (ii = 0; ii < num; ii++)
241 adj_index_t ai = va_arg(ap, adj_index_t);
243 FIB_TEST_RPF(ai == urpf->furpf_itfs[ii],
244 "RPF:%d item:%d - %d == %d",
245 ui, ii, ai, urpf->furpf_itfs[ii]);
246 FIB_TEST_RPF(fib_urpf_check(ui, ai),
259 fib_test_build_rewrite (u8 *eth_addr)
263 vec_validate(rewrite, 13);
265 memcpy(rewrite, eth_addr, 6);
266 memcpy(rewrite+6, eth_addr, 6);
271 #define FIB_TEST_LB(_cond, _comment, _args...) \
273 if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
279 fib_test_validate_rep_v (const replicate_t *rep,
283 const fib_test_rep_bucket_t *exp;
287 FIB_TEST_LB((n_buckets == rep->rep_n_buckets),
288 "n_buckets = %d", rep->rep_n_buckets);
290 for (bucket = 0; bucket < n_buckets; bucket++)
292 exp = va_arg(*ap, fib_test_rep_bucket_t*);
294 dpo = replicate_get_bucket_i(rep, bucket);
298 case FT_REP_LABEL_O_ADJ:
300 const mpls_label_dpo_t *mld;
302 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
303 "bucket %d stacks on %U",
305 format_dpo_type, dpo->dpoi_type);
307 mld = mpls_label_dpo_get(dpo->dpoi_index);
308 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
310 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
311 exp->label_o_adj.label),
312 "bucket %d stacks on label %d",
314 exp->label_o_adj.label);
316 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
317 exp->label_o_adj.eos),
318 "bucket %d stacks on label %d %U",
320 exp->label_o_adj.label,
321 format_mpls_eos_bit, exp->label_o_adj.eos);
323 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
324 "bucket %d label stacks on %U",
326 format_dpo_type, mld->mld_dpo.dpoi_type);
328 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
329 "bucket %d label stacks on adj %d",
331 exp->label_o_adj.adj);
335 FIB_TEST_LB((DPO_INTERFACE_RX == dpo->dpoi_type),
336 "bucket %d stacks on %U",
338 format_dpo_type, dpo->dpoi_type);
340 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
341 "bucket %d stacks on adj %d",
345 case FT_REP_DISP_MFIB_LOOKUP:
355 fib_test_validate_lb_v (const load_balance_t *lb,
362 FIB_TEST_LB((n_buckets == lb->lb_n_buckets), "n_buckets = %d", lb->lb_n_buckets);
364 for (bucket = 0; bucket < n_buckets; bucket++)
366 const fib_test_lb_bucket_t *exp;
368 exp = va_arg(*ap, fib_test_lb_bucket_t*);
369 dpo = load_balance_get_bucket_i(lb, bucket);
373 case FT_LB_LABEL_STACK_O_ADJ:
375 const mpls_label_dpo_t *mld;
379 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
380 "bucket %d stacks on %U",
382 format_dpo_type, dpo->dpoi_type);
384 mld = mpls_label_dpo_get(dpo->dpoi_index);
386 FIB_TEST_LB(exp->label_stack_o_adj.label_stack_size == mld->mld_n_labels,
390 for (ii = 0; ii < mld->mld_n_labels; ii++)
392 hdr = clib_net_to_host_u32(mld->mld_hdr[ii].label_exp_s_ttl);
393 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
394 exp->label_stack_o_adj.label_stack[ii]),
395 "bucket %d stacks on label %d",
397 exp->label_stack_o_adj.label_stack[ii]);
399 if (ii == mld->mld_n_labels-1)
401 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
402 exp->label_o_adj.eos),
403 "bucket %d stacks on label %d %U!=%U",
405 exp->label_stack_o_adj.label_stack[ii],
406 format_mpls_eos_bit, exp->label_o_adj.eos,
407 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
411 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) == MPLS_NON_EOS),
412 "bucket %d stacks on label %d %U",
414 exp->label_stack_o_adj.label_stack[ii],
415 format_mpls_eos_bit, vnet_mpls_uc_get_s(hdr));
419 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
420 "bucket %d label stacks on %U",
422 format_dpo_type, mld->mld_dpo.dpoi_type);
424 FIB_TEST_LB((exp->label_stack_o_adj.adj == mld->mld_dpo.dpoi_index),
425 "bucket %d label stacks on adj %d",
427 exp->label_stack_o_adj.adj);
430 case FT_LB_LABEL_O_ADJ:
432 const mpls_label_dpo_t *mld;
434 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
435 "bucket %d stacks on %U",
437 format_dpo_type, dpo->dpoi_type);
439 mld = mpls_label_dpo_get(dpo->dpoi_index);
440 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
442 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
443 exp->label_o_adj.label),
444 "bucket %d stacks on label %d",
446 exp->label_o_adj.label);
448 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
449 exp->label_o_adj.eos),
450 "bucket %d stacks on label %d %U",
452 exp->label_o_adj.label,
453 format_mpls_eos_bit, exp->label_o_adj.eos);
455 FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
456 "bucket %d label stacks on %U",
458 format_dpo_type, mld->mld_dpo.dpoi_type);
460 FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
461 "bucket %d label stacks on adj %d",
463 exp->label_o_adj.adj);
466 case FT_LB_LABEL_O_LB:
468 const mpls_label_dpo_t *mld;
471 FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
472 "bucket %d stacks on %U",
474 format_dpo_type, dpo->dpoi_type);
476 mld = mpls_label_dpo_get(dpo->dpoi_index);
477 hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
479 FIB_TEST_LB(1 == mld->mld_n_labels, "label stack size",
481 FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
482 exp->label_o_lb.label),
483 "bucket %d stacks on label %d",
485 exp->label_o_lb.label);
487 FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
488 exp->label_o_lb.eos),
489 "bucket %d stacks on label %d %U",
491 exp->label_o_lb.label,
492 format_mpls_eos_bit, exp->label_o_lb.eos);
494 FIB_TEST_LB((DPO_LOAD_BALANCE == mld->mld_dpo.dpoi_type),
495 "bucket %d label stacks on %U",
497 format_dpo_type, mld->mld_dpo.dpoi_type);
499 FIB_TEST_LB((exp->label_o_lb.lb == mld->mld_dpo.dpoi_index),
500 "bucket %d label stacks on LB %d",
506 FIB_TEST_I(((DPO_ADJACENCY == dpo->dpoi_type) ||
507 (DPO_ADJACENCY_INCOMPLETE == dpo->dpoi_type)),
508 "bucket %d stacks on %U",
510 format_dpo_type, dpo->dpoi_type);
511 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
512 "bucket %d stacks on adj %d",
517 FIB_TEST_I((DPO_INTERFACE_RX == dpo->dpoi_type),
518 "bucket %d stacks on %U",
520 format_dpo_type, dpo->dpoi_type);
521 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
522 "bucket %d stacks on adj %d",
527 FIB_TEST_I((DPO_L2_BRIDGE == dpo->dpoi_type),
528 "bucket %d stacks on %U",
530 format_dpo_type, dpo->dpoi_type);
531 FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
532 "bucket %d stacks on adj %d",
537 FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
538 "bucket %d stacks on %U",
540 format_dpo_type, dpo->dpoi_type);
541 FIB_TEST_LB((exp->lb.lb == dpo->dpoi_index),
542 "bucket %d stacks on lb %d not %d",
548 FIB_TEST_I((DPO_DROP == dpo->dpoi_type),
549 "bucket %d stacks on %U",
551 format_dpo_type, dpo->dpoi_type);
552 FIB_TEST_LB((exp->special.adj == dpo->dpoi_index),
553 "bucket %d stacks on drop %d",
563 fib_test_validate_entry (fib_node_index_t fei,
564 fib_forward_chain_type_t fct,
568 dpo_id_t dpo = DPO_INVALID;
575 va_start(ap, n_buckets);
577 fib_entry_get_prefix(fei, &pfx);
578 fib_index = fib_entry_get_fib_index(fei);
579 fib_entry_contribute_forwarding(fei, fct, &dpo);
581 if (DPO_REPLICATE == dpo.dpoi_type)
583 const replicate_t *rep;
585 rep = replicate_get(dpo.dpoi_index);
586 res = fib_test_validate_rep_v(rep, n_buckets, &ap);
590 const load_balance_t *lb;
592 FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
594 format_dpo_type, dpo.dpoi_type);
596 lb = load_balance_get(dpo.dpoi_index);
597 res = fib_test_validate_lb_v(lb, n_buckets, &ap);
600 * ensure that the LB contributed by the entry is the
601 * same as the LB in the forwarding tables
603 if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
605 switch (pfx.fp_proto)
607 case FIB_PROTOCOL_IP4:
608 fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
610 case FIB_PROTOCOL_IP6:
611 fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
613 case FIB_PROTOCOL_MPLS:
615 mpls_unicast_header_t hdr = {
616 .label_exp_s_ttl = 0,
619 vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
620 vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
621 hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
623 fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
629 FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
630 "Contributed LB = FW LB: %U\n %U",
631 format_load_balance, fw_lbi, 0,
632 format_load_balance, dpo.dpoi_index, 0);
647 * In the default table check for the presence and correct forwarding
648 * of the special entries
650 fib_node_index_t dfrt, fei, ai, ai2, locked_ai, ai_01, ai_02, ai_03;
651 const dpo_id_t *dpo, *dpo1, *dpo2, *dpo_drop;
652 const ip_adjacency_t *adj;
653 const load_balance_t *lb;
660 ip46_address_t nh_10_10_10_1 = {
661 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
664 ip46_address_t nh_10_10_10_2 = {
665 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
668 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
669 pool_elts(load_balance_map_pool));
673 /* record the nubmer of load-balances in use before we start */
674 lb_count = pool_elts(load_balance_pool);
676 /* Find or create FIB table 11 */
677 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 11,
680 for (ii = 0; ii < 4; ii++)
682 ip4_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
685 fib_prefix_t pfx_0_0_0_0_s_0 = {
687 .fp_proto = FIB_PROTOCOL_IP4,
697 .fp_proto = FIB_PROTOCOL_IP4,
705 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
707 dfrt = fib_table_lookup(fib_index, &pfx_0_0_0_0_s_0);
708 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
709 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
710 "Default route is DROP");
713 fei = fib_table_lookup(fib_index, &pfx);
714 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all zeros route present");
715 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
716 "all 0s route is DROP");
718 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xffffffff);
720 fei = fib_table_lookup(fib_index, &pfx);
721 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all ones route present");
722 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
723 "all 1s route is DROP");
725 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xe0000000);
727 fei = fib_table_lookup(fib_index, &pfx);
728 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "all-mcast route present");
729 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
730 "all-mcast route is DROP");
732 pfx.fp_addr.ip4.as_u32 = clib_host_to_net_u32(0xf0000000);
734 fei = fib_table_lookup(fib_index, &pfx);
735 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "class-e route present");
736 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
737 "class-e route is DROP");
740 * at this stage there are 5 entries in the test FIB (plus 5 in the default),
741 * all of which are special sourced and so none of which share path-lists.
742 * There are also 2 entries, and 2 non-shared path-lists, in the v6 default
743 * table, and 4 path-lists in the v6 MFIB table
747 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
748 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
749 fib_path_list_pool_size());
750 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
751 fib_entry_pool_size());
754 * add interface routes.
755 * validate presence of /24 attached and /32 recieve.
756 * test for the presence of the receive address in the glean and local adj
758 fib_prefix_t local_pfx = {
760 .fp_proto = FIB_PROTOCOL_IP4,
763 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
768 fib_table_entry_update_one_path(fib_index, &local_pfx,
769 FIB_SOURCE_INTERFACE,
770 (FIB_ENTRY_FLAG_CONNECTED |
771 FIB_ENTRY_FLAG_ATTACHED),
774 tm->hw[0]->sw_if_index,
775 ~0, // invalid fib index
778 FIB_ROUTE_PATH_FLAG_NONE);
779 fei = fib_table_lookup(fib_index, &local_pfx);
780 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
781 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
782 fib_entry_get_flags(fei)),
783 "Flags set on attached interface");
785 ai = fib_entry_get_adj(fei);
786 FIB_TEST((FIB_NODE_INDEX_INVALID != ai),
787 "attached interface route adj present %d", ai);
789 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
790 "attached interface adj is glean");
791 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
792 &adj->sub_type.glean.receive_addr)),
793 "attached interface adj is receive ok");
795 local_pfx.fp_len = 32;
796 fib_table_entry_update_one_path(fib_index, &local_pfx,
797 FIB_SOURCE_INTERFACE,
798 (FIB_ENTRY_FLAG_CONNECTED |
799 FIB_ENTRY_FLAG_LOCAL),
802 tm->hw[0]->sw_if_index,
803 ~0, // invalid fib index
806 FIB_ROUTE_PATH_FLAG_NONE);
807 fei = fib_table_lookup(fib_index, &local_pfx);
808 FIB_TEST(((FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_CONNECTED) ==
809 fib_entry_get_flags(fei)),
810 "Flags set on local interface");
812 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
814 dpo = fib_entry_contribute_ip_forwarding(fei);
815 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
816 "RPF list for local length 0");
817 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
818 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
819 "local interface adj is local");
820 receive_dpo_t *rd = receive_dpo_get(dpo->dpoi_index);
822 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
824 "local interface adj is receive ok");
826 FIB_TEST((2 == fib_table_get_num_entries(fib_index,
828 FIB_SOURCE_INTERFACE)),
829 "2 Interface Source'd prefixes");
832 * +2 interface routes +2 non-shared path-lists
834 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
835 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
836 fib_path_list_pool_size());
837 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
838 fib_entry_pool_size());
841 * Modify the default route to be via an adj not yet known.
842 * this sources the defalut route with the API source, which is
843 * a higher preference to the DEFAULT_ROUTE source
845 pfx.fp_addr.ip4.as_u32 = 0;
847 fib_table_entry_path_add(fib_index, &pfx,
852 tm->hw[0]->sw_if_index,
853 ~0, // invalid fib index
856 FIB_ROUTE_PATH_FLAG_NONE);
857 fei = fib_table_lookup(fib_index, &pfx);
858 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
859 "Flags set on API route");
861 FIB_TEST((fei == dfrt), "default route same index");
862 ai = fib_entry_get_adj(fei);
863 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
865 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
866 "adj is incomplete");
867 FIB_TEST((0 == ip46_address_cmp(&nh_10_10_10_1, &adj->sub_type.nbr.next_hop)),
868 "adj nbr next-hop ok");
869 FIB_TEST((1 == fib_table_get_num_entries(fib_index,
872 "1 API Source'd prefixes");
875 * find the adj in the shared db
877 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
880 tm->hw[0]->sw_if_index);
881 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
882 adj_unlock(locked_ai);
885 * +1 shared path-list
887 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
888 fib_path_list_db_size());
889 FIB_TEST((PNBR+3 == fib_path_list_pool_size()), "path list pool size is%d",
890 fib_path_list_pool_size());
891 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
892 fib_entry_pool_size());
895 * remove the API source from the default route. We expected
896 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
898 pfx.fp_addr.ip4.as_u32 = 0;
900 fib_table_entry_path_remove(fib_index, &pfx,
904 tm->hw[0]->sw_if_index,
905 ~0, // non-recursive path, so no FIB index
907 FIB_ROUTE_PATH_FLAG_NONE);
909 fei = fib_table_lookup(fib_index, &pfx);
911 FIB_TEST((fei == dfrt), "default route same index");
912 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
913 "Default route is DROP");
916 * -1 shared-path-list
918 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
919 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is%d",
920 fib_path_list_pool_size());
921 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
922 fib_entry_pool_size());
925 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
927 fib_prefix_t pfx_10_10_10_1_s_32 = {
929 .fp_proto = FIB_PROTOCOL_IP4,
932 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
935 fib_prefix_t pfx_10_10_10_2_s_32 = {
937 .fp_proto = FIB_PROTOCOL_IP4,
940 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
943 fib_prefix_t pfx_11_11_11_11_s_32 = {
945 .fp_proto = FIB_PROTOCOL_IP4,
948 .ip4.as_u32 = clib_host_to_net_u32(0x0b0b0b0b),
952 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
955 ip46_address_t nh_12_12_12_12 = {
956 .ip4.as_u32 = clib_host_to_net_u32(0x0c0c0c0c),
958 adj_index_t ai_12_12_12_12;
961 * Add a route via an incomplete ADJ. then complete the ADJ
962 * Expect the route LB is updated to use complete adj type.
964 fei = fib_table_entry_update_one_path(fib_index,
965 &pfx_11_11_11_11_s_32,
967 FIB_ENTRY_FLAG_ATTACHED,
969 &pfx_10_10_10_1_s_32.fp_addr,
970 tm->hw[0]->sw_if_index,
971 ~0, // invalid fib index
974 FIB_ROUTE_PATH_FLAG_NONE);
976 dpo = fib_entry_contribute_ip_forwarding(fei);
977 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
978 FIB_TEST(DPO_ADJACENCY_INCOMPLETE == dpo1->dpoi_type,
979 "11.11.11.11/32 via incomplete adj");
981 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
983 &pfx_10_10_10_1_s_32.fp_addr,
984 tm->hw[0]->sw_if_index);
985 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
986 adj = adj_get(ai_01);
987 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
988 "adj is incomplete");
989 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
990 &adj->sub_type.nbr.next_hop)),
991 "adj nbr next-hop ok");
993 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
994 fib_test_build_rewrite(eth_addr));
995 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
997 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_1_s_32.fp_addr,
998 &adj->sub_type.nbr.next_hop)),
999 "adj nbr next-hop ok");
1000 ai = fib_entry_get_adj(fei);
1001 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
1003 dpo = fib_entry_contribute_ip_forwarding(fei);
1004 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1005 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type,
1006 "11.11.11.11/32 via complete adj");
1007 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1008 tm->hw[0]->sw_if_index),
1009 "RPF list for adj-fib contains adj");
1011 ai_12_12_12_12 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1014 tm->hw[1]->sw_if_index);
1015 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_12_12_12_12), "adj created");
1016 adj = adj_get(ai_12_12_12_12);
1017 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1018 "adj is incomplete");
1019 FIB_TEST((0 == ip46_address_cmp(&nh_12_12_12_12,
1020 &adj->sub_type.nbr.next_hop)),
1021 "adj nbr next-hop ok");
1022 adj_nbr_update_rewrite(ai_12_12_12_12, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1023 fib_test_build_rewrite(eth_addr));
1024 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1030 fei = fib_table_entry_path_add(fib_index,
1031 &pfx_10_10_10_1_s_32,
1033 FIB_ENTRY_FLAG_ATTACHED,
1035 &pfx_10_10_10_1_s_32.fp_addr,
1036 tm->hw[0]->sw_if_index,
1037 ~0, // invalid fib index
1040 FIB_ROUTE_PATH_FLAG_NONE);
1041 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
1042 "Flags set on adj-fib");
1043 ai = fib_entry_get_adj(fei);
1044 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj, %d", ai);
1046 fib_table_entry_path_remove(fib_index,
1047 &pfx_11_11_11_11_s_32,
1050 &pfx_10_10_10_1_s_32.fp_addr,
1051 tm->hw[0]->sw_if_index,
1052 ~0, // invalid fib index
1054 FIB_ROUTE_PATH_FLAG_NONE);
1058 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
1060 &pfx_10_10_10_2_s_32.fp_addr,
1061 tm->hw[0]->sw_if_index);
1062 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
1063 adj = adj_get(ai_02);
1064 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
1065 "adj is incomplete");
1066 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1067 &adj->sub_type.nbr.next_hop)),
1068 "adj nbr next-hop ok");
1070 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
1071 fib_test_build_rewrite(eth_addr));
1072 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
1074 FIB_TEST((0 == ip46_address_cmp(&pfx_10_10_10_2_s_32.fp_addr,
1075 &adj->sub_type.nbr.next_hop)),
1076 "adj nbr next-hop ok");
1077 FIB_TEST((ai_01 != ai_02), "ADJs are different");
1079 fib_table_entry_path_add(fib_index,
1080 &pfx_10_10_10_2_s_32,
1082 FIB_ENTRY_FLAG_ATTACHED,
1084 &pfx_10_10_10_2_s_32.fp_addr,
1085 tm->hw[0]->sw_if_index,
1086 ~0, // invalid fib index
1089 FIB_ROUTE_PATH_FLAG_NONE);
1091 fei = fib_table_lookup(fib_index, &pfx_10_10_10_2_s_32);
1092 ai = fib_entry_get_adj(fei);
1093 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
1096 * +2 adj-fibs, and their non-shared path-lists
1098 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
1099 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
1100 fib_path_list_pool_size());
1101 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
1102 fib_entry_pool_size());
1105 * Add 2 routes via the first ADJ. ensure path-list sharing
1107 fib_prefix_t pfx_1_1_1_1_s_32 = {
1109 .fp_proto = FIB_PROTOCOL_IP4,
1112 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1116 fib_table_entry_path_add(fib_index,
1119 FIB_ENTRY_FLAG_NONE,
1122 tm->hw[0]->sw_if_index,
1123 ~0, // invalid fib index
1126 FIB_ROUTE_PATH_FLAG_NONE);
1127 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
1128 ai = fib_entry_get_adj(fei);
1129 FIB_TEST((ai_01 == ai), "1.1.1.1 resolves via 10.10.10.1");
1132 * +1 entry and a shared path-list
1134 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1135 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1136 fib_path_list_pool_size());
1137 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
1138 fib_entry_pool_size());
1141 fib_prefix_t pfx_1_1_2_0_s_24 = {
1143 .fp_proto = FIB_PROTOCOL_IP4,
1145 .ip4.as_u32 = clib_host_to_net_u32(0x01010200),
1149 fib_table_entry_path_add(fib_index,
1152 FIB_ENTRY_FLAG_NONE,
1155 tm->hw[0]->sw_if_index,
1156 ~0, // invalid fib index
1159 FIB_ROUTE_PATH_FLAG_NONE);
1160 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1161 ai = fib_entry_get_adj(fei);
1162 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1167 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is empty");
1168 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1169 fib_path_list_pool_size());
1170 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1171 fib_entry_pool_size());
1174 * modify 1.1.2.0/24 to use multipath.
1176 fib_table_entry_path_add(fib_index,
1179 FIB_ENTRY_FLAG_NONE,
1182 tm->hw[0]->sw_if_index,
1183 ~0, // invalid fib index
1186 FIB_ROUTE_PATH_FLAG_NONE);
1187 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1188 dpo = fib_entry_contribute_ip_forwarding(fei);
1189 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1190 1, tm->hw[0]->sw_if_index),
1191 "RPF list for 1.1.2.0/24 contains both adjs");
1193 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 0);
1194 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1195 FIB_TEST((ai_01 == dpo1->dpoi_index),
1196 "1.1.2.0/24 bucket 0 resolves via 10.10.10.1 (%d=%d)",
1197 ai_01, dpo1->dpoi_index);
1199 dpo1 = load_balance_get_bucket(dpo->dpoi_index, 1);
1200 FIB_TEST(DPO_ADJACENCY == dpo1->dpoi_type, "type is %d", dpo1->dpoi_type);
1201 FIB_TEST((ai_02 == dpo1->dpoi_index),
1202 "1.1.2.0/24 bucket 1 resolves via 10.10.10.2");
1205 * +1 shared-pathlist
1207 FIB_TEST((2 == fib_path_list_db_size()), "path list DB is empty");
1208 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1209 fib_path_list_pool_size());
1210 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1211 fib_entry_pool_size());
1216 fib_table_entry_path_remove(fib_index,
1221 tm->hw[0]->sw_if_index,
1224 FIB_ROUTE_PATH_FLAG_NONE);
1225 fei = fib_table_lookup(fib_index, &pfx_1_1_2_0_s_24);
1226 dpo = fib_entry_contribute_ip_forwarding(fei);
1227 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1228 1, tm->hw[0]->sw_if_index),
1229 "RPF list for 1.1.2.0/24 contains one adj");
1231 ai = fib_entry_get_adj(fei);
1232 FIB_TEST((ai_01 == ai), "1.1.2.0/24 resolves via 10.10.10.1");
1235 * +1 shared-pathlist
1237 FIB_TEST((1 == fib_path_list_db_size()), "path list DB is %d",
1238 fib_path_list_db_size());
1239 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
1240 fib_path_list_pool_size());
1241 FIB_TEST((ENBR+6 == fib_entry_pool_size()), "entry pool size is %d",
1242 fib_entry_pool_size());
1245 * Add 2 recursive routes:
1246 * 100.100.100.100/32 via 1.1.1.1/32 => the via entry is installed.
1247 * 100.100.100.101/32 via 1.1.1.1/32 => the via entry is installed.
1249 fib_prefix_t bgp_100_pfx = {
1251 .fp_proto = FIB_PROTOCOL_IP4,
1253 /* 100.100.100.100/32 */
1254 .ip4.as_u32 = clib_host_to_net_u32(0x64646464),
1258 ip46_address_t nh_1_1_1_1 = {
1259 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
1262 fei = fib_table_entry_path_add(fib_index,
1265 FIB_ENTRY_FLAG_NONE,
1268 ~0, // no index provided.
1269 fib_index, // nexthop in same fib as route
1272 FIB_ROUTE_PATH_FLAG_NONE);
1274 FIB_TEST_REC_FORW(&bgp_100_pfx, &pfx_1_1_1_1_s_32, 0);
1275 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1276 tm->hw[0]->sw_if_index),
1277 "RPF list for adj-fib contains adj");
1280 * +1 entry and +1 shared-path-list
1282 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1283 fib_path_list_db_size());
1284 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1285 fib_path_list_pool_size());
1286 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
1287 fib_entry_pool_size());
1289 fib_prefix_t bgp_101_pfx = {
1291 .fp_proto = FIB_PROTOCOL_IP4,
1293 /* 100.100.100.101/32 */
1294 .ip4.as_u32 = clib_host_to_net_u32(0x64646465),
1298 fib_table_entry_path_add(fib_index,
1301 FIB_ENTRY_FLAG_NONE,
1304 ~0, // no index provided.
1305 fib_index, // nexthop in same fib as route
1308 FIB_ROUTE_PATH_FLAG_NONE);
1310 FIB_TEST_REC_FORW(&bgp_101_pfx, &pfx_1_1_1_1_s_32, 0);
1311 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
1312 tm->hw[0]->sw_if_index),
1313 "RPF list for adj-fib contains adj");
1316 * +1 entry, but the recursive path-list is shared.
1318 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
1319 fib_path_list_db_size());
1320 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
1321 fib_path_list_pool_size());
1322 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
1323 fib_entry_pool_size());
1326 * An special route; one where the user (me) provides the
1327 * adjacency through which the route will resovle by setting the flags
1329 fib_prefix_t ex_pfx = {
1331 .fp_proto = FIB_PROTOCOL_IP4,
1334 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
1338 fib_table_entry_special_add(fib_index,
1341 FIB_ENTRY_FLAG_LOCAL);
1342 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1343 dpo = fib_entry_contribute_ip_forwarding(fei);
1344 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
1345 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
1346 "local interface adj is local");
1348 fib_table_entry_special_remove(fib_index,
1350 FIB_SOURCE_SPECIAL);
1351 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1352 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1353 "Exclusive reoute removed");
1356 * An EXCLUSIVE route; one where the user (me) provides the exclusive
1357 * adjacency through which the route will resovle
1359 dpo_id_t ex_dpo = DPO_INVALID;
1361 lookup_dpo_add_or_lock_w_fib_index(fib_index,
1364 LOOKUP_INPUT_DST_ADDR,
1365 LOOKUP_TABLE_FROM_CONFIG,
1368 fib_table_entry_special_dpo_add(fib_index,
1371 FIB_ENTRY_FLAG_EXCLUSIVE,
1373 fei = fib_table_lookup_exact_match(fib_index, &ex_pfx);
1374 dpo = fib_entry_contribute_ip_forwarding(fei);
1375 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1376 "exclusive remote uses lookup DPO");
1379 * update the exclusive to use a different DPO
1381 ip_null_dpo_add_and_lock(DPO_PROTO_IP4,
1382 IP_NULL_ACTION_SEND_ICMP_UNREACH,
1384 fib_table_entry_special_dpo_update(fib_index,
1387 FIB_ENTRY_FLAG_EXCLUSIVE,
1389 dpo = fib_entry_contribute_ip_forwarding(fei);
1390 FIB_TEST(!dpo_cmp(&ex_dpo, load_balance_get_bucket(dpo->dpoi_index, 0)),
1391 "exclusive remote uses now uses NULL DPO");
1393 fib_table_entry_special_remove(fib_index,
1395 FIB_SOURCE_SPECIAL);
1396 FIB_TEST(FIB_NODE_INDEX_INVALID ==
1397 fib_table_lookup_exact_match(fib_index, &ex_pfx),
1398 "Exclusive reoute removed");
1402 * Add a recursive route:
1403 * 200.200.200.200/32 via 1.1.1.2/32 => the via entry is NOT installed.
1405 fib_prefix_t bgp_200_pfx = {
1407 .fp_proto = FIB_PROTOCOL_IP4,
1409 /* 200.200.200.200/32 */
1410 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c8),
1414 fib_prefix_t pfx_1_1_1_2_s_32 = {
1416 .fp_proto = FIB_PROTOCOL_IP4,
1418 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
1422 fei = fib_table_entry_path_add(fib_index,
1425 FIB_ENTRY_FLAG_NONE,
1427 &pfx_1_1_1_2_s_32.fp_addr,
1428 ~0, // no index provided.
1429 fib_index, // nexthop in same fib as route
1432 FIB_ROUTE_PATH_FLAG_NONE);
1434 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
1435 "Recursive via unresolved is drop");
1438 * the adj should be recursive via drop, since the route resolves via
1439 * the default route, which is itself a DROP
1441 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
1442 dpo1 = fib_entry_contribute_ip_forwarding(fei);
1443 FIB_TEST(load_balance_is_drop(dpo1), "1.1.1.2/32 is drop");
1444 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
1445 "RPF list for 1.1.1.2/32 contains 0 adjs");
1448 * +2 entry and +1 shared-path-list
1450 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
1451 fib_path_list_db_size());
1452 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
1453 fib_path_list_pool_size());
1454 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
1455 fib_entry_pool_size());
1458 * Unequal Cost load-balance. 3:1 ratio. fits in a 4 bucket LB
1459 * The paths are sort by NH first. in this case the the path with greater
1460 * weight is first in the set. This ordering is to test the RPF sort|uniq logic
1462 fib_prefix_t pfx_1_2_3_4_s_32 = {
1464 .fp_proto = FIB_PROTOCOL_IP4,
1466 .ip4.as_u32 = clib_host_to_net_u32(0x01020304),
1469 fib_table_entry_path_add(fib_index,
1472 FIB_ENTRY_FLAG_NONE,
1475 tm->hw[0]->sw_if_index,
1479 FIB_ROUTE_PATH_FLAG_NONE);
1480 fei = fib_table_entry_path_add(fib_index,
1483 FIB_ENTRY_FLAG_NONE,
1486 tm->hw[1]->sw_if_index,
1490 FIB_ROUTE_PATH_FLAG_NONE);
1492 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.4/32 presnet");
1493 dpo = fib_entry_contribute_ip_forwarding(fei);
1494 lb = load_balance_get(dpo->dpoi_index);
1495 FIB_TEST((lb->lb_n_buckets == 4),
1496 "1.2.3.4/32 LB has %d bucket",
1499 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 0, ai_12_12_12_12);
1500 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 1, ai_12_12_12_12);
1501 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 2, ai_12_12_12_12);
1502 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_4_s_32, 3, ai_01);
1504 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1505 tm->hw[0]->sw_if_index,
1506 tm->hw[1]->sw_if_index),
1507 "RPF list for 1.2.3.4/32 contains both adjs");
1511 * Unequal Cost load-balance. 4:1 ratio.
1512 * fits in a 16 bucket LB with ratio 13:3
1514 fib_prefix_t pfx_1_2_3_5_s_32 = {
1516 .fp_proto = FIB_PROTOCOL_IP4,
1518 .ip4.as_u32 = clib_host_to_net_u32(0x01020305),
1521 fib_table_entry_path_add(fib_index,
1524 FIB_ENTRY_FLAG_NONE,
1527 tm->hw[1]->sw_if_index,
1531 FIB_ROUTE_PATH_FLAG_NONE);
1532 fei = fib_table_entry_path_add(fib_index,
1535 FIB_ENTRY_FLAG_NONE,
1538 tm->hw[0]->sw_if_index,
1542 FIB_ROUTE_PATH_FLAG_NONE);
1544 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.2.3.5/32 presnet");
1545 dpo = fib_entry_contribute_ip_forwarding(fei);
1546 lb = load_balance_get(dpo->dpoi_index);
1547 FIB_TEST((lb->lb_n_buckets == 16),
1548 "1.2.3.5/32 LB has %d bucket",
1551 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 0, ai_01);
1552 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 1, ai_01);
1553 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 2, ai_01);
1554 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 3, ai_01);
1555 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 4, ai_01);
1556 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 5, ai_01);
1557 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 6, ai_01);
1558 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 7, ai_01);
1559 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 8, ai_01);
1560 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 9, ai_01);
1561 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 10, ai_01);
1562 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 11, ai_01);
1563 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 12, ai_01);
1564 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 13, ai_12_12_12_12);
1565 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 14, ai_12_12_12_12);
1566 FIB_TEST_LB_BUCKET_VIA_ADJ(&pfx_1_2_3_5_s_32, 15, ai_12_12_12_12);
1568 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1569 tm->hw[0]->sw_if_index,
1570 tm->hw[1]->sw_if_index),
1571 "RPF list for 1.2.3.4/32 contains both adjs");
1574 * Test UCMP with a large weight skew - this produces load-balance objects with large
1575 * numbers of buckets to accommodate the skew. By updating said load-balances we are
1576 * laso testing the LB in placce modify code when number of buckets is large.
1578 fib_prefix_t pfx_6_6_6_6_s_32 = {
1580 .fp_proto = FIB_PROTOCOL_IP4,
1583 .ip4.as_u32 = clib_host_to_net_u32(0x06060606),
1586 fib_test_lb_bucket_t ip_o_10_10_10_1 = {
1592 fib_test_lb_bucket_t ip_o_10_10_10_2 = {
1598 fib_test_lb_bucket_t ip_6_6_6_6_o_12_12_12_12 = {
1601 .adj = ai_12_12_12_12,
1604 fib_table_entry_update_one_path(fib_index,
1607 FIB_ENTRY_FLAG_NONE,
1610 tm->hw[0]->sw_if_index,
1611 ~0, // invalid fib index
1614 FIB_ROUTE_PATH_FLAG_NONE);
1616 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1617 FIB_TEST(fib_test_validate_entry(fei,
1618 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1621 "6.6.6.6/32 via 10.10.10.1");
1623 fib_table_entry_path_add(fib_index,
1626 FIB_ENTRY_FLAG_NONE,
1629 tm->hw[0]->sw_if_index,
1630 ~0, // invalid fib index
1633 FIB_ROUTE_PATH_FLAG_NONE);
1635 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1636 FIB_TEST(fib_test_validate_entry(fei,
1637 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1703 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1705 fib_table_entry_path_add(fib_index,
1708 FIB_ENTRY_FLAG_NONE,
1711 tm->hw[1]->sw_if_index,
1712 ~0, // invalid fib index
1715 FIB_ROUTE_PATH_FLAG_NONE);
1717 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1718 FIB_TEST(fib_test_validate_entry(fei,
1719 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1786 &ip_6_6_6_6_o_12_12_12_12,
1787 &ip_6_6_6_6_o_12_12_12_12,
1788 &ip_6_6_6_6_o_12_12_12_12,
1789 &ip_6_6_6_6_o_12_12_12_12,
1790 &ip_6_6_6_6_o_12_12_12_12,
1791 &ip_6_6_6_6_o_12_12_12_12,
1792 &ip_6_6_6_6_o_12_12_12_12,
1793 &ip_6_6_6_6_o_12_12_12_12,
1794 &ip_6_6_6_6_o_12_12_12_12,
1795 &ip_6_6_6_6_o_12_12_12_12,
1796 &ip_6_6_6_6_o_12_12_12_12,
1797 &ip_6_6_6_6_o_12_12_12_12,
1798 &ip_6_6_6_6_o_12_12_12_12,
1799 &ip_6_6_6_6_o_12_12_12_12,
1800 &ip_6_6_6_6_o_12_12_12_12,
1801 &ip_6_6_6_6_o_12_12_12_12,
1802 &ip_6_6_6_6_o_12_12_12_12,
1803 &ip_6_6_6_6_o_12_12_12_12,
1804 &ip_6_6_6_6_o_12_12_12_12,
1805 &ip_6_6_6_6_o_12_12_12_12,
1806 &ip_6_6_6_6_o_12_12_12_12,
1807 &ip_6_6_6_6_o_12_12_12_12,
1808 &ip_6_6_6_6_o_12_12_12_12,
1809 &ip_6_6_6_6_o_12_12_12_12,
1810 &ip_6_6_6_6_o_12_12_12_12,
1811 &ip_6_6_6_6_o_12_12_12_12,
1812 &ip_6_6_6_6_o_12_12_12_12,
1813 &ip_6_6_6_6_o_12_12_12_12,
1814 &ip_6_6_6_6_o_12_12_12_12,
1815 &ip_6_6_6_6_o_12_12_12_12,
1816 &ip_6_6_6_6_o_12_12_12_12,
1817 &ip_6_6_6_6_o_12_12_12_12,
1818 &ip_6_6_6_6_o_12_12_12_12,
1819 &ip_6_6_6_6_o_12_12_12_12,
1820 &ip_6_6_6_6_o_12_12_12_12,
1821 &ip_6_6_6_6_o_12_12_12_12,
1822 &ip_6_6_6_6_o_12_12_12_12,
1823 &ip_6_6_6_6_o_12_12_12_12,
1824 &ip_6_6_6_6_o_12_12_12_12,
1825 &ip_6_6_6_6_o_12_12_12_12,
1826 &ip_6_6_6_6_o_12_12_12_12,
1827 &ip_6_6_6_6_o_12_12_12_12,
1828 &ip_6_6_6_6_o_12_12_12_12,
1829 &ip_6_6_6_6_o_12_12_12_12,
1830 &ip_6_6_6_6_o_12_12_12_12,
1831 &ip_6_6_6_6_o_12_12_12_12,
1832 &ip_6_6_6_6_o_12_12_12_12,
1833 &ip_6_6_6_6_o_12_12_12_12,
1834 &ip_6_6_6_6_o_12_12_12_12,
1835 &ip_6_6_6_6_o_12_12_12_12,
1836 &ip_6_6_6_6_o_12_12_12_12,
1837 &ip_6_6_6_6_o_12_12_12_12,
1838 &ip_6_6_6_6_o_12_12_12_12,
1839 &ip_6_6_6_6_o_12_12_12_12,
1840 &ip_6_6_6_6_o_12_12_12_12,
1841 &ip_6_6_6_6_o_12_12_12_12,
1842 &ip_6_6_6_6_o_12_12_12_12,
1843 &ip_6_6_6_6_o_12_12_12_12,
1844 &ip_6_6_6_6_o_12_12_12_12,
1845 &ip_6_6_6_6_o_12_12_12_12,
1846 &ip_6_6_6_6_o_12_12_12_12,
1847 &ip_6_6_6_6_o_12_12_12_12,
1848 &ip_6_6_6_6_o_12_12_12_12),
1849 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1851 fib_table_entry_path_remove(fib_index,
1856 tm->hw[1]->sw_if_index,
1857 ~0, // invalid fib index
1859 FIB_ROUTE_PATH_FLAG_NONE);
1861 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1862 FIB_TEST(fib_test_validate_entry(fei,
1863 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1929 "6.6.6.6/32 via 10.10.10.1 and 10.10.10.2 in 63:1 ratio");
1931 fib_table_entry_path_remove(fib_index,
1936 tm->hw[0]->sw_if_index,
1937 ~0, // invalid fib index
1939 FIB_ROUTE_PATH_FLAG_NONE);
1941 fei = fib_table_lookup(fib_index, &pfx_6_6_6_6_s_32);
1942 FIB_TEST(fib_test_validate_entry(fei,
1943 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
1946 "6.6.6.6/32 via 10.10.10.1");
1948 fib_table_entry_delete(fib_index, &pfx_6_6_6_6_s_32, FIB_SOURCE_API);
1951 * A recursive via the two unequal cost entries
1953 fib_prefix_t bgp_44_s_32 = {
1955 .fp_proto = FIB_PROTOCOL_IP4,
1957 /* 200.200.200.201/32 */
1958 .ip4.as_u32 = clib_host_to_net_u32(0x44444444),
1961 fei = fib_table_entry_path_add(fib_index,
1964 FIB_ENTRY_FLAG_NONE,
1966 &pfx_1_2_3_4_s_32.fp_addr,
1971 FIB_ROUTE_PATH_FLAG_NONE);
1972 fei = fib_table_entry_path_add(fib_index,
1975 FIB_ENTRY_FLAG_NONE,
1977 &pfx_1_2_3_5_s_32.fp_addr,
1982 FIB_ROUTE_PATH_FLAG_NONE);
1984 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_4_s_32, 0);
1985 FIB_TEST_REC_FORW(&bgp_44_s_32, &pfx_1_2_3_5_s_32, 1);
1986 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 2,
1987 tm->hw[0]->sw_if_index,
1988 tm->hw[1]->sw_if_index),
1989 "RPF list for 1.2.3.4/32 contains both adjs");
1992 * test the uRPF check functions
1994 dpo_id_t dpo_44 = DPO_INVALID;
1997 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
1998 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
2000 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
2001 "uRPF check for 68.68.68.68/32 on %d OK",
2002 tm->hw[0]->sw_if_index);
2003 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
2004 "uRPF check for 68.68.68.68/32 on %d OK",
2005 tm->hw[1]->sw_if_index);
2006 FIB_TEST(!fib_urpf_check(urpfi, 99),
2007 "uRPF check for 68.68.68.68/32 on 99 not-OK",
2011 fib_table_entry_delete(fib_index,
2014 fib_table_entry_delete(fib_index,
2017 fib_table_entry_delete(fib_index,
2022 * Add a recursive route:
2023 * 200.200.200.201/32 via 1.1.1.200/32 => the via entry is NOT installed.
2025 fib_prefix_t bgp_201_pfx = {
2027 .fp_proto = FIB_PROTOCOL_IP4,
2029 /* 200.200.200.201/32 */
2030 .ip4.as_u32 = clib_host_to_net_u32(0xc8c8c8c9),
2034 fib_prefix_t pfx_1_1_1_200_s_32 = {
2036 .fp_proto = FIB_PROTOCOL_IP4,
2038 .ip4.as_u32 = clib_host_to_net_u32(0x010101c8),
2042 fei = fib_table_entry_path_add(fib_index,
2045 FIB_ENTRY_FLAG_NONE,
2047 &pfx_1_1_1_200_s_32.fp_addr,
2048 ~0, // no index provided.
2049 fib_index, // nexthop in same fib as route
2052 FIB_ROUTE_PATH_FLAG_NONE);
2054 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2055 "Recursive via unresolved is drop");
2057 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2058 FIB_TEST((FIB_ENTRY_FLAG_NONE == fib_entry_get_flags(fei)),
2059 "Flags set on RR via non-attached");
2060 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
2061 "RPF list for BGP route empty");
2064 * +2 entry (BGP & RR) and +1 shared-path-list
2066 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2067 fib_path_list_db_size());
2068 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2069 fib_path_list_pool_size());
2070 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2071 fib_entry_pool_size());
2074 * insert a route that covers the missing 1.1.1.2/32. we epxect
2075 * 200.200.200.200/32 and 200.200.200.201/32 to resolve through it.
2077 fib_prefix_t pfx_1_1_1_0_s_24 = {
2079 .fp_proto = FIB_PROTOCOL_IP4,
2082 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2086 fib_table_entry_path_add(fib_index,
2089 FIB_ENTRY_FLAG_NONE,
2092 tm->hw[0]->sw_if_index,
2093 ~0, // invalid fib index
2096 FIB_ROUTE_PATH_FLAG_NONE);
2097 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24);
2098 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2099 ai = fib_entry_get_adj(fei);
2100 FIB_TEST((ai_01 == ai), "1.1.1.0/24 resolves via 10.10.10.1");
2101 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2102 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2103 ai = fib_entry_get_adj(fei);
2104 FIB_TEST((ai_01 == ai), "1.1.1.2/32 resolves via 10.10.10.1");
2105 fei = fib_table_lookup(fib_index, &pfx_1_1_1_200_s_32);
2106 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2107 ai = fib_entry_get_adj(fei);
2108 FIB_TEST((ai_01 == ai), "1.1.1.200/24 resolves via 10.10.10.1");
2111 * +1 entry. 1.1.1.1/32 already uses 10.10.10.1 so no new pah-list
2113 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2114 fib_path_list_db_size());
2115 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2116 fib_path_list_pool_size());
2117 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2118 fib_entry_pool_size());
2121 * the recursive adj for 200.200.200.200 should be updated.
2123 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2124 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2125 fei = fib_table_lookup(fib_index, &bgp_200_pfx);
2126 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1,
2127 tm->hw[0]->sw_if_index),
2128 "RPF list for BGP route has itf index 0");
2131 * insert a more specific route than 1.1.1.0/24 that also covers the
2132 * missing 1.1.1.2/32, but not 1.1.1.200/32. we epxect
2133 * 200.200.200.200 to resolve through it.
2135 fib_prefix_t pfx_1_1_1_0_s_28 = {
2137 .fp_proto = FIB_PROTOCOL_IP4,
2140 .ip4.as_u32 = clib_host_to_net_u32(0x01010100),
2144 fib_table_entry_path_add(fib_index,
2147 FIB_ENTRY_FLAG_NONE,
2150 tm->hw[0]->sw_if_index,
2151 ~0, // invalid fib index
2154 FIB_ROUTE_PATH_FLAG_NONE);
2155 fei = fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28);
2156 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2157 ai = fib_entry_get_adj(fei);
2158 FIB_TEST((ai_02 == ai), "1.1.1.0/24 resolves via 10.10.10.2");
2161 * +1 entry. +1 shared path-list
2163 FIB_TEST((5 == fib_path_list_db_size()), "path list DB population:%d",
2164 fib_path_list_db_size());
2165 FIB_TEST((PNBR+9 == fib_path_list_pool_size()), "path list pool size is %d",
2166 fib_path_list_pool_size());
2167 FIB_TEST((ENBR+14 == fib_entry_pool_size()), "entry pool size is %d",
2168 fib_entry_pool_size());
2171 * the recursive adj for 200.200.200.200 should be updated.
2172 * 200.200.200.201 remains unchanged.
2174 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2175 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2178 * remove this /28. 200.200.200.200/32 should revert back to via 1.1.1.0/24
2180 fib_table_entry_path_remove(fib_index,
2185 tm->hw[0]->sw_if_index,
2188 FIB_ROUTE_PATH_FLAG_NONE);
2189 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28) ==
2190 FIB_NODE_INDEX_INVALID),
2191 "1.1.1.0/28 removed");
2192 FIB_TEST((fib_table_lookup(fib_index, &pfx_1_1_1_0_s_28) ==
2193 fib_table_lookup(fib_index, &pfx_1_1_1_0_s_24)),
2194 "1.1.1.0/28 lookup via /24");
2195 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_200_s_32, 0);
2196 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2199 * -1 entry. -1 shared path-list
2201 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2202 fib_path_list_db_size());
2203 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2204 fib_path_list_pool_size());
2205 FIB_TEST((ENBR+13 == fib_entry_pool_size()), "entry pool size is %d",
2206 fib_entry_pool_size());
2209 * remove 1.1.1.0/24. 200.200.200.200/32 should revert back to via 0.0.0.0/0
2211 fib_table_entry_path_remove(fib_index,
2216 tm->hw[0]->sw_if_index,
2219 FIB_ROUTE_PATH_FLAG_NONE);
2220 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_24) ==
2221 FIB_NODE_INDEX_INVALID),
2222 "1.1.1.0/24 removed");
2224 fei = fib_table_lookup(fib_index, &pfx_1_1_1_2_s_32);
2225 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2226 "1.1.1.2/32 route is DROP");
2227 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32);
2228 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2229 "1.1.1.200/32 route is DROP");
2231 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2232 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2234 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2235 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2241 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2242 fib_path_list_db_size());
2243 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2244 fib_path_list_pool_size());
2245 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2246 fib_entry_pool_size());
2249 * insert the missing 1.1.1.2/32
2251 fei = fib_table_entry_path_add(fib_index,
2254 FIB_ENTRY_FLAG_NONE,
2257 tm->hw[0]->sw_if_index,
2258 ~0, // invalid fib index
2261 FIB_ROUTE_PATH_FLAG_NONE);
2262 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2263 ai = fib_entry_get_adj(fei);
2264 FIB_TEST((ai = ai_01), "1.1.1.2/32 resolves via 10.10.10.1");
2266 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2267 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2269 FIB_TEST_REC_FORW(&bgp_200_pfx, &pfx_1_1_1_2_s_32, 0);
2272 * no change. 1.1.1.2/32 was already there RR sourced.
2274 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2275 fib_path_list_db_size());
2276 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2277 fib_path_list_pool_size());
2278 FIB_TEST((ENBR+12 == fib_entry_pool_size()), "entry pool size is %d",
2279 fib_entry_pool_size());
2282 * give 201 a resolved path.
2283 * it now has the unresolved 1.1.1.200 and the resolved 1.1.1.2,
2284 * only the latter contributes forwarding.
2286 fei = fib_table_entry_path_add(fib_index,
2289 FIB_ENTRY_FLAG_NONE,
2291 &pfx_1_1_1_2_s_32.fp_addr,
2296 FIB_ROUTE_PATH_FLAG_NONE);
2297 FIB_TEST_REC_FORW(&bgp_201_pfx, &pfx_1_1_1_2_s_32, 0);
2298 fib_table_entry_path_remove(fib_index,
2302 &pfx_1_1_1_2_s_32.fp_addr,
2306 FIB_ROUTE_PATH_FLAG_NONE);
2309 * remove 200.200.200.201/32 which does not have a valid via FIB
2311 fib_table_entry_path_remove(fib_index,
2315 &pfx_1_1_1_200_s_32.fp_addr,
2316 ~0, // no index provided.
2319 FIB_ROUTE_PATH_FLAG_NONE);
2322 * -2 entries (BGP and RR). -1 shared path-list;
2324 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2325 FIB_NODE_INDEX_INVALID),
2326 "200.200.200.201/32 removed");
2327 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_200_s_32) ==
2328 FIB_NODE_INDEX_INVALID),
2329 "1.1.1.200/32 removed");
2331 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2332 fib_path_list_db_size());
2333 FIB_TEST((PNBR+7 == fib_path_list_pool_size()), "path list pool size is %d",
2334 fib_path_list_pool_size());
2335 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2336 fib_entry_pool_size());
2339 * remove 200.200.200.200/32 which does have a valid via FIB
2341 fib_table_entry_path_remove(fib_index,
2345 &pfx_1_1_1_2_s_32.fp_addr,
2346 ~0, // no index provided.
2349 FIB_ROUTE_PATH_FLAG_NONE);
2351 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2352 FIB_NODE_INDEX_INVALID),
2353 "200.200.200.200/32 removed");
2354 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32) !=
2355 FIB_NODE_INDEX_INVALID),
2356 "1.1.1.2/32 still present");
2359 * -1 entry (BGP, the RR source is also API sourced). -1 shared path-list;
2361 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2362 fib_path_list_db_size());
2363 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2364 fib_path_list_pool_size());
2365 FIB_TEST((ENBR+9 == fib_entry_pool_size()), "entry pool size is %d",
2366 fib_entry_pool_size());
2369 * A recursive prefix that has a 2 path load-balance.
2370 * It also shares a next-hop with other BGP prefixes and hence
2371 * test the ref counting of RR sourced prefixes and 2 level LB.
2373 const fib_prefix_t bgp_102 = {
2375 .fp_proto = FIB_PROTOCOL_IP4,
2377 /* 100.100.100.101/32 */
2378 .ip4.as_u32 = clib_host_to_net_u32(0x64646466),
2381 fib_table_entry_path_add(fib_index,
2384 FIB_ENTRY_FLAG_NONE,
2386 &pfx_1_1_1_1_s_32.fp_addr,
2387 ~0, // no index provided.
2388 fib_index, // same as route
2391 FIB_ROUTE_PATH_FLAG_NONE);
2392 fib_table_entry_path_add(fib_index,
2395 FIB_ENTRY_FLAG_NONE,
2397 &pfx_1_1_1_2_s_32.fp_addr,
2398 ~0, // no index provided.
2399 fib_index, // same as route's FIB
2402 FIB_ROUTE_PATH_FLAG_NONE);
2403 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2404 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "100.100.100.102/32 presnet");
2405 dpo = fib_entry_contribute_ip_forwarding(fei);
2407 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2408 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2409 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32);
2410 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2412 lb = load_balance_get(dpo->dpoi_index);
2413 FIB_TEST((lb->lb_n_buckets == 2), "Recursive LB has %d bucket", lb->lb_n_buckets);
2414 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2415 "First via 10.10.10.1");
2416 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 1)),
2417 "Second via 10.10.10.1");
2419 fib_table_entry_path_remove(fib_index,
2423 &pfx_1_1_1_1_s_32.fp_addr,
2424 ~0, // no index provided.
2425 fib_index, // same as route's FIB
2427 FIB_ROUTE_PATH_FLAG_NONE);
2428 fib_table_entry_path_remove(fib_index,
2432 &pfx_1_1_1_2_s_32.fp_addr,
2433 ~0, // no index provided.
2434 fib_index, // same as route's FIB
2436 FIB_ROUTE_PATH_FLAG_NONE);
2437 fei = fib_table_lookup_exact_match(fib_index, &bgp_102);
2438 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "100.100.100.102/32 removed");
2441 * remove the remaining recursives
2443 fib_table_entry_path_remove(fib_index,
2447 &pfx_1_1_1_1_s_32.fp_addr,
2448 ~0, // no index provided.
2449 fib_index, // same as route's FIB
2451 FIB_ROUTE_PATH_FLAG_NONE);
2452 fib_table_entry_path_remove(fib_index,
2456 &pfx_1_1_1_1_s_32.fp_addr,
2457 ~0, // no index provided.
2458 fib_index, // same as route's FIB
2460 FIB_ROUTE_PATH_FLAG_NONE);
2461 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_100_pfx) ==
2462 FIB_NODE_INDEX_INVALID),
2463 "100.100.100.100/32 removed");
2464 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_101_pfx) ==
2465 FIB_NODE_INDEX_INVALID),
2466 "100.100.100.101/32 removed");
2469 * -2 entry (2*BGP, the RR source is also API sourced). -1 shared path-list;
2471 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2472 fib_path_list_db_size());
2473 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2474 fib_path_list_pool_size());
2475 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2476 fib_entry_pool_size());
2479 * Add a recursive route via a connected cover, using an adj-fib that does exist
2481 fib_table_entry_path_add(fib_index,
2484 FIB_ENTRY_FLAG_NONE,
2487 ~0, // no index provided.
2488 fib_index, // Same as route's FIB
2491 FIB_ROUTE_PATH_FLAG_NONE);
2494 * +1 entry. +1 shared path-list (recursive via 10.10.10.1)
2496 FIB_TEST((2 == fib_path_list_db_size()), "path list DB population:%d",
2497 fib_path_list_db_size());
2498 FIB_TEST((PNBR+6 == fib_path_list_pool_size()), "path list pool size is %d",
2499 fib_path_list_pool_size());
2500 FIB_TEST((ENBR+8 == fib_entry_pool_size()), "entry pool size is %d",
2501 fib_entry_pool_size());
2503 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
2504 dpo = fib_entry_contribute_ip_forwarding(fei);
2506 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
2507 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2509 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2510 "200.200.200.200/32 is recursive via adj for 10.10.10.1");
2512 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED == fib_entry_get_flags(fei)),
2513 "Flags set on RR via existing attached");
2516 * Add a recursive route via a connected cover, using and adj-fib that does
2519 ip46_address_t nh_10_10_10_3 = {
2520 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
2522 fib_prefix_t pfx_10_10_10_3 = {
2524 .fp_proto = FIB_PROTOCOL_IP4,
2525 .fp_addr = nh_10_10_10_3,
2528 fib_table_entry_path_add(fib_index,
2531 FIB_ENTRY_FLAG_NONE,
2534 ~0, // no index provided.
2538 FIB_ROUTE_PATH_FLAG_NONE);
2541 * +2 entries (BGP and RR). +1 shared path-list (recursive via 10.10.10.3) and
2542 * one unshared non-recursive via 10.10.10.3
2544 FIB_TEST((3 == fib_path_list_db_size()), "path list DB population:%d",
2545 fib_path_list_db_size());
2546 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2547 fib_path_list_pool_size());
2548 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2549 fib_entry_pool_size());
2551 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
2554 tm->hw[0]->sw_if_index);
2556 fei = fib_table_lookup_exact_match(fib_index, &bgp_201_pfx);
2557 dpo = fib_entry_contribute_ip_forwarding(fei);
2558 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3);
2559 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2561 ai = fib_entry_get_adj(fei);
2562 FIB_TEST((ai == ai_03), "adj for 10.10.10.3/32 is via adj for 10.10.10.3");
2563 FIB_TEST(((FIB_ENTRY_FLAG_ATTACHED | FIB_ENTRY_FLAG_CONNECTED) ==
2564 fib_entry_get_flags(fei)),
2565 "Flags set on RR via non-existing attached");
2567 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 0)),
2568 "adj for 200.200.200.200/32 is recursive via adj for 10.10.10.3");
2573 * remove the recursives
2575 fib_table_entry_path_remove(fib_index,
2580 ~0, // no index provided.
2581 fib_index, // same as route's FIB
2583 FIB_ROUTE_PATH_FLAG_NONE);
2584 fib_table_entry_path_remove(fib_index,
2589 ~0, // no index provided.
2590 fib_index, // same as route's FIB
2592 FIB_ROUTE_PATH_FLAG_NONE);
2594 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_201_pfx) ==
2595 FIB_NODE_INDEX_INVALID),
2596 "200.200.200.201/32 removed");
2597 FIB_TEST((fib_table_lookup_exact_match(fib_index, &bgp_200_pfx) ==
2598 FIB_NODE_INDEX_INVALID),
2599 "200.200.200.200/32 removed");
2600 FIB_TEST((fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3) ==
2601 FIB_NODE_INDEX_INVALID),
2602 "10.10.10.3/32 removed");
2605 * -3 entries (2*BGP and RR). -2 shared path-list (recursive via 10.10.10.3 &
2606 * 10.10.10.1) and one unshared non-recursive via 10.10.10.3
2608 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2609 fib_path_list_db_size());
2610 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2611 fib_path_list_pool_size());
2612 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2613 fib_entry_pool_size());
2618 * Add 5.5.5.5/32 -> 5.5.5.6/32 -> 5.5.5.7/32 -> 5.5.5.5/32
2620 fib_prefix_t pfx_5_5_5_5_s_32 = {
2622 .fp_proto = FIB_PROTOCOL_IP4,
2624 .ip4.as_u32 = clib_host_to_net_u32(0x05050505),
2627 fib_prefix_t pfx_5_5_5_6_s_32 = {
2629 .fp_proto = FIB_PROTOCOL_IP4,
2631 .ip4.as_u32 = clib_host_to_net_u32(0x05050506),
2634 fib_prefix_t pfx_5_5_5_7_s_32 = {
2636 .fp_proto = FIB_PROTOCOL_IP4,
2638 .ip4.as_u32 = clib_host_to_net_u32(0x05050507),
2642 fib_table_entry_path_add(fib_index,
2645 FIB_ENTRY_FLAG_NONE,
2647 &pfx_5_5_5_6_s_32.fp_addr,
2648 ~0, // no index provided.
2652 FIB_ROUTE_PATH_FLAG_NONE);
2653 fib_table_entry_path_add(fib_index,
2656 FIB_ENTRY_FLAG_NONE,
2658 &pfx_5_5_5_7_s_32.fp_addr,
2659 ~0, // no index provided.
2663 FIB_ROUTE_PATH_FLAG_NONE);
2664 fib_table_entry_path_add(fib_index,
2667 FIB_ENTRY_FLAG_NONE,
2669 &pfx_5_5_5_5_s_32.fp_addr,
2670 ~0, // no index provided.
2674 FIB_ROUTE_PATH_FLAG_NONE);
2676 * +3 entries, +3 shared path-list
2678 FIB_TEST((4 == fib_path_list_db_size()), "path list DB population:%d",
2679 fib_path_list_db_size());
2680 FIB_TEST((PNBR+8 == fib_path_list_pool_size()), "path list pool size is %d",
2681 fib_path_list_pool_size());
2682 FIB_TEST((ENBR+10 == fib_entry_pool_size()), "entry pool size is %d",
2683 fib_entry_pool_size());
2686 * All the entries have only looped paths, so they are all drop
2688 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2689 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2690 "LB for 5.5.5.7/32 is via adj for DROP");
2691 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2692 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2693 "LB for 5.5.5.5/32 is via adj for DROP");
2694 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2695 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2696 "LB for 5.5.5.6/32 is via adj for DROP");
2699 * provide 5.5.5.6/32 with alternate path.
2700 * this will allow only 5.5.5.6/32 to forward with this path, the others
2701 * are still drop since the loop is still present.
2703 fib_table_entry_path_add(fib_index,
2706 FIB_ENTRY_FLAG_NONE,
2709 tm->hw[0]->sw_if_index,
2713 FIB_ROUTE_PATH_FLAG_NONE);
2715 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2716 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2718 lb = load_balance_get(dpo1->dpoi_index);
2719 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.6 LB has %d bucket", lb->lb_n_buckets);
2721 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2722 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2723 FIB_TEST((ai_01 == dpo2->dpoi_index),
2724 "5.5.5.6 bucket 0 resolves via 10.10.10.2");
2726 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2727 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2728 "LB for 5.5.5.7/32 is via adj for DROP");
2729 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2730 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2731 "LB for 5.5.5.5/32 is via adj for DROP");
2734 * remove the alternate path for 5.5.5.6/32
2737 fib_table_entry_path_remove(fib_index,
2742 tm->hw[0]->sw_if_index,
2745 FIB_ROUTE_PATH_FLAG_NONE);
2747 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2748 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2749 "LB for 5.5.5.7/32 is via adj for DROP");
2750 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2751 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2752 "LB for 5.5.5.5/32 is via adj for DROP");
2753 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2754 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2755 "LB for 5.5.5.6/32 is via adj for DROP");
2758 * break the loop by giving 5.5.5.5/32 a new set of paths
2759 * expect all to forward via this new path.
2761 fib_table_entry_update_one_path(fib_index,
2764 FIB_ENTRY_FLAG_NONE,
2767 tm->hw[0]->sw_if_index,
2768 ~0, // invalid fib index
2771 FIB_ROUTE_PATH_FLAG_NONE);
2773 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2774 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2775 lb = load_balance_get(dpo1->dpoi_index);
2776 FIB_TEST((lb->lb_n_buckets == 1), "5.5.5.5 LB has %d bucket", lb->lb_n_buckets);
2778 dpo2 = load_balance_get_bucket(dpo1->dpoi_index, 0);
2779 FIB_TEST(DPO_ADJACENCY == dpo2->dpoi_type, "type is %d", dpo2->dpoi_type);
2780 FIB_TEST((ai_01 == dpo2->dpoi_index),
2781 "5.5.5.5 bucket 0 resolves via 10.10.10.2");
2783 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_7_s_32);
2784 dpo2 = fib_entry_contribute_ip_forwarding(fei);
2786 lb = load_balance_get(dpo2->dpoi_index);
2787 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2788 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo2->dpoi_index, 0)),
2789 "5.5.5.5.7 via 5.5.5.5");
2791 fei = fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32);
2792 dpo1 = fib_entry_contribute_ip_forwarding(fei);
2794 lb = load_balance_get(dpo1->dpoi_index);
2795 FIB_TEST((lb->lb_n_buckets == 1), "Recursive LB has %d bucket", lb->lb_n_buckets);
2796 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
2797 "5.5.5.5.6 via 5.5.5.7");
2800 * revert back to the loop. so we can remove the prefixes with
2803 fib_table_entry_update_one_path(fib_index,
2806 FIB_ENTRY_FLAG_NONE,
2808 &pfx_5_5_5_6_s_32.fp_addr,
2809 ~0, // no index provided.
2813 FIB_ROUTE_PATH_FLAG_NONE);
2815 fei = fib_table_lookup(fib_index, &pfx_5_5_5_7_s_32);
2816 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2817 "LB for 5.5.5.7/32 is via adj for DROP");
2818 fei = fib_table_lookup(fib_index, &pfx_5_5_5_5_s_32);
2819 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2820 "LB for 5.5.5.5/32 is via adj for DROP");
2821 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2822 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2823 "LB for 5.5.5.6/32 is via adj for DROP");
2826 * remove all the 5.5.5.x/32 prefixes
2828 fib_table_entry_path_remove(fib_index,
2832 &pfx_5_5_5_6_s_32.fp_addr,
2833 ~0, // no index provided.
2834 fib_index, // same as route's FIB
2836 FIB_ROUTE_PATH_FLAG_NONE);
2837 fib_table_entry_path_remove(fib_index,
2841 &pfx_5_5_5_7_s_32.fp_addr,
2842 ~0, // no index provided.
2843 fib_index, // same as route's FIB
2845 FIB_ROUTE_PATH_FLAG_NONE);
2846 fib_table_entry_path_remove(fib_index,
2850 &pfx_5_5_5_5_s_32.fp_addr,
2851 ~0, // no index provided.
2852 fib_index, // same as route's FIB
2854 FIB_ROUTE_PATH_FLAG_NONE);
2855 fib_table_entry_path_remove(fib_index,
2860 ~0, // no index provided.
2861 fib_index, // same as route's FIB
2863 FIB_ROUTE_PATH_FLAG_NONE);
2866 * -3 entries, -3 shared path-list
2868 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2869 fib_path_list_db_size());
2870 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2871 fib_path_list_pool_size());
2872 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2873 fib_entry_pool_size());
2876 * Single level loop 5.5.5.5/32 via 5.5.5.5/32
2878 fib_table_entry_path_add(fib_index,
2881 FIB_ENTRY_FLAG_NONE,
2883 &pfx_5_5_5_6_s_32.fp_addr,
2884 ~0, // no index provided.
2888 FIB_ROUTE_PATH_FLAG_NONE);
2889 fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
2890 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
2891 "1-level 5.5.5.6/32 loop is via adj for DROP");
2893 fib_table_entry_path_remove(fib_index,
2897 &pfx_5_5_5_6_s_32.fp_addr,
2898 ~0, // no index provided.
2899 fib_index, // same as route's FIB
2901 FIB_ROUTE_PATH_FLAG_NONE);
2902 FIB_TEST(FIB_NODE_INDEX_INVALID ==
2903 fib_table_lookup_exact_match(fib_index, &pfx_5_5_5_6_s_32),
2904 "1-level 5.5.5.6/32 loop is removed");
2907 * A recursive route whose next-hop is covered by the prefix.
2908 * This would mean the via-fib, which inherits forwarding from its
2909 * cover, thus picks up forwarding from the prfix, which is via the
2910 * via-fib, and we have a loop.
2912 fib_prefix_t pfx_23_23_23_0_s_24 = {
2914 .fp_proto = FIB_PROTOCOL_IP4,
2916 .ip4.as_u32 = clib_host_to_net_u32(0x17171700),
2919 fib_prefix_t pfx_23_23_23_23_s_32 = {
2921 .fp_proto = FIB_PROTOCOL_IP4,
2923 .ip4.as_u32 = clib_host_to_net_u32(0x17171717),
2926 fei = fib_table_entry_path_add(fib_index,
2927 &pfx_23_23_23_0_s_24,
2929 FIB_ENTRY_FLAG_NONE,
2931 &pfx_23_23_23_23_s_32.fp_addr,
2936 FIB_ROUTE_PATH_FLAG_NONE);
2937 dpo = fib_entry_contribute_ip_forwarding(fei);
2938 FIB_TEST(load_balance_is_drop(dpo),
2939 "23.23.23.0/24 via covered is DROP");
2940 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
2943 * add-remove test. no change.
2945 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
2946 fib_path_list_db_size());
2947 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
2948 fib_path_list_pool_size());
2949 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
2950 fib_entry_pool_size());
2953 * Make the default route recursive via a unknown next-hop. Thus the
2954 * next hop's cover would be the default route
2956 fei = fib_table_entry_path_add(fib_index,
2959 FIB_ENTRY_FLAG_NONE,
2961 &pfx_23_23_23_23_s_32.fp_addr,
2966 FIB_ROUTE_PATH_FLAG_NONE);
2967 dpo = fib_entry_contribute_ip_forwarding(fei);
2968 FIB_TEST(load_balance_is_drop(dpo),
2969 "0.0.0.0.0/0 via is DROP");
2970 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
2971 "no resolving interface for looped 0.0.0.0/0");
2973 fei = fib_table_lookup_exact_match(fib_index, &pfx_23_23_23_23_s_32);
2974 dpo = fib_entry_contribute_ip_forwarding(fei);
2975 FIB_TEST(load_balance_is_drop(dpo),
2976 "23.23.23.23/32 via is DROP");
2977 FIB_TEST((fib_entry_get_resolving_interface(fei) == ~0),
2978 "no resolving interface for looped 23.23.23.23/32");
2980 fib_table_entry_delete(fib_index, &pfx_0_0_0_0_s_0, FIB_SOURCE_API);
2983 * A recursive route with recursion constraints.
2984 * 200.200.200.200/32 via 1.1.1.1 is recurse via host constrained
2986 fib_table_entry_path_add(fib_index,
2989 FIB_ENTRY_FLAG_NONE,
2996 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
2998 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
2999 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3001 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3002 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3004 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3005 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3008 * save the load-balance. we expect it to be inplace modified
3010 lb = load_balance_get(dpo1->dpoi_index);
3013 * add a covering prefix for the via fib that would otherwise serve
3014 * as the resolving route when the host is removed
3016 fib_table_entry_path_add(fib_index,
3019 FIB_ENTRY_FLAG_NONE,
3022 tm->hw[0]->sw_if_index,
3023 ~0, // invalid fib index
3026 FIB_ROUTE_PATH_FLAG_NONE);
3027 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28);
3028 ai = fib_entry_get_adj(fei);
3029 FIB_TEST((ai == ai_01),
3030 "adj for 1.1.1.0/28 is via adj for 1.1.1.1");
3033 * remove the host via FIB - expect the BGP prefix to be drop
3035 fib_table_entry_path_remove(fib_index,
3040 tm->hw[0]->sw_if_index,
3041 ~0, // invalid fib index
3043 FIB_ROUTE_PATH_FLAG_NONE);
3045 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3046 "adj for 200.200.200.200/32 is recursive via adj for DROP");
3049 * add the via-entry host reoute back. expect to resolve again
3051 fib_table_entry_path_add(fib_index,
3054 FIB_ENTRY_FLAG_NONE,
3057 tm->hw[0]->sw_if_index,
3058 ~0, // invalid fib index
3061 FIB_ROUTE_PATH_FLAG_NONE);
3062 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo1->dpoi_index, 0)),
3063 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3066 * add another path for the recursive. it will then have 2.
3068 fib_prefix_t pfx_1_1_1_3_s_32 = {
3070 .fp_proto = FIB_PROTOCOL_IP4,
3072 .ip4.as_u32 = clib_host_to_net_u32(0x01010103),
3075 fib_table_entry_path_add(fib_index,
3078 FIB_ENTRY_FLAG_NONE,
3081 tm->hw[0]->sw_if_index,
3082 ~0, // invalid fib index
3085 FIB_ROUTE_PATH_FLAG_NONE);
3087 fib_table_entry_path_add(fib_index,
3090 FIB_ENTRY_FLAG_NONE,
3092 &pfx_1_1_1_3_s_32.fp_addr,
3097 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3100 * add a bunch load more entries using this path combo so that we get
3101 * an LB-map created.
3104 fib_prefix_t bgp_78s[N_P];
3105 for (ii = 0; ii < N_P; ii++)
3107 bgp_78s[ii].fp_len = 32;
3108 bgp_78s[ii].fp_proto = FIB_PROTOCOL_IP4;
3109 bgp_78s[ii].fp_addr.ip4.as_u32 = clib_host_to_net_u32(0x4e000000+ii);
3112 fib_table_entry_path_add(fib_index,
3115 FIB_ENTRY_FLAG_NONE,
3117 &pfx_1_1_1_3_s_32.fp_addr,
3122 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3123 fib_table_entry_path_add(fib_index,
3126 FIB_ENTRY_FLAG_NONE,
3133 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3136 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3137 dpo = fib_entry_contribute_ip_forwarding(fei);
3139 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32);
3140 dpo2 = fib_entry_contribute_ip_forwarding(fei);
3141 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket(dpo->dpoi_index, 0)),
3142 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.1");
3143 fei = fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32);
3144 dpo1 = fib_entry_contribute_ip_forwarding(fei);
3145 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket(dpo->dpoi_index, 1)),
3146 "adj for 200.200.200.200/32 is recursive via adj for 1.1.1.3");
3149 * expect the lb-map used by the recursive's load-balance is using both buckets
3151 load_balance_map_t *lbm;
3154 lb = load_balance_get(dpo->dpoi_index);
3156 load_balance_map_lock(lbmi);
3157 lbm = load_balance_map_get(lbmi);
3159 FIB_TEST(lbm->lbm_buckets[0] == 0,
3160 "LB maps's bucket 0 is %d",
3161 lbm->lbm_buckets[0]);
3162 FIB_TEST(lbm->lbm_buckets[1] == 1,
3163 "LB maps's bucket 1 is %d",
3164 lbm->lbm_buckets[1]);
3167 * withdraw one of the /32 via-entrys.
3168 * that ECMP path will be unresolved and forwarding should continue on the
3169 * other available path. this is an iBGP PIC edge failover.
3170 * Test the forwarding changes without re-fetching the adj from the
3171 * recursive entry. this ensures its the same one that is updated; i.e. an
3174 fib_table_entry_path_remove(fib_index,
3179 tm->hw[0]->sw_if_index,
3180 ~0, // invalid fib index
3182 FIB_ROUTE_PATH_FLAG_NONE);
3184 /* suspend so the update walk kicks int */
3185 vlib_process_suspend(vlib_get_main(), 1e-5);
3187 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3188 FIB_TEST(!dpo_cmp(dpo, fib_entry_contribute_ip_forwarding(fei)),
3189 "post PIC 200.200.200.200/32 was inplace modified");
3191 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 0)),
3192 "post PIC adj for 200.200.200.200/32 is recursive"
3193 " via adj for 1.1.1.3");
3196 * the LB maps that was locked above should have been modified to remove
3197 * the path that was down, and thus its bucket points to a path that is
3200 FIB_TEST(lbm->lbm_buckets[0] == 1,
3201 "LB maps's bucket 0 is %d",
3202 lbm->lbm_buckets[0]);
3203 FIB_TEST(lbm->lbm_buckets[1] == 1,
3204 "LB maps's bucket 1 is %d",
3205 lbm->lbm_buckets[1]);
3207 load_balance_map_unlock(lbmi);
3210 * add it back. again
3212 fib_table_entry_path_add(fib_index,
3215 FIB_ENTRY_FLAG_NONE,
3218 tm->hw[0]->sw_if_index,
3219 ~0, // invalid fib index
3222 FIB_ROUTE_PATH_FLAG_NONE);
3224 /* suspend so the update walk kicks in */
3225 vlib_process_suspend(vlib_get_main(), 1e-5);
3227 FIB_TEST(!dpo_cmp(dpo2, load_balance_get_bucket_i(lb, 0)),
3228 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3229 "via adj for 1.1.1.1");
3230 FIB_TEST(!dpo_cmp(dpo1, load_balance_get_bucket_i(lb, 1)),
3231 "post PIC recovery adj for 200.200.200.200/32 is recursive "
3232 "via adj for 1.1.1.3");
3234 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3235 dpo = fib_entry_contribute_ip_forwarding(fei);
3236 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3237 "post PIC 200.200.200.200/32 was inplace modified");
3240 * add a 3rd path. this makes the LB 16 buckets.
3242 fib_table_entry_path_add(fib_index,
3245 FIB_ENTRY_FLAG_NONE,
3247 &pfx_1_1_1_2_s_32.fp_addr,
3252 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3253 for (ii = 0; ii < N_P; ii++)
3255 fib_table_entry_path_add(fib_index,
3258 FIB_ENTRY_FLAG_NONE,
3260 &pfx_1_1_1_2_s_32.fp_addr,
3265 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3268 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3269 dpo = fib_entry_contribute_ip_forwarding(fei);
3270 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3271 "200.200.200.200/32 was inplace modified for 3rd path");
3272 FIB_TEST(16 == lb->lb_n_buckets,
3273 "200.200.200.200/32 was inplace modified for 3rd path to 16 buckets");
3276 load_balance_map_lock(lbmi);
3277 lbm = load_balance_map_get(lbmi);
3279 for (ii = 0; ii < 16; ii++)
3281 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3282 "LB Map for 200.200.200.200/32 at %d is %d",
3283 ii, lbm->lbm_buckets[ii]);
3287 * trigger PIC by removing the first via-entry
3288 * the first 6 buckets of the map should map to the next 6
3290 fib_table_entry_path_remove(fib_index,
3295 tm->hw[0]->sw_if_index,
3298 FIB_ROUTE_PATH_FLAG_NONE);
3299 /* suspend so the update walk kicks int */
3300 vlib_process_suspend(vlib_get_main(), 1e-5);
3302 fei = fib_table_lookup_exact_match(fib_index, &bgp_200_pfx);
3303 dpo = fib_entry_contribute_ip_forwarding(fei);
3304 FIB_TEST(lb == load_balance_get(dpo->dpoi_index),
3305 "200.200.200.200/32 was inplace modified for 3rd path");
3306 FIB_TEST(2 == lb->lb_n_buckets,
3307 "200.200.200.200/32 was inplace modified for 3rd path remove to 2 buckets");
3309 for (ii = 0; ii < 6; ii++)
3311 FIB_TEST(lbm->lbm_buckets[ii] == ii+6,
3312 "LB Map for 200.200.200.200/32 at %d is %d",
3313 ii, lbm->lbm_buckets[ii]);
3315 for (ii = 6; ii < 16; ii++)
3317 FIB_TEST(lbm->lbm_buckets[ii] == ii,
3318 "LB Map for 200.200.200.200/32 at %d is %d",
3319 ii, lbm->lbm_buckets[ii]);
3321 load_balance_map_unlock(lbmi);
3326 fib_table_entry_path_add(fib_index,
3329 FIB_ENTRY_FLAG_NONE,
3332 tm->hw[0]->sw_if_index,
3336 FIB_ROUTE_PATH_FLAG_NONE);
3338 for (ii = 0; ii < N_P; ii++)
3340 fib_table_entry_delete(fib_index,
3343 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3344 fib_table_lookup_exact_match(fib_index, &bgp_78s[ii])),
3346 format_fib_prefix, &bgp_78s[ii]);
3348 fib_table_entry_path_remove(fib_index,
3352 &pfx_1_1_1_2_s_32.fp_addr,
3356 MPLS_LABEL_INVALID);
3357 fib_table_entry_path_remove(fib_index,
3365 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3366 fib_table_entry_path_remove(fib_index,
3370 &pfx_1_1_1_3_s_32.fp_addr,
3374 FIB_ROUTE_PATH_RESOLVE_VIA_HOST);
3375 fib_table_entry_delete(fib_index,
3378 fib_table_entry_delete(fib_index,
3381 /* suspend so the update walk kicks int */
3382 vlib_process_suspend(vlib_get_main(), 1e-5);
3383 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3384 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_0_s_28)),
3385 "1.1.1.1/28 removed");
3386 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3387 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_3_s_32)),
3388 "1.1.1.3/32 removed");
3389 FIB_TEST((FIB_NODE_INDEX_INVALID ==
3390 fib_table_lookup_exact_match(fib_index, &bgp_200_pfx)),
3391 "200.200.200.200/32 removed");
3394 * add-remove test. no change.
3396 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3397 fib_path_list_db_size());
3398 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3399 fib_path_list_pool_size());
3400 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3401 fib_entry_pool_size());
3404 * A route whose paths are built up iteratively and then removed
3407 fib_prefix_t pfx_4_4_4_4_s_32 = {
3409 .fp_proto = FIB_PROTOCOL_IP4,
3412 .ip4.as_u32 = clib_host_to_net_u32(0x04040404),
3416 fib_table_entry_path_add(fib_index,
3419 FIB_ENTRY_FLAG_NONE,
3422 tm->hw[0]->sw_if_index,
3426 FIB_ROUTE_PATH_FLAG_NONE);
3427 fib_table_entry_path_add(fib_index,
3430 FIB_ENTRY_FLAG_NONE,
3433 tm->hw[0]->sw_if_index,
3437 FIB_ROUTE_PATH_FLAG_NONE);
3438 fib_table_entry_path_add(fib_index,
3441 FIB_ENTRY_FLAG_NONE,
3444 tm->hw[0]->sw_if_index,
3448 FIB_ROUTE_PATH_FLAG_NONE);
3449 FIB_TEST(FIB_NODE_INDEX_INVALID !=
3450 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3451 "4.4.4.4/32 present");
3453 fib_table_entry_delete(fib_index,
3456 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3457 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3458 "4.4.4.4/32 removed");
3461 * add-remove test. no change.
3463 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3464 fib_path_list_db_size());
3465 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3466 fib_path_list_pool_size());
3467 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3468 fib_entry_pool_size());
3471 * A route with multiple paths at once
3473 fib_route_path_t *r_paths = NULL;
3475 for (ii = 0; ii < 4; ii++)
3477 fib_route_path_t r_path = {
3478 .frp_proto = DPO_PROTO_IP4,
3480 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02 + ii),
3482 .frp_sw_if_index = tm->hw[0]->sw_if_index,
3484 .frp_fib_index = ~0,
3486 vec_add1(r_paths, r_path);
3489 fib_table_entry_update(fib_index,
3492 FIB_ENTRY_FLAG_NONE,
3495 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3496 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3497 dpo = fib_entry_contribute_ip_forwarding(fei);
3499 lb = load_balance_get(dpo->dpoi_index);
3500 FIB_TEST((lb->lb_n_buckets == 4), "4.4.4.4/32 lb over %d paths", lb->lb_n_buckets);
3502 fib_table_entry_delete(fib_index,
3505 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3506 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3507 "4.4.4.4/32 removed");
3511 * add-remove test. no change.
3513 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3514 fib_path_list_db_size());
3515 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3516 fib_path_list_pool_size());
3517 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3518 fib_entry_pool_size());
3521 * A route deag route
3523 fib_table_entry_path_add(fib_index,
3526 FIB_ENTRY_FLAG_NONE,
3533 FIB_ROUTE_PATH_FLAG_NONE);
3535 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3536 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3538 dpo = fib_entry_contribute_ip_forwarding(fei);
3539 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3540 lookup_dpo_t *lkd = lookup_dpo_get(dpo->dpoi_index);
3542 FIB_TEST((fib_index == lkd->lkd_fib_index),
3543 "4.4.4.4/32 is deag in %d %U",
3545 format_dpo_id, dpo, 0);
3546 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
3547 "4.4.4.4/32 is source deag in %d %U",
3549 format_dpo_id, dpo, 0);
3551 fib_table_entry_delete(fib_index,
3554 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3555 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3556 "4.4.4.4/32 removed");
3560 * A route deag route in a source lookup table
3562 fib_table_entry_path_add(fib_index,
3565 FIB_ENTRY_FLAG_NONE,
3572 FIB_ROUTE_PATH_SOURCE_LOOKUP);
3574 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32);
3575 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.4.4.4/32 present");
3577 dpo = fib_entry_contribute_ip_forwarding(fei);
3578 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
3579 lkd = lookup_dpo_get(dpo->dpoi_index);
3581 FIB_TEST((fib_index == lkd->lkd_fib_index),
3582 "4.4.4.4/32 is deag in %d %U",
3584 format_dpo_id, dpo, 0);
3585 FIB_TEST((LOOKUP_INPUT_SRC_ADDR == lkd->lkd_input),
3586 "4.4.4.4/32 is source deag in %d %U",
3588 format_dpo_id, dpo, 0);
3590 fib_table_entry_delete(fib_index,
3593 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3594 fib_table_lookup_exact_match(fib_index, &pfx_4_4_4_4_s_32),
3595 "4.4.4.4/32 removed");
3599 * add-remove test. no change.
3601 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3602 fib_path_list_db_size());
3603 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3604 fib_path_list_pool_size());
3605 FIB_TEST((ENBR+7 == fib_entry_pool_size()), "entry pool size is %d",
3606 fib_entry_pool_size());
3610 * add a recursive with duplicate paths. Expect the duplicate to be ignored.
3612 fib_prefix_t pfx_34_1_1_1_s_32 = {
3614 .fp_proto = FIB_PROTOCOL_IP4,
3616 .ip4.as_u32 = clib_host_to_net_u32(0x22010101),
3619 fib_prefix_t pfx_34_34_1_1_s_32 = {
3621 .fp_proto = FIB_PROTOCOL_IP4,
3623 .ip4.as_u32 = clib_host_to_net_u32(0x22220101),
3626 fei = fib_table_entry_path_add(fib_index,
3627 &pfx_34_34_1_1_s_32,
3629 FIB_ENTRY_FLAG_NONE,
3632 tm->hw[0]->sw_if_index,
3636 FIB_ROUTE_PATH_FLAG_NONE);
3637 fei = fib_table_entry_path_add(fib_index,
3640 FIB_ENTRY_FLAG_NONE,
3642 &pfx_34_34_1_1_s_32.fp_addr,
3647 FIB_ROUTE_PATH_FLAG_NONE);
3648 fei = fib_table_entry_path_add(fib_index,
3651 FIB_ENTRY_FLAG_NONE,
3653 &pfx_34_34_1_1_s_32.fp_addr,
3658 FIB_ROUTE_PATH_FLAG_NONE);
3659 FIB_TEST_REC_FORW(&pfx_34_1_1_1_s_32, &pfx_34_34_1_1_s_32, 0);
3660 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
3661 fib_table_entry_delete(fib_index,
3662 &pfx_34_34_1_1_s_32,
3667 * remove: 1.1.1.2/32, 1.1.2.0/24 and 1.1.1.1/32
3668 * all of which are via 10.10.10.1, Itf1
3670 fib_table_entry_path_remove(fib_index,
3675 tm->hw[0]->sw_if_index,
3678 FIB_ROUTE_PATH_FLAG_NONE);
3679 fib_table_entry_path_remove(fib_index,
3684 tm->hw[0]->sw_if_index,
3687 FIB_ROUTE_PATH_FLAG_NONE);
3688 fib_table_entry_path_remove(fib_index,
3693 tm->hw[0]->sw_if_index,
3696 FIB_ROUTE_PATH_FLAG_NONE);
3698 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3699 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_1_s_32),
3700 "1.1.1.1/32 removed");
3701 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3702 fib_table_lookup_exact_match(fib_index, &pfx_1_1_1_2_s_32),
3703 "1.1.1.2/32 removed");
3704 FIB_TEST(FIB_NODE_INDEX_INVALID ==
3705 fib_table_lookup_exact_match(fib_index, &pfx_1_1_2_0_s_24),
3706 "1.1.2.0/24 removed");
3709 * -3 entries and -1 shared path-list
3711 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3712 fib_path_list_db_size());
3713 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3714 fib_path_list_pool_size());
3715 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3716 fib_entry_pool_size());
3719 * An attached-host route. Expect to link to the incomplete adj
3721 fib_prefix_t pfx_4_1_1_1_s_32 = {
3723 .fp_proto = FIB_PROTOCOL_IP4,
3726 .ip4.as_u32 = clib_host_to_net_u32(0x04010101),
3729 fib_table_entry_path_add(fib_index,
3732 FIB_ENTRY_FLAG_NONE,
3735 tm->hw[0]->sw_if_index,
3739 FIB_ROUTE_PATH_FLAG_NONE);
3741 fei = fib_table_lookup_exact_match(fib_index, &pfx_4_1_1_1_s_32);
3742 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "4.1.1.1/32 present");
3743 ai = fib_entry_get_adj(fei);
3745 ai2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3747 &pfx_4_1_1_1_s_32.fp_addr,
3748 tm->hw[0]->sw_if_index);
3749 FIB_TEST((ai == ai2), "Attached-host link to incomplete ADJ");
3753 * +1 entry and +1 shared path-list
3755 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
3756 fib_path_list_db_size());
3757 FIB_TEST((PNBR+5 == fib_path_list_pool_size()), "path list pool size is %d",
3758 fib_path_list_pool_size());
3759 FIB_TEST((ENBR+5 == fib_entry_pool_size()), "entry pool size is %d",
3760 fib_entry_pool_size());
3762 fib_table_entry_delete(fib_index,
3766 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
3767 fib_path_list_db_size());
3768 FIB_TEST((PNBR+4 == fib_path_list_pool_size()), "path list pool size is %d",
3769 fib_path_list_pool_size());
3770 FIB_TEST((ENBR+4 == fib_entry_pool_size()), "entry pool size is %d",
3771 fib_entry_pool_size());
3774 * add a v6 prefix via v4 next-hops
3776 fib_prefix_t pfx_2001_s_64 = {
3778 .fp_proto = FIB_PROTOCOL_IP6,
3780 .ip6.as_u64[0] = clib_host_to_net_u64(0x2001000000000000),
3783 fei = fib_table_entry_path_add(0, //default v6 table
3786 FIB_ENTRY_FLAG_NONE,
3789 tm->hw[0]->sw_if_index,
3793 FIB_ROUTE_PATH_FLAG_NONE);
3795 fei = fib_table_lookup_exact_match(0, &pfx_2001_s_64);
3796 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "2001::/64 present");
3797 ai = fib_entry_get_adj(fei);
3799 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
3800 "2001::/64 via ARP-adj");
3801 FIB_TEST((adj->ia_link == VNET_LINK_IP6),
3802 "2001::/64 is link type v6");
3803 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP4),
3804 "2001::/64 ADJ-adj is NH proto v4");
3805 fib_table_entry_delete(0, &pfx_2001_s_64, FIB_SOURCE_API);
3808 * add a uRPF exempt prefix:
3810 * - it's forwarding is drop
3811 * - it's uRPF list is not empty
3812 * - the uRPF list for the default route (it's cover) is empty
3814 fei = fib_table_entry_special_add(fib_index,
3816 FIB_SOURCE_URPF_EXEMPT,
3817 FIB_ENTRY_FLAG_DROP);
3818 dpo = fib_entry_contribute_ip_forwarding(fei);
3819 FIB_TEST(load_balance_is_drop(dpo),
3820 "uRPF exempt 4.1.1.1/32 DROP");
3821 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 1, 0),
3822 "uRPF list for exempt prefix has itf index 0");
3823 fei = fib_table_lookup_exact_match(fib_index, &pfx_0_0_0_0_s_0);
3824 FIB_TEST(fib_test_urpf_is_equal(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, 0),
3825 "uRPF list for 0.0.0.0/0 empty");
3827 fib_table_entry_delete(fib_index, &pfx_4_1_1_1_s_32, FIB_SOURCE_URPF_EXEMPT);
3830 * An adj-fib that fails the refinement criteria - no connected cover
3832 fib_prefix_t pfx_12_10_10_2_s_32 = {
3834 .fp_proto = FIB_PROTOCOL_IP4,
3837 .ip4.as_u32 = clib_host_to_net_u32(0x0c0a0a02),
3841 fib_table_entry_path_add(fib_index,
3842 &pfx_12_10_10_2_s_32,
3844 FIB_ENTRY_FLAG_ATTACHED,
3846 &pfx_12_10_10_2_s_32.fp_addr,
3847 tm->hw[0]->sw_if_index,
3848 ~0, // invalid fib index
3851 FIB_ROUTE_PATH_FLAG_NONE);
3853 fei = fib_table_lookup_exact_match(fib_index, &pfx_12_10_10_2_s_32);
3854 dpo = fib_entry_contribute_ip_forwarding(fei);
3855 FIB_TEST(!dpo_id_is_valid(dpo),
3856 "no connected cover adj-fib fails refinement");
3858 fib_table_entry_delete(fib_index,
3859 &pfx_12_10_10_2_s_32,
3863 * An adj-fib that fails the refinement criteria - cover is connected
3864 * but on a different interface
3866 fib_prefix_t pfx_10_10_10_127_s_32 = {
3868 .fp_proto = FIB_PROTOCOL_IP4,
3871 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a7f),
3875 fib_table_entry_path_add(fib_index,
3876 &pfx_10_10_10_127_s_32,
3878 FIB_ENTRY_FLAG_ATTACHED,
3880 &pfx_10_10_10_127_s_32.fp_addr,
3881 tm->hw[1]->sw_if_index,
3882 ~0, // invalid fib index
3885 FIB_ROUTE_PATH_FLAG_NONE);
3887 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_127_s_32);
3888 dpo = fib_entry_contribute_ip_forwarding(fei);
3889 FIB_TEST(!dpo_id_is_valid(dpo),
3890 "wrong interface adj-fib fails refinement");
3892 fib_table_entry_delete(fib_index,
3893 &pfx_10_10_10_127_s_32,
3897 * add a second path to an adj-fib
3898 * this is a sumiluation of another ARP entry created
3899 * on an interface on which the connected prefi does not exist.
3900 * The second path fails refinement. Expect to forward through the
3903 fib_prefix_t pfx_10_10_10_3_s_32 = {
3905 .fp_proto = FIB_PROTOCOL_IP4,
3908 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
3912 ai_03 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
3915 tm->hw[0]->sw_if_index);
3917 fib_test_lb_bucket_t ip_o_10_10_10_3 = {
3923 fei = fib_table_entry_path_add(fib_index,
3924 &pfx_10_10_10_3_s_32,
3926 FIB_ENTRY_FLAG_NONE,
3929 tm->hw[0]->sw_if_index,
3933 FIB_ROUTE_PATH_FLAG_NONE);
3934 fei = fib_table_entry_path_add(fib_index,
3935 &pfx_10_10_10_3_s_32,
3937 FIB_ENTRY_FLAG_NONE,
3940 tm->hw[1]->sw_if_index,
3944 FIB_ROUTE_PATH_FLAG_NONE);
3945 FIB_TEST(fib_test_validate_entry(fei,
3946 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
3949 "10.10.10.3 via 10.10.10.3/Eth0 only");
3952 * remove the path that refines the cover, should go unresolved
3954 fib_table_entry_path_remove(fib_index,
3955 &pfx_10_10_10_3_s_32,
3959 tm->hw[0]->sw_if_index,
3962 FIB_ROUTE_PATH_FLAG_NONE);
3963 dpo = fib_entry_contribute_ip_forwarding(fei);
3964 FIB_TEST(!dpo_id_is_valid(dpo),
3965 "wrong interface adj-fib fails refinement");
3968 * add back the path that refines the cover
3970 fei = fib_table_entry_path_add(fib_index,
3971 &pfx_10_10_10_3_s_32,
3973 FIB_ENTRY_FLAG_NONE,
3976 tm->hw[0]->sw_if_index,
3980 FIB_ROUTE_PATH_FLAG_NONE);
3981 FIB_TEST(fib_test_validate_entry(fei,
3982 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
3985 "10.10.10.3 via 10.10.10.3/Eth0 only");
3988 * remove the path that does not refine the cover
3990 fib_table_entry_path_remove(fib_index,
3991 &pfx_10_10_10_3_s_32,
3995 tm->hw[1]->sw_if_index,
3998 FIB_ROUTE_PATH_FLAG_NONE);
3999 FIB_TEST(fib_test_validate_entry(fei,
4000 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4003 "10.10.10.3 via 10.10.10.3/Eth0 only");
4006 * remove the path that does refine, it's the last path, so
4007 * the entry should be gone
4009 fib_table_entry_path_remove(fib_index,
4010 &pfx_10_10_10_3_s_32,
4014 tm->hw[0]->sw_if_index,
4017 FIB_ROUTE_PATH_FLAG_NONE);
4018 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
4019 FIB_TEST((fei == FIB_NODE_INDEX_INVALID), "10.10.10.3 gone");
4024 * change the table's flow-hash config - expect the update to propagete to
4025 * the entries' load-balance objects
4027 flow_hash_config_t old_hash_config, new_hash_config;
4029 old_hash_config = fib_table_get_flow_hash_config(fib_index,
4031 new_hash_config = (IP_FLOW_HASH_SRC_ADDR |
4032 IP_FLOW_HASH_DST_ADDR);
4034 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
4035 dpo = fib_entry_contribute_ip_forwarding(fei);
4036 lb = load_balance_get(dpo->dpoi_index);
4037 FIB_TEST((lb->lb_hash_config == old_hash_config),
4038 "Table and LB hash config match: %U",
4039 format_ip_flow_hash_config, lb->lb_hash_config);
4041 fib_table_set_flow_hash_config(fib_index, FIB_PROTOCOL_IP4, new_hash_config);
4043 FIB_TEST((lb->lb_hash_config == new_hash_config),
4044 "Table and LB newhash config match: %U",
4045 format_ip_flow_hash_config, lb->lb_hash_config);
4048 * A route via an L2 Bridge
4050 fei = fib_table_entry_path_add(fib_index,
4051 &pfx_10_10_10_3_s_32,
4053 FIB_ENTRY_FLAG_NONE,
4056 tm->hw[0]->sw_if_index,
4060 FIB_ROUTE_PATH_FLAG_NONE);
4061 dpo_id_t l2_dpo = DPO_INVALID;
4062 l2_bridge_dpo_add_or_lock(tm->hw[0]->sw_if_index, &l2_dpo);
4063 fib_test_lb_bucket_t ip_o_l2 = {
4066 .adj = l2_dpo.dpoi_index,
4070 FIB_TEST(fib_test_validate_entry(fei,
4071 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
4074 "10.10.10.3 via L2 on Eth0");
4075 fib_table_entry_path_remove(fib_index,
4076 &pfx_10_10_10_3_s_32,
4080 tm->hw[0]->sw_if_index,
4083 FIB_ROUTE_PATH_FLAG_NONE);
4090 fib_table_entry_delete(fib_index,
4091 &pfx_10_10_10_1_s_32,
4093 fib_table_entry_delete(fib_index,
4094 &pfx_10_10_10_2_s_32,
4096 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4097 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32),
4098 "10.10.10.1/32 adj-fib removed");
4099 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4100 fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32),
4101 "10.10.10.2/32 adj-fib removed");
4104 * -2 entries and -2 non-shared path-list
4106 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4107 fib_path_list_db_size());
4108 FIB_TEST((PNBR+2 == fib_path_list_pool_size()), "path list pool size is %d",
4109 fib_path_list_pool_size());
4110 FIB_TEST((ENBR+2 == fib_entry_pool_size()), "entry pool size is %d",
4111 fib_entry_pool_size());
4114 * unlock the adjacencies for which this test provided a rewrite.
4115 * These are the last locks on these adjs. they should thus go away.
4119 adj_unlock(ai_12_12_12_12);
4121 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4126 * remove the interface prefixes
4128 local_pfx.fp_len = 32;
4129 fib_table_entry_special_remove(fib_index, &local_pfx,
4130 FIB_SOURCE_INTERFACE);
4131 fei = fib_table_lookup(fib_index, &local_pfx);
4133 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4134 fib_table_lookup_exact_match(fib_index, &local_pfx),
4135 "10.10.10.10/32 adj-fib removed");
4137 local_pfx.fp_len = 24;
4138 fib_table_entry_delete(fib_index, &local_pfx,
4139 FIB_SOURCE_INTERFACE);
4141 FIB_TEST(FIB_NODE_INDEX_INVALID ==
4142 fib_table_lookup_exact_match(fib_index, &local_pfx),
4143 "10.10.10.10/24 adj-fib removed");
4146 * -2 entries and -2 non-shared path-list
4148 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4149 fib_path_list_db_size());
4150 FIB_TEST((PNBR == fib_path_list_pool_size()), "path list pool size is %d",
4151 fib_path_list_pool_size());
4152 FIB_TEST((ENBR == fib_entry_pool_size()), "entry pool size is %d",
4153 fib_entry_pool_size());
4156 * Last but not least, remove the VRF
4158 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4161 "NO API Source'd prefixes");
4162 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4165 "NO RR Source'd prefixes");
4166 FIB_TEST((0 == fib_table_get_num_entries(fib_index,
4168 FIB_SOURCE_INTERFACE)),
4169 "NO INterface Source'd prefixes");
4171 fib_table_unlock(fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_API);
4173 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4174 fib_path_list_db_size());
4175 FIB_TEST((PNBR-5 == fib_path_list_pool_size()), "path list pool size is %d",
4176 fib_path_list_pool_size());
4177 FIB_TEST((ENBR-5 == fib_entry_pool_size()), "entry pool size is %d",
4178 fib_entry_pool_size());
4179 FIB_TEST((ENBR-5 == pool_elts(fib_urpf_list_pool)), "uRPF pool size is %d",
4180 pool_elts(fib_urpf_list_pool));
4181 FIB_TEST((0 == pool_elts(load_balance_map_pool)), "LB-map pool size is %d",
4182 pool_elts(load_balance_map_pool));
4183 FIB_TEST((lb_count == pool_elts(load_balance_pool)), "LB pool size is %d",
4184 pool_elts(load_balance_pool));
4185 FIB_TEST((0 == pool_elts(l2_bridge_dpo_pool)), "L2 DPO pool size is %d",
4186 pool_elts(l2_bridge_dpo_pool));
4195 * In the default table check for the presence and correct forwarding
4196 * of the special entries
4198 fib_node_index_t dfrt, fei, ai, locked_ai, ai_01, ai_02;
4199 const dpo_id_t *dpo, *dpo_drop;
4200 const ip_adjacency_t *adj;
4201 const receive_dpo_t *rd;
4206 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
4209 /* via 2001:0:0:1::2 */
4210 ip46_address_t nh_2001_2 = {
4213 [0] = clib_host_to_net_u64(0x2001000000000001),
4214 [1] = clib_host_to_net_u64(0x0000000000000002),
4221 dpo_drop = drop_dpo_get(DPO_PROTO_IP6);
4223 /* Find or create FIB table 11 */
4224 fib_index = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP6, 11,
4227 for (ii = 0; ii < 4; ii++)
4229 ip6_main.fib_index_by_sw_if_index[tm->hw[ii]->sw_if_index] = fib_index;
4232 fib_prefix_t pfx_0_0 = {
4234 .fp_proto = FIB_PROTOCOL_IP6,
4242 dfrt = fib_table_lookup(fib_index, &pfx_0_0);
4243 FIB_TEST((FIB_NODE_INDEX_INVALID != dfrt), "default route present");
4244 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4245 "Default route is DROP");
4247 dpo = fib_entry_contribute_ip_forwarding(dfrt);
4248 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4251 &pfx_0_0.fp_addr.ip6)),
4252 "default-route; fwd and non-fwd tables match");
4254 // FIXME - check specials.
4257 * At this stage there is one v4 FIB with 5 routes and two v6 FIBs
4258 * each with 2 entries and a v6 mfib with 4 path-lists.
4259 * All entries are special so no path-list sharing.
4262 #define PNPS (5+4+4)
4263 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4264 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is %d",
4265 fib_path_list_pool_size());
4266 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
4267 fib_entry_pool_size());
4270 * add interface routes.
4271 * validate presence of /64 attached and /128 recieve.
4272 * test for the presence of the receive address in the glean and local adj
4274 * receive on 2001:0:0:1::1/128
4276 fib_prefix_t local_pfx = {
4278 .fp_proto = FIB_PROTOCOL_IP6,
4282 [0] = clib_host_to_net_u64(0x2001000000000001),
4283 [1] = clib_host_to_net_u64(0x0000000000000001),
4289 fib_table_entry_update_one_path(fib_index, &local_pfx,
4290 FIB_SOURCE_INTERFACE,
4291 (FIB_ENTRY_FLAG_CONNECTED |
4292 FIB_ENTRY_FLAG_ATTACHED),
4295 tm->hw[0]->sw_if_index,
4299 FIB_ROUTE_PATH_FLAG_NONE);
4300 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4302 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4304 ai = fib_entry_get_adj(fei);
4305 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "attached interface route adj present");
4307 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4308 "attached interface adj is glean");
4309 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4310 &adj->sub_type.glean.receive_addr)),
4311 "attached interface adj is receive ok");
4312 dpo = fib_entry_contribute_ip_forwarding(fei);
4313 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4316 &local_pfx.fp_addr.ip6)),
4317 "attached-route; fwd and non-fwd tables match");
4319 local_pfx.fp_len = 128;
4320 fib_table_entry_update_one_path(fib_index, &local_pfx,
4321 FIB_SOURCE_INTERFACE,
4322 (FIB_ENTRY_FLAG_CONNECTED |
4323 FIB_ENTRY_FLAG_LOCAL),
4326 tm->hw[0]->sw_if_index,
4327 ~0, // invalid fib index
4330 FIB_ROUTE_PATH_FLAG_NONE);
4331 fei = fib_table_lookup(fib_index, &local_pfx);
4333 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4335 dpo = fib_entry_contribute_ip_forwarding(fei);
4336 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4337 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4338 "local interface adj is local");
4339 rd = receive_dpo_get(dpo->dpoi_index);
4341 FIB_TEST((0 == ip46_address_cmp(&local_pfx.fp_addr,
4343 "local interface adj is receive ok");
4345 dpo = fib_entry_contribute_ip_forwarding(fei);
4346 FIB_TEST((dpo->dpoi_index == ip6_fib_table_fwding_lookup(
4349 &local_pfx.fp_addr.ip6)),
4350 "local-route; fwd and non-fwd tables match");
4353 * +2 entries. +2 unshared path-lists
4355 FIB_TEST((0 == fib_path_list_db_size()), "path list DB is empty");
4356 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4357 fib_path_list_pool_size());
4358 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4359 fib_entry_pool_size());
4362 * Modify the default route to be via an adj not yet known.
4363 * this sources the defalut route with the API source, which is
4364 * a higher preference to the DEFAULT_ROUTE source
4366 fib_table_entry_path_add(fib_index, &pfx_0_0,
4368 FIB_ENTRY_FLAG_NONE,
4371 tm->hw[0]->sw_if_index,
4375 FIB_ROUTE_PATH_FLAG_NONE);
4376 fei = fib_table_lookup(fib_index, &pfx_0_0);
4378 FIB_TEST((fei == dfrt), "default route same index");
4379 ai = fib_entry_get_adj(fei);
4380 FIB_TEST((FIB_NODE_INDEX_INVALID != ai), "default route adj present");
4382 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4383 "adj is incomplete");
4384 FIB_TEST((0 == ip46_address_cmp(&nh_2001_2, &adj->sub_type.nbr.next_hop)),
4385 "adj nbr next-hop ok");
4388 * find the adj in the shared db
4390 locked_ai = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4393 tm->hw[0]->sw_if_index);
4394 FIB_TEST((locked_ai == ai), "ADJ NBR DB find");
4395 adj_unlock(locked_ai);
4398 * no more entires. +1 shared path-list
4400 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4401 fib_path_list_db_size());
4402 FIB_TEST((PNPS+3 == fib_path_list_pool_size()), "path list pool size is%d",
4403 fib_path_list_pool_size());
4404 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4405 fib_entry_pool_size());
4408 * remove the API source from the default route. We expected
4409 * the route to remain, sourced by DEFAULT_ROUTE, and hence a DROP
4411 fib_table_entry_path_remove(fib_index, &pfx_0_0,
4415 tm->hw[0]->sw_if_index,
4418 FIB_ROUTE_PATH_FLAG_NONE);
4419 fei = fib_table_lookup(fib_index, &pfx_0_0);
4421 FIB_TEST((fei == dfrt), "default route same index");
4422 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(dfrt)),
4423 "Default route is DROP");
4426 * no more entires. -1 shared path-list
4428 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4429 fib_path_list_db_size());
4430 FIB_TEST((PNPS+2 == fib_path_list_pool_size()), "path list pool size is%d",
4431 fib_path_list_pool_size());
4432 FIB_TEST((ENPS+2 == fib_entry_pool_size()), "entry pool size is %d",
4433 fib_entry_pool_size());
4436 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
4438 fib_prefix_t pfx_2001_1_2_s_128 = {
4440 .fp_proto = FIB_PROTOCOL_IP6,
4444 [0] = clib_host_to_net_u64(0x2001000000000001),
4445 [1] = clib_host_to_net_u64(0x0000000000000002),
4450 fib_prefix_t pfx_2001_1_3_s_128 = {
4452 .fp_proto = FIB_PROTOCOL_IP6,
4456 [0] = clib_host_to_net_u64(0x2001000000000001),
4457 [1] = clib_host_to_net_u64(0x0000000000000003),
4463 0xde, 0xde, 0xde, 0xba, 0xba, 0xba,
4466 ai_01 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4468 &pfx_2001_1_2_s_128.fp_addr,
4469 tm->hw[0]->sw_if_index);
4470 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_01), "adj created");
4471 adj = adj_get(ai_01);
4472 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4473 "adj is incomplete");
4474 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4475 &adj->sub_type.nbr.next_hop)),
4476 "adj nbr next-hop ok");
4478 adj_nbr_update_rewrite(ai_01, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4479 fib_test_build_rewrite(eth_addr));
4480 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4482 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_2_s_128.fp_addr,
4483 &adj->sub_type.nbr.next_hop)),
4484 "adj nbr next-hop ok");
4486 fib_table_entry_path_add(fib_index,
4487 &pfx_2001_1_2_s_128,
4489 FIB_ENTRY_FLAG_ATTACHED,
4491 &pfx_2001_1_2_s_128.fp_addr,
4492 tm->hw[0]->sw_if_index,
4496 FIB_ROUTE_PATH_FLAG_NONE);
4498 fei = fib_table_lookup(fib_index, &pfx_2001_1_2_s_128);
4499 ai = fib_entry_get_adj(fei);
4500 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4504 ai_02 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP6,
4506 &pfx_2001_1_3_s_128.fp_addr,
4507 tm->hw[0]->sw_if_index);
4508 FIB_TEST((FIB_NODE_INDEX_INVALID != ai_02), "adj created");
4509 adj = adj_get(ai_02);
4510 FIB_TEST((IP_LOOKUP_NEXT_ARP == adj->lookup_next_index),
4511 "adj is incomplete");
4512 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4513 &adj->sub_type.nbr.next_hop)),
4514 "adj nbr next-hop ok");
4516 adj_nbr_update_rewrite(ai_02, ADJ_NBR_REWRITE_FLAG_COMPLETE,
4517 fib_test_build_rewrite(eth_addr));
4518 FIB_TEST((IP_LOOKUP_NEXT_REWRITE == adj->lookup_next_index),
4520 FIB_TEST((0 == ip46_address_cmp(&pfx_2001_1_3_s_128.fp_addr,
4521 &adj->sub_type.nbr.next_hop)),
4522 "adj nbr next-hop ok");
4523 FIB_TEST((ai_01 != ai_02), "ADJs are different");
4525 fib_table_entry_path_add(fib_index,
4526 &pfx_2001_1_3_s_128,
4528 FIB_ENTRY_FLAG_ATTACHED,
4530 &pfx_2001_1_3_s_128.fp_addr,
4531 tm->hw[0]->sw_if_index,
4535 FIB_ROUTE_PATH_FLAG_NONE);
4537 fei = fib_table_lookup(fib_index, &pfx_2001_1_3_s_128);
4538 ai = fib_entry_get_adj(fei);
4539 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4542 * +2 entries, +2 unshread path-lists.
4544 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
4545 fib_path_list_db_size());
4546 FIB_TEST((PNPS+4 == fib_path_list_pool_size()), "path list pool size is%d",
4547 fib_path_list_pool_size());
4548 FIB_TEST((ENPS+4 == fib_entry_pool_size()), "entry pool size is %d",
4549 fib_entry_pool_size());
4552 * Add a 2 routes via the first ADJ. ensure path-list sharing
4554 fib_prefix_t pfx_2001_a_s_64 = {
4556 .fp_proto = FIB_PROTOCOL_IP6,
4560 [0] = clib_host_to_net_u64(0x200100000000000a),
4561 [1] = clib_host_to_net_u64(0x0000000000000000),
4566 fib_prefix_t pfx_2001_b_s_64 = {
4568 .fp_proto = FIB_PROTOCOL_IP6,
4572 [0] = clib_host_to_net_u64(0x200100000000000b),
4573 [1] = clib_host_to_net_u64(0x0000000000000000),
4579 fib_table_entry_path_add(fib_index,
4582 FIB_ENTRY_FLAG_NONE,
4585 tm->hw[0]->sw_if_index,
4589 FIB_ROUTE_PATH_FLAG_NONE);
4590 fei = fib_table_lookup(fib_index, &pfx_2001_a_s_64);
4591 ai = fib_entry_get_adj(fei);
4592 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4593 fib_table_entry_path_add(fib_index,
4596 FIB_ENTRY_FLAG_NONE,
4599 tm->hw[0]->sw_if_index,
4603 FIB_ROUTE_PATH_FLAG_NONE);
4604 fei = fib_table_lookup(fib_index, &pfx_2001_b_s_64);
4605 ai = fib_entry_get_adj(fei);
4606 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4609 * +2 entries, +1 shared path-list.
4611 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4612 fib_path_list_db_size());
4613 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4614 fib_path_list_pool_size());
4615 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4616 fib_entry_pool_size());
4619 * add a v4 prefix via a v6 next-hop
4621 fib_prefix_t pfx_1_1_1_1_s_32 = {
4623 .fp_proto = FIB_PROTOCOL_IP4,
4625 .ip4.as_u32 = 0x01010101,
4628 fei = fib_table_entry_path_add(0, // default table
4631 FIB_ENTRY_FLAG_NONE,
4634 tm->hw[0]->sw_if_index,
4638 FIB_ROUTE_PATH_FLAG_NONE);
4639 FIB_TEST(fei == fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32),
4640 "1.1.1.1/32 o v6 route present");
4641 ai = fib_entry_get_adj(fei);
4643 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_ARP),
4644 "1.1.1.1/32 via ARP-adj");
4645 FIB_TEST((adj->ia_link == VNET_LINK_IP4),
4646 "1.1.1.1/32 ADJ-adj is link type v4");
4647 FIB_TEST((adj->ia_nh_proto == FIB_PROTOCOL_IP6),
4648 "1.1.1.1/32 ADJ-adj is NH proto v6");
4649 fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
4654 fib_prefix_t pfx_2001_c_s_64 = {
4656 .fp_proto = FIB_PROTOCOL_IP6,
4660 [0] = clib_host_to_net_u64(0x200100000000000c),
4661 [1] = clib_host_to_net_u64(0x0000000000000000),
4666 fib_table_entry_path_add(fib_index,
4669 FIB_ENTRY_FLAG_ATTACHED,
4672 tm->hw[0]->sw_if_index,
4676 FIB_ROUTE_PATH_FLAG_NONE);
4677 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4678 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached route present");
4679 ai = fib_entry_get_adj(fei);
4681 FIB_TEST((adj->lookup_next_index == IP_LOOKUP_NEXT_GLEAN),
4682 "2001:0:0:c/64 attached resolves via glean");
4684 fib_table_entry_path_remove(fib_index,
4689 tm->hw[0]->sw_if_index,
4692 FIB_ROUTE_PATH_FLAG_NONE);
4693 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_c_s_64);
4694 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached route removed");
4697 * Shutdown the interface on which we have a connected and through
4698 * which the routes are reachable.
4699 * This will result in the connected, adj-fibs, and routes linking to drop
4700 * The local/for-us prefix continues to receive.
4702 clib_error_t * error;
4704 error = vnet_sw_interface_set_flags(vnet_get_main(),
4705 tm->hw[0]->sw_if_index,
4706 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4707 FIB_TEST((NULL == error), "Interface shutdown OK");
4709 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4710 dpo = fib_entry_contribute_ip_forwarding(fei);
4711 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4712 "2001::b/64 resolves via drop");
4714 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4715 dpo = fib_entry_contribute_ip_forwarding(fei);
4716 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4717 "2001::a/64 resolves via drop");
4718 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4719 dpo = fib_entry_contribute_ip_forwarding(fei);
4720 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4721 "2001:0:0:1::3/64 resolves via drop");
4722 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4723 dpo = fib_entry_contribute_ip_forwarding(fei);
4724 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4725 "2001:0:0:1::2/64 resolves via drop");
4726 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4727 dpo = fib_entry_contribute_ip_forwarding(fei);
4728 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4729 "2001:0:0:1::1/128 not drop");
4730 local_pfx.fp_len = 64;
4731 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4732 dpo = fib_entry_contribute_ip_forwarding(fei);
4733 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4734 "2001:0:0:1/64 resolves via drop");
4739 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4740 fib_path_list_db_size());
4741 FIB_TEST((PNPS+5 == fib_path_list_pool_size()), "path list pool size is%d",
4742 fib_path_list_pool_size());
4743 FIB_TEST((ENPS+6 == fib_entry_pool_size()), "entry pool size is %d",
4744 fib_entry_pool_size());
4747 * shutdown one of the other interfaces, then add a connected.
4748 * and swap one of the routes to it.
4750 error = vnet_sw_interface_set_flags(vnet_get_main(),
4751 tm->hw[1]->sw_if_index,
4752 ~VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4753 FIB_TEST((NULL == error), "Interface 1 shutdown OK");
4755 fib_prefix_t connected_pfx = {
4757 .fp_proto = FIB_PROTOCOL_IP6,
4760 /* 2001:0:0:2::1/64 */
4762 [0] = clib_host_to_net_u64(0x2001000000000002),
4763 [1] = clib_host_to_net_u64(0x0000000000000001),
4768 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4769 FIB_SOURCE_INTERFACE,
4770 (FIB_ENTRY_FLAG_CONNECTED |
4771 FIB_ENTRY_FLAG_ATTACHED),
4774 tm->hw[1]->sw_if_index,
4778 FIB_ROUTE_PATH_FLAG_NONE);
4779 fei = fib_table_lookup_exact_match(fib_index, &connected_pfx);
4780 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached interface route present");
4781 dpo = fib_entry_contribute_ip_forwarding(fei);
4782 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4783 FIB_TEST(!dpo_cmp(dpo, dpo_drop),
4784 "2001:0:0:2/64 not resolves via drop");
4786 connected_pfx.fp_len = 128;
4787 fib_table_entry_update_one_path(fib_index, &connected_pfx,
4788 FIB_SOURCE_INTERFACE,
4789 (FIB_ENTRY_FLAG_CONNECTED |
4790 FIB_ENTRY_FLAG_LOCAL),
4793 tm->hw[0]->sw_if_index,
4794 ~0, // invalid fib index
4797 FIB_ROUTE_PATH_FLAG_NONE);
4798 fei = fib_table_lookup(fib_index, &connected_pfx);
4800 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local interface route present");
4801 dpo = fib_entry_contribute_ip_forwarding(fei);
4802 dpo = load_balance_get_bucket(dpo->dpoi_index, 0);
4803 FIB_TEST((DPO_RECEIVE == dpo->dpoi_type),
4804 "local interface adj is local");
4805 rd = receive_dpo_get(dpo->dpoi_index);
4806 FIB_TEST((0 == ip46_address_cmp(&connected_pfx.fp_addr,
4808 "local interface adj is receive ok");
4811 * +2 entries, +2 unshared path-lists
4813 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4814 fib_path_list_db_size());
4815 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4816 fib_path_list_pool_size());
4817 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4818 fib_entry_pool_size());
4822 * bring the interface back up. we expected the routes to return
4823 * to normal forwarding.
4825 error = vnet_sw_interface_set_flags(vnet_get_main(),
4826 tm->hw[0]->sw_if_index,
4827 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
4828 FIB_TEST((NULL == error), "Interface bring-up OK");
4829 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4830 ai = fib_entry_get_adj(fei);
4831 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4832 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4833 ai = fib_entry_get_adj(fei);
4834 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4835 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4836 ai = fib_entry_get_adj(fei);
4837 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4838 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4839 ai = fib_entry_get_adj(fei);
4840 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4841 local_pfx.fp_len = 64;
4842 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4843 ai = fib_entry_get_adj(fei);
4845 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4846 "attached interface adj is glean");
4849 * Same test as above, but this time the HW interface goes down
4851 error = vnet_hw_interface_set_flags(vnet_get_main(),
4852 tm->hw_if_indicies[0],
4853 ~VNET_HW_INTERFACE_FLAG_LINK_UP);
4854 FIB_TEST((NULL == error), "Interface shutdown OK");
4856 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4857 dpo = fib_entry_contribute_ip_forwarding(fei);
4858 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4859 "2001::b/64 resolves via drop");
4860 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4861 dpo = fib_entry_contribute_ip_forwarding(fei);
4862 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4863 "2001::a/64 resolves via drop");
4864 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4865 dpo = fib_entry_contribute_ip_forwarding(fei);
4866 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4867 "2001:0:0:1::3/128 resolves via drop");
4868 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4869 dpo = fib_entry_contribute_ip_forwarding(fei);
4870 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4871 "2001:0:0:1::2/128 resolves via drop");
4872 local_pfx.fp_len = 128;
4873 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4874 dpo = fib_entry_contribute_ip_forwarding(fei);
4875 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4876 "2001:0:0:1::1/128 not drop");
4877 local_pfx.fp_len = 64;
4878 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4879 dpo = fib_entry_contribute_ip_forwarding(fei);
4880 FIB_TEST(!dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
4881 "2001:0:0:1/64 resolves via drop");
4883 error = vnet_hw_interface_set_flags(vnet_get_main(),
4884 tm->hw_if_indicies[0],
4885 VNET_HW_INTERFACE_FLAG_LINK_UP);
4886 FIB_TEST((NULL == error), "Interface bring-up OK");
4887 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4888 ai = fib_entry_get_adj(fei);
4889 FIB_TEST((ai_01 == ai), "2001::a/64 resolves via 2001:0:0:1::1");
4890 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4891 ai = fib_entry_get_adj(fei);
4892 FIB_TEST((ai_01 == ai), "2001::b/64 resolves via 2001:0:0:1::1");
4893 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4894 ai = fib_entry_get_adj(fei);
4895 FIB_TEST((ai_02 == ai), "ADJ-FIB resolves via adj");
4896 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4897 ai = fib_entry_get_adj(fei);
4898 FIB_TEST((ai_01 == ai), "ADJ-FIB resolves via adj");
4899 local_pfx.fp_len = 64;
4900 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4901 ai = fib_entry_get_adj(fei);
4903 FIB_TEST((IP_LOOKUP_NEXT_GLEAN == adj->lookup_next_index),
4904 "attached interface adj is glean");
4907 * Delete the interface that the routes reolve through.
4908 * Again no routes are removed. They all point to drop.
4910 * This is considered an error case. The control plane should
4911 * not remove interfaces through which routes resolve, but
4912 * such things can happen. ALL affected routes will drop.
4914 vnet_delete_hw_interface(vnet_get_main(), tm->hw_if_indicies[0]);
4916 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4917 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4918 "2001::b/64 resolves via drop");
4919 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4920 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4921 "2001::b/64 resolves via drop");
4922 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4923 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4924 "2001:0:0:1::3/64 resolves via drop");
4925 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4926 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4927 "2001:0:0:1::2/64 resolves via drop");
4928 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4929 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4930 "2001:0:0:1::1/128 is drop");
4931 local_pfx.fp_len = 64;
4932 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4933 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4934 "2001:0:0:1/64 resolves via drop");
4939 FIB_TEST((1 == fib_path_list_db_size()), "path list DB population:%d",
4940 fib_path_list_db_size());
4941 FIB_TEST((PNPS+7 == fib_path_list_pool_size()), "path list pool size is%d",
4942 fib_path_list_pool_size());
4943 FIB_TEST((ENPS+8 == fib_entry_pool_size()), "entry pool size is %d",
4944 fib_entry_pool_size());
4947 * Add the interface back. routes stay unresolved.
4949 error = ethernet_register_interface(vnet_get_main(),
4950 test_interface_device_class.index,
4953 &tm->hw_if_indicies[0],
4954 /* flag change */ 0);
4956 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64);
4957 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4958 "2001::b/64 resolves via drop");
4959 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64);
4960 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4961 "2001::b/64 resolves via drop");
4962 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128);
4963 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4964 "2001:0:0:1::3/64 resolves via drop");
4965 fei = fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128);
4966 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4967 "2001:0:0:1::2/64 resolves via drop");
4968 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4969 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4970 "2001:0:0:1::1/128 is drop");
4971 local_pfx.fp_len = 64;
4972 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
4973 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
4974 "2001:0:0:1/64 resolves via drop");
4977 * CLEANUP ALL the routes
4979 fib_table_entry_delete(fib_index,
4982 fib_table_entry_delete(fib_index,
4985 fib_table_entry_delete(fib_index,
4988 fib_table_entry_delete(fib_index,
4989 &pfx_2001_1_3_s_128,
4991 fib_table_entry_delete(fib_index,
4992 &pfx_2001_1_2_s_128,
4994 local_pfx.fp_len = 64;
4995 fib_table_entry_delete(fib_index, &local_pfx,
4996 FIB_SOURCE_INTERFACE);
4997 local_pfx.fp_len = 128;
4998 fib_table_entry_special_remove(fib_index, &local_pfx,
4999 FIB_SOURCE_INTERFACE);
5000 connected_pfx.fp_len = 64;
5001 fib_table_entry_delete(fib_index, &connected_pfx,
5002 FIB_SOURCE_INTERFACE);
5003 connected_pfx.fp_len = 128;
5004 fib_table_entry_special_remove(fib_index, &connected_pfx,
5005 FIB_SOURCE_INTERFACE);
5007 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5008 fib_table_lookup_exact_match(fib_index, &pfx_2001_a_s_64)),
5009 "2001::a/64 removed");
5010 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5011 fib_table_lookup_exact_match(fib_index, &pfx_2001_b_s_64)),
5012 "2001::b/64 removed");
5013 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5014 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_3_s_128)),
5015 "2001:0:0:1::3/128 removed");
5016 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5017 fib_table_lookup_exact_match(fib_index, &pfx_2001_1_2_s_128)),
5018 "2001:0:0:1::3/128 removed");
5019 local_pfx.fp_len = 64;
5020 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5021 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5022 "2001:0:0:1/64 removed");
5023 local_pfx.fp_len = 128;
5024 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5025 fib_table_lookup_exact_match(fib_index, &local_pfx)),
5026 "2001:0:0:1::1/128 removed");
5027 connected_pfx.fp_len = 64;
5028 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5029 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5030 "2001:0:0:2/64 removed");
5031 connected_pfx.fp_len = 128;
5032 FIB_TEST((FIB_NODE_INDEX_INVALID ==
5033 fib_table_lookup_exact_match(fib_index, &connected_pfx)),
5034 "2001:0:0:2::1/128 removed");
5037 * -8 entries. -7 path-lists (1 was shared).
5039 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5040 fib_path_list_db_size());
5041 FIB_TEST((PNPS == fib_path_list_pool_size()), "path list pool size is%d",
5042 fib_path_list_pool_size());
5043 FIB_TEST((ENPS == fib_entry_pool_size()), "entry pool size is %d",
5044 fib_entry_pool_size());
5047 * now remove the VRF
5049 fib_table_unlock(fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_API);
5051 FIB_TEST((0 == fib_path_list_db_size()), "path list DB population:%d",
5052 fib_path_list_db_size());
5053 FIB_TEST((PNPS-2 == fib_path_list_pool_size()), "path list pool size is%d",
5054 fib_path_list_pool_size());
5055 FIB_TEST((ENPS-2 == fib_entry_pool_size()), "entry pool size is %d",
5056 fib_entry_pool_size());
5062 * return the interfaces to up state
5064 error = vnet_sw_interface_set_flags(vnet_get_main(),
5065 tm->hw[0]->sw_if_index,
5066 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5067 error = vnet_sw_interface_set_flags(vnet_get_main(),
5068 tm->hw[1]->sw_if_index,
5069 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5071 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5078 * Test Attached Exports
5083 const dpo_id_t *dpo, *dpo_drop;
5084 const u32 fib_index = 0;
5085 fib_node_index_t fei;
5092 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5096 * add interface routes. We'll assume this works. It's more rigorously
5099 fib_prefix_t local_pfx = {
5101 .fp_proto = FIB_PROTOCOL_IP4,
5105 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
5110 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
5111 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
5113 dpo_drop = drop_dpo_get(DPO_PROTO_IP4);
5115 fib_table_entry_update_one_path(fib_index, &local_pfx,
5116 FIB_SOURCE_INTERFACE,
5117 (FIB_ENTRY_FLAG_CONNECTED |
5118 FIB_ENTRY_FLAG_ATTACHED),
5121 tm->hw[0]->sw_if_index,
5125 FIB_ROUTE_PATH_FLAG_NONE);
5126 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5127 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5128 "attached interface route present");
5130 local_pfx.fp_len = 32;
5131 fib_table_entry_update_one_path(fib_index, &local_pfx,
5132 FIB_SOURCE_INTERFACE,
5133 (FIB_ENTRY_FLAG_CONNECTED |
5134 FIB_ENTRY_FLAG_LOCAL),
5137 tm->hw[0]->sw_if_index,
5138 ~0, // invalid fib index
5141 FIB_ROUTE_PATH_FLAG_NONE);
5142 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5144 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
5145 "local interface route present");
5148 * Add an 2 ARP entry => a complete ADJ plus adj-fib.
5150 fib_prefix_t pfx_10_10_10_1_s_32 = {
5152 .fp_proto = FIB_PROTOCOL_IP4,
5155 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5158 fib_node_index_t ai;
5160 fib_table_entry_path_add(fib_index,
5161 &pfx_10_10_10_1_s_32,
5163 FIB_ENTRY_FLAG_ATTACHED,
5165 &pfx_10_10_10_1_s_32.fp_addr,
5166 tm->hw[0]->sw_if_index,
5167 ~0, // invalid fib index
5170 FIB_ROUTE_PATH_FLAG_NONE);
5172 fei = fib_table_lookup(fib_index, &pfx_10_10_10_1_s_32);
5173 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 created");
5174 ai = fib_entry_get_adj(fei);
5177 * create another FIB table into which routes will be imported
5179 u32 import_fib_index1;
5181 import_fib_index1 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4,
5186 * Add an attached route in the import FIB
5188 local_pfx.fp_len = 24;
5189 fib_table_entry_update_one_path(import_fib_index1,
5192 FIB_ENTRY_FLAG_NONE,
5195 tm->hw[0]->sw_if_index,
5196 ~0, // invalid fib index
5199 FIB_ROUTE_PATH_FLAG_NONE);
5200 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5201 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5204 * check for the presence of the adj-fibs in the import table
5206 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5207 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5208 FIB_TEST((ai == fib_entry_get_adj(fei)),
5209 "adj-fib1 Import uses same adj as export");
5212 * check for the presence of the local in the import table
5214 local_pfx.fp_len = 32;
5215 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5216 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5219 * Add another adj-fin in the export table. Expect this
5220 * to get magically exported;
5222 fib_prefix_t pfx_10_10_10_2_s_32 = {
5224 .fp_proto = FIB_PROTOCOL_IP4,
5227 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5231 fib_table_entry_path_add(fib_index,
5232 &pfx_10_10_10_2_s_32,
5234 FIB_ENTRY_FLAG_ATTACHED,
5236 &pfx_10_10_10_2_s_32.fp_addr,
5237 tm->hw[0]->sw_if_index,
5238 ~0, // invalid fib index
5241 FIB_ROUTE_PATH_FLAG_NONE);
5242 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5243 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 present");
5244 ai = fib_entry_get_adj(fei);
5246 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5247 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5248 FIB_TEST((ai == fib_entry_get_adj(fei)),
5249 "Import uses same adj as export");
5250 FIB_TEST((FIB_ENTRY_FLAG_ATTACHED & fib_entry_get_flags(fei)),
5251 "ADJ-fib2 imported flags %d",
5252 fib_entry_get_flags(fei));
5255 * create a 2nd FIB table into which routes will be imported
5257 u32 import_fib_index2;
5259 import_fib_index2 = fib_table_find_or_create_and_lock(FIB_PROTOCOL_IP4, 12,
5263 * Add an attached route in the import FIB
5265 local_pfx.fp_len = 24;
5266 fib_table_entry_update_one_path(import_fib_index2,
5269 FIB_ENTRY_FLAG_NONE,
5272 tm->hw[0]->sw_if_index,
5273 ~0, // invalid fib index
5276 FIB_ROUTE_PATH_FLAG_NONE);
5277 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5278 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached export created");
5281 * check for the presence of all the adj-fibs and local in the import table
5283 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5284 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5285 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5286 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5287 local_pfx.fp_len = 32;
5288 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5289 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5292 * add a 3rd adj-fib. expect it to be exported to both tables.
5294 fib_prefix_t pfx_10_10_10_3_s_32 = {
5296 .fp_proto = FIB_PROTOCOL_IP4,
5299 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a03),
5303 fib_table_entry_path_add(fib_index,
5304 &pfx_10_10_10_3_s_32,
5306 FIB_ENTRY_FLAG_ATTACHED,
5308 &pfx_10_10_10_3_s_32.fp_addr,
5309 tm->hw[0]->sw_if_index,
5310 ~0, // invalid fib index
5313 FIB_ROUTE_PATH_FLAG_NONE);
5314 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5315 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 present");
5316 ai = fib_entry_get_adj(fei);
5318 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5319 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB1");
5320 FIB_TEST((ai == fib_entry_get_adj(fei)),
5321 "Import uses same adj as export");
5322 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5323 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib3 imported to FIB2");
5324 FIB_TEST((ai == fib_entry_get_adj(fei)),
5325 "Import uses same adj as export");
5328 * remove the 3rd adj fib. we expect it to be removed from both FIBs
5330 fib_table_entry_delete(fib_index,
5331 &pfx_10_10_10_3_s_32,
5334 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_3_s_32);
5335 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 remved");
5337 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_3_s_32);
5338 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB1");
5340 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_3_s_32);
5341 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib3 removed from FIB2");
5344 * remove the attached route from the 2nd FIB. expect the imported
5345 * entires to be removed
5347 local_pfx.fp_len = 24;
5348 fib_table_entry_delete(import_fib_index2,
5351 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5352 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "attached export removed");
5354 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_1_s_32);
5355 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB2");
5356 fei = fib_table_lookup_exact_match(import_fib_index2, &pfx_10_10_10_2_s_32);
5357 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB2");
5358 local_pfx.fp_len = 32;
5359 fei = fib_table_lookup_exact_match(import_fib_index2, &local_pfx);
5360 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB2");
5362 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5363 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 still in FIB1");
5364 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5365 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 still in FIB1");
5366 local_pfx.fp_len = 32;
5367 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5368 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local still in FIB1");
5371 * modify the route in FIB1 so it is no longer attached. expect the imported
5372 * entires to be removed
5374 local_pfx.fp_len = 24;
5375 fib_table_entry_update_one_path(import_fib_index1,
5378 FIB_ENTRY_FLAG_NONE,
5380 &pfx_10_10_10_2_s_32.fp_addr,
5381 tm->hw[0]->sw_if_index,
5382 ~0, // invalid fib index
5385 FIB_ROUTE_PATH_FLAG_NONE);
5386 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5387 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5388 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5389 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5390 local_pfx.fp_len = 32;
5391 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5392 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5395 * modify it back to attached. expect the adj-fibs back
5397 local_pfx.fp_len = 24;
5398 fib_table_entry_update_one_path(import_fib_index1,
5401 FIB_ENTRY_FLAG_NONE,
5404 tm->hw[0]->sw_if_index,
5405 ~0, // invalid fib index
5408 FIB_ROUTE_PATH_FLAG_NONE);
5409 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5410 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported in FIB1");
5411 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5412 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported in FIB1");
5413 local_pfx.fp_len = 32;
5414 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5415 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported in FIB1");
5418 * add a covering attached next-hop for the interface address, so we have
5419 * a valid adj to find when we check the forwarding tables
5421 fib_prefix_t pfx_10_0_0_0_s_8 = {
5423 .fp_proto = FIB_PROTOCOL_IP4,
5426 .ip4.as_u32 = clib_host_to_net_u32(0x0a000000),
5430 fei = fib_table_entry_update_one_path(fib_index,
5433 FIB_ENTRY_FLAG_NONE,
5435 &pfx_10_10_10_3_s_32.fp_addr,
5436 tm->hw[0]->sw_if_index,
5437 ~0, // invalid fib index
5440 FIB_ROUTE_PATH_FLAG_NONE);
5441 dpo = fib_entry_contribute_ip_forwarding(fei);
5444 * remove the route in the export fib. expect the adj-fibs to be removed
5446 local_pfx.fp_len = 24;
5447 fib_table_entry_delete(fib_index,
5449 FIB_SOURCE_INTERFACE);
5451 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5452 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "Delete export: ADJ-fib1 removed from FIB1");
5453 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5454 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5455 local_pfx.fp_len = 32;
5456 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5457 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5460 * the adj-fibs in the export VRF are present in the FIB table,
5461 * but not installed in forwarding, since they have no attached cover.
5462 * Consequently a lookup in the MTRIE gives the adj for the covering
5465 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5466 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5469 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5470 FIB_TEST(lbi == dpo->dpoi_index,
5471 "10.10.10.1 forwards on \n%U not \n%U",
5472 format_load_balance, lbi, 0,
5473 format_dpo_id, dpo, 0);
5474 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5475 FIB_TEST(lbi == dpo->dpoi_index,
5476 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5477 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_3_s_32.fp_addr.ip4);
5478 FIB_TEST(lbi == dpo->dpoi_index,
5479 "10.10.10.3 forwards on %U", format_dpo_id, dpo, 0);
5482 * add the export prefix back, but not as attached.
5483 * No adj-fibs in export nor import tables
5485 local_pfx.fp_len = 24;
5486 fei = fib_table_entry_update_one_path(fib_index,
5489 FIB_ENTRY_FLAG_NONE,
5491 &pfx_10_10_10_1_s_32.fp_addr,
5492 tm->hw[0]->sw_if_index,
5493 ~0, // invalid fib index
5496 FIB_ROUTE_PATH_FLAG_NONE);
5497 dpo = fib_entry_contribute_ip_forwarding(fei);
5499 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5500 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "non-attached in export: ADJ-fib1 in export");
5501 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_1_s_32.fp_addr.ip4);
5502 FIB_TEST(lbi == dpo->dpoi_index,
5503 "10.10.10.1 forwards on %U", format_dpo_id, dpo, 0);
5504 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5505 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 in export");
5506 lbi = ip4_fib_forwarding_lookup(fib_index, &pfx_10_10_10_2_s_32.fp_addr.ip4);
5507 FIB_TEST(lbi == dpo->dpoi_index,
5508 "10.10.10.2 forwards on %U", format_dpo_id, dpo, 0);
5510 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5511 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib1 removed from FIB1");
5512 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5513 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "ADJ-fib2 removed from FIB1");
5514 local_pfx.fp_len = 32;
5515 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5516 FIB_TEST((FIB_NODE_INDEX_INVALID == fei), "local removed from FIB1");
5519 * modify the export prefix so it is attached. expect all covereds to return
5521 local_pfx.fp_len = 24;
5522 fib_table_entry_update_one_path(fib_index,
5525 FIB_ENTRY_FLAG_NONE,
5528 tm->hw[0]->sw_if_index,
5529 ~0, // invalid fib index
5532 FIB_ROUTE_PATH_FLAG_NONE);
5534 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5535 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5536 dpo = fib_entry_contribute_ip_forwarding(fei);
5537 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5538 "Adj-fib1 is not drop in export");
5539 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5540 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5541 local_pfx.fp_len = 32;
5542 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5543 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5544 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5545 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5546 dpo = fib_entry_contribute_ip_forwarding(fei);
5547 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5548 "Adj-fib1 is not drop in export");
5549 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5550 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 imported");
5551 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5552 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5553 local_pfx.fp_len = 32;
5554 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5555 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5558 * modify the export prefix so connected. no change.
5560 local_pfx.fp_len = 24;
5561 fib_table_entry_update_one_path(fib_index, &local_pfx,
5562 FIB_SOURCE_INTERFACE,
5563 (FIB_ENTRY_FLAG_CONNECTED |
5564 FIB_ENTRY_FLAG_ATTACHED),
5567 tm->hw[0]->sw_if_index,
5571 FIB_ROUTE_PATH_FLAG_NONE);
5573 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_1_s_32);
5574 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib1 reinstalled in export");
5575 dpo = fib_entry_contribute_ip_forwarding(fei);
5576 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5577 "Adj-fib1 is not drop in export");
5578 fei = fib_table_lookup_exact_match(fib_index, &pfx_10_10_10_2_s_32);
5579 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 reinstalled in export");
5580 local_pfx.fp_len = 32;
5581 fei = fib_table_lookup_exact_match(fib_index, &local_pfx);
5582 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local reinstalled in export");
5583 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_1_s_32);
5584 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "attached in export: ADJ-fib1 imported");
5585 dpo = fib_entry_contribute_ip_forwarding(fei);
5586 FIB_TEST(dpo_cmp(dpo_drop, load_balance_get_bucket(dpo->dpoi_index, 0)),
5587 "Adj-fib1 is not drop in export");
5588 fei = fib_table_lookup_exact_match(import_fib_index1, &pfx_10_10_10_2_s_32);
5589 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "ADJ-fib2 imported");
5590 local_pfx.fp_len = 32;
5591 fei = fib_table_lookup_exact_match(import_fib_index1, &local_pfx);
5592 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "local imported");
5597 fib_table_entry_delete(fib_index,
5600 fib_table_entry_delete(fib_index,
5601 &pfx_10_10_10_1_s_32,
5603 fib_table_entry_delete(fib_index,
5604 &pfx_10_10_10_2_s_32,
5606 local_pfx.fp_len = 32;
5607 fib_table_entry_delete(fib_index,
5609 FIB_SOURCE_INTERFACE);
5610 local_pfx.fp_len = 24;
5611 fib_table_entry_delete(fib_index,
5614 fib_table_entry_delete(fib_index,
5616 FIB_SOURCE_INTERFACE);
5617 local_pfx.fp_len = 24;
5618 fib_table_entry_delete(import_fib_index1,
5622 fib_table_unlock(import_fib_index1, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5623 fib_table_unlock(import_fib_index2, FIB_PROTOCOL_IP4, FIB_SOURCE_CLI);
5625 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
5632 * Test Path Preference
5635 fib_test_pref (void)
5637 test_main_t *tm = &test_main;
5639 const fib_prefix_t pfx_1_1_1_1_s_32 = {
5641 .fp_proto = FIB_PROTOCOL_IP4,
5644 .as_u32 = clib_host_to_net_u32(0x01010101),
5650 * 2 high, 2 medium and 2 low preference non-recursive paths
5652 fib_route_path_t nr_path_hi_1 = {
5653 .frp_proto = DPO_PROTO_IP4,
5654 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5655 .frp_fib_index = ~0,
5657 .frp_preference = 0,
5658 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5660 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
5663 fib_route_path_t nr_path_hi_2 = {
5664 .frp_proto = DPO_PROTO_IP4,
5665 .frp_sw_if_index = tm->hw[0]->sw_if_index,
5666 .frp_fib_index = ~0,
5668 .frp_preference = 0,
5669 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5671 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
5674 fib_route_path_t nr_path_med_1 = {
5675 .frp_proto = DPO_PROTO_IP4,
5676 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5677 .frp_fib_index = ~0,
5679 .frp_preference = 1,
5680 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5682 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5685 fib_route_path_t nr_path_med_2 = {
5686 .frp_proto = DPO_PROTO_IP4,
5687 .frp_sw_if_index = tm->hw[1]->sw_if_index,
5688 .frp_fib_index = ~0,
5690 .frp_preference = 1,
5691 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5693 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0c01),
5696 fib_route_path_t nr_path_low_1 = {
5697 .frp_proto = DPO_PROTO_IP4,
5698 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5699 .frp_fib_index = ~0,
5701 .frp_preference = 2,
5702 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5704 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b01),
5707 fib_route_path_t nr_path_low_2 = {
5708 .frp_proto = DPO_PROTO_IP4,
5709 .frp_sw_if_index = tm->hw[2]->sw_if_index,
5710 .frp_fib_index = ~0,
5712 .frp_preference = 2,
5713 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5715 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0b02),
5718 fib_route_path_t *nr_paths = NULL;
5720 vec_add1(nr_paths, nr_path_hi_1);
5721 vec_add1(nr_paths, nr_path_hi_2);
5722 vec_add1(nr_paths, nr_path_med_1);
5723 vec_add1(nr_paths, nr_path_med_2);
5724 vec_add1(nr_paths, nr_path_low_1);
5725 vec_add1(nr_paths, nr_path_low_2);
5727 adj_index_t ai_hi_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5729 &nr_path_hi_1.frp_addr,
5730 nr_path_hi_1.frp_sw_if_index);
5731 adj_index_t ai_hi_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5733 &nr_path_hi_2.frp_addr,
5734 nr_path_hi_2.frp_sw_if_index);
5735 adj_index_t ai_med_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5737 &nr_path_med_1.frp_addr,
5738 nr_path_med_1.frp_sw_if_index);
5739 adj_index_t ai_med_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5741 &nr_path_med_2.frp_addr,
5742 nr_path_med_2.frp_sw_if_index);
5743 adj_index_t ai_low_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5745 &nr_path_low_1.frp_addr,
5746 nr_path_low_1.frp_sw_if_index);
5747 adj_index_t ai_low_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
5749 &nr_path_low_2.frp_addr,
5750 nr_path_low_2.frp_sw_if_index);
5752 fib_test_lb_bucket_t ip_hi_1 = {
5758 fib_test_lb_bucket_t ip_hi_2 = {
5764 fib_test_lb_bucket_t ip_med_1 = {
5770 fib_test_lb_bucket_t ip_med_2 = {
5776 fib_test_lb_bucket_t ip_low_1 = {
5782 fib_test_lb_bucket_t ip_low_2 = {
5789 fib_node_index_t fei;
5791 fei = fib_table_entry_path_add2(0,
5794 FIB_ENTRY_FLAG_NONE,
5797 FIB_TEST(fib_test_validate_entry(fei,
5798 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5802 "1.1.1.1/32 via high preference paths");
5805 * bring down the interface on which the high preference path lie
5807 vnet_sw_interface_set_flags(vnet_get_main(),
5808 tm->hw[0]->sw_if_index,
5811 FIB_TEST(fib_test_validate_entry(fei,
5812 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5816 "1.1.1.1/32 via medium preference paths");
5819 * bring down the interface on which the medium preference path lie
5821 vnet_sw_interface_set_flags(vnet_get_main(),
5822 tm->hw[1]->sw_if_index,
5825 FIB_TEST(fib_test_validate_entry(fei,
5826 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5830 "1.1.1.1/32 via low preference paths");
5833 * bring up the interface on which the high preference path lie
5835 vnet_sw_interface_set_flags(vnet_get_main(),
5836 tm->hw[0]->sw_if_index,
5837 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5839 FIB_TEST(fib_test_validate_entry(fei,
5840 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5844 "1.1.1.1/32 via high preference paths");
5847 * bring up the interface on which the medium preference path lie
5849 vnet_sw_interface_set_flags(vnet_get_main(),
5850 tm->hw[1]->sw_if_index,
5851 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
5853 FIB_TEST(fib_test_validate_entry(fei,
5854 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5858 "1.1.1.1/32 via high preference paths");
5860 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
5861 fib_entry_contribute_forwarding(fei,
5862 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5866 * 3 recursive paths of different preference
5868 const fib_prefix_t pfx_1_1_1_2_s_32 = {
5870 .fp_proto = FIB_PROTOCOL_IP4,
5873 .as_u32 = clib_host_to_net_u32(0x01010102),
5877 const fib_prefix_t pfx_1_1_1_3_s_32 = {
5879 .fp_proto = FIB_PROTOCOL_IP4,
5882 .as_u32 = clib_host_to_net_u32(0x01010103),
5886 fei = fib_table_entry_path_add2(0,
5889 FIB_ENTRY_FLAG_NONE,
5891 dpo_id_t ip_1_1_1_2 = DPO_INVALID;
5892 fib_entry_contribute_forwarding(fei,
5893 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5895 fei = fib_table_entry_path_add2(0,
5898 FIB_ENTRY_FLAG_NONE,
5900 dpo_id_t ip_1_1_1_3 = DPO_INVALID;
5901 fib_entry_contribute_forwarding(fei,
5902 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5905 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
5908 .lb = ip_1_1_1_1.dpoi_index,
5911 fib_test_lb_bucket_t ip_o_1_1_1_2 = {
5914 .lb = ip_1_1_1_2.dpoi_index,
5917 fib_test_lb_bucket_t ip_o_1_1_1_3 = {
5920 .lb = ip_1_1_1_3.dpoi_index,
5923 fib_route_path_t r_path_hi = {
5924 .frp_proto = DPO_PROTO_IP4,
5925 .frp_sw_if_index = ~0,
5928 .frp_preference = 0,
5929 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5930 .frp_addr = pfx_1_1_1_1_s_32.fp_addr,
5932 fib_route_path_t r_path_med = {
5933 .frp_proto = DPO_PROTO_IP4,
5934 .frp_sw_if_index = ~0,
5937 .frp_preference = 10,
5938 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
5939 .frp_addr = pfx_1_1_1_2_s_32.fp_addr,
5941 fib_route_path_t r_path_low = {
5942 .frp_proto = DPO_PROTO_IP4,
5943 .frp_sw_if_index = ~0,
5946 .frp_preference = 255,
5947 .frp_flags = FIB_ROUTE_PATH_RESOLVE_VIA_HOST,
5948 .frp_addr = pfx_1_1_1_3_s_32.fp_addr,
5950 fib_route_path_t *r_paths = NULL;
5952 vec_add1(r_paths, r_path_hi);
5953 vec_add1(r_paths, r_path_low);
5954 vec_add1(r_paths, r_path_med);
5957 * add many recursive so we get the LB MAp created
5960 fib_prefix_t pfx_r[N_PFXS];
5961 unsigned int n_pfxs;
5962 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
5964 pfx_r[n_pfxs].fp_len = 32;
5965 pfx_r[n_pfxs].fp_proto = FIB_PROTOCOL_IP4;
5966 pfx_r[n_pfxs].fp_addr.ip4.as_u32 =
5967 clib_host_to_net_u32(0x02000000 + n_pfxs);
5969 fei = fib_table_entry_path_add2(0,
5972 FIB_ENTRY_FLAG_NONE,
5975 FIB_TEST(fib_test_validate_entry(fei,
5976 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5979 "recursive via high preference paths");
5982 * withdraw hig pref resolving entry
5984 fib_table_entry_delete(0,
5988 /* suspend so the update walk kicks int */
5989 vlib_process_suspend(vlib_get_main(), 1e-5);
5991 FIB_TEST(fib_test_validate_entry(fei,
5992 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
5995 "recursive via medium preference paths");
5998 * withdraw medium pref resolving entry
6000 fib_table_entry_delete(0,
6004 /* suspend so the update walk kicks int */
6005 vlib_process_suspend(vlib_get_main(), 1e-5);
6007 FIB_TEST(fib_test_validate_entry(fei,
6008 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6011 "recursive via low preference paths");
6014 * add back paths for next iteration
6016 fei = fib_table_entry_update(0,
6019 FIB_ENTRY_FLAG_NONE,
6021 fei = fib_table_entry_update(0,
6024 FIB_ENTRY_FLAG_NONE,
6027 /* suspend so the update walk kicks int */
6028 vlib_process_suspend(vlib_get_main(), 1e-5);
6030 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6031 FIB_TEST(fib_test_validate_entry(fei,
6032 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6035 "recursive via high preference paths");
6039 fib_table_entry_delete(0,
6043 /* suspend so the update walk kicks int */
6044 vlib_process_suspend(vlib_get_main(), 1e-5);
6046 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6048 fei = fib_table_lookup_exact_match(0, &pfx_r[n_pfxs]);
6050 FIB_TEST(fib_test_validate_entry(fei,
6051 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6054 "recursive via medium preference paths");
6056 for (n_pfxs = 0; n_pfxs < N_PFXS; n_pfxs++)
6058 fib_table_entry_delete(0,
6066 fib_table_entry_delete(0,
6069 fib_table_entry_delete(0,
6073 dpo_reset(&ip_1_1_1_1);
6074 dpo_reset(&ip_1_1_1_2);
6075 dpo_reset(&ip_1_1_1_3);
6076 adj_unlock(ai_low_2);
6077 adj_unlock(ai_low_1);
6078 adj_unlock(ai_med_2);
6079 adj_unlock(ai_med_1);
6080 adj_unlock(ai_hi_2);
6081 adj_unlock(ai_hi_1);
6086 * Test the recursive route route handling for GRE tunnels
6089 fib_test_label (void)
6091 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;
6092 const u32 fib_index = 0;
6097 lb_count = pool_elts(load_balance_pool);
6102 * add interface routes. We'll assume this works. It's more rigorously
6105 fib_prefix_t local0_pfx = {
6107 .fp_proto = FIB_PROTOCOL_IP4,
6111 .as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
6116 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
6119 vec_validate(im->fib_index_by_sw_if_index, tm->hw[0]->sw_if_index);
6120 im->fib_index_by_sw_if_index[tm->hw[0]->sw_if_index] = fib_index;
6122 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6123 FIB_SOURCE_INTERFACE,
6124 (FIB_ENTRY_FLAG_CONNECTED |
6125 FIB_ENTRY_FLAG_ATTACHED),
6128 tm->hw[0]->sw_if_index,
6132 FIB_ROUTE_PATH_FLAG_NONE);
6133 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6134 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6135 "attached interface route present");
6137 local0_pfx.fp_len = 32;
6138 fib_table_entry_update_one_path(fib_index, &local0_pfx,
6139 FIB_SOURCE_INTERFACE,
6140 (FIB_ENTRY_FLAG_CONNECTED |
6141 FIB_ENTRY_FLAG_LOCAL),
6144 tm->hw[0]->sw_if_index,
6145 ~0, // invalid fib index
6148 FIB_ROUTE_PATH_FLAG_NONE);
6149 fei = fib_table_lookup_exact_match(fib_index, &local0_pfx);
6151 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6152 "local interface route present");
6154 fib_prefix_t local1_pfx = {
6156 .fp_proto = FIB_PROTOCOL_IP4,
6160 .as_u32 = clib_host_to_net_u32(0x0a0a0b0a),
6165 vec_validate(im->fib_index_by_sw_if_index, tm->hw[1]->sw_if_index);
6166 im->fib_index_by_sw_if_index[tm->hw[1]->sw_if_index] = fib_index;
6168 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6169 FIB_SOURCE_INTERFACE,
6170 (FIB_ENTRY_FLAG_CONNECTED |
6171 FIB_ENTRY_FLAG_ATTACHED),
6174 tm->hw[1]->sw_if_index,
6178 FIB_ROUTE_PATH_FLAG_NONE);
6179 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6180 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6181 "attached interface route present");
6183 local1_pfx.fp_len = 32;
6184 fib_table_entry_update_one_path(fib_index, &local1_pfx,
6185 FIB_SOURCE_INTERFACE,
6186 (FIB_ENTRY_FLAG_CONNECTED |
6187 FIB_ENTRY_FLAG_LOCAL),
6190 tm->hw[1]->sw_if_index,
6191 ~0, // invalid fib index
6194 FIB_ROUTE_PATH_FLAG_NONE);
6195 fei = fib_table_lookup_exact_match(fib_index, &local1_pfx);
6197 FIB_TEST((FIB_NODE_INDEX_INVALID != fei),
6198 "local interface route present");
6200 ip46_address_t nh_10_10_10_1 = {
6202 .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
6205 ip46_address_t nh_10_10_11_1 = {
6207 .as_u32 = clib_host_to_net_u32(0x0a0a0b01),
6210 ip46_address_t nh_10_10_11_2 = {
6212 .as_u32 = clib_host_to_net_u32(0x0a0a0b02),
6216 ai_v4_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6219 tm->hw[1]->sw_if_index);
6220 ai_v4_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6223 tm->hw[1]->sw_if_index);
6224 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6227 tm->hw[0]->sw_if_index);
6228 ai_mpls_10_10_11_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6231 tm->hw[1]->sw_if_index);
6232 ai_mpls_10_10_11_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
6235 tm->hw[1]->sw_if_index);
6238 * Add an etry with one path with a real out-going label
6240 fib_prefix_t pfx_1_1_1_1_s_32 = {
6242 .fp_proto = FIB_PROTOCOL_IP4,
6244 .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
6247 fib_test_lb_bucket_t l99_eos_o_10_10_10_1 = {
6248 .type = FT_LB_LABEL_O_ADJ,
6250 .adj = ai_mpls_10_10_10_1,
6255 fib_test_lb_bucket_t l99_neos_o_10_10_10_1 = {
6256 .type = FT_LB_LABEL_O_ADJ,
6258 .adj = ai_mpls_10_10_10_1,
6260 .eos = MPLS_NON_EOS,
6263 mpls_label_t *l99 = NULL;
6266 fib_table_entry_update_one_path(fib_index,
6269 FIB_ENTRY_FLAG_NONE,
6272 tm->hw[0]->sw_if_index,
6273 ~0, // invalid fib index
6276 FIB_ROUTE_PATH_FLAG_NONE);
6278 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6279 FIB_TEST((FIB_NODE_INDEX_INVALID != fei), "1.1.1.1/32 created");
6281 FIB_TEST(fib_test_validate_entry(fei,
6282 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6284 &l99_eos_o_10_10_10_1),
6285 "1.1.1.1/32 LB 1 bucket via label 99 over 10.10.10.1");
6288 * add a path with an implicit NULL label
6290 fib_test_lb_bucket_t a_o_10_10_11_1 = {
6293 .adj = ai_v4_10_10_11_1,
6296 fib_test_lb_bucket_t a_mpls_o_10_10_11_1 = {
6299 .adj = ai_mpls_10_10_11_1,
6302 mpls_label_t *l_imp_null = NULL;
6303 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6305 fei = fib_table_entry_path_add(fib_index,
6308 FIB_ENTRY_FLAG_NONE,
6311 tm->hw[1]->sw_if_index,
6312 ~0, // invalid fib index
6315 FIB_ROUTE_PATH_FLAG_NONE);
6317 FIB_TEST(fib_test_validate_entry(fei,
6318 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6320 &l99_eos_o_10_10_10_1,
6322 "1.1.1.1/32 LB 2 buckets via: "
6323 "label 99 over 10.10.10.1, "
6324 "adj over 10.10.11.1");
6327 * assign the route a local label
6329 fib_table_entry_local_label_add(fib_index,
6333 fib_prefix_t pfx_24001_eos = {
6334 .fp_proto = FIB_PROTOCOL_MPLS,
6338 fib_prefix_t pfx_24001_neos = {
6339 .fp_proto = FIB_PROTOCOL_MPLS,
6341 .fp_eos = MPLS_NON_EOS,
6345 * The EOS entry should link to both the paths,
6346 * and use an ip adj for the imp-null
6347 * The NON-EOS entry should link to both the paths,
6348 * and use an mpls adj for the imp-null
6350 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6352 FIB_TEST(fib_test_validate_entry(fei,
6353 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6355 &l99_eos_o_10_10_10_1,
6357 "24001/eos LB 2 buckets via: "
6358 "label 99 over 10.10.10.1, "
6359 "adj over 10.10.11.1");
6362 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6364 FIB_TEST(fib_test_validate_entry(fei,
6365 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6367 &l99_neos_o_10_10_10_1,
6368 &a_mpls_o_10_10_11_1),
6369 "24001/neos LB 1 bucket via: "
6370 "label 99 over 10.10.10.1 ",
6371 "mpls-adj via 10.10.11.1");
6374 * add an unlabelled path, this is excluded from the neos chains,
6376 fib_test_lb_bucket_t adj_o_10_10_11_2 = {
6379 .adj = ai_v4_10_10_11_2,
6383 fei = fib_table_entry_path_add(fib_index,
6386 FIB_ENTRY_FLAG_NONE,
6389 tm->hw[1]->sw_if_index,
6390 ~0, // invalid fib index
6393 FIB_ROUTE_PATH_FLAG_NONE);
6395 FIB_TEST(fib_test_validate_entry(fei,
6396 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6397 16, // 3 choices spread over 16 buckets
6398 &l99_eos_o_10_10_10_1,
6399 &l99_eos_o_10_10_10_1,
6400 &l99_eos_o_10_10_10_1,
6401 &l99_eos_o_10_10_10_1,
6402 &l99_eos_o_10_10_10_1,
6403 &l99_eos_o_10_10_10_1,
6414 "1.1.1.1/32 LB 16 buckets via: "
6415 "label 99 over 10.10.10.1, "
6416 "adj over 10.10.11.1",
6417 "adj over 10.10.11.2");
6420 * get and lock a reference to the non-eos of the via entry 1.1.1.1/32
6422 dpo_id_t non_eos_1_1_1_1 = DPO_INVALID;
6423 fib_entry_contribute_forwarding(fei,
6424 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6428 * n-eos has only the 2 labelled paths
6430 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6433 FIB_TEST(fib_test_validate_entry(fei,
6434 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6436 &l99_neos_o_10_10_10_1,
6437 &a_mpls_o_10_10_11_1),
6438 "24001/neos LB 2 buckets via: "
6439 "label 99 over 10.10.10.1, "
6440 "adj-mpls over 10.10.11.2");
6443 * A labelled recursive
6445 fib_prefix_t pfx_2_2_2_2_s_32 = {
6447 .fp_proto = FIB_PROTOCOL_IP4,
6449 .ip4.as_u32 = clib_host_to_net_u32(0x02020202),
6452 fib_test_lb_bucket_t l1600_eos_o_1_1_1_1 = {
6453 .type = FT_LB_LABEL_O_LB,
6455 .lb = non_eos_1_1_1_1.dpoi_index,
6460 mpls_label_t *l1600 = NULL;
6461 vec_add1(l1600, 1600);
6463 fib_table_entry_update_one_path(fib_index,
6466 FIB_ENTRY_FLAG_NONE,
6468 &pfx_1_1_1_1_s_32.fp_addr,
6473 FIB_ROUTE_PATH_FLAG_NONE);
6475 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6476 FIB_TEST(fib_test_validate_entry(fei,
6477 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6479 &l1600_eos_o_1_1_1_1),
6480 "2.2.2.2.2/32 LB 1 buckets via: "
6481 "label 1600 over 1.1.1.1");
6483 dpo_id_t dpo_44 = DPO_INVALID;
6486 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_UNICAST_IP4, &dpo_44);
6487 urpfi = load_balance_get_urpf(dpo_44.dpoi_index);
6489 FIB_TEST(fib_urpf_check(urpfi, tm->hw[0]->sw_if_index),
6490 "uRPF check for 2.2.2.2/32 on %d OK",
6491 tm->hw[0]->sw_if_index);
6492 FIB_TEST(fib_urpf_check(urpfi, tm->hw[1]->sw_if_index),
6493 "uRPF check for 2.2.2.2/32 on %d OK",
6494 tm->hw[1]->sw_if_index);
6495 FIB_TEST(!fib_urpf_check(urpfi, 99),
6496 "uRPF check for 2.2.2.2/32 on 99 not-OK",
6499 fib_entry_contribute_forwarding(fei, FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS, &dpo_44);
6500 FIB_TEST(urpfi == load_balance_get_urpf(dpo_44.dpoi_index),
6501 "Shared uRPF on IP and non-EOS chain");
6506 * we are holding a lock on the non-eos LB of the via-entry.
6507 * do a PIC-core failover by shutting the link of the via-entry.
6509 * shut down the link with the valid label
6511 vnet_sw_interface_set_flags(vnet_get_main(),
6512 tm->hw[0]->sw_if_index,
6515 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6516 FIB_TEST(fib_test_validate_entry(fei,
6517 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6521 "1.1.1.1/32 LB 2 buckets via: "
6522 "adj over 10.10.11.1, ",
6523 "adj-v4 over 10.10.11.2");
6525 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6527 FIB_TEST(fib_test_validate_entry(fei,
6528 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6532 "24001/eos LB 2 buckets via: "
6533 "adj over 10.10.11.1, ",
6534 "adj-v4 over 10.10.11.2");
6536 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6538 FIB_TEST(fib_test_validate_entry(fei,
6539 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6541 &a_mpls_o_10_10_11_1),
6542 "24001/neos LB 1 buckets via: "
6543 "adj-mpls over 10.10.11.2");
6546 * test that the pre-failover load-balance has been in-place
6549 dpo_id_t current = DPO_INVALID;
6550 fib_entry_contribute_forwarding(fei,
6551 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6554 FIB_TEST(!dpo_cmp(&non_eos_1_1_1_1,
6556 "PIC-core LB inplace modified %U %U",
6557 format_dpo_id, &non_eos_1_1_1_1, 0,
6558 format_dpo_id, ¤t, 0);
6560 dpo_reset(&non_eos_1_1_1_1);
6561 dpo_reset(¤t);
6564 * no-shut the link with the valid label
6566 vnet_sw_interface_set_flags(vnet_get_main(),
6567 tm->hw[0]->sw_if_index,
6568 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
6570 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6571 FIB_TEST(fib_test_validate_entry(fei,
6572 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6573 16, // 3 choices spread over 16 buckets
6574 &l99_eos_o_10_10_10_1,
6575 &l99_eos_o_10_10_10_1,
6576 &l99_eos_o_10_10_10_1,
6577 &l99_eos_o_10_10_10_1,
6578 &l99_eos_o_10_10_10_1,
6579 &l99_eos_o_10_10_10_1,
6590 "1.1.1.1/32 LB 16 buckets via: "
6591 "label 99 over 10.10.10.1, "
6592 "adj over 10.10.11.1",
6593 "adj-v4 over 10.10.11.2");
6596 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6598 FIB_TEST(fib_test_validate_entry(fei,
6599 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6600 16, // 3 choices spread over 16 buckets
6601 &l99_eos_o_10_10_10_1,
6602 &l99_eos_o_10_10_10_1,
6603 &l99_eos_o_10_10_10_1,
6604 &l99_eos_o_10_10_10_1,
6605 &l99_eos_o_10_10_10_1,
6606 &l99_eos_o_10_10_10_1,
6617 "24001/eos LB 16 buckets via: "
6618 "label 99 over 10.10.10.1, "
6619 "adj over 10.10.11.1",
6620 "adj-v4 over 10.10.11.2");
6622 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6624 FIB_TEST(fib_test_validate_entry(fei,
6625 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6627 &l99_neos_o_10_10_10_1,
6628 &a_mpls_o_10_10_11_1),
6629 "24001/neos LB 2 buckets via: "
6630 "label 99 over 10.10.10.1, "
6631 "adj-mpls over 10.10.11.2");
6634 * remove the first path with the valid label
6636 fib_table_entry_path_remove(fib_index,
6641 tm->hw[0]->sw_if_index,
6642 ~0, // invalid fib index
6644 FIB_ROUTE_PATH_FLAG_NONE);
6646 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6647 FIB_TEST(fib_test_validate_entry(fei,
6648 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6652 "1.1.1.1/32 LB 2 buckets via: "
6653 "adj over 10.10.11.1, "
6654 "adj-v4 over 10.10.11.2");
6656 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6658 FIB_TEST(fib_test_validate_entry(fei,
6659 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6663 "24001/eos LB 2 buckets via: "
6664 "adj over 10.10.11.1, "
6665 "adj-v4 over 10.10.11.2");
6667 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6670 FIB_TEST(fib_test_validate_entry(fei,
6671 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6673 &a_mpls_o_10_10_11_1),
6674 "24001/neos LB 1 buckets via: "
6675 "adj-mpls over 10.10.11.2");
6678 * remove the other path with a valid label
6680 fib_test_lb_bucket_t bucket_drop = {
6681 .type = FT_LB_SPECIAL,
6683 .adj = DPO_PROTO_IP4,
6686 fib_test_lb_bucket_t mpls_bucket_drop = {
6687 .type = FT_LB_SPECIAL,
6689 .adj = DPO_PROTO_MPLS,
6693 fib_table_entry_path_remove(fib_index,
6698 tm->hw[1]->sw_if_index,
6699 ~0, // invalid fib index
6701 FIB_ROUTE_PATH_FLAG_NONE);
6703 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6704 FIB_TEST(fib_test_validate_entry(fei,
6705 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6708 "1.1.1.1/32 LB 1 buckets via: "
6709 "adj over 10.10.11.2");
6711 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6713 FIB_TEST(fib_test_validate_entry(fei,
6714 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6717 "24001/eos LB 1 buckets via: "
6718 "adj over 10.10.11.2");
6720 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6722 FIB_TEST(fib_test_validate_entry(fei,
6723 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6726 "24001/neos LB 1 buckets via: DROP");
6729 * add back the path with the valid label
6734 fib_table_entry_path_add(fib_index,
6737 FIB_ENTRY_FLAG_NONE,
6740 tm->hw[0]->sw_if_index,
6741 ~0, // invalid fib index
6744 FIB_ROUTE_PATH_FLAG_NONE);
6746 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6747 FIB_TEST(fib_test_validate_entry(fei,
6748 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6750 &l99_eos_o_10_10_10_1,
6752 "1.1.1.1/32 LB 2 buckets via: "
6753 "label 99 over 10.10.10.1, "
6754 "adj over 10.10.11.2");
6756 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6758 FIB_TEST(fib_test_validate_entry(fei,
6759 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6761 &l99_eos_o_10_10_10_1,
6763 "24001/eos LB 2 buckets via: "
6764 "label 99 over 10.10.10.1, "
6765 "adj over 10.10.11.2");
6767 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6769 FIB_TEST(fib_test_validate_entry(fei,
6770 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6772 &l99_neos_o_10_10_10_1),
6773 "24001/neos LB 1 buckets via: "
6774 "label 99 over 10.10.10.1");
6777 * change the local label
6779 fib_table_entry_local_label_add(fib_index,
6783 fib_prefix_t pfx_25005_eos = {
6784 .fp_proto = FIB_PROTOCOL_MPLS,
6788 fib_prefix_t pfx_25005_neos = {
6789 .fp_proto = FIB_PROTOCOL_MPLS,
6791 .fp_eos = MPLS_NON_EOS,
6794 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6795 fib_table_lookup(fib_index, &pfx_24001_eos)),
6796 "24001/eos removed after label change");
6797 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6798 fib_table_lookup(fib_index, &pfx_24001_neos)),
6799 "24001/eos removed after label change");
6801 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6803 FIB_TEST(fib_test_validate_entry(fei,
6804 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
6806 &l99_eos_o_10_10_10_1,
6808 "25005/eos LB 2 buckets via: "
6809 "label 99 over 10.10.10.1, "
6810 "adj over 10.10.11.2");
6812 fei = fib_table_lookup(MPLS_FIB_DEFAULT_TABLE_ID,
6814 FIB_TEST(fib_test_validate_entry(fei,
6815 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6817 &l99_neos_o_10_10_10_1),
6818 "25005/neos LB 1 buckets via: "
6819 "label 99 over 10.10.10.1");
6822 * remove the local label.
6823 * the check that the MPLS entries are gone is done by the fact the
6824 * MPLS table is no longer present.
6826 fib_table_entry_local_label_remove(fib_index,
6830 fei = fib_table_lookup(fib_index, &pfx_1_1_1_1_s_32);
6831 FIB_TEST(fib_test_validate_entry(fei,
6832 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6834 &l99_eos_o_10_10_10_1,
6836 "24001/eos LB 2 buckets via: "
6837 "label 99 over 10.10.10.1, "
6838 "adj over 10.10.11.2");
6840 FIB_TEST((FIB_NODE_INDEX_INVALID ==
6841 mpls_fib_index_from_table_id(MPLS_FIB_DEFAULT_TABLE_ID)),
6842 "No more MPLS FIB entries => table removed");
6845 * add another via-entry for the recursive
6847 fib_prefix_t pfx_1_1_1_2_s_32 = {
6849 .fp_proto = FIB_PROTOCOL_IP4,
6851 .ip4.as_u32 = clib_host_to_net_u32(0x01010102),
6854 fib_test_lb_bucket_t l101_eos_o_10_10_10_1 = {
6855 .type = FT_LB_LABEL_O_ADJ,
6857 .adj = ai_mpls_10_10_10_1,
6862 mpls_label_t *l101 = NULL;
6863 vec_add1(l101, 101);
6865 fei = fib_table_entry_update_one_path(fib_index,
6868 FIB_ENTRY_FLAG_NONE,
6871 tm->hw[0]->sw_if_index,
6872 ~0, // invalid fib index
6875 FIB_ROUTE_PATH_FLAG_NONE);
6877 FIB_TEST(fib_test_validate_entry(fei,
6878 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6880 &l101_eos_o_10_10_10_1),
6881 "1.1.1.2/32 LB 1 buckets via: "
6882 "label 101 over 10.10.10.1");
6884 dpo_id_t non_eos_1_1_1_2 = DPO_INVALID;
6885 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6887 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6889 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
6891 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
6894 fib_test_lb_bucket_t l1601_eos_o_1_1_1_2 = {
6895 .type = FT_LB_LABEL_O_LB,
6897 .lb = non_eos_1_1_1_2.dpoi_index,
6902 mpls_label_t *l1601 = NULL;
6903 vec_add1(l1601, 1601);
6905 l1600_eos_o_1_1_1_1.label_o_lb.lb = non_eos_1_1_1_1.dpoi_index;
6907 fei = fib_table_entry_path_add(fib_index,
6910 FIB_ENTRY_FLAG_NONE,
6912 &pfx_1_1_1_2_s_32.fp_addr,
6917 FIB_ROUTE_PATH_FLAG_NONE);
6919 FIB_TEST(fib_test_validate_entry(fei,
6920 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6922 &l1600_eos_o_1_1_1_1,
6923 &l1601_eos_o_1_1_1_2),
6924 "2.2.2.2/32 LB 2 buckets via: "
6925 "label 1600 via 1.1,1.1, "
6926 "label 16001 via 1.1.1.2");
6929 * update the via-entry so it no longer has an imp-null path.
6930 * the LB for the recursive can use an imp-null
6933 vec_add1(l_imp_null, MPLS_IETF_IMPLICIT_NULL_LABEL);
6935 fei = fib_table_entry_update_one_path(fib_index,
6938 FIB_ENTRY_FLAG_NONE,
6941 tm->hw[1]->sw_if_index,
6942 ~0, // invalid fib index
6945 FIB_ROUTE_PATH_FLAG_NONE);
6947 FIB_TEST(fib_test_validate_entry(fei,
6948 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6951 "1.1.1.2/32 LB 1 buckets via: "
6954 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6955 FIB_TEST(fib_test_validate_entry(fei,
6956 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6958 &l1600_eos_o_1_1_1_1,
6959 &l1601_eos_o_1_1_1_2),
6960 "2.2.2.2/32 LB 2 buckets via: "
6961 "label 1600 via 1.1,1.1, "
6962 "label 16001 via 1.1.1.2");
6965 * update the via-entry so it no longer has labelled paths.
6966 * the LB for the recursive should exclue this via form its LB
6968 fei = fib_table_entry_update_one_path(fib_index,
6971 FIB_ENTRY_FLAG_NONE,
6974 tm->hw[1]->sw_if_index,
6975 ~0, // invalid fib index
6978 FIB_ROUTE_PATH_FLAG_NONE);
6980 FIB_TEST(fib_test_validate_entry(fei,
6981 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6984 "1.1.1.2/32 LB 1 buckets via: "
6987 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
6988 FIB_TEST(fib_test_validate_entry(fei,
6989 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
6991 &l1600_eos_o_1_1_1_1),
6992 "2.2.2.2/32 LB 1 buckets via: "
6993 "label 1600 via 1.1,1.1");
6995 dpo_reset(&non_eos_1_1_1_1);
6996 dpo_reset(&non_eos_1_1_1_2);
6999 * Add a recursive with no out-labels. We expect to use the IP of the via
7001 fib_prefix_t pfx_2_2_2_3_s_32 = {
7003 .fp_proto = FIB_PROTOCOL_IP4,
7005 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
7008 dpo_id_t ip_1_1_1_1 = DPO_INVALID;
7010 fib_table_entry_update_one_path(fib_index,
7013 FIB_ENTRY_FLAG_NONE,
7015 &pfx_1_1_1_1_s_32.fp_addr,
7020 FIB_ROUTE_PATH_FLAG_NONE);
7022 fib_entry_contribute_forwarding(fib_table_lookup(fib_index,
7024 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7027 fib_test_lb_bucket_t ip_o_1_1_1_1 = {
7030 .lb = ip_1_1_1_1.dpoi_index,
7034 fei = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
7035 FIB_TEST(fib_test_validate_entry(fei,
7036 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7039 "2.2.2.2.3/32 LB 1 buckets via: "
7043 * Add a recursive with an imp-null out-label.
7044 * We expect to use the IP of the via
7046 fib_prefix_t pfx_2_2_2_4_s_32 = {
7048 .fp_proto = FIB_PROTOCOL_IP4,
7050 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
7054 fib_table_entry_update_one_path(fib_index,
7057 FIB_ENTRY_FLAG_NONE,
7059 &pfx_1_1_1_1_s_32.fp_addr,
7064 FIB_ROUTE_PATH_FLAG_NONE);
7066 fei = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
7067 FIB_TEST(fib_test_validate_entry(fei,
7068 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7071 "2.2.2.2.4/32 LB 1 buckets via: "
7074 dpo_reset(&ip_1_1_1_1);
7077 * Create an entry with a deep label stack
7079 fib_prefix_t pfx_2_2_5_5_s_32 = {
7081 .fp_proto = FIB_PROTOCOL_IP4,
7083 .ip4.as_u32 = clib_host_to_net_u32(0x02020505),
7086 fib_test_lb_bucket_t ls_eos_o_10_10_10_1 = {
7087 .type = FT_LB_LABEL_STACK_O_ADJ,
7088 .label_stack_o_adj = {
7089 .adj = ai_mpls_10_10_11_1,
7090 .label_stack_size = 8,
7092 200, 201, 202, 203, 204, 205, 206, 207
7097 mpls_label_t *label_stack = NULL;
7098 vec_validate(label_stack, 7);
7099 for (ii = 0; ii < 8; ii++)
7101 label_stack[ii] = ii + 200;
7104 fei = fib_table_entry_update_one_path(fib_index,
7107 FIB_ENTRY_FLAG_NONE,
7110 tm->hw[1]->sw_if_index,
7111 ~0, // invalid fib index
7114 FIB_ROUTE_PATH_FLAG_NONE);
7116 FIB_TEST(fib_test_validate_entry(fei,
7117 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7119 &ls_eos_o_10_10_10_1),
7120 "2.2.5.5/32 LB 1 buckets via: "
7122 fib_table_entry_delete_index(fei, FIB_SOURCE_API);
7127 fib_table_entry_delete(fib_index,
7131 fei = fib_table_lookup(fib_index, &pfx_2_2_2_2_s_32);
7132 FIB_TEST(fib_test_validate_entry(fei,
7133 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7135 &l1600_eos_o_1_1_1_1),
7136 "2.2.2.2/32 LB 1 buckets via: "
7137 "label 1600 via 1.1,1.1");
7139 fib_table_entry_delete(fib_index,
7143 FIB_TEST(fib_test_validate_entry(fei,
7144 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7147 "2.2.2.2/32 LB 1 buckets via: DROP");
7149 fib_table_entry_delete(fib_index,
7152 fib_table_entry_delete(fib_index,
7155 fib_table_entry_delete(fib_index,
7159 adj_unlock(ai_mpls_10_10_10_1);
7160 adj_unlock(ai_mpls_10_10_11_2);
7161 adj_unlock(ai_v4_10_10_11_1);
7162 adj_unlock(ai_v4_10_10_11_2);
7163 adj_unlock(ai_mpls_10_10_11_1);
7165 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
7168 local0_pfx.fp_len = 32;
7169 fib_table_entry_delete(fib_index,
7171 FIB_SOURCE_INTERFACE);
7172 local0_pfx.fp_len = 24;
7173 fib_table_entry_delete(fib_index,
7175 FIB_SOURCE_INTERFACE);
7176 local1_pfx.fp_len = 32;
7177 fib_table_entry_delete(fib_index,
7179 FIB_SOURCE_INTERFACE);
7180 local1_pfx.fp_len = 24;
7181 fib_table_entry_delete(fib_index,
7183 FIB_SOURCE_INTERFACE);
7186 * +1 for the drop LB in the MPLS tables.
7188 FIB_TEST(lb_count+1 == pool_elts(load_balance_pool),
7189 "Load-balance resources freed %d of %d",
7190 lb_count+1, pool_elts(load_balance_pool));
7195 #define N_TEST_CHILDREN 4
7196 #define PARENT_INDEX 0
7198 typedef struct fib_node_test_t_
7203 fib_node_back_walk_ctx_t *ctxs;
7207 static fib_node_test_t fib_test_nodes[N_TEST_CHILDREN+1];
7209 #define PARENT() (&fib_test_nodes[PARENT_INDEX].node)
7211 #define FOR_EACH_TEST_CHILD(_tc) \
7212 for (ii = 1, (_tc) = &fib_test_nodes[1]; \
7213 ii < N_TEST_CHILDREN+1; \
7214 ii++, (_tc) = &fib_test_nodes[ii])
7217 fib_test_child_get_node (fib_node_index_t index)
7219 return (&fib_test_nodes[index].node);
7222 static int fib_test_walk_spawns_walks;
7224 static fib_node_back_walk_rc_t
7225 fib_test_child_back_walk_notify (fib_node_t *node,
7226 fib_node_back_walk_ctx_t *ctx)
7228 fib_node_test_t *tc = (fib_node_test_t*) node;
7230 vec_add1(tc->ctxs, *ctx);
7232 if (1 == fib_test_walk_spawns_walks)
7233 fib_walk_sync(FIB_NODE_TYPE_TEST, tc->index, ctx);
7234 if (2 == fib_test_walk_spawns_walks)
7235 fib_walk_async(FIB_NODE_TYPE_TEST, tc->index,
7236 FIB_WALK_PRIORITY_HIGH, ctx);
7238 return (FIB_NODE_BACK_WALK_CONTINUE);
7242 fib_test_child_last_lock_gone (fib_node_t *node)
7244 fib_node_test_t *tc = (fib_node_test_t *)node;
7250 * The FIB walk's graph node virtual function table
7252 static const fib_node_vft_t fib_test_child_vft = {
7253 .fnv_get = fib_test_child_get_node,
7254 .fnv_last_lock = fib_test_child_last_lock_gone,
7255 .fnv_back_walk = fib_test_child_back_walk_notify,
7259 * the function (that should have been static but isn't so I can do this)
7260 * that processes the walk from the async queue,
7262 f64 fib_walk_process_queues(vlib_main_t * vm,
7264 u32 fib_walk_queue_get_size(fib_walk_priority_t prio);
7267 fib_test_walk (void)
7269 fib_node_back_walk_ctx_t high_ctx = {}, low_ctx = {};
7270 fib_node_test_t *tc;
7274 vm = vlib_get_main();
7275 fib_node_register_type(FIB_NODE_TYPE_TEST, &fib_test_child_vft);
7278 * init a fake node on which we will add children
7280 fib_node_init(&fib_test_nodes[PARENT_INDEX].node,
7281 FIB_NODE_TYPE_TEST);
7283 FOR_EACH_TEST_CHILD(tc)
7285 fib_node_init(&tc->node, FIB_NODE_TYPE_TEST);
7286 fib_node_lock(&tc->node);
7289 tc->sibling = fib_node_child_add(FIB_NODE_TYPE_TEST,
7291 FIB_NODE_TYPE_TEST, ii);
7295 * enqueue a walk across the parents children.
7297 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7299 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7300 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7301 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7302 "Parent has %d children pre-walk",
7303 fib_node_list_get_size(PARENT()->fn_children));
7306 * give the walk a large amount of time so it gets to the end
7308 fib_walk_process_queues(vm, 1);
7310 FOR_EACH_TEST_CHILD(tc)
7312 FIB_TEST(1 == vec_len(tc->ctxs),
7313 "%d child visitsed %d times",
7314 ii, vec_len(tc->ctxs));
7317 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7318 "Queue is empty post walk");
7319 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7320 "Parent has %d children post walk",
7321 fib_node_list_get_size(PARENT()->fn_children));
7324 * walk again. should be no increase in the number of visits, since
7325 * the walk will have terminated.
7327 fib_walk_process_queues(vm, 1);
7329 FOR_EACH_TEST_CHILD(tc)
7331 FIB_TEST(0 == vec_len(tc->ctxs),
7332 "%d child visitsed %d times",
7333 ii, vec_len(tc->ctxs));
7337 * schedule a low and hig priority walk. expect the high to be performed
7339 * schedule the high prio walk first so that it is further from the head
7340 * of the dependency list. that way it won't merge with the low one.
7342 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7343 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7345 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7346 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7347 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7348 FIB_WALK_PRIORITY_LOW, &low_ctx);
7350 fib_walk_process_queues(vm, 1);
7352 FOR_EACH_TEST_CHILD(tc)
7354 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7355 "%d child visitsed by high prio walk", ii);
7356 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7357 "%d child visitsed by low prio walk", ii);
7360 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7361 "Queue is empty post prio walk");
7362 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7363 "Parent has %d children post prio walk",
7364 fib_node_list_get_size(PARENT()->fn_children));
7367 * schedule 2 walks of the same priority that can be megred.
7368 * expect that each child is thus visited only once.
7370 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7371 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7373 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7374 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7375 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7376 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7378 fib_walk_process_queues(vm, 1);
7380 FOR_EACH_TEST_CHILD(tc)
7382 FIB_TEST(1 == vec_len(tc->ctxs),
7383 "%d child visitsed %d times during merge walk",
7384 ii, vec_len(tc->ctxs));
7387 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7388 "Queue is empty post merge walk");
7389 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7390 "Parent has %d children post merge walk",
7391 fib_node_list_get_size(PARENT()->fn_children));
7394 * schedule 2 walks of the same priority that cannot be megred.
7395 * expect that each child is thus visited twice and in the order
7396 * in which the walks were scheduled.
7398 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7399 low_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE;
7401 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7402 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7403 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7404 FIB_WALK_PRIORITY_HIGH, &low_ctx);
7406 fib_walk_process_queues(vm, 1);
7408 FOR_EACH_TEST_CHILD(tc)
7410 FIB_TEST(high_ctx.fnbw_reason == tc->ctxs[0].fnbw_reason,
7411 "%d child visitsed by high prio walk", ii);
7412 FIB_TEST(low_ctx.fnbw_reason == tc->ctxs[1].fnbw_reason,
7413 "%d child visitsed by low prio walk", ii);
7416 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7417 "Queue is empty post no-merge walk");
7418 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7419 "Parent has %d children post no-merge walk",
7420 fib_node_list_get_size(PARENT()->fn_children));
7423 * schedule a walk that makes one one child progress.
7424 * we do this by giving the queue draining process zero
7425 * time quanta. it's a do..while loop, so it does something.
7427 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7429 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7430 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7431 fib_walk_process_queues(vm, 0);
7433 FOR_EACH_TEST_CHILD(tc)
7435 if (ii == N_TEST_CHILDREN)
7437 FIB_TEST(1 == vec_len(tc->ctxs),
7438 "%d child visitsed %d times in zero quanta walk",
7439 ii, vec_len(tc->ctxs));
7443 FIB_TEST(0 == vec_len(tc->ctxs),
7444 "%d child visitsed %d times in 0 quanta walk",
7445 ii, vec_len(tc->ctxs));
7448 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7449 "Queue is not empty post zero quanta walk");
7450 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7451 "Parent has %d children post zero qunta walk",
7452 fib_node_list_get_size(PARENT()->fn_children));
7457 fib_walk_process_queues(vm, 0);
7459 FOR_EACH_TEST_CHILD(tc)
7461 if (ii >= N_TEST_CHILDREN-1)
7463 FIB_TEST(1 == vec_len(tc->ctxs),
7464 "%d child visitsed %d times in 2nd zero quanta walk",
7465 ii, vec_len(tc->ctxs));
7469 FIB_TEST(0 == vec_len(tc->ctxs),
7470 "%d child visitsed %d times in 2nd 0 quanta walk",
7471 ii, vec_len(tc->ctxs));
7474 FIB_TEST(1 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7475 "Queue is not empty post zero quanta walk");
7476 FIB_TEST(N_TEST_CHILDREN+1 == fib_node_list_get_size(PARENT()->fn_children),
7477 "Parent has %d children post zero qunta walk",
7478 fib_node_list_get_size(PARENT()->fn_children));
7481 * schedule another walk that will catch-up and merge.
7483 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7484 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7485 fib_walk_process_queues(vm, 1);
7487 FOR_EACH_TEST_CHILD(tc)
7489 if (ii >= N_TEST_CHILDREN-1)
7491 FIB_TEST(2 == vec_len(tc->ctxs),
7492 "%d child visitsed %d times in 2nd zero quanta merge walk",
7493 ii, vec_len(tc->ctxs));
7498 FIB_TEST(1 == vec_len(tc->ctxs),
7499 "%d child visitsed %d times in 2nd 0 quanta merge walk",
7500 ii, vec_len(tc->ctxs));
7504 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7505 "Queue is not empty post 2nd zero quanta merge walk");
7506 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7507 "Parent has %d children post 2nd zero qunta merge walk",
7508 fib_node_list_get_size(PARENT()->fn_children));
7511 * park a async walk in the middle of the list, then have an sync walk catch
7512 * it. same expectations as async catches async.
7514 high_ctx.fnbw_reason = FIB_NODE_BW_REASON_FLAG_RESOLVE;
7516 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7517 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7519 fib_walk_process_queues(vm, 0);
7520 fib_walk_process_queues(vm, 0);
7522 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7524 FOR_EACH_TEST_CHILD(tc)
7526 if (ii >= N_TEST_CHILDREN-1)
7528 FIB_TEST(2 == vec_len(tc->ctxs),
7529 "%d child visitsed %d times in sync catches async walk",
7530 ii, vec_len(tc->ctxs));
7535 FIB_TEST(1 == vec_len(tc->ctxs),
7536 "%d child visitsed %d times in sync catches async walk",
7537 ii, vec_len(tc->ctxs));
7541 FIB_TEST(0 == fib_walk_queue_get_size(FIB_WALK_PRIORITY_HIGH),
7542 "Queue is not empty post 2nd zero quanta merge walk");
7543 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7544 "Parent has %d children post 2nd zero qunta merge walk",
7545 fib_node_list_get_size(PARENT()->fn_children));
7548 * make the parent a child of one of its children, thus inducing a routing loop.
7550 fib_test_nodes[PARENT_INDEX].sibling =
7551 fib_node_child_add(FIB_NODE_TYPE_TEST,
7552 1, // the first child
7557 * execute a sync walk from the parent. each child visited spawns more sync
7558 * walks. we expect the walk to terminate.
7560 fib_test_walk_spawns_walks = 1;
7562 fib_walk_sync(FIB_NODE_TYPE_TEST, PARENT_INDEX, &high_ctx);
7564 FOR_EACH_TEST_CHILD(tc)
7567 * child 1 - which is last in the list - has the loop.
7568 * the other children a re thus visitsed first. the we meet
7569 * child 1. we go round the loop again, visting the other children.
7570 * then we meet the walk in the dep list and bail. child 1 is not visitsed
7575 FIB_TEST(1 == vec_len(tc->ctxs),
7576 "child %d visitsed %d times during looped sync walk",
7577 ii, vec_len(tc->ctxs));
7581 FIB_TEST(2 == vec_len(tc->ctxs),
7582 "child %d visitsed %d times during looped sync walk",
7583 ii, vec_len(tc->ctxs));
7587 FIB_TEST(N_TEST_CHILDREN == fib_node_list_get_size(PARENT()->fn_children),
7588 "Parent has %d children post sync loop walk",
7589 fib_node_list_get_size(PARENT()->fn_children));
7592 * the walk doesn't reach the max depth because the infra knows that sync
7593 * meets sync implies a loop and bails early.
7595 FIB_TEST(high_ctx.fnbw_depth == 9,
7596 "Walk context depth %d post sync loop walk",
7597 high_ctx.fnbw_depth);
7600 * execute an async walk of the graph loop, with each child spawns sync walks
7602 high_ctx.fnbw_depth = 0;
7603 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7604 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7606 fib_walk_process_queues(vm, 1);
7608 FOR_EACH_TEST_CHILD(tc)
7611 * we don't really care how many times the children are visisted, as long as
7612 * it is more than once.
7614 FIB_TEST(1 <= vec_len(tc->ctxs),
7615 "child %d visitsed %d times during looped aync spawns sync walk",
7616 ii, vec_len(tc->ctxs));
7621 * execute an async walk of the graph loop, with each child spawns async walks
7623 fib_test_walk_spawns_walks = 2;
7624 high_ctx.fnbw_depth = 0;
7625 fib_walk_async(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7626 FIB_WALK_PRIORITY_HIGH, &high_ctx);
7628 fib_walk_process_queues(vm, 1);
7630 FOR_EACH_TEST_CHILD(tc)
7633 * we don't really care how many times the children are visisted, as long as
7634 * it is more than once.
7636 FIB_TEST(1 <= vec_len(tc->ctxs),
7637 "child %d visitsed %d times during looped async spawns async walk",
7638 ii, vec_len(tc->ctxs));
7643 fib_node_child_remove(FIB_NODE_TYPE_TEST,
7644 1, // the first child
7645 fib_test_nodes[PARENT_INDEX].sibling);
7650 FOR_EACH_TEST_CHILD(tc)
7652 fib_node_child_remove(FIB_NODE_TYPE_TEST, PARENT_INDEX,
7654 fib_node_deinit(&tc->node);
7655 fib_node_unlock(&tc->node);
7657 fib_node_deinit(PARENT());
7660 * The parent will be destroyed when the last lock on it goes.
7661 * this test ensures all the walk objects are unlocking it.
7663 FIB_TEST((1 == fib_test_nodes[PARENT_INDEX].destroyed),
7664 "Parent was destroyed");
7670 * declaration of the otherwise static callback functions
7672 void fib_bfd_notify (bfd_listen_event_e event,
7673 const bfd_session_t *session);
7674 void adj_bfd_notify (bfd_listen_event_e event,
7675 const bfd_session_t *session);
7678 * Test BFD session interaction with FIB
7683 fib_node_index_t fei;
7687 /* via 10.10.10.1 */
7688 ip46_address_t nh_10_10_10_1 = {
7689 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
7691 /* via 10.10.10.2 */
7692 ip46_address_t nh_10_10_10_2 = {
7693 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02),
7695 /* via 10.10.10.10 */
7696 ip46_address_t nh_10_10_10_10 = {
7697 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a),
7699 n_feis = fib_entry_pool_size();
7704 * add interface routes. we'll assume this works. it's tested elsewhere
7706 fib_prefix_t pfx_10_10_10_10_s_24 = {
7708 .fp_proto = FIB_PROTOCOL_IP4,
7709 .fp_addr = nh_10_10_10_10,
7712 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24,
7713 FIB_SOURCE_INTERFACE,
7714 (FIB_ENTRY_FLAG_CONNECTED |
7715 FIB_ENTRY_FLAG_ATTACHED),
7718 tm->hw[0]->sw_if_index,
7719 ~0, // invalid fib index
7722 FIB_ROUTE_PATH_FLAG_NONE);
7724 fib_prefix_t pfx_10_10_10_10_s_32 = {
7726 .fp_proto = FIB_PROTOCOL_IP4,
7727 .fp_addr = nh_10_10_10_10,
7729 fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32,
7730 FIB_SOURCE_INTERFACE,
7731 (FIB_ENTRY_FLAG_CONNECTED |
7732 FIB_ENTRY_FLAG_LOCAL),
7735 tm->hw[0]->sw_if_index,
7736 ~0, // invalid fib index
7739 FIB_ROUTE_PATH_FLAG_NONE);
7742 * A BFD session via a neighbour we do not yet know
7744 bfd_session_t bfd_10_10_10_1 = {
7748 .peer_addr = nh_10_10_10_1,
7751 .hop_type = BFD_HOP_TYPE_MULTI,
7752 .local_state = BFD_STATE_init,
7755 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7758 * A new entry will be created that forwards via the adj
7760 adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
7763 tm->hw[0]->sw_if_index);
7764 fib_prefix_t pfx_10_10_10_1_s_32 = {
7765 .fp_addr = nh_10_10_10_1,
7767 .fp_proto = FIB_PROTOCOL_IP4,
7769 fib_test_lb_bucket_t adj_o_10_10_10_1 = {
7772 .adj = ai_10_10_10_1,
7776 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7777 FIB_TEST(fib_test_validate_entry(fei,
7778 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7781 "BFD sourced %U via %U",
7782 format_fib_prefix, &pfx_10_10_10_1_s_32,
7783 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7786 * Delete the BFD session. Expect the fib_entry to be removed
7788 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7790 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7791 FIB_TEST(FIB_NODE_INDEX_INVALID == fei,
7792 "BFD sourced %U removed",
7793 format_fib_prefix, &pfx_10_10_10_1_s_32);
7796 * Add the BFD source back
7798 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7801 * source the entry via the ADJ fib
7803 fei = fib_table_entry_path_add(0,
7804 &pfx_10_10_10_1_s_32,
7806 FIB_ENTRY_FLAG_ATTACHED,
7809 tm->hw[0]->sw_if_index,
7810 ~0, // invalid fib index
7813 FIB_ROUTE_PATH_FLAG_NONE);
7816 * Delete the BFD session. Expect the fib_entry to remain
7818 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
7820 fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32);
7821 FIB_TEST(fib_test_validate_entry(fei,
7822 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7825 "BFD sourced %U remains via %U",
7826 format_fib_prefix, &pfx_10_10_10_1_s_32,
7827 format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE);
7830 * Add the BFD source back
7832 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
7835 * Create another ADJ FIB
7837 fib_prefix_t pfx_10_10_10_2_s_32 = {
7838 .fp_addr = nh_10_10_10_2,
7840 .fp_proto = FIB_PROTOCOL_IP4,
7842 fib_table_entry_path_add(0,
7843 &pfx_10_10_10_2_s_32,
7845 FIB_ENTRY_FLAG_ATTACHED,
7848 tm->hw[0]->sw_if_index,
7849 ~0, // invalid fib index
7852 FIB_ROUTE_PATH_FLAG_NONE);
7854 * A BFD session for the new ADJ FIB
7856 bfd_session_t bfd_10_10_10_2 = {
7860 .peer_addr = nh_10_10_10_2,
7863 .hop_type = BFD_HOP_TYPE_MULTI,
7864 .local_state = BFD_STATE_init,
7867 fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2);
7870 * remove the adj-fib source whilst the session is present
7873 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
7874 fib_table_entry_path_add(0,
7875 &pfx_10_10_10_2_s_32,
7877 FIB_ENTRY_FLAG_ATTACHED,
7880 tm->hw[0]->sw_if_index,
7881 ~0, // invalid fib index
7884 FIB_ROUTE_PATH_FLAG_NONE);
7887 * Before adding a recursive via the BFD tracked ADJ-FIBs,
7888 * bring one of the sessions UP, leave the other down
7890 bfd_10_10_10_1.local_state = BFD_STATE_up;
7891 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
7892 bfd_10_10_10_2.local_state = BFD_STATE_down;
7893 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7896 * A recursive prefix via both of the ADJ FIBs
7898 fib_prefix_t pfx_200_0_0_0_s_24 = {
7899 .fp_proto = FIB_PROTOCOL_IP4,
7902 .ip4.as_u32 = clib_host_to_net_u32(0xc8000000),
7905 const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2;
7908 fib_entry_contribute_ip_forwarding(
7909 fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32));
7911 fib_entry_contribute_ip_forwarding(
7912 fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32));
7914 fib_test_lb_bucket_t lb_o_10_10_10_1 = {
7917 .lb = dpo_10_10_10_1->dpoi_index,
7920 fib_test_lb_bucket_t lb_o_10_10_10_2 = {
7923 .lb = dpo_10_10_10_2->dpoi_index,
7928 * A prefix via the adj-fib that is BFD down => DROP
7930 fei = fib_table_entry_path_add(0,
7931 &pfx_200_0_0_0_s_24,
7933 FIB_ENTRY_FLAG_NONE,
7937 0, // default fib index
7940 FIB_ROUTE_PATH_FLAG_NONE);
7941 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
7942 "%U resolves via drop",
7943 format_fib_prefix, &pfx_200_0_0_0_s_24);
7946 * add a path via the UP BFD adj-fib.
7947 * we expect that the DOWN BFD ADJ FIB is not used.
7949 fei = fib_table_entry_path_add(0,
7950 &pfx_200_0_0_0_s_24,
7952 FIB_ENTRY_FLAG_NONE,
7956 0, // default fib index
7959 FIB_ROUTE_PATH_FLAG_NONE);
7961 FIB_TEST(fib_test_validate_entry(fei,
7962 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7965 "Recursive %U only UP BFD adj-fibs",
7966 format_fib_prefix, &pfx_200_0_0_0_s_24);
7969 * Send a BFD state change to UP - both sessions are now up
7970 * the recursive prefix should LB over both
7972 bfd_10_10_10_2.local_state = BFD_STATE_up;
7973 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7976 FIB_TEST(fib_test_validate_entry(fei,
7977 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7981 "Recursive %U via both UP BFD adj-fibs",
7982 format_fib_prefix, &pfx_200_0_0_0_s_24);
7985 * Send a BFD state change to DOWN
7986 * the recursive prefix should exclude the down
7988 bfd_10_10_10_2.local_state = BFD_STATE_down;
7989 fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2);
7992 FIB_TEST(fib_test_validate_entry(fei,
7993 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
7996 "Recursive %U via only UP",
7997 format_fib_prefix, &pfx_200_0_0_0_s_24);
8000 * Delete the BFD session while it is in the DOWN state.
8001 * FIB should consider the entry's state as back up
8003 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2);
8005 FIB_TEST(fib_test_validate_entry(fei,
8006 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8010 "Recursive %U via both UP BFD adj-fibs post down session delete",
8011 format_fib_prefix, &pfx_200_0_0_0_s_24);
8014 * Delete the BFD other session while it is in the UP state.
8016 fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8018 FIB_TEST(fib_test_validate_entry(fei,
8019 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8023 "Recursive %U via both UP BFD adj-fibs post up session delete",
8024 format_fib_prefix, &pfx_200_0_0_0_s_24);
8029 fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API);
8030 fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ);
8031 fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ);
8033 fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE);
8034 fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE);
8036 adj_unlock(ai_10_10_10_1);
8038 * test no-one left behind
8040 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8041 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8044 * Single-hop BFD tests
8046 bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE;
8047 bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index;
8049 adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1);
8051 ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8054 tm->hw[0]->sw_if_index);
8056 * whilst the BFD session is not signalled, the adj is up
8058 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session");
8061 * bring the BFD session up
8063 bfd_10_10_10_1.local_state = BFD_STATE_up;
8064 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8065 FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session");
8068 * bring the BFD session down
8070 bfd_10_10_10_1.local_state = BFD_STATE_down;
8071 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8072 FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session");
8076 * add an attached next hop FIB entry via the down adj
8078 fib_prefix_t pfx_5_5_5_5_s_32 = {
8081 .as_u32 = clib_host_to_net_u32(0x05050505),
8085 .fp_proto = FIB_PROTOCOL_IP4,
8088 fei = fib_table_entry_path_add(0,
8091 FIB_ENTRY_FLAG_NONE,
8094 tm->hw[0]->sw_if_index,
8095 ~0, // invalid fib index
8098 FIB_ROUTE_PATH_FLAG_NONE);
8099 FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)),
8100 "%U resolves via drop",
8101 format_fib_prefix, &pfx_5_5_5_5_s_32);
8104 * Add a path via an ADJ that is up
8106 adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8109 tm->hw[0]->sw_if_index);
8111 fib_test_lb_bucket_t adj_o_10_10_10_2 = {
8114 .adj = ai_10_10_10_2,
8117 adj_o_10_10_10_1.adj.adj = ai_10_10_10_1;
8119 fei = fib_table_entry_path_add(0,
8122 FIB_ENTRY_FLAG_NONE,
8125 tm->hw[0]->sw_if_index,
8126 ~0, // invalid fib index
8129 FIB_ROUTE_PATH_FLAG_NONE);
8131 FIB_TEST(fib_test_validate_entry(fei,
8132 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8135 "BFD sourced %U via %U",
8136 format_fib_prefix, &pfx_5_5_5_5_s_32,
8137 format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE);
8140 * Bring up the down session - should now LB
8142 bfd_10_10_10_1.local_state = BFD_STATE_up;
8143 adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1);
8144 FIB_TEST(fib_test_validate_entry(fei,
8145 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8149 "BFD sourced %U via noth adjs",
8150 format_fib_prefix, &pfx_5_5_5_5_s_32);
8153 * remove the BFD session state from the adj
8155 adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1);
8160 fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI);
8161 adj_unlock(ai_10_10_10_1);
8162 adj_unlock(ai_10_10_10_2);
8165 * test no-one left behind
8167 FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone");
8168 FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed");
8175 const mpls_label_t deag_label = 50;
8176 const u32 lfib_index = 0;
8177 const u32 fib_index = 0;
8178 dpo_id_t dpo = DPO_INVALID;
8179 const dpo_id_t *dpo1;
8180 fib_node_index_t lfe;
8184 adj_index_t ai_mpls_10_10_10_1;
8187 lb_count = pool_elts(load_balance_pool);
8189 FIB_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
8193 * MPLS enable an interface so we get the MPLS table created
8195 mpls_table_create(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API, NULL);
8196 mpls_sw_interface_enable_disable(&mpls_main,
8197 tm->hw[0]->sw_if_index,
8200 ip46_address_t nh_10_10_10_1 = {
8201 .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01),
8203 ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
8206 tm->hw[0]->sw_if_index);
8209 * Test the specials stack properly.
8211 fib_prefix_t exp_null_v6_pfx = {
8212 .fp_proto = FIB_PROTOCOL_MPLS,
8214 .fp_label = MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8215 .fp_payload_proto = DPO_PROTO_IP6,
8217 lfe = fib_table_lookup(lfib_index, &exp_null_v6_pfx);
8218 FIB_TEST((FIB_NODE_INDEX_INVALID != lfe),
8220 format_mpls_unicast_label, MPLS_IETF_IPV6_EXPLICIT_NULL_LABEL,
8221 format_mpls_eos_bit, MPLS_EOS);
8222 fib_entry_contribute_forwarding(lfe,
8223 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8225 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8226 lkd = lookup_dpo_get(dpo1->dpoi_index);
8228 FIB_TEST((fib_index == lkd->lkd_fib_index),
8229 "%U/%U is deag in %d %U",
8230 format_mpls_unicast_label, deag_label,
8231 format_mpls_eos_bit, MPLS_EOS,
8233 format_dpo_id, &dpo, 0);
8234 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8235 "%U/%U is dst deag",
8236 format_mpls_unicast_label, deag_label,
8237 format_mpls_eos_bit, MPLS_EOS);
8238 FIB_TEST((LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table),
8239 "%U/%U is lookup in interface's table",
8240 format_mpls_unicast_label, deag_label,
8241 format_mpls_eos_bit, MPLS_EOS);
8242 FIB_TEST((DPO_PROTO_IP6 == lkd->lkd_proto),
8243 "%U/%U is %U dst deag",
8244 format_mpls_unicast_label, deag_label,
8245 format_mpls_eos_bit, MPLS_EOS,
8246 format_dpo_proto, lkd->lkd_proto);
8250 * A route deag route for EOS
8252 fib_prefix_t pfx = {
8253 .fp_proto = FIB_PROTOCOL_MPLS,
8255 .fp_label = deag_label,
8256 .fp_payload_proto = DPO_PROTO_IP4,
8258 lfe = fib_table_entry_path_add(lfib_index,
8261 FIB_ENTRY_FLAG_NONE,
8268 FIB_ROUTE_PATH_FLAG_NONE);
8270 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8272 format_mpls_unicast_label, deag_label,
8273 format_mpls_eos_bit, MPLS_EOS);
8275 fib_entry_contribute_forwarding(lfe,
8276 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8278 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8279 lkd = lookup_dpo_get(dpo1->dpoi_index);
8281 FIB_TEST((fib_index == lkd->lkd_fib_index),
8282 "%U/%U is deag in %d %U",
8283 format_mpls_unicast_label, deag_label,
8284 format_mpls_eos_bit, MPLS_EOS,
8286 format_dpo_id, &dpo, 0);
8287 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8288 "%U/%U is dst deag",
8289 format_mpls_unicast_label, deag_label,
8290 format_mpls_eos_bit, MPLS_EOS);
8291 FIB_TEST((DPO_PROTO_IP4 == lkd->lkd_proto),
8292 "%U/%U is %U dst deag",
8293 format_mpls_unicast_label, deag_label,
8294 format_mpls_eos_bit, MPLS_EOS,
8295 format_dpo_proto, lkd->lkd_proto);
8297 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8299 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8301 "%U/%U not present",
8302 format_mpls_unicast_label, deag_label,
8303 format_mpls_eos_bit, MPLS_EOS);
8306 * A route deag route for non-EOS
8308 pfx.fp_eos = MPLS_NON_EOS;
8309 lfe = fib_table_entry_path_add(lfib_index,
8312 FIB_ENTRY_FLAG_NONE,
8319 FIB_ROUTE_PATH_FLAG_NONE);
8321 FIB_TEST((lfe == fib_table_lookup(lfib_index, &pfx)),
8323 format_mpls_unicast_label, deag_label,
8324 format_mpls_eos_bit, MPLS_NON_EOS);
8326 fib_entry_contribute_forwarding(lfe,
8327 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8329 dpo1 = load_balance_get_bucket(dpo.dpoi_index, 0);
8330 lkd = lookup_dpo_get(dpo1->dpoi_index);
8332 FIB_TEST((fib_index == lkd->lkd_fib_index),
8333 "%U/%U is deag in %d %U",
8334 format_mpls_unicast_label, deag_label,
8335 format_mpls_eos_bit, MPLS_NON_EOS,
8337 format_dpo_id, &dpo, 0);
8338 FIB_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
8339 "%U/%U is dst deag",
8340 format_mpls_unicast_label, deag_label,
8341 format_mpls_eos_bit, MPLS_NON_EOS);
8343 FIB_TEST((DPO_PROTO_MPLS == lkd->lkd_proto),
8344 "%U/%U is %U dst deag",
8345 format_mpls_unicast_label, deag_label,
8346 format_mpls_eos_bit, MPLS_NON_EOS,
8347 format_dpo_proto, lkd->lkd_proto);
8349 fib_table_entry_delete_index(lfe, FIB_SOURCE_CLI);
8351 FIB_TEST((FIB_NODE_INDEX_INVALID == fib_table_lookup(lfib_index,
8353 "%U/%U not present",
8354 format_mpls_unicast_label, deag_label,
8355 format_mpls_eos_bit, MPLS_EOS);
8362 fib_prefix_t pfx_1200 = {
8364 .fp_proto = FIB_PROTOCOL_MPLS,
8366 .fp_eos = MPLS_NON_EOS,
8368 fib_test_lb_bucket_t neos_o_10_10_10_1 = {
8369 .type = FT_LB_LABEL_STACK_O_ADJ,
8370 .label_stack_o_adj = {
8371 .adj = ai_mpls_10_10_10_1,
8372 .label_stack_size = 4,
8376 .eos = MPLS_NON_EOS,
8379 dpo_id_t neos_1200 = DPO_INVALID;
8380 dpo_id_t ip_1200 = DPO_INVALID;
8381 mpls_label_t *l200 = NULL;
8382 vec_add1(l200, 200);
8383 vec_add1(l200, 300);
8384 vec_add1(l200, 400);
8385 vec_add1(l200, 500);
8387 lfe = fib_table_entry_update_one_path(fib_index,
8390 FIB_ENTRY_FLAG_NONE,
8393 tm->hw[0]->sw_if_index,
8394 ~0, // invalid fib index
8397 FIB_ROUTE_PATH_FLAG_NONE);
8399 FIB_TEST(fib_test_validate_entry(lfe,
8400 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8402 &neos_o_10_10_10_1),
8403 "1200/0 LB 1 buckets via: "
8407 * A recursive route via the MPLS x-connect
8409 fib_prefix_t pfx_2_2_2_3_s_32 = {
8411 .fp_proto = FIB_PROTOCOL_IP4,
8413 .ip4.as_u32 = clib_host_to_net_u32(0x02020203),
8416 fib_route_path_t *rpaths = NULL, rpath = {
8417 .frp_proto = DPO_PROTO_MPLS,
8418 .frp_local_label = 1200,
8419 .frp_eos = MPLS_NON_EOS,
8420 .frp_sw_if_index = ~0, // recurive
8421 .frp_fib_index = 0, // Default MPLS fib
8423 .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
8424 .frp_label_stack = NULL,
8426 vec_add1(rpaths, rpath);
8428 fib_table_entry_path_add2(fib_index,
8431 FIB_ENTRY_FLAG_NONE,
8435 * A labelled recursive route via the MPLS x-connect
8437 fib_prefix_t pfx_2_2_2_4_s_32 = {
8439 .fp_proto = FIB_PROTOCOL_IP4,
8441 .ip4.as_u32 = clib_host_to_net_u32(0x02020204),
8444 mpls_label_t *l999 = NULL;
8445 vec_add1(l999, 999);
8446 rpaths[0].frp_label_stack = l999,
8448 fib_table_entry_path_add2(fib_index,
8451 FIB_ENTRY_FLAG_NONE,
8454 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8455 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8457 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8458 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8461 fib_test_lb_bucket_t ip_o_1200 = {
8464 .lb = ip_1200.dpoi_index,
8467 fib_test_lb_bucket_t mpls_o_1200 = {
8468 .type = FT_LB_LABEL_O_LB,
8470 .lb = neos_1200.dpoi_index,
8476 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_3_s_32);
8477 FIB_TEST(fib_test_validate_entry(lfe,
8478 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8481 "2.2.2.2.3/32 LB 1 buckets via: label 1200 EOS");
8482 lfe = fib_table_lookup(fib_index, &pfx_2_2_2_4_s_32);
8483 FIB_TEST(fib_test_validate_entry(lfe,
8484 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8487 "2.2.2.2.4/32 LB 1 buckets via: label 1200 non-EOS");
8489 fib_table_entry_delete(fib_index, &pfx_1200, FIB_SOURCE_API);
8490 fib_table_entry_delete(fib_index, &pfx_2_2_2_3_s_32, FIB_SOURCE_API);
8491 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8493 dpo_reset(&neos_1200);
8494 dpo_reset(&ip_1200);
8497 * A recursive via a label that does not exist
8499 fib_test_lb_bucket_t bucket_drop = {
8500 .type = FT_LB_SPECIAL,
8502 .adj = DPO_PROTO_IP4,
8505 fib_test_lb_bucket_t mpls_bucket_drop = {
8506 .type = FT_LB_SPECIAL,
8508 .adj = DPO_PROTO_MPLS,
8512 rpaths[0].frp_label_stack = NULL;
8513 lfe = fib_table_entry_path_add2(fib_index,
8516 FIB_ENTRY_FLAG_NONE,
8519 fib_entry_contribute_forwarding(fib_table_lookup(fib_index, &pfx_1200),
8520 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8522 ip_o_1200.lb.lb = ip_1200.dpoi_index;
8524 FIB_TEST(fib_test_validate_entry(lfe,
8525 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8528 "2.2.2.2.4/32 LB 1 buckets via: drop");
8529 lfe = fib_table_lookup(fib_index, &pfx_1200);
8530 FIB_TEST(fib_test_validate_entry(lfe,
8531 FIB_FORW_CHAIN_TYPE_UNICAST_IP4,
8534 "1200/neos LB 1 buckets via: ip4-DROP");
8535 FIB_TEST(fib_test_validate_entry(lfe,
8536 FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
8539 "1200/neos LB 1 buckets via: mpls-DROP");
8541 fib_table_entry_delete(fib_index, &pfx_2_2_2_4_s_32, FIB_SOURCE_API);
8543 dpo_reset(&ip_1200);
8546 * An rx-interface route.
8547 * like the tail of an mcast LSP
8549 dpo_id_t idpo = DPO_INVALID;
8551 interface_rx_dpo_add_or_lock(DPO_PROTO_IP4,
8552 tm->hw[0]->sw_if_index,
8555 fib_prefix_t pfx_2500 = {
8557 .fp_proto = FIB_PROTOCOL_MPLS,
8560 .fp_payload_proto = DPO_PROTO_IP4,
8562 fib_test_lb_bucket_t rx_intf_0 = {
8565 .adj = idpo.dpoi_index,
8569 lfe = fib_table_entry_update_one_path(fib_index,
8572 FIB_ENTRY_FLAG_NONE,
8575 tm->hw[0]->sw_if_index,
8576 ~0, // invalid fib index
8579 FIB_ROUTE_PATH_INTF_RX);
8580 FIB_TEST(fib_test_validate_entry(lfe,
8581 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8584 "2500 rx-interface 0");
8585 fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
8588 * An MPLS mulicast entry
8590 fib_prefix_t pfx_3500 = {
8592 .fp_proto = FIB_PROTOCOL_MPLS,
8595 .fp_payload_proto = DPO_PROTO_IP4,
8597 fib_test_rep_bucket_t mc_0 = {
8598 .type = FT_REP_LABEL_O_ADJ,
8600 .adj = ai_mpls_10_10_10_1,
8605 fib_test_rep_bucket_t mc_intf_0 = {
8606 .type = FT_REP_INTF,
8608 .adj = idpo.dpoi_index,
8611 mpls_label_t *l3300 = NULL;
8612 vec_add1(l3300, 3300);
8614 lfe = fib_table_entry_update_one_path(lfib_index,
8617 FIB_ENTRY_FLAG_MULTICAST,
8620 tm->hw[0]->sw_if_index,
8621 ~0, // invalid fib index
8624 FIB_ROUTE_PATH_FLAG_NONE);
8625 FIB_TEST(fib_test_validate_entry(lfe,
8626 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8629 "3500 via replicate over 10.10.10.1");
8632 * MPLS Bud-node. Add a replication via an interface-receieve path
8634 lfe = fib_table_entry_path_add(lfib_index,
8637 FIB_ENTRY_FLAG_MULTICAST,
8640 tm->hw[0]->sw_if_index,
8641 ~0, // invalid fib index
8644 FIB_ROUTE_PATH_INTF_RX);
8645 FIB_TEST(fib_test_validate_entry(lfe,
8646 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8650 "3500 via replicate over 10.10.10.1 and interface-rx");
8653 * Add a replication via an interface-free for-us path
8655 fib_test_rep_bucket_t mc_disp = {
8656 .type = FT_REP_DISP_MFIB_LOOKUP,
8658 .adj = idpo.dpoi_index,
8661 lfe = fib_table_entry_path_add(lfib_index,
8664 FIB_ENTRY_FLAG_MULTICAST,
8671 FIB_ROUTE_PATH_RPF_ID);
8672 FIB_TEST(fib_test_validate_entry(lfe,
8673 FIB_FORW_CHAIN_TYPE_MPLS_EOS,
8678 "3500 via replicate over 10.10.10.1 and interface-rx");
8682 fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
8688 mpls_sw_interface_enable_disable(&mpls_main,
8689 tm->hw[0]->sw_if_index,
8691 mpls_table_delete(MPLS_FIB_DEFAULT_TABLE_ID, FIB_SOURCE_API);
8693 FIB_TEST(lb_count == pool_elts(load_balance_pool),
8694 "Load-balance resources freed %d of %d",
8695 lb_count, pool_elts(load_balance_pool));
8696 FIB_TEST(0 == pool_elts(interface_rx_dpo_pool),
8697 "interface_rx_dpo resources freed %d of %d",
8698 0, pool_elts(interface_rx_dpo_pool));
8703 static clib_error_t *
8704 fib_test (vlib_main_t * vm,
8705 unformat_input_t * input,
8706 vlib_cli_command_t * cmd_arg)
8711 fib_test_mk_intf(4);
8713 if (unformat (input, "debug"))
8715 fib_test_do_debug = 1;
8718 if (unformat (input, "ip"))
8720 res += fib_test_v4();
8721 res += fib_test_v6();
8723 else if (unformat (input, "label"))
8725 res += fib_test_label();
8727 else if (unformat (input, "ae"))
8729 res += fib_test_ae();
8731 else if (unformat (input, "pref"))
8733 res += fib_test_pref();
8735 else if (unformat (input, "lfib"))
8739 else if (unformat (input, "walk"))
8741 res += fib_test_walk();
8743 else if (unformat (input, "bfd"))
8745 res += fib_test_bfd();
8749 res += fib_test_v4();
8750 res += fib_test_v6();
8751 res += fib_test_ae();
8752 res += fib_test_bfd();
8753 res += fib_test_pref();
8754 res += fib_test_label();
8758 * fib-walk process must be disabled in order for the walk tests to work
8760 fib_walk_process_disable();
8761 res += fib_test_walk();
8762 fib_walk_process_enable();
8767 return clib_error_return(0, "FIB Unit Test Failed");
8775 VLIB_CLI_COMMAND (test_fib_command, static) = {
8777 .short_help = "fib unit tests - DO NOT RUN ON A LIVE SYSTEM",
8778 .function = fib_test,
8782 fib_test_init (vlib_main_t *vm)
8787 VLIB_INIT_FUNCTION (fib_test_init);