aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWANG Cong <xiyou.wangcong@gmail.com>2017-05-08 13:12:13 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-14 08:00:21 -0400
commit8795ee7bed243c291d30830efe925966253aa2d6 (patch)
treede221ddf359bdb88394cfa56b47a386515c49802
parentecbd3ed2ddfe5fbae4db6aa3a0903af479e0543d (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.h2
-rw-r--r--net/ipv6/addrconf.c1
-rw-r--r--net/ipv6/route.c13
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 */
3493static struct notifier_block ipv6_dev_notf = { 3493static 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
3497static void addrconf_type_change(struct net_device *dev, unsigned long event) 3498static 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
3796static struct notifier_block ip6_route_dev_notifier = { 3805static 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
3801void __init ip6_route_init_special_entries(void) 3810void __init ip6_route_init_special_entries(void)