svn commit: r290348 - stable/10/sys/netinet6

Hiroki Sato hrs at FreeBSD.org
Wed Nov 4 01:00:43 UTC 2015


Author: hrs
Date: Wed Nov  4 01:00:42 2015
New Revision: 290348
URL: https://svnweb.freebsd.org/changeset/base/290348

Log:
  MFC r288600:
  
    - Schedule DAD for IN6_IFF_TENTATIVE addresses in nd6_timer().  This
      catches cases that DAD probes cannot be sent because of
      IFF_UP && !IFF_DRV_RUNNING.
  
    - nd6_dad_starttimer() now calls nd6_dad_ns_output(), instead of
      calling it before nd6_dad_starttimer().
  
    - Do not release an entry in dadq when a duplicate entry is being
      added.

Modified:
  stable/10/sys/netinet6/nd6.c
  stable/10/sys/netinet6/nd6_nbr.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/netinet6/nd6.c
==============================================================================
--- stable/10/sys/netinet6/nd6.c	Wed Nov  4 00:21:02 2015	(r290347)
+++ stable/10/sys/netinet6/nd6.c	Wed Nov  4 01:00:42 2015	(r290348)
@@ -687,8 +687,31 @@ nd6_timer(void *arg)
 					goto addrloop;
 				}
 			}
