summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid Ahern <dsa@cumulusnetworks.com>2016-04-08 12:01:21 -0700
committerDavid S. Miller <davem@davemloft.net>2016-04-13 22:58:37 -0400
commit70af921db6f8835f4b11c65731116560adb00c14 (patch)
tree396dc640e04cfaa80b07e9e701570dffb79bc2d9 /net
parenta6d37131c02f15463daa00e2f1da6824e8e00de2 (diff)
downloadlinux-70af921db6f8835f4b11c65731116560adb00c14.tar.bz2
net: ipv6: Do not keep linklocal and loopback addresses
f1705ec197e7 added the option to retain user configured addresses on an admin down. A comment to one of the later revisions suggested using the IFA_F_PERMANENT flag rather than adding a user_managed boolean to the ifaddr struct. A side effect of this change is that link local and loopback addresses are also retained which is not part of the objective of f1705ec197e7. Add check to drop those addresses. Fixes: f1705ec197e7 ("net: ipv6: Make address flushing on ifdown optional") Signed-off-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/addrconf.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 2db2116d3e6b..23cec53b568a 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3448,6 +3448,12 @@ static void addrconf_type_change(struct net_device *dev, unsigned long event)
ipv6_mc_unmap(idev);
}
+static bool addr_is_local(const struct in6_addr *addr)
+{
+ return ipv6_addr_type(addr) &
+ (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
+}
+
static int addrconf_ifdown(struct net_device *dev, int how)
{
struct net *net = dev_net(dev);
@@ -3505,7 +3511,8 @@ restart:
* address is retained on a down event
*/
if (!keep_addr ||
- !(ifa->flags & IFA_F_PERMANENT)) {
+ !(ifa->flags & IFA_F_PERMANENT) ||
+ addr_is_local(&ifa->addr)) {
hlist_del_init_rcu(&ifa->addr_lst);
goto restart;
}
@@ -3554,7 +3561,8 @@ restart:
write_unlock_bh(&idev->lock);
spin_lock_bh(&ifa->lock);
- if (keep_addr && (ifa->flags & IFA_F_PERMANENT)) {
+ if (keep_addr && (ifa->flags & IFA_F_PERMANENT) &&
+ !addr_is_local(&ifa->addr)) {
/* set state to skip the notifier below */
state = INET6_IFADDR_STATE_DEAD;
ifa->state = 0;