Page MenuHomeFreeBSD

D2254.id4737.diff
No OneTemporary

D2254.id4737.diff

Index: sys/netinet6/in6.c
===================================================================
--- sys/netinet6/in6.c
+++ sys/netinet6/in6.c
@@ -1334,11 +1334,7 @@
in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
{
char ip6buf[INET6_ADDRSTRLEN];
-
- IF_ADDR_WLOCK(ifp);
- TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
- IF_ADDR_WUNLOCK(ifp);
- ifa_free(&ia->ia_ifa); /* if_addrhead */
+ struct in6_ifaddr *iatmp;
/*
* Defer the release of what might be the last reference to the
@@ -1346,10 +1342,23 @@
* cleanup.
*/
IN6_IFADDR_WLOCK();
+ LIST_FOREACH(iatmp, IN6ADDR_HASH(&ia->ia_addr.sin6_addr), ia6_hash) {
+ if (iatmp == ia)
+ break;
+ }
+ if (iatmp == NULL) {
+ IN6_IFADDR_WUNLOCK();
+ return;
+ }
TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link);
LIST_REMOVE(ia, ia6_hash);
IN6_IFADDR_WUNLOCK();
+ IF_ADDR_WLOCK(ifp);
+ TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
+ IF_ADDR_WUNLOCK(ifp);
+ ifa_free(&ia->ia_ifa); /* if_addrhead */
+
/*
* Release the reference to the base prefix. There should be a
* positive reference.
Index: sys/netinet6/in6_var.h
===================================================================
--- sys/netinet6/in6_var.h
+++ sys/netinet6/in6_var.h
@@ -119,7 +119,6 @@
struct sockaddr_in6 ia_net; /* network number of interface */
struct sockaddr_in6 ia_dstaddr; /* space for destination addr */
struct sockaddr_in6 ia_prefixmask; /* prefix mask */
- u_int32_t ia_plen; /* prefix length */
TAILQ_ENTRY(in6_ifaddr) ia_link; /* list of IPv6 addresses */
int ia6_flags;
@@ -136,6 +135,8 @@
LIST_HEAD(, in6_multi_mship) ia6_memberships;
/* entry in bucket of inet6 addresses */
LIST_ENTRY(in6_ifaddr) ia6_hash;
+ /* expiring address list, only to be used by nd6_timer() */
+ SLIST_ENTRY(in6_ifaddr) ia6_expiring;
};
/* List of in6_ifaddr's. */
Index: sys/netinet6/nd6.c
===================================================================
--- sys/netinet6/nd6.c
+++ sys/netinet6/nd6.c
@@ -112,11 +112,6 @@
VNET_DEFINE(int, nd6_debug) = 0;
#endif
-/* for debugging? */
-#if 0
-static int nd6_inuse, nd6_allocated;
-#endif
-
VNET_DEFINE(struct nd_drhead, nd_defrouter);
VNET_DEFINE(struct nd_prhead, nd_prefix);
@@ -606,7 +601,7 @@
/*
- * ND6 timer routine to expire default route list and prefix list
+ * ND6 timer routine to expire default router, address, and prefix list entries.
*/
void
nd6_timer(void *arg)
@@ -615,6 +610,7 @@
struct nd_defrouter *dr, *ndr;
struct nd_prefix *pr, *npr;
struct in6_ifaddr *ia6, *nia6;
+ SLIST_HEAD(, in6_ifaddr) topurge;
callout_reset(&V_nd6_timer_ch, V_nd6_prune * hz,
nd6_timer, curvnet);
@@ -631,15 +627,27 @@
* However, from a stricter speci-confrmance standpoint, we should
* rather separate address lifetimes and prefix lifetimes.
*
- * XXXRW: in6_ifaddrhead locking.
+ * Expired address are placed in the topurge list and are freed only
+ * after we have scanned the full list to avoid acquiring the address
+ * list write lock more often than is necessary.
*/
+
+ SLIST_INIT(&topurge);
+
addrloop:
+ IN6_IFADDR_RLOCK();
TAILQ_FOREACH_SAFE(ia6, &V_in6_ifaddrhead, ia_link, nia6) {
/* check address lifetime */
if (IFA6_IS_INVALID(ia6)) {
int regen = 0;
/*
+ * regen_tmpaddr() may release the address list lock, so
+ * take a reference before calling it.
+ */
+ ifa_ref(&ia6->ia_ifa);
+
+ /*
* If the expiring address is temporary, try
* regenerating a new one. This would be useful when
* we suspended a laptop PC, then turned it on after a
@@ -655,7 +663,7 @@
regen = 1;
}
- in6_purgeaddr(&ia6->ia_ifa);
+ SLIST_INSERT_HEAD(&topurge, ia6, ia6_expiring);
if (regen)
goto addrloop; /* XXX: see below */
@@ -696,6 +704,12 @@
ia6->ia6_flags &= ~IN6_IFF_DEPRECATED;
}
}
+ IN6_IFADDR_RUNLOCK();
+
+ SLIST_FOREACH_SAFE(ia6, &topurge, ia6_expiring, nia6) {
+ in6_purgeaddr(&ia6->ia_ifa);
+ ifa_free(&ia6->ia_ifa);
+ }
/* expire prefix list */
LIST_FOREACH_SAFE(pr, &V_nd_prefix, ndpr_entry, npr) {
@@ -719,6 +733,9 @@
/*
* ia6 - deprecated/invalidated temporary address
+ *
+ * Must be called with the in6_ifaddr read lock held. The lock is released if we
+ * add a new address, in which case 0 is returned.
*/
static int
regen_tmpaddr(struct in6_ifaddr *ia6)
@@ -727,6 +744,8 @@
struct ifnet *ifp;
struct in6_ifaddr *public_ifa6 = NULL;
+ IN6_IFADDR_RLOCK_ASSERT();
+
ifp = ia6->ia_ifa.ifa_ifp;
IF_ADDR_RLOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
@@ -774,12 +793,10 @@
if (public_ifa6 != NULL) {
int e;
- if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) {
- ifa_free(&public_ifa6->ia_ifa);
- log(LOG_NOTICE, "regen_tmpaddr: failed to create a new"
- " tmp addr,errno=%d\n", e);
- return (-1);
- }
+ IN6_IFADDR_RUNLOCK();
+ if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0)
+ log(LOG_NOTICE,
+ "regen_tmpaddr: failed to create a new tmp addr, errno=%d\n", e);
ifa_free(&public_ifa6->ia_ifa);
return (0);
}
Index: sys/netinet6/nd6_rtr.c
===================================================================
--- sys/netinet6/nd6_rtr.c
+++ sys/netinet6/nd6_rtr.c
@@ -1468,9 +1468,8 @@
* detached. Note, however, that a manually configured address should
* always be attached.
* The precise detection logic is same as the one for prefixes.
- *
- * XXXRW: in6_ifaddrhead locking.
*/
+ IN6_IFADDR_RLOCK();
TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) {
if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF))
continue;
@@ -1505,8 +1504,7 @@
ifa->ia6_flags |= IN6_IFF_DETACHED;
}
}
- }
- else {
+ } else {
TAILQ_FOREACH(ifa, &V_in6_ifaddrhead, ia_link) {
if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
continue;
@@ -1519,6 +1517,7 @@
}
}
}
+ IN6_IFADDR_RUNLOCK();
}
static int

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 22, 8:18 AM (17 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31964329
Default Alt Text
D2254.id4737.diff (5 KB)

Event Timeline