svn commit: r279676 - in head: sbin/ifconfig sys/netinet6

Hiroki Sato hrs at FreeBSD.org
Thu Mar 5 21:27:51 UTC 2015


Author: hrs
Date: Thu Mar  5 21:27:49 2015
New Revision: 279676
URL: https://svnweb.freebsd.org/changeset/base/279676

Log:
  - Implement loopback probing state in enhanced DAD algorithm.
  
  - Add no_dad and ignoreloop per-IF knob.  no_dad disables DAD completely,
    and ignoreloop is to prevent infinite loop in loopback probing state when
    loopback is permanently expected.

Modified:
  head/sbin/ifconfig/af_inet6.c
  head/sbin/ifconfig/af_nd6.c
  head/sbin/ifconfig/ifconfig.8
  head/sys/netinet6/in6.c
  head/sys/netinet6/nd6.h
  head/sys/netinet6/nd6_nbr.c

Modified: head/sbin/ifconfig/af_inet6.c
==============================================================================
--- head/sbin/ifconfig/af_inet6.c	Thu Mar  5 20:29:18 2015	(r279675)
+++ head/sbin/ifconfig/af_inet6.c	Thu Mar  5 21:27:49 2015	(r279676)
@@ -485,6 +485,10 @@ static struct cmd inet6_cmds[] = {
 	DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
 	DEF_CMD("no_prefer_iface",ND6_IFF_NO_PREFER_IFACE,setnd6flags),
 	DEF_CMD("-no_prefer_iface",-ND6_IFF_NO_PREFER_IFACE,setnd6flags),
+	DEF_CMD("no_dad",	ND6_IFF_NO_DAD,		setnd6flags),
+	DEF_CMD("-no_dad",	-ND6_IFF_NO_DAD,	setnd6flags),
+	DEF_CMD("ignoreloop",	ND6_IFF_IGNORELOOP,	setnd6flags),
+	DEF_CMD("-ignoreloop",	-ND6_IFF_IGNORELOOP,	setnd6flags),
 	DEF_CMD_ARG("pltime",        			setip6pltime),
 	DEF_CMD_ARG("vltime",        			setip6vltime),
 	DEF_CMD("eui64",	0,			setip6eui64),

Modified: head/sbin/ifconfig/af_nd6.c
==============================================================================
--- head/sbin/ifconfig/af_nd6.c	Thu Mar  5 20:29:18 2015	(r279675)
+++ head/sbin/ifconfig/af_nd6.c	Thu Mar  5 21:27:49 2015	(r279676)
@@ -58,7 +58,8 @@ static const char rcsid[] =
 #define	MAX_SYSCTL_TRY	5
 #define	ND6BITS	"\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
 		"\004IFDISABLED\005DONT_SET_IFROUTE\006AUTO_LINKLOCAL" \
-		"\007NO_RADR\010NO_PREFER_IFACE\020DEFAULTIF"
+		"\007NO_RADR\010NO_PREFER_IFACE\011IGNORELOOP\012NO_DAD" \
+		"\020DEFAULTIF"
 
 static int isnd6defif(int);
 void setnd6flags(const char *, int, int, const struct afswtch *);

Modified: head/sbin/ifconfig/ifconfig.8
==============================================================================
--- head/sbin/ifconfig/ifconfig.8	Thu Mar  5 20:29:18 2015	(r279675)
+++ head/sbin/ifconfig/ifconfig.8	Thu Mar  5 21:27:49 2015	(r279676)
@@ -28,7 +28,7 @@
 .\"     From: @(#)ifconfig.8	8.3 (Berkeley) 1/5/94
 .\" $FreeBSD$
 .\"
-.Dd December 16, 2014
+.Dd March 6, 2015
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -687,6 +687,20 @@ policy table, configurable with
 .It Cm -no_prefer_iface
 Clear a flag
 .Cm no_prefer_iface .
+.It Cm no_dad
+Set a flag to disable Duplicate Address Detection.
+.It Cm -no_dad
+Clear a flag
+.Cm no_dad .
+.It Cm ignoreloop
+Set a flag to disable loopback detection in Enhanced Duplicate Address
+Detection Algorithm.
+When this flag is set,
+Duplicate Address Detection will stop in a finite number of probings
+even if a loopback configuration is detected.
+.It Cm -ignoreloop
+Clear a flag
+.Cm ignoreloop .
 .El
 .Pp
 The following parameters are specific for IPv6 addresses.

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Thu Mar  5 20:29:18 2015	(r279675)
+++ head/sys/netinet6/in6.c	Thu Mar  5 21:27:49 2015	(r279676)
@@ -1910,7 +1910,8 @@ in6if_do_dad(struct ifnet *ifp)
 	if ((ifp->if_flags & IFF_LOOPBACK) != 0)
 		return (0);
 
-	if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
+	if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) ||
+	    (ND_IFINFO(ifp)->flags & ND6_IFF_NO_DAD))
 		return (0);
 
 	/*

Modified: head/sys/netinet6/nd6.h
==============================================================================
--- head/sys/netinet6/nd6.h	Thu Mar  5 20:29:18 2015	(r279675)
+++ head/sys/netinet6/nd6.h	Thu Mar  5 21:27:49 2015	(r279676)
@@ -87,6 +87,8 @@ struct nd_ifinfo {
 #define ND6_IFF_AUTO_LINKLOCAL	0x20
 #define	ND6_IFF_NO_RADR		0x40
 #define ND6_IFF_NO_PREFER_IFACE	0x80 /* XXX: not related to ND. */
