summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2015-03-05 21:27:49 +0000
committerhrs <hrs@FreeBSD.org>2015-03-05 21:27:49 +0000
commit218de7f1d6c414ce3c5e25f027e34b3c576cea9e (patch)
tree3dc5e8f9cc0b000331bc7fe060702512b6613672
parenta0ef792dfe8e65fc36f4df479d1d4044ea825b67 (diff)
downloadFreeBSD-src-218de7f1d6c414ce3c5e25f027e34b3c576cea9e.zip
FreeBSD-src-218de7f1d6c414ce3c5e25f027e34b3c576cea9e.tar.gz
- 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.
-rw-r--r--sbin/ifconfig/af_inet6.c4
-rw-r--r--sbin/ifconfig/af_nd6.c3
-rw-r--r--sbin/ifconfig/ifconfig.816
-rw-r--r--sys/netinet6/in6.c3
-rw-r--r--sys/netinet6/nd6.h2
-rw-r--r--sys/netinet6/nd6_nbr.c57
6 files changed, 73 insertions, 12 deletions
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
index 3749400..bff66e0 100644
--- a/sbin/ifconfig/af_inet6.c
+++ b/sbin/ifconfig/af_inet6.c
@@ -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),
diff --git a/sbin/ifconfig/af_nd6.c b/sbin/ifconfig/af_nd6.c
index b3db0a8..3a510a5 100644
--- a/sbin/ifconfig/af_nd6.c
+++ b/sbin/ifconfig/af_nd6.c
@@ -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 *);
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index fdd398b..1e4870d 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -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.
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 448f8f2..ae68f26 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -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);
/*
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 80dc037..22509ac 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -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
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index 6937971..827f44b 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -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 nd_opt_nonce *n)
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 delay)
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:
OpenPOWER on IntegriCloud