[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20090109093105.742cf72e@extreme>
Date: Fri, 9 Jan 2009 09:31:05 -0800
From: Stephen Hemminger <shemminger@...tta.com>
To: "Rémi Denis-Courmont" <remi.denis-courmont@...ia.com>
Cc: David Miller <davem@...emloft.net>, yoshfuji@...ux-ipv6.org,
netdev@...r.kernel.org
Subject: Re: [PATCH] ipv6: address preservation on link down
On Fri, 9 Jan 2009 10:02:06 +0200
"Rémi Denis-Courmont" <remi.denis-courmont@...ia.com> wrote:
> On Friday 09 January 2009 03:14:15 ext Stephen Hemminger, you wrote:
> > When an interface goes down, IPV6 deletes all addresses unlike IPV4. This
> > is a problem since it can break routing protocols and other applications.
> > It looks like this was done to handle DAD, but is a big stick solution when
> > other code is possible.
> >
> > The following patch changes the behaviour to delete link local addresses
> > but keep all configured addresses and restart DAD when interface comes back
> > up.
>
> Let alone the backward compatibility problem for a minute. I have two _other_
> problems with this:
>
> 1/ If DAD should fail when the interface is brought back up, wouldn't all the
> EAU-64 autoconfigured address become invalid, rather than just the link-local
> one?
>
> 2/ In some case the link-local address is assigned by userland, no different
> from the other ones. At least miredo is behaving this way.
>
1: The address DAD path is same as the initial setup. I.e. it is same as if
the address was added manually (after ifup)
2: New patch honors the permanent flag. Another alternative would be to add a new
IFA_F_DYNAMIC flag
Updated patch that combines earlier efforts..
---
By default, IPV6 deletes all addresses when an interface is deconfigured.
This behaviour is different the IPV4 and confusing, so make it optional.
Add a new sysctl /proc/sys/net/ipv6/conf/ethX/address_flush that controls this.
The new behaviour that happens only if address_flush is set to zero is:
* all addresses are flushed on device deletion
* linklocal addresses are flushed unless the permanent flag is set
* other addresses are saved but duplicate address detection is restarted
unless nodad flag has been set.
---
Documentation/networking/ip-sysctl.txt | 9 +++++
include/linux/ipv6.h | 2 +
net/ipv6/addrconf.c | 50 ++++++++++++++++++++++++++-------
3 files changed, 51 insertions(+), 10 deletions(-)
--- a/Documentation/networking/ip-sysctl.txt 2009-01-09 08:48:56.701039688 -0800
+++ b/Documentation/networking/ip-sysctl.txt 2009-01-09 09:23:13.208788522 -0800
@@ -925,6 +925,15 @@ accept_source_route - INTEGER
Default: 0
+address_flush - BOOLEAN
+ Flush all addresses when link goes down
+ Default: TRUE
+
+ When network device is set to admin down:
+ TRUE - Delete all addresses
+ FALSE - Only addresses that are temporary or linklocal and not permanent
+ are deleted. Other addresses restart DAD (if configured).
+
autoconf - BOOLEAN
Autoconfigure addresses using Prefix Information in Router
Advertisements.
--- a/include/linux/ipv6.h 2009-01-09 08:49:14.170039111 -0800
+++ b/include/linux/ipv6.h 2009-01-09 08:57:33.592912530 -0800
@@ -166,6 +166,7 @@ struct ipv6_devconf {
#endif
__s32 disable_ipv6;
__s32 accept_dad;
+ __s32 address_flush;
void *sysctl;
};
#endif
@@ -200,6 +201,7 @@ enum {
DEVCONF_MC_FORWARDING,
DEVCONF_DISABLE_IPV6,
DEVCONF_ACCEPT_DAD,
+ DEVCONF_ADDRESS_FLUSH,
DEVCONF_MAX
};
--- a/net/ipv6/addrconf.c 2009-01-09 08:48:48.184789198 -0800
+++ b/net/ipv6/addrconf.c 2009-01-09 09:15:53.288788798 -0800
@@ -186,6 +186,7 @@ static struct ipv6_devconf ipv6_devconf
.accept_source_route = 0, /* we do not accept RH0 by default. */
.disable_ipv6 = 0,
.accept_dad = 1,
+ .address_flush = 1,
};
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -220,6 +221,7 @@ static struct ipv6_devconf ipv6_devconf_
.accept_source_route = 0, /* we do not accept RH0 by default. */
.disable_ipv6 = 0,
.accept_dad = 1,
+ .address_flush = 1,
};
/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -2678,18 +2680,37 @@ static int addrconf_ifdown(struct net_de
write_lock_bh(&idev->lock);
}
#endif
- while ((ifa = idev->addr_list) != NULL) {
- idev->addr_list = ifa->if_next;
- ifa->if_next = NULL;
- ifa->dead = 1;
- addrconf_del_timer(ifa);
- write_unlock_bh(&idev->lock);
+ /* clear regular address list on removal */
+ bifa = &idev->addr_list;
+ while ((ifa = *bifa) != NULL) {
+ if (how || idev->cnf.address_flush ||
+ ((ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)
+ && !(ifa->flags & IFA_F_PERMANENT))) {
+ *bifa = ifa->if_next;
+ ifa->if_next = NULL;
+ ifa->dead = 1;
+ addrconf_del_timer(ifa);
+ write_unlock_bh(&idev->lock);
+
+ __ipv6_ifa_notify(RTM_DELADDR, ifa);
+ atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
+ in6_ifa_put(ifa);
- __ipv6_ifa_notify(RTM_DELADDR, ifa);
- atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
- in6_ifa_put(ifa);
+ write_lock_bh(&idev->lock);
+ continue;
+ }
- write_lock_bh(&idev->lock);
+ bifa = &ifa->if_next;
+ if (ifa->flags & IFA_F_NODAD)
+ continue;
+
+ /* Retain address but force DAD */
+ ifa->flags |= IFA_F_TENTATIVE;
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
+ if (idev->cnf.optimistic_dad &&
+ !dev_net(idev->dev)->ipv6.devconf_all->forwarding)
+ ifa->flags |= IFA_F_OPTIMISTIC;
+#endif
}
write_unlock_bh(&idev->lock);
@@ -3697,6 +3718,7 @@ static inline void ipv6_store_devconf(st
#endif
array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
+ array[DEVCONF_ADDRESS_FLUSH] = cnf->address_flush;
}
static inline size_t inet6_if_nlmsg_size(void)
@@ -4271,6 +4293,14 @@ static struct addrconf_sysctl_table
.proc_handler = proc_dointvec,
},
{
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "address_flush",
+ .data = &ipv6_devconf.address_flush,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
.ctl_name = 0, /* sentinel */
}
},
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists