]>
Commit | Line | Data |
---|---|---|
8dced6ec GKH |
1 | From foo@baz Thu May 11 11:08:24 CEST 2017 |
2 | From: WANG Cong <xiyou.wangcong@gmail.com> | |
3 | Date: Mon, 8 May 2017 10:12:13 -0700 | |
4 | Subject: ipv6: reorder ip6_route_dev_notifier after ipv6_dev_notf | |
5 | ||
6 | From: WANG Cong <xiyou.wangcong@gmail.com> | |
7 | ||
8 | ||
9 | [ Upstream commit 242d3a49a2a1a71d8eb9f953db1bcaa9d698ce00 ] | |
10 | ||
11 | For each netns (except init_net), we initialize its null entry | |
12 | in 3 places: | |
13 | ||
14 | 1) The template itself, as we use kmemdup() | |
15 | 2) Code around dst_init_metrics() in ip6_route_net_init() | |
16 | 3) ip6_route_dev_notify(), which is supposed to initialize it after | |
17 | loopback registers | |
18 | ||
19 | Unfortunately the last one still happens in a wrong order because | |
20 | we expect to initialize net->ipv6.ip6_null_entry->rt6i_idev to | |
21 | net->loopback_dev's idev, thus we have to do that after we add | |
22 | idev to loopback. However, this notifier has priority == 0 same as | |
23 | ipv6_dev_notf, and ipv6_dev_notf is registered after | |
24 | ip6_route_dev_notifier so it is called actually after | |
25 | ip6_route_dev_notifier. This is similar to commit 2f460933f58e | |
26 | ("ipv6: initialize route null entry in addrconf_init()") which | |
27 | fixes init_net. | |
28 | ||
29 | Fix it by picking a smaller priority for ip6_route_dev_notifier. | |
30 | Also, we have to release the refcnt accordingly when unregistering | |
31 | loopback_dev because device exit functions are called before subsys | |
32 | exit functions. | |
33 | ||
34 | Acked-by: David Ahern <dsahern@gmail.com> | |
35 | Tested-by: David Ahern <dsahern@gmail.com> | |
36 | Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> | |
37 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
38 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
39 | --- | |
40 | include/net/addrconf.h | 2 ++ | |
41 | net/ipv6/addrconf.c | 1 + | |
42 | net/ipv6/route.c | 13 +++++++++++-- | |
43 | 3 files changed, 14 insertions(+), 2 deletions(-) | |
44 | ||
45 | --- a/include/net/addrconf.h | |
46 | +++ b/include/net/addrconf.h | |
47 | @@ -20,6 +20,8 @@ | |
48 | #define ADDRCONF_TIMER_FUZZ (HZ / 4) | |
49 | #define ADDRCONF_TIMER_FUZZ_MAX (HZ) | |
50 | ||
51 | +#define ADDRCONF_NOTIFY_PRIORITY 0 | |
52 | + | |
53 | #include <linux/in.h> | |
54 | #include <linux/in6.h> | |
55 | ||
56 | --- a/net/ipv6/addrconf.c | |
57 | +++ b/net/ipv6/addrconf.c | |
58 | @@ -3492,6 +3492,7 @@ static int addrconf_notify(struct notifi | |
59 | */ | |
60 | static struct notifier_block ipv6_dev_notf = { | |
61 | .notifier_call = addrconf_notify, | |
62 | + .priority = ADDRCONF_NOTIFY_PRIORITY, | |
63 | }; | |
64 | ||
65 | static void addrconf_type_change(struct net_device *dev, unsigned long event) | |
66 | --- a/net/ipv6/route.c | |
67 | +++ b/net/ipv6/route.c | |
68 | @@ -3480,7 +3480,10 @@ static int ip6_route_dev_notify(struct n | |
69 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | |
70 | struct net *net = dev_net(dev); | |
71 | ||
72 | - if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { | |
73 | + if (!(dev->flags & IFF_LOOPBACK)) | |
74 | + return NOTIFY_OK; | |
75 | + | |
76 | + if (event == NETDEV_REGISTER) { | |
77 | net->ipv6.ip6_null_entry->dst.dev = dev; | |
78 | net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); | |
79 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | |
80 | @@ -3489,6 +3492,12 @@ static int ip6_route_dev_notify(struct n | |
81 | net->ipv6.ip6_blk_hole_entry->dst.dev = dev; | |
82 | net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); | |
83 | #endif | |
84 | + } else if (event == NETDEV_UNREGISTER) { | |
85 | + in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev); | |
86 | +#ifdef CONFIG_IPV6_MULTIPLE_TABLES | |
87 | + in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev); | |
88 | + in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev); | |
89 | +#endif | |
90 | } | |
91 | ||
92 | return NOTIFY_OK; | |
93 | @@ -3795,7 +3804,7 @@ static struct pernet_operations ip6_rout | |
94 | ||
95 | static struct notifier_block ip6_route_dev_notifier = { | |
96 | .notifier_call = ip6_route_dev_notify, | |
97 | - .priority = 0, | |
98 | + .priority = ADDRCONF_NOTIFY_PRIORITY - 10, | |
99 | }; | |
100 | ||
101 | void __init ip6_route_init_special_entries(void) |