Add support to track current link status of ipv6 nexthops to match recent changes that added support for ipv4 nexthops. There was not a field already available that could track these and no space available in the existing rt6i_flags field, so this patch adds rt6i_nhflags to struct rt6_info.
Signed-off-by: Andy Gospodarek <go...@cumulusnetworks.com> Signed-off-by: Dinesh Dutt <dd...@cumulusnetworks.com> --- include/net/ip6_fib.h | 1 + include/net/ip6_route.h | 1 + net/ipv6/addrconf.c | 2 ++ net/ipv6/route.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 276328e..371780b 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -119,6 +119,7 @@ struct rt6_info { /* These are in a separate cache line. */ struct rt6key rt6i_dst ____cacheline_aligned_in_smp; u32 rt6i_flags; + u32 rt6i_nhflags; struct rt6key rt6i_src; struct rt6key rt6i_prefsrc; diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 297629a..6ba5e9e 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -125,6 +125,7 @@ struct rt6_rtnl_dump_arg { int rt6_dump_route(struct rt6_info *rt, void *p_arg); void rt6_ifdown(struct net *net, struct net_device *dev); +void rt6_link_change(struct net *net, struct net_device *dev); void rt6_mtu_change(struct net_device *dev, unsigned int mtu); void rt6_remove_prefsrc(struct inet6_ifaddr *ifp); void rt6_clean_tohost(struct net *net, struct in6_addr *gateway); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 53e3a9d..3fc8ee2 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3126,6 +3126,8 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, run_pending = 1; } } else { + rt6_link_change(dev_net(dev), dev); + if (!addrconf_qdisc_ok(dev)) { /* device is still not ready. */ break; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 54fccf0..a5c8c6a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1919,6 +1919,9 @@ install_route: rt->rt6i_idev = idev; rt->rt6i_table = table; + if (!netif_carrier_ok(dev)) + rt->rt6i_nhflags |= RTNH_F_LINKDOWN; + cfg->fc_nlinfo.nl_net = dev_net(dev); err = ip6_convert_metrics(&mxc, cfg); @@ -2161,6 +2164,7 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) rt->rt6i_prefsrc = ort->rt6i_prefsrc; rt->rt6i_table = ort->rt6i_table; rt->rt6i_lwtstate = lwtstate_get(ort->rt6i_lwtstate); + rt->rt6i_nhflags = ort->rt6i_nhflags; } #ifdef CONFIG_IPV6_ROUTE_INFO @@ -2526,6 +2530,30 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg) return 0; } +static int fib6_linkup(struct rt6_info *rt, void *arg) +{ + const struct arg_dev_net *adn = arg; + const struct net_device *dev = adn->dev; + + if (rt->dst.dev == dev || !dev) + rt->rt6i_nhflags &= ~RTNH_F_LINKDOWN; + return 0; +} + +static int fib6_linkdown(struct rt6_info *rt, void *arg) +{ + const struct arg_dev_net *adn = arg; + const struct net_device *dev = adn->dev; + + if (rt->dst.dev == dev || !dev) { + rt->rt6i_nhflags |= RTNH_F_LINKDOWN; + + if (rt->rt6i_flags & RTF_CACHE) + return -1; + } + return 0; +} + void rt6_ifdown(struct net *net, struct net_device *dev) { struct arg_dev_net adn = { @@ -2538,6 +2566,23 @@ void rt6_ifdown(struct net *net, struct net_device *dev) rt6_uncached_list_flush_dev(net, dev); } +void rt6_link_change(struct net *net, struct net_device *dev) +{ + struct arg_dev_net adn = { + .dev = dev, + .net = net, + }; + unsigned int flags = dev_get_flags(dev); + + if (flags & (IFF_RUNNING | IFF_LOWER_UP)) { + fib6_clean_all(net, fib6_linkup, &adn); + icmp6_clean_all(fib6_linkup, &adn); + } else { + fib6_clean_all(net, fib6_linkdown, &adn); + icmp6_clean_all(fib6_linkdown, &adn); + } +} + struct rt6_mtu_change_arg { struct net_device *dev; unsigned int mtu; @@ -2884,7 +2929,7 @@ static int rt6_fill_node(struct net *net, rtm->rtm_type = RTN_LOCAL; else rtm->rtm_type = RTN_UNICAST; - rtm->rtm_flags = 0; + rtm->rtm_flags = rt->rt6i_nhflags; rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_protocol = rt->rt6i_protocol; if (rt->rt6i_flags & RTF_DYNAMIC) -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html