| From foo@baz Wed Apr 11 10:26:56 CEST 2018 |
| From: Xin Long <lucien.xin@gmail.com> |
| Date: Sun, 1 Apr 2018 22:40:35 +0800 |
| Subject: route: check sysctl_fib_multipath_use_neigh earlier than hash |
| |
| From: Xin Long <lucien.xin@gmail.com> |
| |
| |
| [ Upstream commit 6174a30df1b902e1fedbd728f5343937e83e64e6 ] |
| |
| Prior to this patch, when one packet is hashed into path [1] |
| (hash <= nh_upper_bound) and it's neigh is dead, it will try |
| path [2]. However, if path [2]'s neigh is alive but it's |
| hash > nh_upper_bound, it will not return this alive path. |
| This packet will never be sent even if path [2] is alive. |
| |
| 3.3.3.1/24: |
| nexthop via 1.1.1.254 dev eth1 weight 1 <--[1] (dead neigh) |
| nexthop via 2.2.2.254 dev eth2 weight 1 <--[2] |
| |
| With sysctl_fib_multipath_use_neigh set is supposed to find an |
| available path respecting to the l3/l4 hash. But if there is |
| no available route with this hash, it should at least return |
| an alive route even with other hash. |
| |
| This patch is to fix it by processing fib_multipath_use_neigh |
| earlier than the hash check, so that it will at least return |
| an alive route if there is when fib_multipath_use_neigh is |
| enabled. It's also compatible with before when there are alive |
| routes with the l3/l4 hash. |
| |
| Fixes: a6db4494d218 ("net: ipv4: Consider failed nexthops in multipath routes") |
| Reported-by: Jianlin Shi <jishi@redhat.com> |
| Signed-off-by: Xin Long <lucien.xin@gmail.com> |
| Acked-by: David Ahern <dsa@cumulusnetworks.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv4/fib_semantics.c | 20 +++++++++++--------- |
| 1 file changed, 11 insertions(+), 9 deletions(-) |
| |
| --- a/net/ipv4/fib_semantics.c |
| +++ b/net/ipv4/fib_semantics.c |
| @@ -1611,18 +1611,20 @@ void fib_select_multipath(struct fib_res |
| bool first = false; |
| |
| for_nexthops(fi) { |
| + if (net->ipv4.sysctl_fib_multipath_use_neigh) { |
| + if (!fib_good_nh(nh)) |
| + continue; |
| + if (!first) { |
| + res->nh_sel = nhsel; |
| + first = true; |
| + } |
| + } |
| + |
| if (hash > atomic_read(&nh->nh_upper_bound)) |
| continue; |
| |
| - if (!net->ipv4.sysctl_fib_multipath_use_neigh || |
| - fib_good_nh(nh)) { |
| - res->nh_sel = nhsel; |
| - return; |
| - } |
| - if (!first) { |
| - res->nh_sel = nhsel; |
| - first = true; |
| - } |
| + res->nh_sel = nhsel; |
| + return; |
| } endfor_nexthops(fi); |
| } |
| #endif |