BIER API and load-balancing fixes
Change-Id: Ibda19d786070c942c75016ab568c8361de2f24af
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vnet/bier/bier.api b/src/vnet/bier/bier.api
index fb6923b..da2989b 100644
--- a/src/vnet/bier/bier.api
+++ b/src/vnet/bier/bier.api
@@ -72,6 +72,8 @@
@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 93048a0..2e8fc62 100644
--- a/src/vnet/bier/bier_api.c
+++ b/src/vnet/bier/bier_api.c
@@ -204,13 +204,24 @@
}
}
- 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 2f8d250..80f7cfd 100644
--- a/src/vnet/bier/bier_entry.c
+++ b/src/vnet/bier/bier_entry.c
@@ -73,27 +73,6 @@
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 @@
}
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 @@
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 @@
}
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 e514c64..629e47a 100644
--- a/src/vnet/bier/bier_entry.h
+++ b/src/vnet/bier/bier_entry.h
@@ -75,6 +75,9 @@
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 73f7194..cb61681 100644
--- a/src/vnet/bier/bier_fmask.c
+++ b/src/vnet/bier/bier_fmask.c
@@ -165,14 +165,14 @@
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 @@
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 @@
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 @@
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 @@
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 0000000..3b0b93b
--- /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 4e544a3..d450082 100644
--- a/src/vnet/bier/bier_lookup.c
+++ b/src/vnet/bier/bier_lookup.c
@@ -250,12 +250,12 @@
{
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 80231fd..3ecda10 100644
--- a/src/vnet/bier/bier_table.c
+++ b/src/vnet/bier/bier_table.c
@@ -510,9 +510,10 @@
}
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 @@
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 @@
}
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)
{
- fib_route_path_t *brp = NULL;
+ 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, *t_paths = NULL;
index_t bfmi, bti, bei;
bier_table_t *bt;
u32 ii;
@@ -616,12 +673,19 @@
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 5af275f..9cd9937 100644
--- a/src/vnet/bier/bier_table.h
+++ b/src/vnet/bier/bier_table.h
@@ -93,12 +93,17 @@
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 d4d1692..06160f6 100644
--- a/src/vnet/bier/bier_test.c
+++ b/src/vnet/bier/bier_test.c
@@ -335,7 +335,7 @@
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 @@
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 @@
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 @@
*/
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 @@
* 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 @@
* 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 @@
};
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_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 326f8bf..4108d09 100644
--- a/src/vnet/bier/bier_update.c
+++ b/src/vnet/bier/bier_update.c
@@ -115,11 +115,11 @@
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 @@
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 bb38233..ae95b6e 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 @@
{
/* 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 4311dc0..95558e0 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 @@
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;
}