void rt6_clean_tohost(struct net *net, struct in6_addr *gateway);
void rt6_sync_up(struct net_device *dev, unsigned int nh_flags);
void rt6_disable_ip(struct net_device *dev, unsigned long event);
+void rt6_sync_down_dev(struct net_device *dev, unsigned long event);
static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb)
{
} else if (event == NETDEV_CHANGE) {
if (!addrconf_link_ready(dev)) {
/* device is still not ready. */
+ rt6_sync_down_dev(dev, event);
break;
}
* multicast snooping switches
*/
ipv6_mc_up(idev);
+ rt6_sync_up(dev, RTNH_F_LINKDOWN);
break;
}
idev->if_flags |= IF_READY;
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,