Commit 1e493d1946a0b26b79001c18d7312d536156ff5a

Authored by David S. Miller
1 parent 08569908ff

ipv6: On interface down/unregister, purge icmp routes too.

Johannes Berg reported that occaisionally, bringing an interface
down or unregistering it would hang for up to 30 seconds.  Using
debugging output he provided it became clear that ICMP6 routes
were the culprit.

The problem is that ICMP6 routes live in their own world totally
separate from normal ipv6 routes.  So there are all kinds of special
cases throughout the ipv6 code to handle this.

While we should really try to unify all of this stuff somehow,
for the time being let's fix this by purging the ICMP6 routes
that match the device in question during rt6_ifdown().

Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 1 changed file with 20 additions and 0 deletions Side-by-side Diff

... ... @@ -1003,6 +1003,25 @@
1003 1003 return more;
1004 1004 }
1005 1005  
  1006 +static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
  1007 + void *arg)
  1008 +{
  1009 + struct dst_entry *dst, **pprev;
  1010 +
  1011 + spin_lock_bh(&icmp6_dst_lock);
  1012 + pprev = &icmp6_dst_gc_list;
  1013 + while ((dst = *pprev) != NULL) {
  1014 + struct rt6_info *rt = (struct rt6_info *) dst;
  1015 + if (func(rt, arg)) {
  1016 + *pprev = dst->next;
  1017 + dst_free(dst);
  1018 + } else {
  1019 + pprev = &dst->next;
  1020 + }
  1021 + }
  1022 + spin_unlock_bh(&icmp6_dst_lock);
  1023 +}
  1024 +
1006 1025 static int ip6_dst_gc(struct dst_ops *ops)
1007 1026 {
1008 1027 unsigned long now = jiffies;
... ... @@ -1930,6 +1949,7 @@
1930 1949 };
1931 1950  
1932 1951 fib6_clean_all(net, fib6_ifdown, 0, &adn);
  1952 + icmp6_clean_all(fib6_ifdown, &adn);
1933 1953 }
1934 1954  
1935 1955 struct rt6_mtu_change_arg