Sticky Load-balance
keep the number of buckets in the load-balanced fixed. If a
path goes dwon fill its buckets with those from the next
available up path.
Change-Id: I15603ccb899fa9b77556b898c99136379cf32eae
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vnet/dpo/load_balance.c b/src/vnet/dpo/load_balance.c
index 37f8ca1..48f7798 100644
--- a/src/vnet/dpo/load_balance.c
+++ b/src/vnet/dpo/load_balance.c
@@ -28,8 +28,9 @@
*/
const f64 multipath_next_hop_error_tolerance = 0.1;
-#undef LB_DEBUG
+static const char *load_balance_attr_names[] = LOAD_BALANCE_ATTR_NAMES;
+#undef LB_DEBUG
#ifdef LB_DEBUG
#define LB_DBG(_lb, _fmt, _args...) \
{ \
@@ -131,6 +132,21 @@
s = format(s, "[proto:%U ", format_dpo_proto, lb->lb_proto);
s = format(s, "index:%d buckets:%d ", lbi, lb->lb_n_buckets);
s = format(s, "uRPF:%d ", lb->lb_urpf);
+ if (lb->lb_flags)
+ {
+ load_balance_attr_t attr;
+
+ s = format(s, "flags:[");
+
+ FOR_EACH_LOAD_BALANCE_ATTR(attr)
+ {
+ if (lb->lb_flags & (1 << attr))
+ {
+ s = format (s, "%s", load_balance_attr_names[attr]);
+ }
+ }
+ s = format(s, "] ");
+ }
s = format(s, "to:[%Ld:%Ld]", to.packets, to.bytes);
if (0 != via.packets)
{
@@ -467,12 +483,12 @@
* next hop adjacencies.
*/
static void
-load_balance_fill_buckets (load_balance_t *lb,
- load_balance_path_t *nhs,
- dpo_id_t *buckets,
- u32 n_buckets)
+load_balance_fill_buckets_norm (load_balance_t *lb,
+ load_balance_path_t *nhs,
+ dpo_id_t *buckets,
+ u32 n_buckets)
{
- load_balance_path_t * nh;
+ load_balance_path_t *nh;
u16 ii, bucket;
bucket = 0;
@@ -490,6 +506,69 @@
}
}
}
+static void
+load_balance_fill_buckets_sticky (load_balance_t *lb,
+ load_balance_path_t *nhs,
+ dpo_id_t *buckets,
+ u32 n_buckets)
+{
+ load_balance_path_t *nh, *fwding_paths;
+ u16 ii, bucket, fpath;
+
+ fpath = bucket = 0;
+ fwding_paths = NULL;
+
+ vec_foreach (nh, nhs)
+ {
+ if (!dpo_is_drop(&nh->path_dpo))
+ {
+ vec_add1(fwding_paths, *nh);
+ }
+ }
+ if (vec_len(fwding_paths) == 0)
+ fwding_paths = vec_dup(nhs);
+
+ /*
+ * the next-hops have normalised weights. that means their sum is the number
+ * of buckets we need to fill.
+ */
+ vec_foreach (nh, nhs)
+ {
+ for (ii = 0; ii < nh->path_weight; ii++)
+ {
+ ASSERT(bucket < n_buckets);
+ if (!dpo_is_drop(&nh->path_dpo))
+ {
+ load_balance_set_bucket_i(lb, bucket++, buckets, &nh->path_dpo);
+ }
+ else
+ {
+ /* fill the bucks from the next up path */
+ load_balance_set_bucket_i(lb, bucket++, buckets, &fwding_paths[fpath].path_dpo);
+ fpath = (fpath + 1) % vec_len(fwding_paths);
+ }
+ }
+ }
+
+ vec_free(fwding_paths);
+}
+
+static void
+load_balance_fill_buckets (load_balance_t *lb,
+ load_balance_path_t *nhs,
+ dpo_id_t *buckets,
+ u32 n_buckets,
+ load_balance_flags_t flags)
+{
+ if (flags & LOAD_BALANCE_FLAG_STICKY)
+ {
+ load_balance_fill_buckets_sticky(lb, nhs, buckets, n_buckets);
+ }
+ else
+ {
+ load_balance_fill_buckets_norm(lb, nhs, buckets, n_buckets);
+ }
+}
static inline void
load_balance_set_n_buckets (load_balance_t *lb,
@@ -514,6 +593,7 @@
ASSERT(DPO_LOAD_BALANCE == dpo->dpoi_type);
lb = load_balance_get(dpo->dpoi_index);
+ lb->lb_flags = flags;
fixed_nhs = load_balance_multipath_next_hop_fixup(raw_nhs, lb->lb_proto);
n_buckets =
ip_multipath_normalize_next_hops((NULL == fixed_nhs ?
@@ -553,7 +633,7 @@
load_balance_fill_buckets(lb, nhs,
load_balance_get_buckets(lb),
- n_buckets);
+ n_buckets, flags);
lb->lb_map = lbmi;
}
else
@@ -574,7 +654,7 @@
*/
load_balance_fill_buckets(lb, nhs,
load_balance_get_buckets(lb),
- n_buckets);
+ n_buckets, flags);
lb->lb_map = lbmi;
}
else if (n_buckets > lb->lb_n_buckets)
@@ -599,7 +679,7 @@
load_balance_fill_buckets(lb, nhs,
lb->lb_buckets,
- n_buckets);
+ n_buckets, flags);
CLIB_MEMORY_BARRIER();
load_balance_set_n_buckets(lb, n_buckets);
@@ -620,7 +700,7 @@
*/
load_balance_fill_buckets(lb, nhs,
load_balance_get_buckets(lb),
- n_buckets);
+ n_buckets, flags);
CLIB_MEMORY_BARRIER();
load_balance_set_n_buckets(lb, n_buckets);
}
@@ -639,7 +719,8 @@
n_buckets - 1,
CLIB_CACHE_LINE_BYTES);
- load_balance_fill_buckets(lb, nhs, new_buckets, n_buckets);
+ load_balance_fill_buckets(lb, nhs, new_buckets,
+ n_buckets, flags);
CLIB_MEMORY_BARRIER();
lb->lb_buckets = new_buckets;
CLIB_MEMORY_BARRIER();
@@ -683,7 +764,7 @@
*/
load_balance_fill_buckets(lb, nhs,
lb->lb_buckets_inline,
- n_buckets);
+ n_buckets, flags);
CLIB_MEMORY_BARRIER();
load_balance_set_n_buckets(lb, n_buckets);
CLIB_MEMORY_BARRIER();
@@ -711,9 +792,8 @@
load_balance_set_n_buckets(lb, n_buckets);
CLIB_MEMORY_BARRIER();
- load_balance_fill_buckets(lb, nhs,
- buckets,
- n_buckets);
+ load_balance_fill_buckets(lb, nhs, buckets,
+ n_buckets, flags);
for (ii = n_buckets; ii < old_n_buckets; ii++)
{
@@ -887,8 +967,15 @@
if (INDEX_INVALID != lbi)
{
- vlib_cli_output (vm, "%U", format_load_balance, lbi,
+ if (pool_is_free_index(load_balance_pool, lbi))
+ {
+ vlib_cli_output (vm, "no such load-balance:%d", lbi);
+ }
+ else
+ {
+ vlib_cli_output (vm, "%U", format_load_balance, lbi,
LOAD_BALANCE_FORMAT_DETAIL);
+ }
}
else
{