Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys When an interface link state changes to down, mark all a...



details:   https://anonhg.NetBSD.org/src/rev/6f28b3650add
branches:  trunk
changeset: 787329:6f28b3650add
user:      roy <roy%NetBSD.org@localhost>
date:      Tue Jun 11 12:08:29 2013 +0000

description:
When an interface link state changes to down, mark all attached IPv6
addresses as detached.
Likewise, when the link state changes to up, mark all detached IPv6
as tentative and start DAD on them.

Advertised router reachability now checks that link state is not down.
This means that when an interface link state changes, the default IPv6
router may change as well.

diffstat:

 sys/net/if.c           |  44 +++++++++++++++++++++++-
 sys/netinet6/in6.c     |  88 +++++++++++++++++++++++++++++++++++++++++++------
 sys/netinet6/in6.h     |   3 +-
 sys/netinet6/nd6_rtr.c |   7 ++-
 4 files changed, 124 insertions(+), 18 deletions(-)

diffs (263 lines):

diff -r fb11f5145f87 -r 6f28b3650add sys/net/if.c
--- a/sys/net/if.c      Tue Jun 11 10:07:09 2013 +0000
+++ b/sys/net/if.c      Tue Jun 11 12:08:29 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if.c,v 1.262 2013/03/10 19:46:12 christos Exp $        */
+/*     $NetBSD: if.c,v 1.263 2013/06/11 12:08:29 roy Exp $     */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.262 2013/03/10 19:46:12 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.263 2013/06/11 12:08:29 roy Exp $");
 
 #include "opt_inet.h"
 
@@ -1337,15 +1337,52 @@
 void
 if_link_state_change(struct ifnet *ifp, int link_state)
 {
+       int old_link_state;
+
        if (ifp->if_link_state == link_state)
                return;
+
+       old_link_state = ifp->if_link_state;
        ifp->if_link_state = link_state;
+#ifdef DEBUG
+       log(LOG_DEBUG, "%s: link state %s (was %s)\n", ifp->if_xname,
+               link_state == LINK_STATE_UP ? "UP" :
+               link_state == LINK_STATE_DOWN ? "DOWN" :
+               "UNKNOWN",
+               old_link_state == LINK_STATE_UP ? "UP" :
+               old_link_state == LINK_STATE_DOWN ? "DOWN" :
+               "UNKNOWN");
+#endif
+
+#ifdef INET6
+       /*
+        * When going from UNKNOWN to UP, we need to mark existing
+        * IPv6 addresses as tentative and restart DAD as we may have
+        * erroneously not found a duplicate.
+        *
+        * This needs to happen before rt_ifmsg to avoid a race where
+        * listeners would have an address and expect it to work right
+        * away.
+        */
+       if (link_state == LINK_STATE_UP &&
+           old_link_state == LINK_STATE_UNKNOWN)
+               in6_if_down(ifp);
+#endif
+
        /* Notify that the link state has changed. */
        rt_ifmsg(ifp);
+
 #if NCARP > 0
        if (ifp->if_carp)
                carp_carpdev_state(ifp);
 #endif
+
+#ifdef INET6
+       if (link_state == LINK_STATE_DOWN)
+               in6_if_down(ifp);
+       else if (link_state == LINK_STATE_UP)
+               in6_if_up(ifp);
+#endif
 }
 
 /*
@@ -1368,6 +1405,9 @@
                carp_carpdev_state(ifp);
 #endif
        rt_ifmsg(ifp);
+#ifdef INET6
+       in6_if_down(ifp);
+#endif
 }
 
 /*
diff -r fb11f5145f87 -r 6f28b3650add sys/netinet6/in6.c
--- a/sys/netinet6/in6.c        Tue Jun 11 10:07:09 2013 +0000
+++ b/sys/netinet6/in6.c        Tue Jun 11 12:08:29 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: in6.c,v 1.163 2013/05/29 12:07:58 roy Exp $    */
+/*     $NetBSD: in6.c,v 1.164 2013/06/11 12:08:29 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.164 2013/06/11 12:08:29 roy Exp $");
 
 #include "opt_inet.h"
 #include "opt_pfil_hooks.h"
@@ -1078,6 +1078,19 @@
         * configure address flags.
         */
        ia->ia6_flags = ifra->ifra_flags;
