aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorDenis V. Lunev <den@openvz.org>2008-04-03 16:33:00 -0400
committerDavid S. Miller <davem@davemloft.net>2008-04-03 16:33:00 -0400
commit84f59370c519449c70dcc813b050f5cbbf0098e7 (patch)
tree247917a098519394b08c52334d6eacc949f10848 /net/ipv6
parenteb867579311a9c1e998d6911af056772c400122a (diff)
[IPV6]: Fix refcounting for anycast dst entries.
Anycast DST entries allocated inside ipv6_dev_ac_inc are leaked when network device is stopped without removing IPv6 addresses from it. The bug has been observed in the reality on 2.6.18-rhel5 kernel. In the above case addrconf_ifdown marks all entries as obsolete and ip6_del_rt called from __ipv6_dev_ac_dec returns ENOENT. The referrence is not dropped. The fix is simple. DST entry should not keep referrence when stored in the FIB6 tree. Signed-off-by: Denis V. Lunev <den@openvz.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/anycast.c9
1 files changed, 2 insertions, 7 deletions
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 9c7f83fbc3a1..e5f56c953b58 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -334,9 +334,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
334 idev->ac_list = aca; 334 idev->ac_list = aca;
335 write_unlock_bh(&idev->lock); 335 write_unlock_bh(&idev->lock);
336 336
337 dst_hold(&rt->u.dst); 337 ip6_ins_rt(rt);
338 if (ip6_ins_rt(rt))
339 dst_release(&rt->u.dst);
340 338
341 addrconf_join_solict(dev, &aca->aca_addr); 339 addrconf_join_solict(dev, &aca->aca_addr);
342 340
@@ -378,10 +376,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr)
378 addrconf_leave_solict(idev, &aca->aca_addr); 376 addrconf_leave_solict(idev, &aca->aca_addr);
379 377
380 dst_hold(&aca->aca_rt->u.dst); 378 dst_hold(&aca->aca_rt->u.dst);
381 if (ip6_del_rt(aca->aca_rt)) 379 ip6_del_rt(aca->aca_rt);
382 dst_free(&aca->aca_rt->u.dst);
383 else
384 dst_release(&aca->aca_rt->u.dst);
385 380
386 aca_put(aca); 381 aca_put(aca);
387 return 0; 382 return 0;