diff options
author | Eric Dumazet <edumazet@google.com> | 2012-10-16 03:37:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-10-16 14:41:47 -0400 |
commit | 9f0d3c2781baa1102108e16efbe640dd74564a7c (patch) | |
tree | 7748c5750e0069ca56d6f98939e91261b00154ed /net/ipv6/addrconf.c | |
parent | 2384d6aa079de7c16c7877220d3cd4c6f4f50767 (diff) |
ipv6: addrconf: fix /proc/net/if_inet6
Commit 1d5783030a1 (ipv6/addrconf: speedup /proc/net/if_inet6 filling)
added bugs hiding some devices from if_inet6 and breaking applications.
"ip -6 addr" could still display all IPv6 addresses, while "ifconfig -a"
couldnt.
One way to reproduce the bug is by starting in a shell :
unshare -n /bin/bash
ifconfig lo up
And in original net namespace, lo device disappeared from if_inet6
Reported-by: Jan Hinnerk Stosch <janhinnerk.stosch@gmail.com>
Tested-by: Jan Hinnerk Stosch <janhinnerk.stosch@gmail.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Mihai Maruseac <mihai.maruseac@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d7c56f8a5b4e..0424e4e27414 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -3064,14 +3064,15 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq, loff_t pos) | |||
3064 | struct hlist_node *n; | 3064 | struct hlist_node *n; |
3065 | hlist_for_each_entry_rcu_bh(ifa, n, &inet6_addr_lst[state->bucket], | 3065 | hlist_for_each_entry_rcu_bh(ifa, n, &inet6_addr_lst[state->bucket], |
3066 | addr_lst) { | 3066 | addr_lst) { |
3067 | if (!net_eq(dev_net(ifa->idev->dev), net)) | ||
3068 | continue; | ||
3067 | /* sync with offset */ | 3069 | /* sync with offset */ |
3068 | if (p < state->offset) { | 3070 | if (p < state->offset) { |
3069 | p++; | 3071 | p++; |
3070 | continue; | 3072 | continue; |
3071 | } | 3073 | } |
3072 | state->offset++; | 3074 | state->offset++; |
3073 | if (net_eq(dev_net(ifa->idev->dev), net)) | 3075 | return ifa; |
3074 | return ifa; | ||
3075 | } | 3076 | } |
3076 | 3077 | ||
3077 | /* prepare for next bucket */ | 3078 | /* prepare for next bucket */ |
@@ -3089,18 +3090,20 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, | |||
3089 | struct hlist_node *n = &ifa->addr_lst; | 3090 | struct hlist_node *n = &ifa->addr_lst; |
3090 | 3091 | ||
3091 | hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst) { | 3092 | hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst) { |
3093 | if (!net_eq(dev_net(ifa->idev->dev), net)) | ||
3094 | continue; | ||
3092 | state->offset++; | 3095 | state->offset++; |
3093 | if (net_eq(dev_net(ifa->idev->dev), net)) | 3096 | return ifa; |
3094 | return ifa; | ||
3095 | } | 3097 | } |
3096 | 3098 | ||
3097 | while (++state->bucket < IN6_ADDR_HSIZE) { | 3099 | while (++state->bucket < IN6_ADDR_HSIZE) { |
3098 | state->offset = 0; | 3100 | state->offset = 0; |
3099 | hlist_for_each_entry_rcu_bh(ifa, n, | 3101 | hlist_for_each_entry_rcu_bh(ifa, n, |
3100 | &inet6_addr_lst[state->bucket], addr_lst) { | 3102 | &inet6_addr_lst[state->bucket], addr_lst) { |
3103 | if (!net_eq(dev_net(ifa->idev->dev), net)) | ||
3104 | continue; | ||
3101 | state->offset++; | 3105 | state->offset++; |
3102 | if (net_eq(dev_net(ifa->idev->dev), net)) | 3106 | return ifa; |
3103 | return ifa; | ||
3104 | } | 3107 | } |
3105 | } | 3108 | } |
3106 | 3109 | ||