+		} else if ((ia6->ia6_flags & IN6_IFF_TENTATIVE) != 0) {
+			/*
+			 * Schedule DAD for a tentative address.  This happens
+			 * if the interface was down or not running
+			 * when the address was configured.
+			 */
+			int delay;
+
+			delay = arc4random() %
+			    (MAX_RTR_SOLICITATION_DELAY * hz);
+			nd6_dad_start((struct ifaddr *)ia6, delay);
 		} else {
 			/*
+			 * Check status of the interface.  If it is down,
+			 * mark the address as tentative for future DAD.
+			 */
+			if ((ia6->ia_ifp->if_flags & IFF_UP) == 0 ||
+			    (ia6->ia_ifp->if_drv_flags & IFF_DRV_RUNNING)
+				== 0 ||
+			    (ND_IFINFO(ia6->ia_ifp)->flags &
+				ND6_IFF_IFDISABLED) != 0) {
+				ia6->ia6_flags &= ~IN6_IFF_DUPLICATED;
+				ia6->ia6_flags |= IN6_IFF_TENTATIVE;
+			}
+			/*
 			 * A new RA might have made a deprecated address
 			 * preferred.
 			 */
@@ -1341,7 +1364,8 @@ nd6_ioctl(u_long cmd, caddr_t data, stru
 			/* Mark all IPv6 address as tentative. */
 
 			ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
-			if ((ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD) == 0) {
+			if (V_ip6_dad_count > 0 &&
+			    (ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD) == 0) {
 				IF_ADDR_RLOCK(ifp);
 				TAILQ_FOREACH(ifa, &ifp->if_addrhead,
 				    ifa_link) {

Modified: stable/10/sys/netinet6/nd6_nbr.c
==============================================================================
--- stable/10/sys/netinet6/nd6_nbr.c	Wed Nov  4 00:21:02 2015	(r290347)
+++ stable/10/sys/netinet6/nd6_nbr.c	Wed Nov  4 01:00:42 2015	(r290348)
@@ -86,11 +86,11 @@ static struct dadq *nd6_dad_find(struct 
 static void nd6_dad_add(struct dadq *dp);
 static void nd6_dad_del(struct dadq *dp);
 static void nd6_dad_rele(struct dadq *);
-static void nd6_dad_starttimer(struct dadq *, int);
+static void nd6_dad_starttimer(struct dadq *, int, int);
 static void nd6_dad_stoptimer(struct dadq *);
 static void nd6_dad_timer(struct dadq *);
 static void nd6_dad_duplicated(struct ifaddr *, struct dadq *);
-static void nd6_dad_ns_output(struct dadq *, struct ifaddr *);
+static void nd6_dad_ns_output(struct dadq *);
 static void nd6_dad_ns_input(struct ifaddr *, struct nd_opt_nonce *);
 static void nd6_dad_na_input(struct ifaddr *);
 static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *,
@@ -1242,9 +1242,11 @@ nd6_dad_find(struct ifaddr *ifa, struct 
 }
 
 static void
-nd6_dad_starttimer(struct dadq *dp, int ticks)
+nd6_dad_starttimer(struct dadq *dp, int ticks, int send_ns)
 {
 
+	if (send_ns != 0)
+		nd6_dad_ns_output(dp);
 	callout_reset(&dp->dad_timer_ch, ticks,
 	    (void (*)(void *))nd6_dad_timer, (void *)dp);
 }
@@ -1283,6 +1285,7 @@ nd6_dad_start(struct ifaddr *ifa, int de
 	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
 	struct dadq *dp;
 	char ip6buf[INET6_ADDRSTRLEN];
+	int send_ns;
 
 	/*
 	 * If we don't need DAD, don't do it.
@@ -1319,8 +1322,10 @@ nd6_dad_start(struct ifaddr *ifa, int de
 		return;
 	}
 	if ((dp = nd6_dad_find(ifa, NULL)) != NULL) {
-		/* DAD already in progress */
-		nd6_dad_rele(dp);
+		/*
+		 * DAD already in progress.  Let the existing entry
+		 * to finish it.
+		 */
 		return;
 	}
 
@@ -1353,13 +1358,12 @@ nd6_dad_start(struct ifaddr *ifa, int de
 	dp->dad_ns_lcount = dp->dad_loopbackprobe = 0;
 	refcount_init(&dp->dad_refcnt, 1);
 	nd6_dad_add(dp);
+	send_ns = 0;
 	if (delay == 0) {
-		nd6_dad_ns_output(dp, ifa);
-		nd6_dad_starttimer(dp,
-		    (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
-	} else {
-		nd6_dad_starttimer(dp, delay);
+		send_ns = 1;
+		delay = (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000;
 	}
+	nd6_dad_starttimer(dp, delay, send_ns);
 }
 
 /*
@@ -1429,7 +1433,8 @@ nd6_dad_timer(struct dadq *dp)
 	if ((dp->dad_ns_tcount > V_dad_maxtry) &&
 	    (((ifp->if_flags & IFF_UP) == 0) ||
 	     ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0))) {
-		nd6log((LOG_INFO, "%s: could not run DAD, driver problem?\n",
+		nd6log((LOG_INFO, "%s: could not run DAD "
+		    "because the interface was down or not running.\n",
 		    if_name(ifa->ifa_ifp)));
 		goto err;
 	}
@@ -1439,9 +1444,8 @@ nd6_dad_timer(struct dadq *dp)
 		/*
 		 * We have more NS to go.  Send NS packet for DAD.
 		 */
-		nd6_dad_ns_output(dp, ifa);
 		nd6_dad_starttimer(dp,
-		    (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
+		    (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000, 1);
 		goto done;
 	} else {
 		/*
@@ -1469,11 +1473,11 @@ nd6_dad_timer(struct dadq *dp)
 			 * Send an NS immediately and increase dad_count by
 			 * V_nd6_mmaxtries - 1.
 			 */
-			nd6_dad_ns_output(dp, ifa);
 			dp->dad_count =
 			    dp->dad_ns_ocount + V_nd6_mmaxtries - 1;
 			nd6_dad_starttimer(dp,
-			    (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
+			    (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000,
+			    1);
 			goto done;
 		} else {
 			/*
@@ -1562,10 +1566,10 @@ nd6_dad_duplicated(struct ifaddr *ifa, s
 }
 
 static void
-nd6_dad_ns_output(struct dadq *dp, struct ifaddr *ifa)
+nd6_dad_ns_output(struct dadq *dp)
 {
-	struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
-	struct ifnet *ifp = ifa->ifa_ifp;
+	struct in6_ifaddr *ia = (struct in6_ifaddr *)dp->dad_ifa;
+	struct ifnet *ifp = dp->dad_ifa->ifa_ifp;
 	int i;
 
 	dp->dad_ns_tcount++;


More information about the svn-src-all mailing list