From ef90ed08fbcde7535b4a789349b39dc25798c77d Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 13 Sep 2018 08:45:12 -0700 Subject: [PATCH] BIER API and load-balancing fixes Change-Id: Ibda19d786070c942c75016ab568c8361de2f24af Signed-off-by: Neale Ranns --- src/vnet/bier/bier.api | 2 + src/vnet/bier/bier_api.c | 17 +++++-- src/vnet/bier/bier_entry.c | 105 ++++++++++++++++++++++++++++++++++---------- src/vnet/bier/bier_entry.h | 3 ++ src/vnet/bier/bier_fmask.c | 18 ++++---- src/vnet/bier/bier_fwd.h | 32 ++++++++++++++ src/vnet/bier/bier_lookup.c | 6 +-- src/vnet/bier/bier_table.c | 88 ++++++++++++++++++++++++++++++++----- src/vnet/bier/bier_table.h | 17 ++++--- src/vnet/bier/bier_test.c | 24 +++++----- src/vnet/bier/bier_update.c | 8 ++-- src/vnet/dpo/load_balance.c | 4 +- src/vnet/mpls/mpls_lookup.h | 5 +++ test/test_bier.py | 94 +++++++++++++++++++++++++++++++++++++++ test/vpp_bier.py | 77 ++++++++++++++++++++++++-------- test/vpp_ip_route.py | 3 ++ test/vpp_papi_provider.py | 6 ++- 17 files changed, 416 insertions(+), 93 deletions(-) create mode 100644 src/vnet/bier/bier_fwd.h diff --git a/src/vnet/bier/bier.api b/src/vnet/bier/bier.api index fb6923b4a01..da2989bbe44 100644 --- a/src/vnet/bier/bier.api +++ b/src/vnet/bier/bier.api @@ -72,6 +72,8 @@ define bier_table_details @param br_is_add - Is this a route add or delete @param br_is_replace - Are the paths specfied replacing those already present or are they to be combined. + is_replace = 1 and n_paths=0 implies delete the + route and all paths; @param br_n_paths - The number of paths @param br_paths - The array of paths */ diff --git a/src/vnet/bier/bier_api.c b/src/vnet/bier/bier_api.c index 93048a0a890..2e8fc626baa 100644 --- a/src/vnet/bier/bier_api.c +++ b/src/vnet/bier/bier_api.c @@ -204,13 +204,24 @@ vl_api_bier_route_add_del_t_handler (vl_api_bier_route_add_del_t * mp) } } - if (mp->br_is_add) + if (mp->br_is_replace) { - bier_table_route_add(&bti, bp, brpaths); + if (0 == vec_len(brpaths)) + { + bier_table_route_delete(&bti, bp); + } + else + { + bier_table_route_path_update(&bti, bp, brpaths); + } + } + else if (mp->br_is_add) + { + bier_table_route_path_add(&bti, bp, brpaths); } else { - bier_table_route_remove(&bti, bp, brpaths); + bier_table_route_path_remove(&bti, bp, brpaths); } vec_free(brpaths); diff --git a/src/vnet/bier/bier_entry.c b/src/vnet/bier/bier_entry.c index 2f8d25008cc..80f7cfd8e56 100644 --- a/src/vnet/bier/bier_entry.c +++ b/src/vnet/bier/bier_entry.c @@ -73,27 +73,6 @@ bier_entry_create (index_t bti, return (bier_entry_get_index(be)); } -void -bier_entry_delete (index_t bei) -{ - bier_entry_t *be; - - be = bier_entry_get(bei); - - /* - * if we still ahve a path-list, unlink from it - */ - if (FIB_NODE_INDEX_INVALID != be->be_path_list) - { - fib_path_list_walk(be->be_path_list, - bier_entry_unlink_walk, - be); - fib_path_list_child_remove(be->be_path_list, - be->be_sibling_index); - } - - pool_put(bier_entry_pool, be); -} static void bier_entry_table_ecmp_walk_add_fmask (index_t btei, @@ -160,6 +139,33 @@ bier_entry_table_ecmp_walk_add_fmask (index_t btei, } } +void +bier_entry_delete (index_t bei) +{ + bier_entry_t *be; + + be = bier_entry_get(bei); + + /* + * if we still ahve a path-list, unlink from it + */ + if (FIB_NODE_INDEX_INVALID != be->be_path_list) + { + fib_path_list_walk(be->be_path_list, + bier_entry_unlink_walk, + be); + fib_path_list_child_remove(be->be_path_list, + be->be_sibling_index); + + be->be_path_list = FIB_NODE_INDEX_INVALID; + bier_table_ecmp_walk(be->be_bti, + bier_entry_table_ecmp_walk_add_fmask, + be); + } + + pool_put(bier_entry_pool, be); +} + void bier_entry_path_add (index_t bei, const fib_route_path_t *rpaths) @@ -230,6 +236,62 @@ bier_entry_path_add (index_t bei, fib_path_list_unlock(old_pl_index); } +void +bier_entry_path_update (index_t bei, + const fib_route_path_t *rpaths) +{ + fib_node_index_t old_pl_index; + bier_entry_t *be; + + be = bier_entry_get(bei); + old_pl_index = be->be_path_list; + + /* + * lock the path-list so it does not go away before we unlink + * from its resolved fmasks + */ + fib_path_list_lock(old_pl_index); + + if (FIB_NODE_INDEX_INVALID != old_pl_index) + { + fib_path_list_child_remove(old_pl_index, + be->be_sibling_index); + } + + be->be_path_list = fib_path_list_create((FIB_PATH_LIST_FLAG_SHARED | + FIB_PATH_LIST_FLAG_NO_URPF), + rpaths); + be->be_sibling_index = fib_path_list_child_add(be->be_path_list, + FIB_NODE_TYPE_BIER_ENTRY, + bier_entry_get_index(be)); + + /* + * link the entry's bit-position to each fmask in the new path-list + * then unlink from the old. + */ + fib_path_list_walk(be->be_path_list, + bier_entry_link_walk, + be); + if (FIB_NODE_INDEX_INVALID != old_pl_index) + { + fib_path_list_walk(old_pl_index, + bier_entry_unlink_walk, + be); + } + + /* + * update the ECNP tables with the new choice + */ + bier_table_ecmp_walk(be->be_bti, + bier_entry_table_ecmp_walk_add_fmask, + be); + + /* + * symmetric unlock. The old path-list may not exist hereinafter + */ + fib_path_list_unlock(old_pl_index); +} + int bier_entry_path_remove (index_t bei, const fib_route_path_t *rpaths) @@ -279,7 +341,6 @@ bier_entry_path_remove (index_t bei, } fib_path_list_unlock(old_pl_index); - /* * update the ECNP tables with the new choice */ diff --git a/src/vnet/bier/bier_entry.h b/src/vnet/bier/bier_entry.h index e514c64bb24..629e47a859a 100644 --- a/src/vnet/bier/bier_entry.h +++ b/src/vnet/bier/bier_entry.h @@ -75,6 +75,9 @@ extern index_t bier_entry_create(index_t bti, bier_bp_t bp); extern void bier_entry_delete(index_t bei); +extern void bier_entry_path_update (index_t bei, + const fib_route_path_t *rpaths); + extern void bier_entry_path_add(index_t bei, const fib_route_path_t *brp); diff --git a/src/vnet/bier/bier_fmask.c b/src/vnet/bier/bier_fmask.c index 73f719460aa..cb61681385d 100644 --- a/src/vnet/bier/bier_fmask.c +++ b/src/vnet/bier/bier_fmask.c @@ -165,14 +165,14 @@ bier_fmask_child_remove (fib_node_index_t bfmi, static void bier_fmask_init (bier_fmask_t *bfm, const bier_fmask_id_t *fmid, - const fib_route_path_t *rpaths) + const fib_route_path_t *rpath) { const bier_table_id_t *btid; + fib_route_path_t *rpaths; mpls_label_t olabel; - ASSERT(1 == vec_len(rpaths)); memset(bfm, 0, sizeof(*bfm)); - + bfm->bfm_id = clib_mem_alloc(sizeof(*bfm->bfm_id)); fib_node_init(&bfm->bfm_node, FIB_NODE_TYPE_BIER_FMASK); @@ -188,9 +188,9 @@ bier_fmask_init (bier_fmask_t *bfm, if (!(bfm->bfm_flags & BIER_FMASK_FLAG_DISP)) { - if (NULL != rpaths->frp_label_stack) + if (NULL != rpath->frp_label_stack) { - olabel = rpaths->frp_label_stack[0].fml_value; + olabel = rpath->frp_label_stack[0].fml_value; vnet_mpls_uc_set_label(&bfm->bfm_label, olabel); vnet_mpls_uc_set_exp(&bfm->bfm_label, 0); vnet_mpls_uc_set_s(&bfm->bfm_label, 1); @@ -220,13 +220,15 @@ bier_fmask_init (bier_fmask_t *bfm, bfm->bfm_label = clib_host_to_net_u32(bfm->bfm_label); } + rpaths = NULL; + vec_add1(rpaths, *rpath); bfm->bfm_pl = fib_path_list_create((FIB_PATH_LIST_FLAG_SHARED | FIB_PATH_LIST_FLAG_NO_URPF), rpaths); bfm->bfm_sibling = fib_path_list_child_add(bfm->bfm_pl, FIB_NODE_TYPE_BIER_FMASK, bier_fmask_get_index(bfm)); - + vec_free(rpaths); bier_fmask_stack(bfm); } @@ -276,7 +278,7 @@ bier_fmask_lock (index_t bfmi) index_t bier_fmask_create_and_lock (const bier_fmask_id_t *fmid, - const fib_route_path_t *rpaths) + const fib_route_path_t *rpath) { bier_fmask_t *bfm; index_t bfmi; @@ -287,7 +289,7 @@ bier_fmask_create_and_lock (const bier_fmask_id_t *fmid, vlib_validate_combined_counter (&(bier_fmask_counters), bfmi); vlib_zero_combined_counter (&(bier_fmask_counters), bfmi); - bier_fmask_init(bfm, fmid, rpaths); + bier_fmask_init(bfm, fmid, rpath); bier_fmask_lock(bfmi); diff --git a/src/vnet/bier/bier_fwd.h b/src/vnet/bier/bier_fwd.h new file mode 100644 index 00000000000..3b0b93b4baf --- /dev/null +++ b/src/vnet/bier/bier_fwd.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BIER_FWD_H__ +#define __BIER_FWD_H__ + +#include +#include + +static_always_inline u32 +bier_compute_flow_hash (const bier_hdr_t *hdr) +{ + u32 first_word = clib_net_to_host_u32(hdr->bh_first_word); + + return ((first_word & + BIER_HDR_ENTROPY_FIELD_MASK) >> + BIER_HDR_ENTROPY_FIELD_SHIFT); +} + +#endif diff --git a/src/vnet/bier/bier_lookup.c b/src/vnet/bier/bier_lookup.c index 4e544a3aca5..d4500823f13 100644 --- a/src/vnet/bier/bier_lookup.c +++ b/src/vnet/bier/bier_lookup.c @@ -250,12 +250,12 @@ bier_lookup (vlib_main_t * vm, { bier_lookup_trace_t *tr; - vlib_trace_buffer (vm, node, next0, c0, 0); + if (c0 != b0) + vlib_buffer_copy_trace_flag (vm, b0, ci0); + tr = vlib_add_trace (vm, node, c0, sizeof (*tr)); tr->bt_index = bti0; tr->bfm_index = blm->blm_fmasks[thread_index][clone]; - - c0->flags |= VLIB_BUFFER_IS_TRACED; } vlib_validate_buffer_enqueue_x1(vm, node, next_index, diff --git a/src/vnet/bier/bier_table.c b/src/vnet/bier/bier_table.c index 80231fd8a72..3ecda105457 100644 --- a/src/vnet/bier/bier_table.c +++ b/src/vnet/bier/bier_table.c @@ -510,9 +510,10 @@ bier_table_remove (bier_table_t *bt, } void -bier_table_route_add (const bier_table_id_t *btid, - bier_bp_t bp, - fib_route_path_t *brps) +bier_table_route_path_update_i (const bier_table_id_t *btid, + bier_bp_t bp, + fib_route_path_t *brps, + u8 is_replace) { index_t bfmi, bti, bei, *bfmip, *bfmis = NULL; fib_route_path_t *brp; @@ -552,7 +553,23 @@ bier_table_route_add (const bier_table_id_t *btid, bei = bier_entry_create(bti, bp); bier_table_insert(bt, bp, bei); } - bier_entry_path_add(bei, brps); + + if (is_replace) + { + bier_entry_path_update(bei, brps); + } + else + { + fib_route_path_t *t_paths = NULL; + + vec_foreach(brp, brps) + { + vec_add1(t_paths, *brp); + bier_entry_path_add(bei, t_paths); + vec_reset_length(t_paths); + } + vec_free(t_paths); + } vec_foreach(bfmip, bfmis) { @@ -562,11 +579,51 @@ bier_table_route_add (const bier_table_id_t *btid, } void -bier_table_route_remove (const bier_table_id_t *btid, - bier_bp_t bp, - fib_route_path_t *brps) +bier_table_route_path_update (const bier_table_id_t *btid, + bier_bp_t bp, + fib_route_path_t *brps) +{ + bier_table_route_path_update_i(btid, bp, brps, 1); +} +void +bier_table_route_path_add (const bier_table_id_t *btid, + bier_bp_t bp, + fib_route_path_t *brps) +{ + bier_table_route_path_update_i(btid, bp, brps, 0); +} + +void +bier_table_route_delete (const bier_table_id_t *btid, + bier_bp_t bp) +{ + bier_table_t *bt; + index_t bei; + + bt = bier_table_find(btid); + + if (NULL == bt) { + return; + } + + bei = bier_table_lookup(bt, bp); + + if (INDEX_INVALID == bei) + { + /* no such entry */ + return; + } + + bier_table_remove(bt, bp); + bier_entry_delete(bei); +} + +void +bier_table_route_path_remove (const bier_table_id_t *btid, + bier_bp_t bp, + fib_route_path_t *brps) { - fib_route_path_t *brp = NULL; + fib_route_path_t *brp = NULL, *t_paths = NULL; index_t bfmi, bti, bei; bier_table_t *bt; u32 ii; @@ -616,12 +673,19 @@ bier_table_route_remove (const bier_table_id_t *btid, return; } - if (0 == bier_entry_path_remove(bei, brps)) + vec_foreach(brp, brps) { - /* 0 remaining paths */ - bier_table_remove(bt, bp); - bier_entry_delete(bei); + vec_add1(t_paths, *brp); + if (0 == bier_entry_path_remove(bei, t_paths)) + { + /* 0 remaining paths */ + bier_table_remove(bt, bp); + bier_entry_delete(bei); + break; + } + vec_reset_length(t_paths); } + vec_free(t_paths); } void diff --git a/src/vnet/bier/bier_table.h b/src/vnet/bier/bier_table.h index 5af275f104a..9cd9937d76c 100644 --- a/src/vnet/bier/bier_table.h +++ b/src/vnet/bier/bier_table.h @@ -93,12 +93,17 @@ extern index_t bier_table_add_or_lock(const bier_table_id_t *id, mpls_label_t ll); extern void bier_table_unlock(const bier_table_id_t *id); -extern void bier_table_route_add(const bier_table_id_t *bti, - bier_bp_t bp, - fib_route_path_t *brp); -extern void bier_table_route_remove(const bier_table_id_t *bti, - bier_bp_t bp, - fib_route_path_t *brp); +extern void bier_table_route_path_add(const bier_table_id_t *bti, + bier_bp_t bp, + fib_route_path_t *brp); +extern void bier_table_route_path_remove(const bier_table_id_t *bti, + bier_bp_t bp, + fib_route_path_t *brp); +extern void bier_table_route_path_update(const bier_table_id_t *bti, + bier_bp_t bp, + fib_route_path_t *brp); +extern void bier_table_route_delete(const bier_table_id_t *bti, + bier_bp_t b); extern void bier_table_show_all(vlib_main_t * vm, bier_show_flags_t flags); diff --git a/src/vnet/bier/bier_test.c b/src/vnet/bier/bier_test.c index d4d1692643c..06160f60aab 100644 --- a/src/vnet/bier/bier_test.c +++ b/src/vnet/bier/bier_test.c @@ -335,7 +335,7 @@ bier_test_mpls_spf (void) index_t bei_1; input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1); - bier_table_route_add(&bt_0_0_0_256, 1, input_paths_1_1_1_1); + bier_table_route_path_add(&bt_0_0_0_256, 1, input_paths_1_1_1_1); bei_1 = bier_table_lookup(bier_table_get(bti), 1); BIER_TEST((INDEX_INVALID != bei_1), "BP:1 present"); @@ -492,7 +492,7 @@ bier_test_mpls_spf (void) index_t bei_2; input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1); - bier_table_route_add(&bt_0_0_0_256, 2, input_paths_1_1_1_1); + bier_table_route_path_add(&bt_0_0_0_256, 2, input_paths_1_1_1_1); bei_2 = bier_table_lookup(bier_table_get(bti), 2); bier_entry_contribute_forwarding(bei_2, &dpo_bei); @@ -541,7 +541,7 @@ bier_test_mpls_spf (void) 1, out_lbl_101, FIB_ROUTE_PATH_FLAG_NONE); - bier_table_route_add(&bt_0_0_0_256, 3, input_paths_1_1_1_2); + bier_table_route_path_update(&bt_0_0_0_256, 3, input_paths_1_1_1_2); bei_3 = bier_table_lookup(bier_table_get(bti), 3); BIER_TEST((INDEX_INVALID != bei_3), "BP:3 present"); @@ -584,7 +584,7 @@ bier_test_mpls_spf (void) */ paths_1_1_1_1[0] = path_1_1_1_1; input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1); - bier_table_route_add(&bt_0_0_0_256, 3, input_paths_1_1_1_1); + bier_table_route_path_add(&bt_0_0_0_256, 3, input_paths_1_1_1_1); BIER_TEST(!bier_test_validate_entry(bei_3, 2, &dpo_o_bfm_1_1_1_1, @@ -653,7 +653,7 @@ bier_test_mpls_spf (void) * remove the original 1.1.1.2 fmask from BP:3 */ input_paths_1_1_1_2 = vec_dup(paths_1_1_1_2); - bier_table_route_remove(&bt_0_0_0_256, 3, input_paths_1_1_1_2); + bier_table_route_path_remove(&bt_0_0_0_256, 3, input_paths_1_1_1_2); bier_entry_contribute_forwarding(bei_3, &dpo_bei); BIER_TEST((dpo_bei.dpoi_index == bfmi_1_1_1_1), "BP:3 stacks on fmask 1.1.1.1"); @@ -672,13 +672,13 @@ bier_test_mpls_spf (void) * remove the routes added */ input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1); - bier_table_route_remove(&bt_0_0_0_256, 2, input_paths_1_1_1_1); + bier_table_route_path_remove(&bt_0_0_0_256, 2, input_paths_1_1_1_1); input_paths_1_1_1_2 = vec_dup(paths_1_1_1_2); - bier_table_route_remove(&bt_0_0_0_256, 3, input_paths_1_1_1_2); + bier_table_route_path_remove(&bt_0_0_0_256, 3, input_paths_1_1_1_2); input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1); - bier_table_route_remove(&bt_0_0_0_256, 3, input_paths_1_1_1_1); - input_paths_1_1_1_1 = vec_dup(paths_1_1_1_1); - bier_table_route_remove(&bt_0_0_0_256, 1, input_paths_1_1_1_1); + bier_table_route_path_remove(&bt_0_0_0_256, 3, input_paths_1_1_1_1); + + bier_table_route_delete(&bt_0_0_0_256, 1); /* * delete the table @@ -827,7 +827,7 @@ bier_test_mpls_disp (void) }; vec_add1(paths_via_disp, path_via_disp); - bier_table_route_add(&bt_0_0_0_256, 3, paths_via_disp); + bier_table_route_path_add(&bt_0_0_0_256, 3, paths_via_disp); /* * the fmask should stack on the BIER disp table @@ -890,7 +890,7 @@ bier_test_mpls_disp (void) bier_disp_table_entry_path_remove(bier_disp_tbl_id, src, BIER_HDR_PROTO_IPV4, rpaths); - bier_table_route_remove(&bt_0_0_0_256, 3, paths_via_disp); + bier_table_route_path_remove(&bt_0_0_0_256, 3, paths_via_disp); bier_disp_table_unlock_w_table_id(bier_disp_tbl_id); diff --git a/src/vnet/bier/bier_update.c b/src/vnet/bier/bier_update.c index 326f8bf3f0b..4108d09f51e 100644 --- a/src/vnet/bier/bier_update.c +++ b/src/vnet/bier/bier_update.c @@ -115,11 +115,11 @@ vnet_bier_route_cmd (vlib_main_t * vm, if (add) { - bier_table_route_add(&bti, bp, brps); + bier_table_route_path_add(&bti, bp, brps); } else { - bier_table_route_remove(&bti, bp, brps); + bier_table_route_path_remove(&bti, bp, brps); } done: @@ -149,11 +149,11 @@ show_bier_fib_command_fn (vlib_main_t * vm, while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "%d %d", &bti, &bp)) { - flags = BIER_SHOW_DETAIL; + flags = BIER_SHOW_DETAIL; } else if (unformat (input, "%d", &bti)) { - flags = BIER_SHOW_DETAIL; + flags = BIER_SHOW_DETAIL; } else { diff --git a/src/vnet/dpo/load_balance.c b/src/vnet/dpo/load_balance.c index bb38233a55e..ae95b6e1b3e 100644 --- a/src/vnet/dpo/load_balance.c +++ b/src/vnet/dpo/load_balance.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include /* * distribution error tolerance for load-balancing @@ -999,7 +999,7 @@ load_balance_inline (vlib_main_t * vm, { /* it's BIER */ const bier_hdr_t *bh0 = vlib_buffer_get_current(b0); - vnet_buffer(b0)->ip.flow_hash = bier_hdr_get_entropy(bh0); + vnet_buffer(b0)->ip.flow_hash = bier_compute_flow_hash(bh0); } dpo0 = load_balance_get_bucket_i(lb0, diff --git a/src/vnet/mpls/mpls_lookup.h b/src/vnet/mpls/mpls_lookup.h index 4311dc053ec..95558e05a4e 100644 --- a/src/vnet/mpls/mpls_lookup.h +++ b/src/vnet/mpls/mpls_lookup.h @@ -18,6 +18,7 @@ #include #include +#include /** * The arc/edge from the MPLS lookup node to the MPLS replicate node @@ -100,6 +101,10 @@ mpls_compute_flow_hash (const mpls_unicast_header_t * hdr, hash ^= ip6_compute_flow_hash ((const ip6_header_t *)hdr, IP_FLOW_HASH_DEFAULT); break; + case 5: + /* incorporate the bier flow-hash */ + hash ^= bier_compute_flow_hash ((const bier_hdr_t *)hdr); + break; default: break; } diff --git a/test/test_bier.py b/test/test_bier.py index 0276f95c4fc..9a1967cc459 100644 --- a/test/test_bier.py +++ b/test/test_bier.py @@ -202,6 +202,100 @@ class TestBier(VppTestCase): """BIER midpoint BSL:64""" self.bier_midpoint(BIERLength.BIER_LEN_64, 8, 64) + def test_bier_load_balance(self): + """BIER load-balance""" + + # + # Add a BIER table for sub-domain 0, set 0, and BSL 256 + # + bti = VppBierTableID(0, 0, BIERLength.BIER_LEN_64) + bt = VppBierTable(self, bti, 77) + bt.add_vpp_config() + + # + # packets with varying entropy + # + pkts = [] + for ii in range(257): + pkts.append((Ether(dst=self.pg0.local_mac, + src=self.pg0.remote_mac) / + MPLS(label=77, ttl=255) / + BIER(length=BIERLength.BIER_LEN_64, + entropy=ii, + BitString=chr(255)*16) / + IPv6(src=self.pg0.remote_ip6, + dst=self.pg0.remote_ip6) / + UDP(sport=1234, dport=1234) / + Raw())) + + # + # 4 next hops + # + nhs = [{'ip': "10.0.0.1", 'label': 201}, + {'ip': "10.0.0.2", 'label': 202}, + {'ip': "10.0.0.3", 'label': 203}, + {'ip': "10.0.0.4", 'label': 204}] + + for nh in nhs: + ipr = VppIpRoute( + self, nh['ip'], 32, + [VppRoutePath(self.pg1.remote_ip4, + self.pg1.sw_if_index, + labels=[VppMplsLabel(nh['label'])])]) + ipr.add_vpp_config() + + bier_route = VppBierRoute( + self, bti, 1, + [VppRoutePath(nhs[0]['ip'], 0xffffffff, + labels=[VppMplsLabel(101)]), + VppRoutePath(nhs[1]['ip'], 0xffffffff, + labels=[VppMplsLabel(101)])]) + bier_route.add_vpp_config() + + rx = self.send_and_expect(self.pg0, pkts, self.pg1) + + # + # we should have recieved a packet from each neighbor + # + for nh in nhs[:2]: + self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx)) + + # + # add the other paths + # + bier_route.update_paths( + [VppRoutePath(nhs[0]['ip'], 0xffffffff, + labels=[VppMplsLabel(101)]), + VppRoutePath(nhs[1]['ip'], 0xffffffff, + labels=[VppMplsLabel(101)]), + VppRoutePath(nhs[2]['ip'], 0xffffffff, + labels=[VppMplsLabel(101)]), + VppRoutePath(nhs[3]['ip'], 0xffffffff, + labels=[VppMplsLabel(101)])]) + + rx = self.send_and_expect(self.pg0, pkts, self.pg1) + for nh in nhs: + self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx)) + + # + # remove first two paths + # + bier_route.remove_path(VppRoutePath(nhs[0]['ip'], 0xffffffff, + labels=[VppMplsLabel(101)])) + bier_route.remove_path(VppRoutePath(nhs[1]['ip'], 0xffffffff, + labels=[VppMplsLabel(101)])) + + rx = self.send_and_expect(self.pg0, pkts, self.pg1) + for nh in nhs[2:]: + self.assertTrue(sum(p[MPLS].label == nh['label'] for p in rx)) + + # + # remove the last of the paths, deleteing the entry + # + bier_route.remove_all_paths() + + self.send_and_assert_no_replies(self.pg0, pkts) + def test_bier_head(self): """BIER head""" diff --git a/test/vpp_bier.py b/test/vpp_bier.py index 88dd79ce3b7..f389ca1b979 100644 --- a/test/vpp_bier.py +++ b/test/vpp_bier.py @@ -120,28 +120,31 @@ class VppBierRoute(VppObject): self.bp = bp self.paths = paths + def encode_path(self, p): + lstack = [] + for l in p.nh_labels: + if type(l) == VppMplsLabel: + lstack.append(l.encode()) + else: + lstack.append({'label': l, 'ttl': 255}) + n_labels = len(lstack) + while (len(lstack) < 16): + lstack.append({}) + return {'next_hop': p.nh_addr, + 'weight': 1, + 'afi': p.proto, + 'sw_if_index': 0xffffffff, + 'preference': 0, + 'table_id': p.nh_table_id, + 'next_hop_id': p.next_hop_id, + 'is_udp_encap': p.is_udp_encap, + 'n_labels': n_labels, + 'label_stack': lstack} + def encode_paths(self): br_paths = [] for p in self.paths: - lstack = [] - for l in p.nh_labels: - if type(l) == VppMplsLabel: - lstack.append(l.encode()) - else: - lstack.append({'label': l, 'ttl': 255}) - n_labels = len(lstack) - while (len(lstack) < 16): - lstack.append({}) - br_paths.append({'next_hop': p.nh_addr, - 'weight': 1, - 'afi': p.proto, - 'sw_if_index': 0xffffffff, - 'preference': 0, - 'table_id': p.nh_table_id, - 'next_hop_id': p.next_hop_id, - 'is_udp_encap': p.is_udp_encap, - 'n_labels': n_labels, - 'label_stack': lstack}) + br_paths.append(self.encode_path(p)) return br_paths def add_vpp_config(self): @@ -159,6 +162,42 @@ class VppBierRoute(VppObject): self.encode_paths(), is_add=0) + def update_paths(self, paths): + self.paths = paths + self._test.vapi.bier_route_add_del( + self.tbl_id, + self.bp, + self.encode_paths(), + is_replace=1) + + def add_path(self, path): + self._test.vapi.bier_route_add_del( + self.tbl_id, + self.bp, + [self.encode_path(path)], + is_add=1, + is_replace=0) + self.paths.append(path) + self._test.registry.register(self, self._test.logger) + + def remove_path(self, path): + self._test.vapi.bier_route_add_del( + self.tbl_id, + self.bp, + [self.encode_path(path)], + is_add=0, + is_replace=0) + self.paths.remove(path) + + def remove_all_paths(self): + self._test.vapi.bier_route_add_del( + self.tbl_id, + self.bp, + [], + is_add=0, + is_replace=1) + self.paths = [] + def __str__(self): return self.object_id() diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py index 9d6bfb77d93..18c27ffa942 100644 --- a/test/vpp_ip_route.py +++ b/test/vpp_ip_route.py @@ -192,6 +192,9 @@ class VppRoutePath(object): 'n_labels': len(self.nh_labels), 'label_stack': self.encode_labels()} + def __eq__(self, other): + return self.nh_addr == other.nh_addr + class VppMRoutePath(VppRoutePath): diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py index 61d80b21fb5..5ff7db990c0 100644 --- a/test/vpp_papi_provider.py +++ b/test/vpp_papi_provider.py @@ -3147,7 +3147,8 @@ class VppPapiProvider(object): bti, bp, paths, - is_add=1): + is_add=1, + is_replace=0): """ BIER Route add/del """ return self.api( self.papi.bier_route_add_del, @@ -3157,7 +3158,8 @@ class VppPapiProvider(object): 'br_bp': bp, 'br_n_paths': len(paths), 'br_paths': paths, - 'br_is_add': is_add}) + 'br_is_add': is_add, + 'br_is_replace': is_replace}) def bier_route_dump(self, bti): return self.api( -- 2.16.6