+#define ND6_IFF_IGNORELOOP	0x100
+#define ND6_IFF_NO_DAD		0x200
 
 #define	ND6_CREATE		LLE_CREATE
 #define	ND6_EXCLUSIVE		LLE_EXCLUSIVE

Modified: head/sys/netinet6/nd6_nbr.c
==============================================================================
--- head/sys/netinet6/nd6_nbr.c	Thu Mar  5 20:29:18 2015	(r279675)
+++ head/sys/netinet6/nd6_nbr.c	Thu Mar  5 21:27:49 2015	(r279676)
@@ -1182,6 +1182,7 @@ struct dadq {
 	int dad_ns_icount;
 	int dad_na_icount;
 	int dad_ns_lcount;	/* looped back NS */
+	int dad_loopbackprobe;	/* probing state for loopback detection */
 	struct callout dad_timer_ch;
 	struct vnet *dad_vnet;
 	u_int dad_refcnt;
@@ -1223,7 +1224,6 @@ static struct dadq *
 nd6_dad_find(struct ifaddr *ifa, struct nd_opt_nonce *n)
 {
 	struct dadq *dp;
-	char ip6buf[INET6_ADDRSTRLEN];
 
 	DADQ_RLOCK();
 	TAILQ_FOREACH(dp, &V_dadq, dad_list) {
@@ -1238,10 +1238,6 @@ nd6_dad_find(struct ifaddr *ifa, struct 
 		    n->nd_opt_nonce_len == (ND_OPT_NONCE_LEN + 2) / 8 &&
 		    memcmp(&n->nd_opt_nonce[0], &dp->dad_nonce[0],
 		        ND_OPT_NONCE_LEN) == 0) {
-			log(LOG_ERR, "%s: a looped back NS message is "
-			    "detected during DAD for %s.\n",
-			    if_name(ifa->ifa_ifp),
-			    ip6_sprintf(ip6buf, IFA_IN6(ifa)));
 			dp->dad_ns_lcount++;
 			continue;
 		}
@@ -1357,7 +1353,7 @@ nd6_dad_start(struct ifaddr *ifa, int de
 	dp->dad_count = V_ip6_dad_count;
 	dp->dad_ns_icount = dp->dad_na_icount = 0;
 	dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
-	dp->dad_ns_lcount = 0;
+	dp->dad_ns_lcount = dp->dad_loopbackprobe = 0;
 	refcount_init(&dp->dad_refcnt, 1);
 	nd6_dad_add(dp);
 	if (delay == 0) {
@@ -1432,8 +1428,10 @@ nd6_dad_timer(struct dadq *dp)
 		goto err;
 	}
 
-	/* timeouted with IFF_{RUNNING,UP} check */
-	if (dp->dad_ns_tcount > V_dad_maxtry) {
+	/* Stop DAD if the interface is down even after dad_maxtry attempts. */
+	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",
 		    if_name(ifa->ifa_ifp)));
 		goto err;
@@ -1456,7 +1454,42 @@ nd6_dad_timer(struct dadq *dp)
 		if (dp->dad_ns_icount > 0 || dp->dad_na_icount > 0)
 			/* We've seen NS or NA, means DAD has failed. */
 			nd6_dad_duplicated(ifa, dp);
-		else {
+		else if (V_dad_enhanced != 0 &&
+		    dp->dad_ns_lcount > 0 &&
+		    dp->dad_ns_lcount > dp->dad_loopbackprobe) {
+			/*
+			 * A looped back probe is detected,
+			 * Sec. 4.1 in draft-ietf-6man-enhanced-dad-13
+			 * requires transmission of additional probes until
+			 * the loopback condition becomes clear.
+			 */
+			log(LOG_ERR, "%s: a looped back NS message is "
+			    "detected during DAD for %s.  "
+			    "Another DAD probes are being sent.\n",
+			    if_name(ifa->ifa_ifp),
+			    ip6_sprintf(ip6buf, IFA_IN6(ifa)));
+			dp->dad_loopbackprobe = dp->dad_ns_lcount;
+			/*
+			 * An interface with IGNORELOOP is one which a
+			 * loopback is permanently expected while regular
+			 * traffic works.  In that case, stop DAD after
+			 * MAX_MULTICAST_SOLICIT number of NS messages
+			 * regardless of the number of received loopback NS
+			 * by increasing dad_loopbackprobe in advance.
+			 */
+			if (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IGNORELOOP)
+				dp->dad_loopbackprobe += V_nd6_mmaxtries;
+			/*
+			 * 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);
+			goto done;
+		} else {
 			/*
 			 * We are done with DAD.  No NA came, no NS came.
 			 * No duplicate address found.  Check IFDISABLED flag
@@ -1470,6 +1503,12 @@ nd6_dad_timer(struct dadq *dp)
 			    "%s: DAD complete for %s - no duplicates found\n",
 			    if_name(ifa->ifa_ifp),
 			    ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));
+			if (dp->dad_ns_lcount > 0)
+				log(LOG_ERR, "%s: DAD completed while "
+				    "a looped back NS message is detected "
+				    "during DAD for %s.\n",
+				    if_name(ifa->ifa_ifp),
+				    ip6_sprintf(ip6buf, IFA_IN6(ifa)));
 		}
 	}
 err:


More information about the svn-src-all mailing list