Give DAD a chance to succeed even if the network is "slightly broken"

(in my case it as a switch set to "monitor" mode):
If we see an NS request for the address we are just probing for, for
three times the number of DAD packets we are supposed to send (the
"ip6.dad_count" sysctl variable), assume that these are our own packets
and let DAD succeed.
The code for this was mostly there, commented out. Just needed some fixes.
The "three times" is heuristic of course.
Being here, reset the "dad_ns_tcount" variable on a successful send;
otherwise we get strange interdependencies with user-settable variables
(ever tried to set ip6.dad_count to something >15?).
This commit is contained in:
drochner 2005-02-02 20:56:27 +00:00
parent ec34356a9c
commit e1e8770b32
1 changed files with 16 additions and 18 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6_nbr.c,v 1.53 2004/02/10 20:57:20 itojun Exp $ */
/* $NetBSD: nd6_nbr.c,v 1.54 2005/02/02 20:56:27 drochner Exp $ */
/* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.53 2004/02/10 20:57:20 itojun Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.54 2005/02/02 20:56:27 drochner Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@ -1007,7 +1007,8 @@ TAILQ_HEAD(dadq_head, dadq);
struct dadq {
TAILQ_ENTRY(dadq) dad_list;
struct ifaddr *dad_ifa;
int dad_count; /* max NS to send */
int dad_count; /* max NS to send, standard case */
int dad_maxcount; /* max NS to send, loopback detection */
int dad_ns_tcount; /* # of trials to send NS */
int dad_ns_ocount; /* NS sent so far */
int dad_ns_icount;
@ -1120,6 +1121,7 @@ nd6_dad_start(ifa, tick)
dp->dad_ifa = ifa;
IFAREF(ifa); /* just for safety */
dp->dad_count = ip6_dad_count;
dp->dad_maxcount = 3 * ip6_dad_count; /* XXX sysctl??? */
dp->dad_ns_icount = dp->dad_na_icount = 0;
dp->dad_ns_ocount = dp->dad_ns_tcount = 0;
if (tick == NULL) {
@ -1211,7 +1213,9 @@ nd6_dad_timer(ifa)
}
/* Need more checks? */
if (dp->dad_ns_ocount < dp->dad_count) {
if ((dp->dad_ns_ocount < dp->dad_count)
|| ((dp->dad_ns_ocount < dp->dad_maxcount)
&& (dp->dad_ns_icount == dp->dad_ns_ocount))) {
/*
* We have more NS to go. Send NS packet for DAD.
*/
@ -1235,34 +1239,27 @@ nd6_dad_timer(ifa)
duplicate++;
}
if (dp->dad_ns_icount) {
#if 0 /* heuristics */
if (dp->dad_ns_icount) { /* heuristics */
/*
* if
* - we have sent many(?) DAD NS, and
* - we have sent many DAD NS, and
* - the number of NS we sent equals to the
* number of NS we've got, and
* - we've got no NA
* we may have a faulty network card/driver which
* we may have a faulty network which
* loops back multicasts to myself.
*/
if (3 < dp->dad_count
&& dp->dad_ns_icount == dp->dad_count
if (dp->dad_ns_ocount == dp->dad_maxcount
&& dp->dad_ns_icount == dp->dad_ns_ocount
&& dp->dad_na_icount == 0) {
log(LOG_INFO, "DAD questionable for %s(%s): "
"network card loops back multicast?\n",
"network loops back multicast?\n",
ip6_sprintf(&ia->ia_addr.sin6_addr),
if_name(ifa->ifa_ifp));
/* XXX consider it a duplicate or not? */
/* duplicate++; */
} else {
/* We've seen NS, means DAD has failed. */
/* DAD has failed. */
duplicate++;
}
#else
/* We've seen NS, means DAD has failed. */
duplicate++;
#endif
}
if (duplicate) {
@ -1349,6 +1346,7 @@ nd6_dad_ns_output(dp, ifa)
return;
}
dp->dad_ns_tcount = 0;
dp->dad_ns_ocount++;
nd6_ns_output(ifp, NULL, &ia->ia_addr.sin6_addr, NULL, 1);
}