summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vnet/bier/bier.api2
-rw-r--r--src/vnet/bier/bier_api.c17
-rw-r--r--src/vnet/bier/bier_entry.c105
-rw-r--r--src/vnet/bier/bier_entry.h3
-rw-r--r--src/vnet/bier/bier_fmask.c18
-rw-r--r--src/vnet/bier/bier_fwd.h32
-rw-r--r--src/vnet/bier/bier_lookup.c6
-rw-r--r--src/vnet/bier/bier_table.c88
-rw-r--r--src/vnet/bier/bier_table.h17
-rw-r--r--src/vnet/bier/bier_test.c24
-rw-r--r--src/vnet/bier/bier_update.c8
-rw-r--r--src/vnet/dpo/load_balance.c4
-rw-r--r--src/vnet/mpls/mpls_lookup.h5
-rw-r--r--test/test_bier.py94
-rw-r--r--test/vpp_bier.py77
-rw-r--r--test/vpp_ip_route.py3
-rw-r--r--test/vpp_papi_provider.py6
17 files changed, 416 insertions, 93 deletions
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,
@@ -161,6 +140,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 <vnet/bier/bier_types.h>
+#include <vnet/bier/bier_hdr_inlines.h>
+
+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 <vnet/adj/adj.h>
#include <vnet/adj/adj_internal.h>
#include <vnet/fib/fib_urpf_list.h>
-#include <vnet/bier/bier_hdr_inlines.h>
+#include <vnet/bier/bier_fwd.h>
/*
* 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 <vnet/mpls/mpls.h>
#include <vnet/ip/ip.h>
+#include <vnet/bier/bier_fwd.h>
/**
* 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(