Skip to content

Commit

Permalink
ipv6: clean up anycast when an interface is destroyed
Browse files Browse the repository at this point in the history
If we try to rmmod the driver for an interface while sockets with
setsockopt(JOIN_ANYCAST) are alive, some refcounts aren't cleaned up
and we get stuck on:

  unregister_netdevice: waiting for ens3 to become free. Usage count = 1

If we LEAVE_ANYCAST/close everything before rmmod'ing, there is no
problem.

We need to perform a cleanup similar to the one for multicast in
addrconf_ifdown(how == 1).

Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Sabrina Dubroca authored and David S. Miller committed Sep 12, 2014
1 parent dcbc005 commit 381f4dc
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 3 deletions.
1 change: 1 addition & 0 deletions include/net/addrconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ void ipv6_sock_ac_close(struct sock *sk);

int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr);
int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr);
void ipv6_ac_destroy_dev(struct inet6_dev *idev);
bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
const struct in6_addr *addr);
bool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev,
Expand Down
8 changes: 5 additions & 3 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3094,11 +3094,13 @@ static int addrconf_ifdown(struct net_device *dev, int how)

write_unlock_bh(&idev->lock);

/* Step 5: Discard multicast list */
if (how)
/* Step 5: Discard anycast and multicast list */
if (how) {
ipv6_ac_destroy_dev(idev);
ipv6_mc_destroy_dev(idev);
else
} else {
ipv6_mc_down(idev);
}

idev->tstamp = jiffies;

Expand Down
21 changes: 21 additions & 0 deletions net/ipv6/anycast.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,27 @@ static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr)
return __ipv6_dev_ac_dec(idev, addr);
}

void ipv6_ac_destroy_dev(struct inet6_dev *idev)
{
struct ifacaddr6 *aca;

write_lock_bh(&idev->lock);
while ((aca = idev->ac_list) != NULL) {
idev->ac_list = aca->aca_next;
write_unlock_bh(&idev->lock);

addrconf_leave_solict(idev, &aca->aca_addr);

dst_hold(&aca->aca_rt->dst);
ip6_del_rt(aca->aca_rt);

aca_put(aca);

write_lock_bh(&idev->lock);
}
write_unlock_bh(&idev->lock);
}

/*
* check if the interface has this anycast address
* called with rcu_read_lock()
Expand Down

0 comments on commit 381f4dc

Please sign in to comment.