summaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@mellanox.com>2018-01-09 16:40:28 +0200
committerDavid S. Miller <davem@davemloft.net>2018-01-10 15:14:44 -0500
commit398958ae48f44bb036d0fa9829cd489270bf1fc2 (patch)
tree1af7f7291b37d5e8c3106540e06a041d9f563d83 /net/ipv6
parent3d709f69a3e749f4d1c195dab499df8ab66e25a8 (diff)
downloadlinux-398958ae48f44bb036d0fa9829cd489270bf1fc2.tar.bz2
ipv6: Add support for non-equal-cost multipath
The use of hash-threshold instead of modulo-N makes it trivial to add support for non-equal-cost multipath. Instead of dividing the multipath hash function's output space equally between the nexthops, each nexthop is assigned a region size which is proportional to its weight. Signed-off-by: Ido Schimmel <idosch@mellanox.com> Acked-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/route.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 7837b8c754a3..1076ae0ea9d5 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2594,6 +2594,7 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
#endif
rt->rt6i_metric = cfg->fc_metric;
+ rt->rt6i_nh_weight = 1;
/* We cannot add true routes via loopback here,
they would result in kernel looping; promote them to reject routes
@@ -3507,11 +3508,11 @@ static int rt6_multipath_total_weight(const struct rt6_info *rt)
int total = 0;
if (!rt6_is_dead(rt))
- total++;
+ total += rt->rt6i_nh_weight;
list_for_each_entry(iter, &rt->rt6i_siblings, rt6i_siblings) {
if (!rt6_is_dead(iter))
- total++;
+ total += iter->rt6i_nh_weight;
}
return total;
@@ -3522,7 +3523,7 @@ static void rt6_upper_bound_set(struct rt6_info *rt, int *weight, int total)
int upper_bound = -1;
if (!rt6_is_dead(rt)) {
- (*weight)++;
+ *weight += rt->rt6i_nh_weight;
upper_bound = DIV_ROUND_CLOSEST_ULL((u64) (*weight) << 31,
total) - 1;
}
@@ -4024,6 +4025,8 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
goto cleanup;
}
+ rt->rt6i_nh_weight = rtnh->rtnh_hops + 1;
+
err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
if (err) {
dst_release_immediate(&rt->dst);
@@ -4246,7 +4249,7 @@ static int rt6_add_nexthop(struct sk_buff *skb, struct rt6_info *rt)
if (!rtnh)
goto nla_put_failure;
- rtnh->rtnh_hops = 0;
+ rtnh->rtnh_hops = rt->rt6i_nh_weight - 1;
rtnh->rtnh_ifindex = rt->dst.dev ? rt->dst.dev->ifindex : 0;
if (rt6_nexthop_info(skb, rt, &flags, true) < 0)