tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
PATCH to mark IPv6 addresses DETACHED when down or link down
Hi List!
When a link status reports no carrier, or an interface is brought down
the state of all IPv6 addresses remains the same.
This means that when carrier is up or the interface is brought up no
duplicate address checking is performed.
We currently have the rather unused IN6_IFF_DETACHED flag and the
attached patch sets this when the interface is brought down or carrier
lost.
When it's brought up again with a carrier, the detached flag is
cleared, the tentative flag is set and DAD starts.
The routing socket is notified of all relevant changes via a
RTM_NEWADDR message.
dhcpcd can now listen to this and knows that it can start dealing with
IPv6 foo once the interface is up AND the locallink address is ready to
be used.
A nice side effect of this is that dhcpcd (latest git code) can now
manipulate the routing table to prefer one interface over another on the
same network
and a ping6 command to the server works seamlessly while the wired and
wireless interfaces are toggled up/down.
Comments welcome.
Thanks
Roy
Index: sys/net/if.c
===================================================================
RCS file: /cvsroot/src/sys/net/if.c,v
retrieving revision 1.262
diff -u -p -r1.262 if.c
--- sys/net/if.c 10 Mar 2013 19:46:12 -0000 1.262
+++ sys/net/if.c 30 May 2013 12:45:24 -0000
@@ -1342,6 +1342,12 @@ if_link_state_change(struct ifnet *ifp,
ifp->if_link_state = link_state;
/* Notify that the link state has changed. */
rt_ifmsg(ifp);
+#ifdef INET6
+ if (link_state == LINK_STATE_UP)
+ in6_if_up(ifp);
+ else if (link_state == LINK_STATE_DOWN)
+ in6_if_down(ifp);
+#endif
#if NCARP > 0
if (ifp->if_carp)
carp_carpdev_state(ifp);
@@ -1363,11 +1369,14 @@ if_down(struct ifnet *ifp)
IFADDR_FOREACH(ifa, ifp)
pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
IFQ_PURGE(&ifp->if_snd);
+ rt_ifmsg(ifp);
#if NCARP > 0
if (ifp->if_carp)
carp_carpdev_state(ifp);
#endif
- rt_ifmsg(ifp);
+#ifdef INET6
+ in6_if_down(ifp);
+#endif
}
/*
Index: sys/netinet6/in6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6.c,v
retrieving revision 1.163
diff -u -p -r1.163 in6.c
--- sys/netinet6/in6.c 29 May 2013 12:07:58 -0000 1.163
+++ sys/netinet6/in6.c 30 May 2013 12:45:24 -0000
@@ -1,4 +1,4 @@
-/* $NetBSD: in6.c,v 1.163 2013/05/29 12:07:58 roy Exp $ */
+/* $NetBSD: in6.c,v 1.162 2013/05/21 08:37:27 roy Exp $ */
/* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $ */
/*
@@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.163 2013/05/29 12:07:58 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.162 2013/05/21 08:37:27 roy Exp $");
#include "opt_inet.h"
#include "opt_pfil_hooks.h"
@@ -1004,6 +1004,9 @@ in6_update_ifa1(struct ifnet *ifp, struc
ia->ia_ifa.ifa_netmask =
(struct sockaddr *)&ia->ia_prefixmask;
+ if (in6if_do_dad(ifp))
+ ia->ia6_flags |= IN6_IFF_TENTATIVE;
+
ia->ia_ifp = ifp;
if ((oia = in6_ifaddr) != NULL) {
for ( ; oia->ia_next; oia = oia->ia_next)
@@ -1078,14 +1081,6 @@ in6_update_ifa1(struct ifnet *ifp, struc
* configure address flags.
*/
ia->ia6_flags = ifra->ifra_flags;
- /*
- * backward compatibility - if IN6_IFF_DEPRECATED is set from the
- * userland, make it deprecated.
- */
- if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
- ia->ia6_lifetime.ia6t_pltime = 0;
- ia->ia6_lifetime.ia6t_preferred = time_second;
- }
/*
* Make the address tentative before joining multicast addresses,
@@ -1093,9 +1088,21 @@ in6_update_ifa1(struct ifnet *ifp, struc
* source address.
*/
ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */
- if (hostIsNew && in6if_do_dad(ifp))
+ if (ifp->if_link_state == LINK_STATE_DOWN) {
+ ia->ia6_flags |= IN6_IFF_DETACHED;
+ ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
+ } else if (hostIsNew && in6if_do_dad(ifp))
ia->ia6_flags |= IN6_IFF_TENTATIVE;
+ /*
+ * backward compatibility - if IN6_IFF_DEPRECATED is set from the
+ * userland, make it deprecated.
+ */
+ if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) {
+ ia->ia6_lifetime.ia6t_pltime = 0;
+ ia->ia6_lifetime.ia6t_preferred = time_second;
+ }
+
/* reset the interface and routing table appropriately. */
if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)
goto unlink;
@@ -2167,10 +2174,25 @@ in6_if_up(struct ifnet *ifp)
struct ifaddr *ifa;
struct in6_ifaddr *ia;
+ /* Ensure it's sane to run DAD */
+ if (ifp->if_link_state == LINK_STATE_DOWN)
+ return;
+ if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+ return;
+
IFADDR_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ia = (struct in6_ifaddr *)ifa;
+ if (ia->ia6_flags & IN6_IFF_DETACHED) {
+ if (in6if_do_dad(ifp)) {
+ ia->ia6_flags |= IN6_IFF_TENTATIVE;
+ nd6log((LOG_ERR, "in6_if_up: "
+ "%s marked tentative\n",
+ ip6_sprintf(&ia->ia_addr.sin6_addr)));
+ }
+ ia->ia6_flags &= ~IN6_IFF_DETACHED;
+ }
if (ia->ia6_flags & IN6_IFF_TENTATIVE) {
/*
* The TENTATIVE flag was likely set by hand
@@ -2190,6 +2212,29 @@ in6_if_up(struct ifnet *ifp)
in6_ifattach(ifp, NULL);
}
+/*
+ * Mark all addresses as detached.
+ */
+void
+in6_if_down(struct ifnet *ifp)
+{
+ struct ifaddr *ifa;
+ struct in6_ifaddr *ia;
+
+ IFADDR_FOREACH(ifa, ifp) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ ia = (struct in6_ifaddr *)ifa;
+ if (!(ia->ia6_flags & IN6_IFF_DETACHED)) {
+ nd6log((LOG_DEBUG, "in6_if_down: "
+ "%s marked detached\n",
+ ip6_sprintf(&ia->ia_addr.sin6_addr)));
+ ia->ia6_flags |= IN6_IFF_DETACHED;
+ nd6_newaddrmsg(ifa);
+ }
+ }
+}
+
int
in6if_do_dad(struct ifnet *ifp)
{
Index: sys/netinet6/in6.h
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6.h,v
retrieving revision 1.71
diff -u -p -r1.71 in6.h
--- sys/netinet6/in6.h 27 Apr 2013 21:35:24 -0000 1.71
+++ sys/netinet6/in6.h 30 May 2013 12:45:24 -0000
@@ -701,6 +701,7 @@ int in6_localaddr(const struct in6_addr
int in6_addrscope(const struct in6_addr *);
struct in6_ifaddr *in6_ifawithifp(struct ifnet *, struct in6_addr *);
extern void in6_if_up(struct ifnet *);
+extern void in6_if_down(struct ifnet *);
#ifndef __FreeBSD__
extern int in6_src_sysctl(void *, size_t *, void *, size_t);
#endif
Home |
Main Index |
Thread Index |
Old Index