diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2015-10-12 12:02:08 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-10-13 07:52:40 -0400 |
commit | e332bc67cf5e5e5b71a1aec9750d0791aac65183 (patch) | |
tree | 1b867c769406705ec8b9b33e2dbfb0b8d5607e3c /net | |
parent | 87aaf2caed8496404d3809edc30d38d4a4a5d273 (diff) |
ipv6: Don't call with rt6_uncached_list_flush_dev
As originally written rt6_uncached_list_flush_dev makes no sense when
called with dev == NULL as it attempts to flush all uncached routes
regardless of network namespace when dev == NULL. Which is simply
incorrect behavior.
Furthermore at the point rt6_ifdown is called with dev == NULL no more
network devices exist in the network namespace so even if the code in
rt6_uncached_list_flush_dev were to attempt something sensible it
would be meaningless.
Therefore remove support in rt6_uncached_list_flush_dev for handling
network devices where dev == NULL, and only call rt6_uncached_list_flush_dev
when rt6_ifdown is called with a network device.
Fixes: 8d0b94afdca8 ("ipv6: Keep track of DST_NOCACHE routes in case of iface down/unregister")
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Reviewed-by: Martin KaFai Lau <kafai@fb.com>
Tested-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/route.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index cb32ce250db0..ed04e29a6aa3 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -142,6 +142,9 @@ static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev) | |||
142 | struct net_device *loopback_dev = net->loopback_dev; | 142 | struct net_device *loopback_dev = net->loopback_dev; |
143 | int cpu; | 143 | int cpu; |
144 | 144 | ||
145 | if (dev == loopback_dev) | ||
146 | return; | ||
147 | |||
145 | for_each_possible_cpu(cpu) { | 148 | for_each_possible_cpu(cpu) { |
146 | struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu); | 149 | struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu); |
147 | struct rt6_info *rt; | 150 | struct rt6_info *rt; |
@@ -151,14 +154,12 @@ static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev) | |||
151 | struct inet6_dev *rt_idev = rt->rt6i_idev; | 154 | struct inet6_dev *rt_idev = rt->rt6i_idev; |
152 | struct net_device *rt_dev = rt->dst.dev; | 155 | struct net_device *rt_dev = rt->dst.dev; |
153 | 156 | ||
154 | if (rt_idev && (rt_idev->dev == dev || !dev) && | 157 | if (rt_idev->dev == dev) { |
155 | rt_idev->dev != loopback_dev) { | ||
156 | rt->rt6i_idev = in6_dev_get(loopback_dev); | 158 | rt->rt6i_idev = in6_dev_get(loopback_dev); |
157 | in6_dev_put(rt_idev); | 159 | in6_dev_put(rt_idev); |
158 | } | 160 | } |
159 | 161 | ||
160 | if (rt_dev && (rt_dev == dev || !dev) && | 162 | if (rt_dev == dev) { |
161 | rt_dev != loopback_dev) { | ||
162 | rt->dst.dev = loopback_dev; | 163 | rt->dst.dev = loopback_dev; |
163 | dev_hold(rt->dst.dev); | 164 | dev_hold(rt->dst.dev); |
164 | dev_put(rt_dev); | 165 | dev_put(rt_dev); |
@@ -2622,7 +2623,8 @@ void rt6_ifdown(struct net *net, struct net_device *dev) | |||
2622 | 2623 | ||
2623 | fib6_clean_all(net, fib6_ifdown, &adn); | 2624 | fib6_clean_all(net, fib6_ifdown, &adn); |
2624 | icmp6_clean_all(fib6_ifdown, &adn); | 2625 | icmp6_clean_all(fib6_ifdown, &adn); |
2625 | rt6_uncached_list_flush_dev(net, dev); | 2626 | if (dev) |
2627 | rt6_uncached_list_flush_dev(net, dev); | ||
2626 | } | 2628 | } |
2627 | 2629 | ||
2628 | struct rt6_mtu_change_arg { | 2630 | struct rt6_mtu_change_arg { |