LCOV - code coverage report
Current view: top level - plugins/unittest - bier_test.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 268 276 97.1 %
Date: 2023-07-05 22:20:52 Functions: 14 15 93.3 %

          Line data    Source code
       1             : /*
       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:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       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.
      14             :  */
      15             : 
      16             : 
      17             : #include <vnet/mpls/mpls.h>
      18             : #include <vnet/bier/bier_table.h>
      19             : #include <vnet/bier/bier_entry.h>
      20             : #include <vnet/bier/bier_fmask.h>
      21             : #include <vnet/bier/bier_bit_string.h>
      22             : #include <vnet/bier/bier_imp.h>
      23             : #include <vnet/bier/bier_disp_table.h>
      24             : #include <vnet/bier/bier_disp_entry.h>
      25             : #include <vnet/fib/fib_entry.h>
      26             : #include <vnet/fib/fib_table.h>
      27             : #include <vnet/fib/mpls_fib.h>
      28             : #include <vnet/dpo/load_balance.h>
      29             : #include <vnet/dpo/drop_dpo.h>
      30             : #include <vnet/dpo/lookup_dpo.h>
      31             : #include <vnet/mfib/mfib_table.h>
      32             : 
      33             : #include <vnet/fib/fib_test.h>
      34             : 
      35             : /*
      36             :  * Add debugs for passing tests
      37             :  */
      38             : static int bier_test_do_debug;
      39             : 
      40             : #define BIER_TEST_I(_cond, _comment, _args...)                  \
      41             : ({                                                              \
      42             :     int _evald = (_cond);                                       \
      43             :     if (!(_evald)) {                                            \
      44             :         fformat(stderr, "FAIL:%d: " _comment "\n",          \
      45             :                 __LINE__, ##_args);                             \
      46             :         res = 1;                                                \
      47             :     } else {                                                    \
      48             :         if (bier_test_do_debug)                                 \
      49             :             fformat(stderr, "PASS:%d: " _comment "\n",          \
      50             :                     __LINE__, ##_args);                         \
      51             :     }                                                           \
      52             :     res;                                                        \
      53             : })
      54             : #define BIER_TEST(_cond, _comment, _args...)                    \
      55             : {                                                               \
      56             :     if (BIER_TEST_I(_cond, _comment, ##_args)) {                \
      57             :         return 1;                                               \
      58             :         ASSERT(!("FAIL: " _comment));                         \
      59             :     }                                                           \
      60             : }
      61             : 
      62             : /**
      63             :  * A 'i'm not fussed is this is not efficient' store of test data
      64             :  */
      65             : typedef struct test_main_t_ {
      66             :     /**
      67             :      * HW if indicies
      68             :      */
      69             :     u32 hw_if_indicies[4];
      70             :     /**
      71             :      * HW interfaces
      72             :      */
      73             :     vnet_hw_interface_t * hw[4];
      74             : 
      75             : } test_main_t;
      76             : static test_main_t test_main;
      77             : 
      78             : /* fake ethernet device class, distinct from "fake-ethX" */
      79           8 : static u8 * format_test_interface_name (u8 * s, va_list * args)
      80             : {
      81           8 :   u32 dev_instance = va_arg (*args, u32);
      82           8 :   return format (s, "test-eth%d", dev_instance);
      83             : }
      84             : 
      85           0 : static uword placeholder_interface_tx (vlib_main_t * vm,
      86             :                                  vlib_node_runtime_t * node,
      87             :                                  vlib_frame_t * frame)
      88             : {
      89           0 :   clib_warning ("you shouldn't be here, leaking buffers...");
      90           0 :   return frame->n_vectors;
      91             : }
      92             : 
      93        2799 : VNET_DEVICE_CLASS (test_interface_device_class,static) = {
      94             :   .name = "Test interface",
      95             :   .format_device_name = format_test_interface_name,
      96             :   .tx_function = placeholder_interface_tx,
      97             : };
      98             : 
      99             : static u8 *hw_address;
     100             : 
     101             : static int
     102           1 : bier_test_mk_intf (u32 ninterfaces)
     103             : {
     104           1 :     clib_error_t * error = NULL;
     105           1 :     test_main_t *tm = &test_main;
     106             :     u8 byte;
     107             :     int res;
     108             :     u32 i;
     109             : 
     110           1 :     res = 0;
     111           1 :     ASSERT(ninterfaces <= ARRAY_LEN(tm->hw_if_indicies));
     112             : 
     113           7 :     for (i=0; i<6; i++)
     114             :     {
     115           6 :         byte = 0xd0+i;
     116           6 :         vec_add1(hw_address, byte);
     117             :     }
     118             : 
     119           5 :     for (i = 0; i < ninterfaces; i++)
     120             :     {
     121           4 :       vnet_eth_interface_registration_t eir = {};
     122           4 :       vnet_main_t *vnm = vnet_get_main ();
     123             : 
     124           4 :       hw_address[5] = i;
     125             : 
     126           4 :       eir.dev_class_index = test_interface_device_class.index;
     127           4 :       eir.dev_instance = i;
     128           4 :       eir.address = hw_address;
     129           4 :       tm->hw_if_indicies[i] = vnet_eth_register_interface (vnm, &eir);
     130             : 
     131             :       error =
     132           4 :         vnet_hw_interface_set_flags (vnet_get_main (), tm->hw_if_indicies[i],
     133             :                                      VNET_HW_INTERFACE_FLAG_LINK_UP);
     134           4 :       BIER_TEST ((NULL == error), "ADD interface %d", i);
     135             : 
     136           4 :       tm->hw[i] =
     137           4 :         vnet_get_hw_interface (vnet_get_main (), tm->hw_if_indicies[i]);
     138           4 :       ip4_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
     139           4 :       ip6_main.fib_index_by_sw_if_index[tm->hw[i]->sw_if_index] = 0;
     140             :       error =
     141           4 :         vnet_sw_interface_set_flags (vnet_get_main (), tm->hw[i]->sw_if_index,
     142             :                                      VNET_SW_INTERFACE_FLAG_ADMIN_UP);
     143           4 :       BIER_TEST ((NULL == error), "UP interface %d", i);
     144             :     }
     145             :     /*
     146             :      * re-eval after the inevitable realloc
     147             :      */
     148           5 :     for (i = 0; i < ninterfaces; i++)
     149             :     {
     150           4 :         tm->hw[i] = vnet_get_hw_interface(vnet_get_main(),
     151             :                                           tm->hw_if_indicies[i]);
     152             :     }
     153             : 
     154           1 :     return (res);
     155             : }
     156             : 
     157             : #define BIER_TEST_LB(_cond, _comment, _args...)                 \
     158             : {                                                               \
     159             :     if (BIER_TEST_I(_cond, _comment, ##_args)) {                \
     160             :         return (1);                                             \
     161             :     }                                                           \
     162             : }
     163             : 
     164             : static int
     165           2 : bier_test_validate_entry (index_t bei,
     166             :                           int n_buckets,
     167             :                           ...)
     168             : {
     169           2 :     dpo_id_t dpo = DPO_INVALID;
     170             :     const load_balance_t *lb;
     171             :     va_list ap;
     172             :     int res;
     173             : 
     174           2 :     va_start(ap, n_buckets);
     175             : 
     176           2 :     res = 0;
     177           2 :     bier_entry_contribute_forwarding(bei, &dpo);
     178             : 
     179           2 :     res = BIER_TEST_I((DPO_LOAD_BALANCE == dpo.dpoi_type),
     180             :                       "Entry links to %U",
     181             :                       format_dpo_type, dpo.dpoi_type);
     182             : 
     183           2 :     if (!res)
     184             :     {
     185           2 :         lb = load_balance_get(dpo.dpoi_index);
     186           2 :         res = fib_test_validate_lb_v(lb, n_buckets, &ap);
     187             :     }
     188             : 
     189           2 :     dpo_reset(&dpo);
     190           2 :     va_end(ap);
     191             : 
     192           2 :     return (res);
     193             : }
     194             : 
     195             : static int
     196           1 : bier_test_mpls_spf (void)
     197             : {
     198             :     fib_node_index_t lfei, fei, bti;
     199             :     u32 mpls_fib_index;
     200             :     test_main_t *tm;
     201             :     int lb_count;
     202             :     int res;
     203             : 
     204           1 :     res = 0;
     205           1 :     lb_count = pool_elts(load_balance_pool);
     206           1 :     tm = &test_main;
     207             : #define N_BIER_ECMP_TABLES 16
     208             :     int ii;
     209             : 
     210             :     /*
     211             :      * Add the BIER Main table
     212             :      */
     213           1 :     const bier_table_id_t bt_0_0_0_256 = {
     214             :         .bti_set = 0,
     215             :         .bti_sub_domain = 0,
     216             :         .bti_hdr_len = BIER_HDR_LEN_256,
     217             :         .bti_type = BIER_TABLE_MPLS_SPF,
     218             :         .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
     219             :     };
     220             : 
     221           1 :     bti = bier_table_add_or_lock(&bt_0_0_0_256, 1600);
     222             : 
     223             :     fib_test_lb_bucket_t l_o_bt[N_BIER_ECMP_TABLES];
     224           1 :     bier_table_id_t bt_ecmp_0_0_0_256 = bt_0_0_0_256;
     225             : 
     226          17 :     for (ii = 0; ii < N_BIER_ECMP_TABLES; ii++)
     227             :     {
     228          16 :         bt_ecmp_0_0_0_256.bti_ecmp = ii;
     229             : 
     230          16 :         l_o_bt[ii].type = FT_LB_BIER_TABLE;
     231          16 :         l_o_bt[ii].bier.table =
     232          16 :             bier_table_ecmp_create_and_lock(&bt_ecmp_0_0_0_256);
     233             :     };
     234           1 :     const fib_prefix_t pfx_1600_neos = {
     235             :         .fp_len = 21,
     236             :         .fp_proto = FIB_PROTOCOL_MPLS,
     237             :         .fp_label = 1600,
     238             :         .fp_eos = MPLS_NON_EOS,
     239             :         .fp_payload_proto = DPO_PROTO_BIER,
     240             :     };
     241           1 :     const fib_prefix_t pfx_1600_eos = {
     242             :         .fp_len = 21,
     243             :         .fp_proto = FIB_PROTOCOL_MPLS,
     244             :         .fp_label = 1600,
     245             :         .fp_eos = MPLS_EOS,
     246             :         .fp_payload_proto = DPO_PROTO_BIER,
     247             :     };
     248             : 
     249           1 :     mpls_fib_index = fib_table_find(FIB_PROTOCOL_MPLS,
     250             :                                     MPLS_FIB_DEFAULT_TABLE_ID);
     251             : 
     252           1 :     lfei = fib_table_lookup(mpls_fib_index, &pfx_1600_neos);
     253           1 :     BIER_TEST(FIB_NODE_INDEX_INVALID == lfei, "1600/0 is not present");
     254             : 
     255           1 :     lfei = fib_table_lookup(mpls_fib_index, &pfx_1600_eos);
     256           1 :     BIER_TEST(!fib_test_validate_entry(lfei, FIB_FORW_CHAIN_TYPE_MPLS_EOS,
     257             :                                        16,
     258             :                                        &l_o_bt[0],
     259             :                                        &l_o_bt[1],
     260             :                                        &l_o_bt[2],
     261             :                                        &l_o_bt[3],
     262             :                                        &l_o_bt[4],
     263             :                                        &l_o_bt[5],
     264             :                                        &l_o_bt[6],
     265             :                                        &l_o_bt[7],
     266             :                                        &l_o_bt[8],
     267             :                                        &l_o_bt[9],
     268             :                                        &l_o_bt[10],
     269             :                                        &l_o_bt[11],
     270             :                                        &l_o_bt[12],
     271             :                                        &l_o_bt[13],
     272             :                                        &l_o_bt[14],
     273             :                                        &l_o_bt[15]),
     274             :               "1600/1 LB stacks on BIER table %d", bti);
     275             : 
     276             :     /*
     277             :      * modify the table's local label - keep the lock count accurate
     278             :      */
     279           1 :     const fib_prefix_t pfx_1601_eos = {
     280             :         .fp_len = 21,
     281             :         .fp_proto = FIB_PROTOCOL_MPLS,
     282             :         .fp_label = 1601,
     283             :         .fp_eos = MPLS_EOS,
     284             :         .fp_payload_proto = DPO_PROTO_BIER,
     285             :     };
     286           1 :     bti = bier_table_add_or_lock(&bt_0_0_0_256, 1601);
     287           1 :     bier_table_unlock(&bt_0_0_0_256);
     288             : 
     289           1 :     lfei = fib_table_lookup(mpls_fib_index, &pfx_1600_eos);
     290           1 :     BIER_TEST(FIB_NODE_INDEX_INVALID == lfei, "1600/1 is deleted");
     291             : 
     292           1 :     lfei = fib_table_lookup(mpls_fib_index, &pfx_1601_eos);
     293           1 :     BIER_TEST(!fib_test_validate_entry(lfei, FIB_FORW_CHAIN_TYPE_MPLS_EOS,
     294             :                                        16,
     295             :                                        &l_o_bt[0],
     296             :                                        &l_o_bt[1],
     297             :                                        &l_o_bt[2],
     298             :                                        &l_o_bt[3],
     299             :                                        &l_o_bt[4],
     300             :                                        &l_o_bt[5],
     301             :                                        &l_o_bt[6],
     302             :                                        &l_o_bt[7],
     303             :                                        &l_o_bt[8],
     304             :                                        &l_o_bt[9],
     305             :                                        &l_o_bt[10],
     306             :                                        &l_o_bt[11],
     307             :                                        &l_o_bt[12],
     308             :                                        &l_o_bt[13],
     309             :                                        &l_o_bt[14],
     310             :                                        &l_o_bt[15]),
     311             :               "1601/1 LB stacks on BIER table %d", bti);
     312             : 
     313             :     /*
     314             :      * add a route to the table. the via IP route does not exist.
     315             :      */
     316           2 :     const ip46_address_t nh_1_1_1_1 = {
     317             :         .ip4 = {
     318           1 :             .as_u32 = clib_host_to_net_u32(0x01010101),
     319             :         },
     320             :     };
     321           1 :     fib_route_path_t *paths_1_1_1_1 = NULL, *input_paths_1_1_1_1;
     322           1 :     fib_route_path_t path_1_1_1_1 = {
     323             :         .frp_addr = nh_1_1_1_1,
     324             :         .frp_sw_if_index = ~0,
     325             :     };
     326           1 :     fib_mpls_label_t fml_500 = {
     327             :         .fml_value = 500,
     328             :     };
     329           1 :     vec_add1(path_1_1_1_1.frp_label_stack, fml_500);
     330           1 :     vec_add1(paths_1_1_1_1, path_1_1_1_1);
     331           1 :     const fib_prefix_t pfx_1_1_1_1_s_32 = {
     332             :         .fp_addr = nh_1_1_1_1,
     333             :         .fp_len = 32,
     334             :         .fp_proto = FIB_PROTOCOL_IP4,
     335             :     };
     336             :     index_t bei_1;
     337             : 
     338           1 :     input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1);
     339           1 :     bier_table_route_path_add(&bt_0_0_0_256, 1, input_paths_1_1_1_1);
     340           1 :     bei_1 = bier_table_lookup(bier_table_get(bti), 1);
     341             : 
     342           1 :     BIER_TEST((INDEX_INVALID != bei_1), "BP:1 present");
     343             : 
     344             :     /*
     345             :      * the newly created fmask should stack on the non-eos chain
     346             :      * of the via-fib-entry
     347             :      */
     348           1 :     dpo_id_t neos_dpo_1_1_1_1 = DPO_INVALID;
     349             :     bier_fmask_t *bfm_1_1_1_1;
     350             :     index_t bfmi_1_1_1_1;
     351             : 
     352           1 :     fei = fib_table_lookup_exact_match(0, &pfx_1_1_1_1_s_32);
     353           1 :     fib_entry_contribute_forwarding(fei,
     354             :                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
     355             :                                     &neos_dpo_1_1_1_1);
     356             : 
     357           1 :     bfmi_1_1_1_1 = bier_fmask_db_find(bti, &path_1_1_1_1);
     358           1 :     bfm_1_1_1_1 = bier_fmask_get(bfmi_1_1_1_1);
     359             : 
     360           1 :     BIER_TEST(!dpo_cmp(drop_dpo_get(DPO_PROTO_MPLS),
     361             :                        &bfm_1_1_1_1->bfm_dpo),
     362             :               "Fmask via 1.1.1.1 stacks on MPLS drop");
     363             : 
     364             :     /*
     365             :      * The BIER entry should stack on the forwarding chain of the fmask
     366             :      */
     367           1 :     const fib_test_lb_bucket_t dpo_o_bfm_1_1_1_1 = {
     368             :         .type = FT_LB_BIER_FMASK,
     369             :         .bier = {
     370             :             .fmask = bfmi_1_1_1_1,
     371             :         },
     372             :     };
     373           1 :     dpo_id_t dpo_bei = DPO_INVALID;
     374           1 :     bier_entry_contribute_forwarding(bei_1, &dpo_bei);
     375             : 
     376           1 :     BIER_TEST(!dpo_cmp(&dpo_bei, drop_dpo_get(DPO_PROTO_BIER)),
     377             :               "BP:1 stacks on bier drop");
     378             : 
     379             :     /*
     380             :      * give 1.1.1.1/32 a path and hence a interesting n-eos chain
     381             :      */
     382           2 :     ip46_address_t nh_10_10_10_1 = {
     383             :         .ip4 = {
     384           1 :             .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
     385             :         },
     386             :     };
     387             :     adj_index_t ai_mpls_10_10_10_1;
     388           1 :     ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
     389             :                                              VNET_LINK_MPLS,
     390             :                                              &nh_10_10_10_1,
     391           1 :                                              tm->hw[0]->sw_if_index);
     392             : 
     393           1 :     fib_test_lb_bucket_t bucket_neos_99_via_10_10_10_1 = {
     394             :         .type = FT_LB_LABEL_O_ADJ,
     395             :         .label_o_adj = {
     396             :             .label = 99,
     397             :             .eos = MPLS_NON_EOS,
     398             :             .adj = ai_mpls_10_10_10_1,
     399             :             .ttl = 255,
     400             :         },
     401             :     };
     402           1 :     fib_mpls_label_t *out_lbl_99 = NULL, fml_99 = {
     403             :         .fml_value = 99,
     404             :     };
     405           1 :     vec_add1(out_lbl_99, fml_99);
     406             : 
     407           1 :     fei = fib_table_entry_update_one_path(0,
     408             :                                           &pfx_1_1_1_1_s_32,
     409             :                                           FIB_SOURCE_API,
     410             :                                           FIB_ENTRY_FLAG_NONE,
     411             :                                           DPO_PROTO_IP4,
     412             :                                           &nh_10_10_10_1,
     413           1 :                                           tm->hw[0]->sw_if_index,
     414             :                                           ~0, // invalid fib index
     415             :                                           1,
     416             :                                           out_lbl_99,
     417             :                                           FIB_ROUTE_PATH_FLAG_NONE);
     418           1 :     fib_entry_contribute_forwarding(fei,
     419             :                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
     420             :                                     &neos_dpo_1_1_1_1);
     421           1 :     BIER_TEST(!fib_test_validate_lb(&neos_dpo_1_1_1_1, 1,
     422             :                                     &bucket_neos_99_via_10_10_10_1),
     423             :               "1.1.1.1/32 n-eos LB 1 buckets via: 99 + 10.10.10.1");
     424           1 :     BIER_TEST(!dpo_cmp(&neos_dpo_1_1_1_1,
     425             :                        &bfm_1_1_1_1->bfm_dpo),
     426             :               "Fmask via 1.1.1.1 stacks on updated non-eos of 1.1.1.1/32");
     427           1 :     bier_entry_contribute_forwarding(bei_1, &dpo_bei);
     428           1 :     BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1),
     429             :               "BP:1  stacks on fmask 1.1.1.1");
     430             : 
     431             :     /*
     432             :      * add another path to the via entry.
     433             :      * this makes the via-entry instantiate a new load-balance with
     434             :      * 2 buckets. and the back-walk to the BIER entry will need to
     435             :      * re-stack on it.
     436             :      */
     437           2 :     ip46_address_t nh_10_10_10_2 = {
     438             :         .ip4 = {
     439           1 :             .as_u32 = clib_host_to_net_u32(0x0a0a0a02),
     440             :         },
     441             :     };
     442             :     adj_index_t ai_mpls_10_10_10_2;
     443             : 
     444           1 :     ai_mpls_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
     445             :                                              VNET_LINK_MPLS,
     446             :                                              &nh_10_10_10_2,
     447           1 :                                              tm->hw[0]->sw_if_index);
     448             : 
     449           1 :     fib_test_lb_bucket_t bucket_neos_100_via_10_10_10_2 = {
     450             :         .type = FT_LB_LABEL_O_ADJ,
     451             :         .label_o_adj = {
     452             :             .label = 100,
     453             :             .eos = MPLS_NON_EOS,
     454             :             .adj = ai_mpls_10_10_10_2,
     455             :             .ttl = 255,
     456             :         },
     457             :     };
     458           1 :     fib_mpls_label_t *out_lbl_100 = NULL, fml_100 = {
     459             :         .fml_value = 100,
     460             :     };
     461           1 :     vec_add1(out_lbl_100, fml_100);
     462             : 
     463           1 :     fei = fib_table_entry_path_add(0,
     464             :                                    &pfx_1_1_1_1_s_32,
     465             :                                    FIB_SOURCE_API,
     466             :                                    FIB_ENTRY_FLAG_NONE,
     467             :                                    DPO_PROTO_IP4,
     468             :                                    &nh_10_10_10_2,
     469           1 :                                    tm->hw[0]->sw_if_index,
     470             :                                    ~0, // invalid fib index
     471             :                                    1,
     472             :                                    out_lbl_100,
     473             :                                    FIB_ROUTE_PATH_FLAG_NONE);
     474             : 
     475           1 :     fib_entry_contribute_forwarding(fei,
     476             :                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
     477             :                                     &neos_dpo_1_1_1_1);
     478           1 :     BIER_TEST(!fib_test_validate_lb(&neos_dpo_1_1_1_1, 2,
     479             :                                     &bucket_neos_99_via_10_10_10_1,
     480             :                                     &bucket_neos_100_via_10_10_10_2),
     481             :               "1.1.1.1/32 n-eos LB 2 buckets "
     482             :               "via: 99 + 10.10.10.1, "
     483             :               "via: 100 + 10.10.10.2");
     484           1 :     BIER_TEST(!dpo_cmp(&neos_dpo_1_1_1_1,
     485             :                        &bfm_1_1_1_1->bfm_dpo),
     486             :               "Fmask via 1.1.1.1 stacks on updated non-eos of 1.1.1.1/32");
     487             : 
     488             :     /*
     489             :      * add another bier bit-position via the same next-hop
     490             :      * since its the same next hop, the two bit-positions should link
     491             :      * to the same fmask
     492             :      */
     493             :     index_t bei_2;
     494             : 
     495           1 :     input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1);
     496           1 :     bier_table_route_path_add(&bt_0_0_0_256, 2, input_paths_1_1_1_1);
     497           1 :     bei_2 = bier_table_lookup(bier_table_get(bti), 2);
     498             : 
     499           1 :     bier_entry_contribute_forwarding(bei_2, &dpo_bei);
     500           1 :     BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1),
     501             :               "BP:2  stacks on fmask 1.1.1.1");
     502             : 
     503             :     /*
     504             :      * now add a bit-position via a different next hop and expect to
     505             :      * link via a different fmask
     506             :      */
     507           2 :     const ip46_address_t nh_1_1_1_2 = {
     508             :         .ip4 = {
     509           1 :             .as_u32 = clib_host_to_net_u32(0x01010102),
     510             :         },
     511             :     };
     512           1 :     const fib_prefix_t pfx_1_1_1_2_s_32 = {
     513             :         .fp_addr = nh_1_1_1_2,
     514             :         .fp_len = 32,
     515             :         .fp_proto = FIB_PROTOCOL_IP4,
     516             :     };
     517           1 :     fib_route_path_t *paths_1_1_1_2 = NULL, *input_paths_1_1_1_2, path_1_1_1_2 = {
     518             :         .frp_addr = nh_1_1_1_2,
     519             :         .frp_sw_if_index = ~0,
     520             :     };
     521           1 :     fib_mpls_label_t fml_501 = {
     522             :         .fml_value = 501,
     523             :     };
     524           1 :     vec_add1(path_1_1_1_2.frp_label_stack, fml_501);
     525           1 :     vec_add1(paths_1_1_1_2, path_1_1_1_2);
     526           1 :     input_paths_1_1_1_2 = vec_dup(paths_1_1_1_2);
     527             :     index_t bei_3;
     528             : 
     529           1 :     fib_mpls_label_t *out_lbl_101 = NULL, fml_101 = {
     530             :         .fml_value = 101,
     531             :     };
     532           1 :     vec_add1(out_lbl_101, fml_101);
     533           1 :     fei = fib_table_entry_path_add(0,
     534             :                                    &pfx_1_1_1_2_s_32,
     535             :                                    FIB_SOURCE_API,
     536             :                                    FIB_ENTRY_FLAG_NONE,
     537             :                                    DPO_PROTO_IP4,
     538             :                                    &nh_10_10_10_2,
     539           1 :                                    tm->hw[0]->sw_if_index,
     540             :                                    ~0, // invalid fib index
     541             :                                    1,
     542             :                                    out_lbl_101,
     543             :                                    FIB_ROUTE_PATH_FLAG_NONE);
     544           1 :     bier_table_route_path_update(&bt_0_0_0_256, 3, input_paths_1_1_1_2);
     545           1 :     bei_3 = bier_table_lookup(bier_table_get(bti), 3);
     546             : 
     547           1 :     BIER_TEST((INDEX_INVALID != bei_3), "BP:3 present");
     548             : 
     549             :     /*
     550             :      * the newly created fmask should stack on the non-eos chain
     551             :      * of the via-fib-entry
     552             :      */
     553           1 :     dpo_id_t neos_dpo_1_1_1_2 = DPO_INVALID;
     554             :     bier_fmask_t *bfm_1_1_1_2;
     555             :     index_t bfmi_1_1_1_2;
     556             : 
     557           1 :     fei = fib_table_lookup_exact_match(0, &pfx_1_1_1_2_s_32);
     558           1 :     fib_entry_contribute_forwarding(fei,
     559             :                                     FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS,
     560             :                                     &neos_dpo_1_1_1_2);
     561             : 
     562           1 :     bfmi_1_1_1_2 = bier_fmask_db_find(bti, &path_1_1_1_2);
     563           1 :     bfm_1_1_1_2 = bier_fmask_get(bfmi_1_1_1_2);
     564             : 
     565           1 :     BIER_TEST(!dpo_cmp(&neos_dpo_1_1_1_2,
     566             :                        &bfm_1_1_1_2->bfm_dpo),
     567             :               "Fmask via 1.1.1.2 stacks on non-eos of 1.1.1.2/32");
     568             : 
     569             :     /*
     570             :      * The BIER entry should stack on the forwarding chain of the fmask
     571             :      */
     572           1 :     const fib_test_lb_bucket_t dpo_o_bfm_1_1_1_2 = {
     573             :         .type = FT_LB_BIER_FMASK,
     574             :         .bier = {
     575             :             .fmask = bfmi_1_1_1_2,
     576             :         },
     577             :     };
     578           1 :     bier_entry_contribute_forwarding(bei_3, &dpo_bei);
     579           1 :     BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_2),
     580             :               "BP:2 stacks on fmask 1.1.1.2");
     581             : 
     582             :     /*
     583             :      * Load-balance BP:3 over both next-hops
     584             :      */
     585           1 :     paths_1_1_1_1[0] = path_1_1_1_1;
     586           1 :     input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1);
     587           1 :     bier_table_route_path_add(&bt_0_0_0_256, 3, input_paths_1_1_1_1);
     588             : 
     589           1 :     BIER_TEST(!bier_test_validate_entry(bei_3, 2,
     590             :                                         &dpo_o_bfm_1_1_1_1,
     591             :                                         &dpo_o_bfm_1_1_1_2),
     592             :               "BP:3 stacks on fmask 1.1.1.2 & 1.1.1.1");
     593             : 
     594             :     /*
     595             :      * test that the ECMP choices for BP:3 have been spread over the
     596             :      * ECMP tables
     597             :      */
     598           1 :     BIER_TEST((bier_table_fwd_lookup(bier_table_get(l_o_bt[0].bier.table), 3) ==
     599             :                bfmi_1_1_1_1),
     600             :               "fwd lookup for BP:3 ECMP:0 is 1.1.1.1");
     601           1 :     BIER_TEST((bier_table_fwd_lookup(bier_table_get(l_o_bt[1].bier.table), 3) ==
     602             :                bfmi_1_1_1_2),
     603             :               "fwd lookup for BP:3 ECMP:1 is 1.1.1.2");
     604             : 
     605             :     /*
     606             :      * Withdraw one of the via FIB and thus bring down the fmask
     607             :      * expect the bier-entry forwarding to remove this from the set
     608             :      */
     609           1 :     fib_table_entry_delete(0, &pfx_1_1_1_2_s_32, FIB_SOURCE_API);
     610             : 
     611           1 :     bier_entry_contribute_forwarding(bei_3, &dpo_bei);
     612           1 :     BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1),
     613             :               "BP:3 stacks on fmask 1.1.1.1");
     614             : 
     615           1 :     BIER_TEST((bier_table_fwd_lookup(bier_table_get(l_o_bt[0].bier.table), 3) ==
     616             :                bfmi_1_1_1_1),
     617             :               "fwd lookup for BP:3 ECMP:0 is 1.1.1.1");
     618           1 :     BIER_TEST((bier_table_fwd_lookup(bier_table_get(l_o_bt[1].bier.table), 3) ==
     619             :                bfmi_1_1_1_1),
     620             :               "fwd lookup for BP:3 ECMP:1 is 1.1.1.1");
     621             : 
     622             :     /*
     623             :      * add the via back
     624             :      */
     625           1 :     out_lbl_101 = NULL;
     626           1 :     vec_add1(out_lbl_101, fml_101);
     627           1 :     fei = fib_table_entry_path_add(0,
     628             :                                    &pfx_1_1_1_2_s_32,
     629             :                                    FIB_SOURCE_API,
     630             :                                    FIB_ENTRY_FLAG_NONE,
     631             :                                    DPO_PROTO_IP4,
     632             :                                    &nh_10_10_10_2,
     633           1 :                                    tm->hw[0]->sw_if_index,
     634             :                                    ~0, // invalid fib index
     635             :                                    1,
     636             :                                    out_lbl_101,
     637             :                                    FIB_ROUTE_PATH_FLAG_NONE);
     638             :     /* suspend so the update walk kicks int */
     639           1 :     vlib_process_suspend(vlib_get_main(), 1e-5);
     640             : 
     641           1 :     BIER_TEST(!bier_test_validate_entry(bei_3, 2,
     642             :                                         &dpo_o_bfm_1_1_1_1,
     643             :                                         &dpo_o_bfm_1_1_1_2),
     644             :               "BP:3 stacks on fmask 1.1.1.2 & 1.1.1.1");
     645           1 :     BIER_TEST((bier_table_fwd_lookup(bier_table_get(l_o_bt[0].bier.table), 3) ==
     646             :                bfmi_1_1_1_1),
     647             :               "fwd lookup for BP:3 ECMP:0 is 1.1.1.1");
     648           1 :     BIER_TEST((bier_table_fwd_lookup(bier_table_get(l_o_bt[1].bier.table), 3) ==
     649             :                bfmi_1_1_1_2),
     650             :               "fwd lookup for BP:3 ECMP:1 is 1.1.1.2");
     651             : 
     652             :     /*
     653             :      * remove the original 1.1.1.2 fmask from BP:3
     654             :      */
     655           1 :     input_paths_1_1_1_2 = vec_dup(paths_1_1_1_2);
     656           1 :     bier_table_route_path_remove(&bt_0_0_0_256, 3, input_paths_1_1_1_2);
     657           1 :     bier_entry_contribute_forwarding(bei_3, &dpo_bei);
     658           1 :     BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1),
     659             :               "BP:3 stacks on fmask 1.1.1.1");
     660             : 
     661             :     /*
     662             :      * test that the ECMP choices for BP:3 have been updated
     663             :      */
     664           1 :     BIER_TEST((bier_table_fwd_lookup(bier_table_get(l_o_bt[0].bier.table), 3) ==
     665             :                bfmi_1_1_1_1),
     666             :               "fwd lookup for BP:3 ECMP:0 is 1.1.1.1");
     667           1 :     BIER_TEST((bier_table_fwd_lookup(bier_table_get(l_o_bt[1].bier.table), 3) ==
     668             :                bfmi_1_1_1_1),
     669             :               "fwd lookup for BP:3 ECMP:1 is 1.1.1.1");
     670             : 
     671             :     /*
     672             :      * remove the routes added
     673             :      */
     674           1 :     input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1);
     675           1 :     bier_table_route_path_remove(&bt_0_0_0_256, 2, input_paths_1_1_1_1);
     676           1 :     input_paths_1_1_1_2 = vec_dup(paths_1_1_1_2);
     677           1 :     bier_table_route_path_remove(&bt_0_0_0_256, 3, input_paths_1_1_1_2);
     678           1 :     input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1);
     679           1 :     bier_table_route_path_remove(&bt_0_0_0_256, 3, input_paths_1_1_1_1);
     680             : 
     681           1 :     bier_table_route_delete(&bt_0_0_0_256, 1);
     682             : 
     683             :     /*
     684             :      * delete the table
     685             :      */
     686           1 :     bier_table_unlock(&bt_0_0_0_256);
     687             : 
     688             :     /*
     689             :      * test resources are freed
     690             :      */
     691           1 :     dpo_reset(&dpo_bei);
     692          17 :     for (ii = 0; ii < N_BIER_ECMP_TABLES; ii++)
     693             :     {
     694          16 :         bier_table_ecmp_unlock(l_o_bt[ii].bier.table);
     695             :     };
     696           1 :     BIER_TEST(0 == pool_elts(bier_table_pool), "BIER table pool empty");
     697           1 :     BIER_TEST(0 == pool_elts(bier_fmask_pool), "BIER fmask pool empty");
     698           1 :     BIER_TEST(0 == pool_elts(bier_entry_pool), "BIER entry pool empty");
     699             : 
     700           1 :     adj_unlock(ai_mpls_10_10_10_1);
     701           1 :     adj_unlock(ai_mpls_10_10_10_2);
     702           1 :     dpo_reset(&neos_dpo_1_1_1_1);
     703           1 :     dpo_reset(&neos_dpo_1_1_1_2);
     704           1 :     fib_table_entry_delete(0, &pfx_1_1_1_1_s_32, FIB_SOURCE_API);
     705           1 :     fib_table_entry_delete(0, &pfx_1_1_1_2_s_32, FIB_SOURCE_API);
     706             : 
     707             :     /* +1 to account for the one time alloc'd drop LB in the MPLS fibs */
     708           1 :     BIER_TEST(lb_count+1 == pool_elts(load_balance_pool),
     709             :               "Load-balance resources freed ");
     710           1 :     BIER_TEST((0 == adj_nbr_db_size()), "ADJ DB size is %d",
     711             :              adj_nbr_db_size());
     712             : 
     713           1 :     vec_free(paths_1_1_1_1);
     714           1 :     vec_free(paths_1_1_1_2);
     715           1 :     vec_free(input_paths_1_1_1_1);
     716           1 :     vec_free(input_paths_1_1_1_2);
     717             : 
     718           1 :     return (0);
     719             : }
     720             : 
     721             : static int
     722           1 : bier_test_mpls_imp (void)
     723             : {
     724             :     fib_node_index_t bii;
     725             :     int res;
     726             : 
     727             :     /*
     728             :      * Add the BIER Main table
     729             :      */
     730           1 :     const bier_table_id_t bt_0_0_0_256 = {
     731             :         .bti_set = 0,
     732             :         .bti_sub_domain = 0,
     733             :         .bti_hdr_len = BIER_HDR_LEN_256,
     734             :         .bti_type = BIER_TABLE_MPLS_SPF,
     735             :         .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
     736             :     };
     737             : 
     738           1 :     bier_table_add_or_lock(&bt_0_0_0_256, 1600);
     739             : 
     740             :     /*
     741             :      * A bit-string for imp 1.
     742             :      */
     743             :     bier_bit_string_t bbs_256;
     744             :     u8 buckets[BIER_HDR_BUCKETS_256];
     745           1 :     clib_memset(buckets, 0x5, BIER_HDR_BUCKETS_256);
     746             : 
     747           1 :     res = 0;
     748           1 :     bier_bit_string_init(&bbs_256, BIER_HDR_LEN_256, buckets);
     749             : 
     750           1 :     bii = bier_imp_add_or_lock(&bt_0_0_0_256, 1, &bbs_256);
     751             : 
     752             :     /*
     753             :      * An mfib entry that resolves via the BIER imposition
     754             :      */
     755           3 :     const mfib_prefix_t pfx_1_1_1_1_c_239_1_1_1 = {
     756             :         .fp_len = 64,
     757             :         .fp_proto = FIB_PROTOCOL_IP4,
     758             :         .fp_grp_addr = {
     759           1 :             .ip4.as_u32 = clib_host_to_net_u32(0xef010101),
     760             :         },
     761             :         .fp_src_addr = {
     762           1 :             .ip4.as_u32 = clib_host_to_net_u32(0x01010101),
     763             :         },
     764             :     };
     765           1 :     fib_route_path_t path_via_bier_imp_1 = {
     766             :         .frp_proto = DPO_PROTO_BIER,
     767             :         .frp_bier_imp = bii,
     768             :         .frp_weight = 0,
     769             :         .frp_flags = FIB_ROUTE_PATH_BIER_IMP,
     770             :         .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
     771             :     };
     772           1 :     mfib_table_entry_path_update (0, // default table
     773             :                                   &pfx_1_1_1_1_c_239_1_1_1, MFIB_SOURCE_API,
     774             :                                   MFIB_ENTRY_FLAG_NONE, &path_via_bier_imp_1);
     775           1 :     mfib_table_entry_delete(0,
     776             :                             &pfx_1_1_1_1_c_239_1_1_1 ,
     777             :                             MFIB_SOURCE_API);
     778             : 
     779           1 :     bier_imp_unlock(bii);
     780           1 :     bier_table_unlock(&bt_0_0_0_256);
     781             : 
     782           1 :     BIER_TEST(0 == pool_elts(bier_imp_pool),
     783             :               "BIER imposition resources freed ");
     784           1 :     BIER_TEST(0 == pool_elts(bier_table_pool),
     785             :               "BIER table resources freed ");
     786             : 
     787           1 :     return (0);
     788             : }
     789             : 
     790             : static int
     791           1 : bier_test_mpls_disp (void)
     792             : {
     793             :     /*
     794             :      * Add the BIER Main table
     795             :      */
     796           1 :     const bier_table_id_t bt_0_0_0_256 = {
     797             :         .bti_set = 0,
     798             :         .bti_sub_domain = 0,
     799             :         .bti_hdr_len = BIER_HDR_LEN_256,
     800             :         .bti_type = BIER_TABLE_MPLS_SPF,
     801             :         .bti_ecmp = BIER_ECMP_TABLE_ID_MAIN,
     802             :     };
     803             :     index_t bti;
     804             :     int res;
     805             : 
     806           1 :     res = 0;
     807           1 :     bti = bier_table_add_or_lock(&bt_0_0_0_256, 1600);
     808             : 
     809             :     /*
     810             :      * Add a BIER disposition table
     811             :      */
     812           1 :     const u32 bier_disp_tbl_id = 1;
     813             :     index_t bdti1;
     814             : 
     815           1 :     bdti1 = bier_disp_table_add_or_lock(bier_disp_tbl_id);
     816             : 
     817             :     /*
     818             :      * add a bit-position in the table that resolves via
     819             :      * DISP table, i.e. a for-us bit-position
     820             :      */
     821           1 :     fib_route_path_t *paths_via_disp = NULL, path_via_disp = {
     822             :         // .frp_addr = all-zeros
     823             :         .frp_proto = DPO_PROTO_BIER,
     824             :         .frp_sw_if_index = ~0,
     825             :     };
     826           1 :     vec_add1(paths_via_disp, path_via_disp);
     827             : 
     828           1 :     bier_table_route_path_add(&bt_0_0_0_256, 3, paths_via_disp);
     829             : 
     830             :     /*
     831             :      * the fmask should stack on the BIER disp table
     832             :      */
     833             :     bier_fmask_t *bfm_0_0_0_0;
     834             :     index_t bfmi_0_0_0_0;
     835           1 :     dpo_id_t dpo_disp_tbl_1 = DPO_INVALID;
     836             : 
     837           1 :     bier_disp_table_contribute_forwarding(bdti1, &dpo_disp_tbl_1);
     838             : 
     839           1 :     bfmi_0_0_0_0 = bier_fmask_db_find(bti, &path_via_disp);
     840           1 :     bfm_0_0_0_0 = bier_fmask_get(bfmi_0_0_0_0);
     841             : 
     842           1 :     BIER_TEST(!dpo_cmp(&dpo_disp_tbl_1, &bfm_0_0_0_0->bfm_dpo),
     843             :               "Fmask via 0.0.0.0 stacks on BIER disp table 1");
     844             : 
     845             :     /*
     846             :      * and a deag entry into the disposition table
     847             :      */
     848           1 :     fib_route_path_t *rpaths = NULL, path_via_mfib = {
     849             :         .frp_proto = DPO_PROTO_IP4,
     850             :         .frp_addr = zero_addr,
     851             :         .frp_fib_index = 0, // default MFIB table
     852             :         .frp_rpf_id = 9, // some non-zero value
     853             :         .frp_flags = FIB_ROUTE_PATH_RPF_ID,
     854             :     };
     855           1 :     bier_hdr_src_id_t src = 99;
     856           1 :     vec_add1(rpaths, path_via_mfib);
     857           1 :     bier_disp_table_entry_path_add(bier_disp_tbl_id, src,
     858             :                                    BIER_HDR_PROTO_IPV4, rpaths);
     859             : 
     860             :     /* which should stack on a lookup in the mfib table */
     861             :     const dpo_id_t *dpo_disp_entry_v4;
     862             :     bier_disp_entry_t *bde_99;
     863             :     index_t bdei;
     864             : 
     865           1 :     bdei = bier_disp_table_lookup(bdti1, clib_host_to_net_u16(src));
     866           1 :     bde_99 = bier_disp_entry_get(bdei);
     867           1 :     dpo_disp_entry_v4 = &bde_99->bde_fwd[BIER_HDR_PROTO_IPV4].bde_dpo;
     868             : 
     869           1 :     lookup_dpo_t *lkd = lookup_dpo_get(dpo_disp_entry_v4->dpoi_index);
     870             : 
     871           1 :     BIER_TEST((bdti1 == lkd->lkd_fib_index),
     872             :               "disp is deag in %d %U",
     873             :               lkd->lkd_fib_index,
     874             :               format_dpo_id, dpo_disp_entry_v4, 0);
     875           1 :     BIER_TEST((LOOKUP_INPUT_DST_ADDR == lkd->lkd_input),
     876             :               "disp is destination deag in %d %U",
     877             :               lkd->lkd_input,
     878             :               format_dpo_id, dpo_disp_entry_v4, 0);
     879           1 :     BIER_TEST((LOOKUP_MULTICAST == lkd->lkd_cast),
     880             :               "disp is multicast deag in %d %U",
     881             :               lkd->lkd_input,
     882             :               format_dpo_id, dpo_disp_entry_v4, 0);
     883             : 
     884             :     /*
     885             :      * cleanup
     886             :      */
     887           1 :     dpo_reset(&dpo_disp_tbl_1);
     888             : 
     889           1 :     bier_disp_table_entry_path_remove(bier_disp_tbl_id, src,
     890             :                                       BIER_HDR_PROTO_IPV4, rpaths);
     891           1 :     bier_table_route_path_remove(&bt_0_0_0_256, 3, paths_via_disp);
     892             : 
     893           1 :     bier_disp_table_unlock_w_table_id(bier_disp_tbl_id);
     894             : 
     895           1 :     bier_table_unlock(&bt_0_0_0_256);
     896             : 
     897           1 :     BIER_TEST(0 == pool_elts(bier_fmask_pool),
     898             :               "BIER fmask resources freed ");
     899           1 :     BIER_TEST(0 == pool_elts(bier_table_pool),
     900             :               "BIER table resources freed ");
     901           1 :     BIER_TEST(0 == pool_elts(bier_disp_table_pool),
     902             :               "BIER Disposition table resources freed ");
     903           1 :     BIER_TEST(0 == pool_elts(bier_disp_entry_pool),
     904             :               "BIER Disposition entry resources freed ");
     905             : 
     906           1 :     vec_free(paths_via_disp);
     907           1 :     return (0);
     908             : }
     909             : 
     910             : static clib_error_t *
     911           1 : bier_test (vlib_main_t * vm,
     912             :            unformat_input_t * input,
     913             :            vlib_cli_command_t * cmd_arg)
     914             : {
     915           1 :     int res = 0;
     916             : 
     917           1 :     res += bier_test_mk_intf(4);
     918             : 
     919           1 :     if (unformat (input, "debug"))
     920             :     {
     921           0 :         bier_test_do_debug = 1;
     922             :     }
     923             : 
     924           1 :     if (unformat (input, "mid"))
     925           0 :         res += bier_test_mpls_spf();
     926           1 :     else if (unformat (input, "head"))
     927           0 :         res += bier_test_mpls_imp();
     928           1 :     else if (unformat (input, "tail"))
     929           0 :         res += bier_test_mpls_disp();
     930             :     else
     931             :     {
     932           1 :         res += bier_test_mpls_spf();
     933           1 :         res += bier_test_mpls_imp();
     934           1 :         res += bier_test_mpls_disp();
     935             :     }
     936             : 
     937           1 :     if (res)
     938             :     {
     939           0 :         return clib_error_return(0, "BIER Unit Test Failed");
     940             :     }
     941             :     else
     942             :     {
     943           1 :         return (NULL);
     944             :     }
     945             : }
     946             : 
     947       16239 : VLIB_CLI_COMMAND (test_route_command, static) = {
     948             :     .path = "test bier",
     949             :     .short_help = "bier unit tests",
     950             :     .function = bier_test,
     951             : };
     952             : 
     953             : clib_error_t *
     954         559 : bier_test_init (vlib_main_t *vm)
     955             : {
     956         559 :     return 0;
     957             : }
     958             : 
     959        1119 : VLIB_INIT_FUNCTION (bier_test_init);

Generated by: LCOV version 1.14