diff options
author | WANG Cong <xiyou.wangcong@gmail.com> | 2017-05-08 13:12:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-05-08 17:31:24 -0400 |
commit | 242d3a49a2a1a71d8eb9f953db1bcaa9d698ce00 (patch) | |
tree | 7565ac4897777e242dc18c26896cb972720aba35 /net | |
parent | 29cee56c0be46ad01e78af104a06223c65ee0c67 (diff) |
ipv6: reorder ip6_route_dev_notifier after ipv6_dev_notf
For each netns (except init_net), we initialize its null entry
in 3 places:
1) The template itself, as we use kmemdup()
2) Code around dst_init_metrics() in ip6_route_net_init()
3) ip6_route_dev_notify(), which is supposed to initialize it after
loopback registers
Unfortunately the last one still happens in a wrong order because
we expect to initialize net->ipv6.ip6_null_entry->rt6i_idev to
net->loopback_dev's idev, thus we have to do that after we add
idev to loopback. However, this notifier has priority == 0 same as
ipv6_dev_notf, and ipv6_dev_notf is registered after
ip6_route_dev_notifier so it is called actually after
ip6_route_dev_notifier. This is similar to commit 2f460933f58e
("ipv6: initialize route null entry in addrconf_init()") which
fixes init_net.
Fix it by picking a smaller priority for ip6_route_dev_notifier.
Also, we have to release the refcnt accordingly when unregistering
loopback_dev because device exit functions are called before subsys
exit functions.
Acked-by: David Ahern <dsahern@gmail.com>
Tested-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/addrconf.c | 1 | ||||
-rw-r--r-- | net/ipv6/route.c | 13 |
2 files changed, 12 insertions, 2 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 77a4bd526d6e..8d297a79b568 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -3548,6 +3548,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
3548 | */ | 3548 | */ |
3549 | static struct notifier_block ipv6_dev_notf = { | 3549 | static struct notifier_block ipv6_dev_notf = { |
3550 | .notifier_call = addrconf_notify, | 3550 | .notifier_call = addrconf_notify, |
3551 | .priority = ADDRCONF_NOTIFY_PRIORITY, | ||
3551 | }; | 3552 | }; |
3552 | 3553 | ||
3553 | static void addrconf_type_change(struct net_device *dev, unsigned long event) | 3554 | static void addrconf_type_change(struct net_device *dev, unsigned long event) |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 2f1136627dcb..dc61b0b5e64e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -3709,7 +3709,10 @@ static int ip6_route_dev_notify(struct notifier_block *this, | |||
3709 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 3709 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
3710 | struct net *net = dev_net(dev); | 3710 | struct net *net = dev_net(dev); |
3711 | 3711 | ||
3712 | if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { | 3712 | if (!(dev->flags & IFF_LOOPBACK)) |
3713 | return NOTIFY_OK; | ||
3714 | |||
3715 | if (event == NETDEV_REGISTER) { | ||
3713 | net->ipv6.ip6_null_entry->dst.dev = dev; | 3716 | net->ipv6.ip6_null_entry->dst.dev = dev; |
3714 | net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); | 3717 | net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); |
3715 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 3718 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
@@ -3718,6 +3721,12 @@ static int ip6_route_dev_notify(struct notifier_block *this, | |||
3718 | net->ipv6.ip6_blk_hole_entry->dst.dev = dev; | 3721 | net->ipv6.ip6_blk_hole_entry->dst.dev = dev; |
3719 | net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); | 3722 | net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); |
3720 | #endif | 3723 | #endif |
3724 | } else if (event == NETDEV_UNREGISTER) { | ||
3725 | in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev); | ||
3726 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
3727 | in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev); | ||
3728 | in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev); | ||
3729 | #endif | ||
3721 | } | 3730 | } |
3722 | 3731 | ||
3723 | return NOTIFY_OK; | 3732 | return NOTIFY_OK; |
@@ -4024,7 +4033,7 @@ static struct pernet_operations ip6_route_net_late_ops = { | |||
4024 | 4033 | ||
4025 | static struct notifier_block ip6_route_dev_notifier = { | 4034 | static struct notifier_block ip6_route_dev_notifier = { |
4026 | .notifier_call = ip6_route_dev_notify, | 4035 | .notifier_call = ip6_route_dev_notify, |
4027 | .priority = 0, | 4036 | .priority = ADDRCONF_NOTIFY_PRIORITY - 10, |
4028 | }; | 4037 | }; |
4029 | 4038 | ||
4030 | void __init ip6_route_init_special_entries(void) | 4039 | void __init ip6_route_init_special_entries(void) |