Page MenuHomeFreeBSD

D31826.diff
No OneTemporary

D31826.diff

diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -84,9 +84,9 @@
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, int);
+static void nd6_dad_starttimer(struct dadq *, int);
static void nd6_dad_stoptimer(struct dadq *);
-static void nd6_dad_timer(struct dadq *);
+static void nd6_dad_timer(void *);
static void nd6_dad_duplicated(struct ifaddr *, struct dadq *);
static void nd6_dad_ns_output(struct dadq *);
static void nd6_dad_ns_input(struct ifaddr *, struct nd_opt_nonce *);
@@ -1135,26 +1135,31 @@
#define V_dadq VNET(dadq)
#define V_dad_rwlock VNET(dad_rwlock)
-#define DADQ_RLOCK() rw_rlock(&V_dad_rwlock)
-#define DADQ_RUNLOCK() rw_runlock(&V_dad_rwlock)
-#define DADQ_WLOCK() rw_wlock(&V_dad_rwlock)
-#define DADQ_WUNLOCK() rw_wunlock(&V_dad_rwlock)
+#define DADQ_LOCKPTR() (&V_dad_rwlock)
+#define DADQ_LOCK_INIT() rw_init(DADQ_LOCKPTR(), "nd6 DAD queue")
+#define DADQ_RLOCK() rw_rlock(DADQ_LOCKPTR())
+#define DADQ_RUNLOCK() rw_runlock(DADQ_LOCKPTR())
+#define DADQ_WLOCK() rw_wlock(DADQ_LOCKPTR())
+#define DADQ_WUNLOCK() rw_wunlock(DADQ_LOCKPTR())
+
+#define DADQ_LOCK_ASSERT() rw_assert(DADQ_LOCKPTR(), RA_LOCKED);
+#define DADQ_RLOCK_ASSERT() rw_assert(DADQ_LOCKPTR(), RA_RLOCKED);
+#define DADQ_WLOCK_ASSERT() rw_assert(DADQ_LOCKPTR(), RA_WLOCKED);
static void
nd6_dad_add(struct dadq *dp)
{
+ DADQ_WLOCK_ASSERT();
- DADQ_WLOCK();
TAILQ_INSERT_TAIL(&V_dadq, dp, dad_list);
dp->dad_ondadq = true;
- DADQ_WUNLOCK();
}
static void
nd6_dad_del(struct dadq *dp)
{
+ DADQ_WLOCK_ASSERT();
- DADQ_WLOCK();
if (dp->dad_ondadq) {
/*
* Remove dp from the dadq and release the dadq's
@@ -1162,10 +1167,8 @@
*/
TAILQ_REMOVE(&V_dadq, dp, dad_list);
dp->dad_ondadq = false;
- DADQ_WUNLOCK();
nd6_dad_rele(dp);
- } else
- DADQ_WUNLOCK();
+ }
}
static struct dadq *
@@ -1173,10 +1176,12 @@
{
struct dadq *dp;
- DADQ_RLOCK();
+ DADQ_LOCK_ASSERT();
+
TAILQ_FOREACH(dp, &V_dadq, dad_list) {
if (dp->dad_ifa != ifa)
continue;
+
/*
* Skip if the nonce matches the received one.
* +2 in the length is required because of type and
@@ -1185,42 +1190,35 @@
if (n != NULL &&
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) {
+ ND_OPT_NONCE_LEN) == 0) {
dp->dad_ns_lcount++;
continue;
}
- refcount_acquire(&dp->dad_refcnt);
break;
}
- DADQ_RUNLOCK();
return (dp);
}
static void
-nd6_dad_starttimer(struct dadq *dp, int ticks, int send_ns)
+nd6_dad_starttimer(struct dadq *dp, int ticks)
{
+ DADQ_WLOCK_ASSERT();
- NET_EPOCH_ASSERT();
-
- if (send_ns != 0)
- nd6_dad_ns_output(dp);
- callout_reset(&dp->dad_timer_ch, ticks,
- (void (*)(void *))nd6_dad_timer, (void *)dp);
+ callout_reset(&dp->dad_timer_ch, ticks, nd6_dad_timer, dp);
}
static void
nd6_dad_stoptimer(struct dadq *dp)
{
-
callout_drain(&dp->dad_timer_ch);
}
static void
nd6_dad_rele(struct dadq *dp)
{
-
if (refcount_release(&dp->dad_refcnt)) {
+ KASSERT(!dp->dad_ondadq, ("dp %p still on DAD queue", dp));
ifa_free(dp->dad_ifa);
free(dp, M_IP6NDP);
}
@@ -1229,8 +1227,7 @@
void
nd6_dad_init(void)
{
-
- rw_init(&V_dad_rwlock, "nd6 DAD queue");
+ DADQ_LOCK_INIT();
TAILQ_INIT(&V_dadq);
}
@@ -1243,7 +1240,6 @@
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
struct dadq *dp;
char ip6buf[INET6_ADDRSTRLEN];
- struct epoch_tracker et;
KASSERT((ia->ia6_flags & IN6_IFF_TENTATIVE) != 0,
("starting DAD on non-tentative address %p", ifa));
@@ -1265,12 +1261,13 @@
(ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED) != 0)
return;
+ DADQ_WLOCK();
if ((dp = nd6_dad_find(ifa, NULL)) != NULL) {
/*
* DAD is already in progress. Let the existing entry
* finish it.
*/
- nd6_dad_rele(dp);
+ DADQ_WUNLOCK();
return;
}
@@ -1282,7 +1279,8 @@
ifa->ifa_ifp ? if_name(ifa->ifa_ifp) : "???");
return;
}
- callout_init(&dp->dad_timer_ch, 0);
+ callout_init_rw(&dp->dad_timer_ch, DADQ_LOCKPTR(),
+ CALLOUT_RETURNUNLOCKED);
#ifdef VIMAGE
dp->dad_vnet = curvnet;
#endif
@@ -1305,9 +1303,8 @@
/* Add this to the dadq and add a reference for the dadq. */
refcount_init(&dp->dad_refcnt, 1);
nd6_dad_add(dp);
- NET_EPOCH_ENTER(et);
- nd6_dad_starttimer(dp, delay, 0);
- NET_EPOCH_EXIT(et);
+ nd6_dad_starttimer(dp, delay);
+ DADQ_WUNLOCK();
}
/*
@@ -1318,29 +1315,36 @@
{
struct dadq *dp;
+ DADQ_WLOCK();
dp = nd6_dad_find(ifa, NULL);
- if (!dp) {
+ if (dp == NULL) {
+ DADQ_WUNLOCK();
/* DAD wasn't started yet */
return;
}
- nd6_dad_stoptimer(dp);
+ /*
+ * Acquire a temporary reference so that we can safely stop the callout.
+ */
+ (void)refcount_acquire(&dp->dad_refcnt);
nd6_dad_del(dp);
+ DADQ_WUNLOCK();
- /* Release this function's reference, acquired by nd6_dad_find(). */
+ nd6_dad_stoptimer(dp);
nd6_dad_rele(dp);
}
static void
-nd6_dad_timer(struct dadq *dp)
+nd6_dad_timer(void *arg)
{
- CURVNET_SET(dp->dad_vnet);
+ struct dadq *dp = arg;
struct ifaddr *ifa = dp->dad_ifa;
struct ifnet *ifp = dp->dad_ifa->ifa_ifp;
struct in6_ifaddr *ia = (struct in6_ifaddr *)ifa;
char ip6buf[INET6_ADDRSTRLEN];
struct epoch_tracker et;
+ CURVNET_SET(dp->dad_vnet);
KASSERT(ia != NULL, ("DAD entry %p with no address", dp));
NET_EPOCH_ENTER(et);
@@ -1381,17 +1385,18 @@
* We have more NS to go. Send NS packet for DAD.
*/
nd6_dad_starttimer(dp,
- (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000, 1);
+ (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
+ nd6_dad_ns_output(dp);
goto done;
} else {
/*
* We have transmitted sufficient number of DAD packets.
* See what we've got.
*/
- if (dp->dad_ns_icount > 0 || dp->dad_na_icount > 0)
+ 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 if (V_dad_enhanced != 0 &&
+ } else if (V_dad_enhanced != 0 &&
dp->dad_ns_lcount > 0 &&
dp->dad_ns_lcount > dp->dad_loopbackprobe) {
/*
@@ -1412,8 +1417,8 @@
dp->dad_count =
dp->dad_ns_ocount + V_nd6_mmaxtries - 1;
nd6_dad_starttimer(dp,
- (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000,
- 1);
+ (long)ND_IFINFO(ifa->ifa_ifp)->retrans * hz / 1000);
+ nd6_dad_ns_output(dp);
goto done;
} else {
/*
@@ -1439,6 +1444,7 @@
}
err:
nd6_dad_del(dp);
+ DADQ_WUNLOCK();
done:
NET_EPOCH_EXIT(et);
CURVNET_RESTORE();
@@ -1498,6 +1504,10 @@
}
}
+/*
+ * Transmit a neighbour solicitation for the purpose of DAD. Returns with the
+ * DAD queue unlocked.
+ */
static void
nd6_dad_ns_output(struct dadq *dp)
{
@@ -1505,11 +1515,15 @@
struct ifnet *ifp = dp->dad_ifa->ifa_ifp;
int i;
+ DADQ_WLOCK_ASSERT();
+
dp->dad_ns_tcount++;
if ((ifp->if_flags & IFF_UP) == 0) {
+ DADQ_WUNLOCK();
return;
}
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ DADQ_WUNLOCK();
return;
}
@@ -1526,6 +1540,7 @@
* should work well in almost all cases.
*/
}
+ DADQ_WUNLOCK();
nd6_ns_output(ifp, NULL, NULL, &ia->ia_addr.sin6_addr,
(uint8_t *)&dp->dad_nonce[0]);
}
@@ -1541,12 +1556,11 @@
/* Ignore Nonce option when Enhanced DAD is disabled. */
if (V_dad_enhanced == 0)
ndopt_nonce = NULL;
+ DADQ_RLOCK();
dp = nd6_dad_find(ifa, ndopt_nonce);
- if (dp == NULL)
- return;
-
- dp->dad_ns_icount++;
- nd6_dad_rele(dp);
+ if (dp != NULL)
+ dp->dad_ns_icount++;
+ DADQ_RUNLOCK();
}
static void
@@ -1557,9 +1571,9 @@
if (ifa == NULL)
panic("ifa == NULL in nd6_dad_na_input");
+ DADQ_RLOCK();
dp = nd6_dad_find(ifa, NULL);
- if (dp != NULL) {
+ if (dp != NULL)
dp->dad_na_icount++;
- nd6_dad_rele(dp);
- }
+ DADQ_RUNLOCK();
}

File Metadata

Mime Type
text/plain
Expires
Tue, Apr 29, 7:40 AM (18 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17838555
Default Alt Text
D31826.diff (7 KB)

Event Timeline