diff options
author | WANG Cong <xiyou.wangcong@gmail.com> | 2017-05-08 13:12:13 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-05-14 08:00:21 -0400 |
commit | 8795ee7bed243c291d30830efe925966253aa2d6 (patch) | |
tree | de221ddf359bdb88394cfa56b47a386515c49802 | |
parent | ecbd3ed2ddfe5fbae4db6aa3a0903af479e0543d (diff) |
ipv6: reorder ip6_route_dev_notifier after ipv6_dev_notf
[ Upstream commit 242d3a49a2a1a71d8eb9f953db1bcaa9d698ce00 ]
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | include/net/addrconf.h | 2 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 1 | ||||
-rw-r--r-- | net/ipv6/route.c | 13 |
3 files changed, 14 insertions, 2 deletions
diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 8f998afc1384..b8ee8a113e32 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h | |||
@@ -20,6 +20,8 @@ | |||
20 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) | 20 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) |
21 | #define ADDRCONF_TIMER_FUZZ_MAX (HZ) | 21 | #define ADDRCONF_TIMER_FUZZ_MAX (HZ) |
22 | 22 | ||
23 | #define ADDRCONF_NOTIFY_PRIORITY 0 | ||
24 | |||
23 | #include <linux/in.h> | 25 | #include <linux/in.h> |
24 | #include <linux/in6.h> | 26 | #include <linux/in6.h> |
25 | 27 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4d115b5cb231..f088a1d9a618 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -3492,6 +3492,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
3492 | */ | 3492 | */ |
3493 | static struct notifier_block ipv6_dev_notf = { | 3493 | static struct notifier_block ipv6_dev_notf = { |
3494 | .notifier_call = addrconf_notify, | 3494 | .notifier_call = addrconf_notify, |
3495 | .priority = ADDRCONF_NOTIFY_PRIORITY, | ||
3495 | }; | 3496 | }; |
3496 | 3497 | ||
3497 | static void addrconf_type_change(struct net_device *dev, unsigned long event) | 3498 | 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 57081bbf21d6..b8b475389ae4 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -3480,7 +3480,10 @@ static int ip6_route_dev_notify(struct notifier_block *this, | |||
3480 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 3480 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
3481 | struct net *net = dev_net(dev); | 3481 | struct net *net = dev_net(dev); |
3482 | 3482 | ||
3483 | if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { | 3483 | if (!(dev->flags & IFF_LOOPBACK)) |
3484 | return NOTIFY_OK; | ||
3485 | |||
3486 | if (event == NETDEV_REGISTER) { | ||
3484 | net->ipv6.ip6_null_entry->dst.dev = dev; | 3487 | net->ipv6.ip6_null_entry->dst.dev = dev; |
3485 | net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); | 3488 | net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); |
3486 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 3489 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
@@ -3489,6 +3492,12 @@ static int ip6_route_dev_notify(struct notifier_block *this, | |||
3489 | net->ipv6.ip6_blk_hole_entry->dst.dev = dev; | 3492 | net->ipv6.ip6_blk_hole_entry->dst.dev = dev; |
3490 | net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); | 3493 | net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); |
3491 | #endif | 3494 | #endif |
3495 | } else if (event == NETDEV_UNREGISTER) { | ||
3496 | in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev); | ||
3497 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
3498 | in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev); | ||
3499 | in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev); | ||
3500 | #endif | ||
3492 | } | 3501 | } |
3493 | 3502 | ||
3494 | return NOTIFY_OK; | 3503 | return NOTIFY_OK; |
@@ -3795,7 +3804,7 @@ static struct pernet_operations ip6_route_net_late_ops = { | |||
3795 | 3804 | ||
3796 | static struct notifier_block ip6_route_dev_notifier = { | 3805 | static struct notifier_block ip6_route_dev_notifier = { |
3797 | .notifier_call = ip6_route_dev_notify, | 3806 | .notifier_call = ip6_route_dev_notify, |
3798 | .priority = 0, | 3807 | .priority = ADDRCONF_NOTIFY_PRIORITY - 10, |
3799 | }; | 3808 | }; |
3800 | 3809 | ||
3801 | void __init ip6_route_init_special_entries(void) | 3810 | void __init ip6_route_init_special_entries(void) |