+
+       /*
+        * Make the address tentative before joining multicast addresses,
+        * so that corresponding MLD responses would not have a tentative
+        * source address.
+        */
+       ia->ia6_flags &= ~IN6_IFF_DUPLICATED;   /* safety */
+       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.
@@ -1087,19 +1100,9 @@
                ia->ia6_lifetime.ia6t_preferred = time_second;
        }
 
-       /*
-        * Make the address tentative before joining multicast addresses,
-        * so that corresponding MLD responses would not have a tentative
-        * source address.
-        */
-       ia->ia6_flags &= ~IN6_IFF_DUPLICATED;   /* safety */
-       if (hostIsNew && in6if_do_dad(ifp)) 
-               ia->ia6_flags |= IN6_IFF_TENTATIVE;
-
        /* reset the interface and routing table appropriately. */
        if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0)
                goto unlink;
-
        /*
         * We are done if we have simply modified an existing address.
         */
@@ -2167,10 +2170,29 @@
        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 detached then mark as tentative */
+               if (ia->ia6_flags & IN6_IFF_DETACHED) {
+                       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)));
+                       } else if ((ia->ia6_flags & IN6_IFF_TENTATIVE) == 0)
+                               nd6_newaddrmsg(ifa);
+               }
+
                if (ia->ia6_flags & IN6_IFF_TENTATIVE) {
                        /*
                         * The TENTATIVE flag was likely set by hand
@@ -2188,6 +2210,48 @@
         * special cases, like 6to4, are handled in in6_ifattach
         */
        in6_ifattach(ifp, NULL);
+
+       /* Restore any detached prefixes */
+       pfxlist_onlink_check();
+}
+
+/*
+ * 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;
+
+               /* Stop DAD processing */
+               nd6_dad_stop(ifa);
+
+               /*
+                * Mark the address as detached.
+                * This satisfies RFC4862 Section 5.3, but we should apply
+                * this logic to all addresses to be a good citizen and
+                * avoid potential duplicated addresses.
+                * When the interface comes up again, detached addresses
+                * are marked tentative and DAD commences.
+                */
+               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;
+                       ia->ia6_flags &= ~IN6_IFF_TENTATIVE;
+                       nd6_newaddrmsg(ifa);
+               }
+       }
+
+       /* Any prefixes on this interface should be detached as well */
+       pfxlist_onlink_check();
 }
 
 int
diff -r fb11f5145f87 -r 6f28b3650add sys/netinet6/in6.h
--- a/sys/netinet6/in6.h        Tue Jun 11 10:07:09 2013 +0000
+++ b/sys/netinet6/in6.h        Tue Jun 11 12:08:29 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: in6.h,v 1.71 2013/04/27 21:35:24 joerg Exp $   */
+/*     $NetBSD: in6.h,v 1.72 2013/06/11 12:08:29 roy Exp $     */
 /*     $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $    */
 
 /*
@@ -701,6 +701,7 @@
 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
diff -r fb11f5145f87 -r 6f28b3650add sys/netinet6/nd6_rtr.c
--- a/sys/netinet6/nd6_rtr.c    Tue Jun 11 10:07:09 2013 +0000
+++ b/sys/netinet6/nd6_rtr.c    Tue Jun 11 12:08:29 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: nd6_rtr.c,v 1.87 2013/05/21 08:37:27 roy Exp $ */
+/*     $NetBSD: nd6_rtr.c,v 1.88 2013/06/11 12:08:29 roy Exp $ */
 /*     $KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $        */
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.87 2013/05/21 08:37:27 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.88 2013/06/11 12:08:29 roy Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -1407,7 +1407,8 @@
                if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
                    pfxrtr->router->ifp)) &&
                    (ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
-                   ND6_IS_LLINFO_PROBREACH(ln))
+                   ND6_IS_LLINFO_PROBREACH(ln) &&
+                   pfxrtr->router->ifp->if_link_state != LINK_STATE_DOWN)
                        break;  /* found */
        }
 



Home | Main Index | Thread Index | Old Index