Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv4: Honor "ignore_routes_with_linkdown" sysctl in nexthop selection

Commit 32607a332cfe ("ipv4: prefer multipath nexthop that matches source
address") changed IPv4 nexthop selection to prefer a nexthop whose
nexthop device is assigned the specified source address for locally
generated traffic.

While the selection honors the "fib_multipath_use_neigh" sysctl and will
not choose a nexthop with an invalid neighbour, it does not honor the
"ignore_routes_with_linkdown" sysctl and can choose a nexthop without a
carrier:

$ sysctl net.ipv4.conf.all.ignore_routes_with_linkdown
net.ipv4.conf.all.ignore_routes_with_linkdown = 1
$ ip route show 198.51.100.0/24
198.51.100.0/24
nexthop via 192.0.2.2 dev dummy1 weight 1
nexthop via 192.0.2.18 dev dummy2 weight 1 dead linkdown
$ ip route get 198.51.100.1 from 192.0.2.17
198.51.100.1 from 192.0.2.17 via 192.0.2.18 dev dummy2 uid 0

Solve this by skipping over nexthops whose assigned hash upper bound is
minus one, which is the value assigned to nexthops that do not have a
carrier when the "ignore_routes_with_linkdown" sysctl is set.

In practice, this probably does not matter a lot as the initial route
lookup for the source address would not choose a nexthop that does not
have a carrier in the first place, but the change does make the code
clearer.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ido Schimmel and committed by
David S. Miller
836b313a 586ceac9

+9 -2
+9 -2
net/ipv4/fib_semantics.c
··· 2188 2188 saddr = fl4 ? fl4->saddr : 0; 2189 2189 2190 2190 change_nexthops(fi) { 2191 - if (use_neigh && !fib_good_nh(nexthop_nh)) 2191 + int nh_upper_bound; 2192 + 2193 + /* Nexthops without a carrier are assigned an upper bound of 2194 + * minus one when "ignore_routes_with_linkdown" is set. 2195 + */ 2196 + nh_upper_bound = atomic_read(&nexthop_nh->fib_nh_upper_bound); 2197 + if (nh_upper_bound == -1 || 2198 + (use_neigh && !fib_good_nh(nexthop_nh))) 2192 2199 continue; 2193 2200 2194 2201 if (!found) { ··· 2204 2197 found = !saddr || nexthop_nh->nh_saddr == saddr; 2205 2198 } 2206 2199 2207 - if (hash > atomic_read(&nexthop_nh->fib_nh_upper_bound)) 2200 + if (hash > nh_upper_bound) 2208 2201 continue; 2209 2202 2210 2203 if (!saddr || nexthop_nh->nh_saddr == saddr) {