diff options
author | Ido Schimmel <idosch@mellanox.com> | 2018-01-07 12:45:05 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-07 21:29:40 -0500 |
commit | 27c6fa73f93b81671a77bdaa242473c3bda0ac4a (patch) | |
tree | 8e7315ee734ecd034ee4fee1059b2ff54a49578f /net/ipv6/route.c | |
parent | 4c981e28d373e391b76577635e7e216976b71c57 (diff) | |
download | linux-stable-27c6fa73f93b81671a77bdaa242473c3bda0ac4a.tar.gz linux-stable-27c6fa73f93b81671a77bdaa242473c3bda0ac4a.tar.bz2 linux-stable-27c6fa73f93b81671a77bdaa242473c3bda0ac4a.zip |
ipv6: Set nexthop flags upon carrier change
Similar to IPv4, when the carrier of a netdev changes we should toggle
the 'linkdown' flag on all the nexthops using it as their nexthop
device.
This will later allow us to test for the presence of this flag during
route lookup and dump.
Up until commit 4832c30d5458 ("net: ipv6: put host and anycast routes on
device with address") host and anycast routes used the loopback netdev
as their nexthop device and thus were not marked with the 'linkdown'
flag. The patch preserves this behavior and allows one to ping the local
address even when the nexthop device does not have a carrier and the
'ignore_routes_with_linkdown' sysctl is set.
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/route.c')
-rw-r--r-- | net/ipv6/route.c | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 194fe9d9cd85..2fd36c7dd143 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -3498,18 +3498,29 @@ static int fib6_ifdown(struct rt6_info *rt, void *p_arg) const struct net_device *dev = arg->dev; const struct net *net = dev_net(dev); - if (rt->dst.dev == dev && - rt != net->ipv6.ip6_null_entry && - (rt->rt6i_nsiblings == 0 || netdev_unregistering(dev) || - !rt->rt6i_idev->cnf.ignore_routes_with_linkdown)) { - rt->rt6i_nh_flags |= (RTNH_F_DEAD | RTNH_F_LINKDOWN); + if (rt->dst.dev != dev || rt == net->ipv6.ip6_null_entry) + return 0; + + switch (arg->event) { + case NETDEV_UNREGISTER: return -1; + case NETDEV_DOWN: + if (rt->rt6i_nsiblings == 0 || + !rt->rt6i_idev->cnf.ignore_routes_with_linkdown) + return -1; + rt->rt6i_nh_flags |= RTNH_F_DEAD; + /* fall through */ + case NETDEV_CHANGE: + if (rt->rt6i_flags & (RTF_LOCAL | RTF_ANYCAST)) + break; + rt->rt6i_nh_flags |= RTNH_F_LINKDOWN; + break; } return 0; } -static void rt6_sync_down_dev(struct net_device *dev, unsigned long event) +void rt6_sync_down_dev(struct net_device *dev, unsigned long event) { struct arg_netdev_event arg = { .dev = dev, |