svn commit: r186035 - in projects/arpv2_merge_1/sys: amd64/conf net
netinet netinet6
Kip Macy
kmacy at FreeBSD.org
Sat Dec 13 02:19:29 PST 2008
Author: kmacy
Date: Sat Dec 13 10:19:28 2008
New Revision: 186035
URL: http://svn.freebsd.org/changeset/base/186035
Log:
- add AFDATA and LLE lock asserts
- fix LLE_REMREF
- add nd6_llinfo_settimer_locked and nd6_output_lle for case where lle lock is already held
- remove inappropriate AFDATA lock in ip6_forward
- change "Qing" to "XXX QL"
Modified:
projects/arpv2_merge_1/sys/amd64/conf/GENERIC
projects/arpv2_merge_1/sys/net/if_llatbl.h
projects/arpv2_merge_1/sys/netinet/in.c
projects/arpv2_merge_1/sys/netinet6/in6.c
projects/arpv2_merge_1/sys/netinet6/ip6_forward.c
projects/arpv2_merge_1/sys/netinet6/nd6.c
projects/arpv2_merge_1/sys/netinet6/nd6.h
projects/arpv2_merge_1/sys/netinet6/nd6_nbr.c
Modified: projects/arpv2_merge_1/sys/amd64/conf/GENERIC
==============================================================================
--- projects/arpv2_merge_1/sys/amd64/conf/GENERIC Sat Dec 13 09:33:03 2008 (r186034)
+++ projects/arpv2_merge_1/sys/amd64/conf/GENERIC Sat Dec 13 10:19:28 2008 (r186035)
@@ -313,3 +313,5 @@ device fwe # Ethernet over FireWire (n
device fwip # IP over FireWire (RFC 2734,3146)
device dcons # Dumb console driver
device dcons_crom # Configuration ROM for dcons
+
+options ALT_BREAK_TO_DEBUGGER
Modified: projects/arpv2_merge_1/sys/net/if_llatbl.h
==============================================================================
--- projects/arpv2_merge_1/sys/net/if_llatbl.h Sat Dec 13 09:33:03 2008 (r186034)
+++ projects/arpv2_merge_1/sys/net/if_llatbl.h Sat Dec 13 10:19:28 2008 (r186035)
@@ -94,9 +94,9 @@ struct llentry {
#define LLE_REMREF(lle) do { \
LLE_WLOCK_ASSERT(lle); \
- KASSERT((lle)->rt_refcnt > 0, \
- ("bogus refcnt %ld", (lle)->rt_refcnt)); \
- (lle)->rt_refcnt--; \
+ KASSERT((lle)->lle_refcnt > 1, \
+ ("bogus refcnt %d", (lle)->lle_refcnt)); \
+ (lle)->lle_refcnt--; \
} while (0)
#define LLE_FREE_LOCKED(lle) do { \
Modified: projects/arpv2_merge_1/sys/netinet/in.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet/in.c Sat Dec 13 09:33:03 2008 (r186034)
+++ projects/arpv2_merge_1/sys/netinet/in.c Sat Dec 13 10:19:28 2008 (r186035)
@@ -1097,6 +1097,7 @@ in_lltable_lookup(struct lltable *llt, u
struct llentries *lleh;
u_int hashkey;
+ IF_AFDATA_LOCK_ASSERT(ifp);
KASSERT(l3addr->sa_family == AF_INET,
("sin_family %d", l3addr->sa_family));
Modified: projects/arpv2_merge_1/sys/netinet6/in6.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/in6.c Sat Dec 13 09:33:03 2008 (r186034)
+++ projects/arpv2_merge_1/sys/netinet6/in6.c Sat Dec 13 10:19:28 2008 (r186035)
@@ -1533,7 +1533,7 @@ in6_ifinit(struct ifnet *ifp, struct in6
* XXX: the logic below rejects assigning multiple addresses on a p2p
* interface that share the same destination.
*/
-#if 0 /* QING - verify */
+#if 0 /* QL - verify */
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
ia->ia_dstaddr.sin6_family == AF_INET6) {
@@ -1587,7 +1587,7 @@ in6_ifinit(struct ifnet *ifp, struct in6
IF_AFDATA_LOCK(ifp);
ia->ia_ifa.ifa_rtrequest = NULL;
- /* Qing
+ /* XXX QL
* we need to report rt_newaddrmsg
*/
ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | LLE_EXCLUSIVE),
@@ -2162,6 +2162,7 @@ in6_lltable_lookup(struct lltable *llt,
struct llentries *lleh;
u_int hashkey;
+ IF_AFDATA_LOCK_ASSERT(ifp);
KASSERT(l3addr->sa_family == AF_INET6,
("sin_family %d", l3addr->sa_family));
Modified: projects/arpv2_merge_1/sys/netinet6/ip6_forward.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/ip6_forward.c Sat Dec 13 09:33:03 2008 (r186034)
+++ projects/arpv2_merge_1/sys/netinet6/ip6_forward.c Sat Dec 13 10:19:28 2008 (r186035)
@@ -610,9 +610,7 @@ ip6_forward(struct mbuf *m, int srcrt)
ip6 = mtod(m, struct ip6_hdr *);
pass:
- IF_AFDATA_LOCK(rt->rt_ifp);
error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
- IF_AFDATA_UNLOCK(rt->rt_ifp);
if (error) {
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
V_ip6stat.ip6s_cantforward++;
Modified: projects/arpv2_merge_1/sys/netinet6/nd6.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/nd6.c Sat Dec 13 09:33:03 2008 (r186034)
+++ projects/arpv2_merge_1/sys/netinet6/nd6.c Sat Dec 13 10:19:28 2008 (r186035)
@@ -434,13 +434,20 @@ skip1:
* ND6 timer routine to handle ND6 entries
*/
void
-nd6_llinfo_settimer(struct llentry *ln, long tick)
+nd6_llinfo_settimer_locked(struct llentry *ln, long tick)
{
- LLE_WLOCK(ln);
if (tick < 0) {
ln->la_expire = 0;
ln->ln_ntick = 0;
callout_stop(&ln->ln_timer_ch);
+ /*
+ * XXX - do we know that there is
+ * callout installed? i.e. are we
+ * guaranteed that we're not dropping
+ * a reference that we did not add?
+ * KMM
+ */
+ LLE_REMREF(ln);
} else {
ln->la_expire = time_second + tick / hz;
LLE_ADDREF(ln);
@@ -454,6 +461,14 @@ nd6_llinfo_settimer(struct llentry *ln,
nd6_llinfo_timer, ln);
}
}
+}
+
+void
+nd6_llinfo_settimer(struct llentry *ln, long tick)
+{
+
+ LLE_WLOCK(ln);
+ nd6_llinfo_settimer_locked(ln, tick);
LLE_WUNLOCK(ln);
}
@@ -477,12 +492,6 @@ nd6_llinfo_timer(void *arg)
CURVNET_SET(ifp->if_vnet);
INIT_VNET_INET6(curvnet);
- /*
- * llentry is refcounted - we shouldn't need to protect it
- * with IF_AFDATA
- */
- IF_AFDATA_LOCK(ifp);
-
if (ln->ln_ntick > 0) {
if (ln->ln_ntick > INT_MAX) {
ln->ln_ntick -= INT_MAX;
@@ -491,21 +500,17 @@ nd6_llinfo_timer(void *arg)
ln->ln_ntick = 0;
nd6_llinfo_settimer(ln, ln->ln_ntick);
}
- IF_AFDATA_UNLOCK(ifp);
goto done;
}
ndi = ND_IFINFO(ifp);
dst = &L3_ADDR_SIN6(ln)->sin6_addr;
-
if ((ln->la_flags & LLE_STATIC) || (ln->la_expire > time_second)) {
- IF_AFDATA_UNLOCK(ifp);
goto done;
}
if (ln->la_flags & LLE_DELETED) {
(void)nd6_free(ln, 0);
- IF_AFDATA_UNLOCK(ifp);
goto done;
}
@@ -574,10 +579,9 @@ nd6_llinfo_timer(void *arg)
}
break;
}
- IF_AFDATA_UNLOCK(ifp);
CURVNET_RESTORE();
done:
- LLE_FREE_LOCKED(ln);
+ LLE_FREE(ln);
}
@@ -1427,6 +1431,7 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
if (ln)
IF_AFDATA_UNLOCK(ifp);
if (ln == NULL) {
+ flags |= LLE_EXCLUSIVE;
ln = nd6_lookup(from, flags |ND6_CREATE, ifp);
IF_AFDATA_UNLOCK(ifp);
is_newentry = 1;
@@ -1436,7 +1441,6 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
goto done;
is_newentry = 0;
}
-
if (ln == NULL)
return (NULL);
@@ -1495,7 +1499,7 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
* we must set the timer now, although it is actually
* meaningless.
*/
- nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
+ nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz);
if (ln->la_hold) {
struct mbuf *m_hold, *m_hold_next;
@@ -1515,12 +1519,12 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
* just set the 2nd argument as the
* 1st one.
*/
- nd6_output(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL);
+ nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln);
}
}
} else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
/* probe right away */
- nd6_llinfo_settimer((void *)ln, 0);
+ nd6_llinfo_settimer_locked((void *)ln, 0);
}
}
@@ -1660,6 +1664,15 @@ nd6_slowtimo(void *arg)
CURVNET_RESTORE();
}
+int
+nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
+ struct sockaddr_in6 *dst, struct rtentry *rt0)
+{
+
+ return (nd6_output_lle(ifp, origifp, m0, dst, rt0, NULL));
+}
+
+
/*
* Note that I'm not enforcing any global serialization
* lle state or asked changes here as the logic is too
@@ -1669,17 +1682,22 @@ nd6_slowtimo(void *arg)
*
*/
#define senderr(e) { error = (e); goto bad;}
+
int
-nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
- struct sockaddr_in6 *dst, struct rtentry *rt0)
+nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
+ struct sockaddr_in6 *dst, struct rtentry *rt0, struct llentry *lle)
{
INIT_VNET_INET6(curvnet);
struct mbuf *m = m0;
struct rtentry *rt = rt0;
- struct llentry *ln = NULL;
+ struct llentry *ln = lle;
int error = 0;
int flags = 0;
+#ifdef INVARIANTS
+ if (lle)
+ LLE_WLOCK_ASSERT(lle);
+#endif
if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
goto sendpkt;
@@ -1696,21 +1714,25 @@ nd6_output(struct ifnet *ifp, struct ifn
* At this point, the destination of the packet must be a unicast
* or an anycast address(i.e. not a multicast).
*/
- flags = m ? LLE_EXCLUSIVE : 0;
- IF_AFDATA_LOCK(rt->rt_ifp);
- ln = lla_lookup(LLTABLE6(ifp), flags, (struct sockaddr *)dst);
- IF_AFDATA_UNLOCK(rt->rt_ifp);
- if ((ln == NULL) && nd6_is_addr_neighbor(dst, ifp)) {
- /*
- * Since nd6_is_addr_neighbor() internally calls nd6_lookup(),
- * the condition below is not very efficient. But we believe
- * it is tolerable, because this should be a rare case.
- */
- flags = ND6_CREATE | (m ? ND6_EXCLUSIVE : 0);
+
+ flags = (m || lle) ? LLE_EXCLUSIVE : 0;
+ if (ln == NULL) {
+ retry:
IF_AFDATA_LOCK(rt->rt_ifp);
- ln = nd6_lookup(&dst->sin6_addr, flags, ifp);
+ ln = lla_lookup(LLTABLE6(ifp), flags, (struct sockaddr *)dst);
IF_AFDATA_UNLOCK(rt->rt_ifp);
- }
+ if ((ln == NULL) && nd6_is_addr_neighbor(dst, ifp)) {
+ /*
+ * Since nd6_is_addr_neighbor() internally calls nd6_lookup(),
+ * the condition below is not very efficient. But we believe
+ * it is tolerable, because this should be a rare case.
+ */
+ flags = ND6_CREATE | (m ? ND6_EXCLUSIVE : 0);
+ IF_AFDATA_LOCK(rt->rt_ifp);
+ ln = nd6_lookup(&dst->sin6_addr, flags, ifp);
+ IF_AFDATA_UNLOCK(rt->rt_ifp);
+ }
+ }
if (ln == NULL) {
if ((ifp->if_flags & IFF_POINTOPOINT) == 0 &&
!(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) {
@@ -1727,8 +1749,12 @@ nd6_output(struct ifnet *ifp, struct ifn
/* We don't have to do link-layer address resolution on a p2p link. */
if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
ln->ln_state < ND6_LLINFO_REACHABLE) {
+ if ((flags & LLE_EXCLUSIVE) == 0) {
+ flags |= LLE_EXCLUSIVE;
+ goto retry;
+ }
ln->ln_state = ND6_LLINFO_STALE;
- nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
+ nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz);
}
/*
@@ -1739,9 +1765,14 @@ nd6_output(struct ifnet *ifp, struct ifn
* (RFC 2461 7.3.3)
*/
if (ln->ln_state == ND6_LLINFO_STALE) {
+ if ((flags & LLE_EXCLUSIVE) == 0) {
+ flags |= LLE_EXCLUSIVE;
+ LLE_RUNLOCK(ln);
+ goto retry;
+ }
ln->la_asked = 0;
ln->ln_state = ND6_LLINFO_DELAY;
- nd6_llinfo_settimer(ln, (long)V_nd6_delay * hz);
+ nd6_llinfo_settimer_locked(ln, (long)V_nd6_delay * hz);
}
/*
@@ -1761,10 +1792,16 @@ nd6_output(struct ifnet *ifp, struct ifn
*/
if (ln->ln_state == ND6_LLINFO_NOSTATE)
ln->ln_state = ND6_LLINFO_INCOMPLETE;
+
+ if ((flags & LLE_EXCLUSIVE) == 0) {
+ flags |= LLE_EXCLUSIVE;
+ LLE_RUNLOCK(ln);
+ goto retry;
+ }
if (ln->la_hold) {
struct mbuf *m_hold;
int i;
-
+
i = 0;
for (m_hold = ln->la_hold; m_hold; m_hold = m_hold->m_nextpkt) {
i++;
@@ -1782,11 +1819,16 @@ nd6_output(struct ifnet *ifp, struct ifn
} else {
ln->la_hold = m;
}
-
- if (flags & LLE_EXCLUSIVE)
- LLE_WUNLOCK(ln);
- else
- LLE_RUNLOCK(ln);
+ /*
+ * We did the lookup (no lle arg) so we
+ * need to do the unlock here
+ */
+ if (lle == NULL) {
+ if (flags & LLE_EXCLUSIVE)
+ LLE_WUNLOCK(ln);
+ else
+ LLE_RUNLOCK(ln);
+ }
/*
* If there has been no NS for the neighbor after entering the
@@ -1807,7 +1849,11 @@ nd6_output(struct ifnet *ifp, struct ifn
error = ENETDOWN; /* better error? */
goto bad;
}
- if (ln) {
+ /*
+ * ln is valid and the caller did not pass in
+ * an llentry
+ */
+ if (ln && (lle == NULL)) {
if (flags & LLE_EXCLUSIVE)
LLE_WUNLOCK(ln);
else
@@ -1825,7 +1871,11 @@ nd6_output(struct ifnet *ifp, struct ifn
return (error);
bad:
- if (ln) {
+ /*
+ * ln is valid and the caller did not pass in
+ * an llentry
+ */
+ if (ln && (lle == NULL)) {
if (flags & LLE_EXCLUSIVE)
LLE_WUNLOCK(ln);
else
Modified: projects/arpv2_merge_1/sys/netinet6/nd6.h
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/nd6.h Sat Dec 13 09:33:03 2008 (r186034)
+++ projects/arpv2_merge_1/sys/netinet6/nd6.h Sat Dec 13 10:19:28 2008 (r186035)
@@ -380,6 +380,7 @@ int nd6_options __P((union nd_opts *));
struct llentry *nd6_lookup __P((struct in6_addr *, int, struct ifnet *));
void nd6_setmtu __P((struct ifnet *));
void nd6_llinfo_settimer __P((struct llentry *, long));
+void nd6_llinfo_settimer_locked __P((struct llentry *, long));
void nd6_timer __P((void *));
void nd6_purge __P((struct ifnet *));
void nd6_nud_hint __P((struct rtentry *, struct in6_addr *, int));
@@ -390,6 +391,8 @@ struct llentry *nd6_cache_lladdr __P((st
char *, int, int, int));
int nd6_output __P((struct ifnet *, struct ifnet *, struct mbuf *,
struct sockaddr_in6 *, struct rtentry *));
+int nd6_output_lle __P((struct ifnet *, struct ifnet *, struct mbuf *,
+ struct sockaddr_in6 *, struct rtentry *, struct llentry *));
int nd6_need_cache __P((struct ifnet *));
int nd6_storelladdr __P((struct ifnet *, struct rtentry *, struct mbuf *,
struct sockaddr *, u_char *, struct llentry **));
Modified: projects/arpv2_merge_1/sys/netinet6/nd6_nbr.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/nd6_nbr.c Sat Dec 13 09:33:03 2008 (r186034)
+++ projects/arpv2_merge_1/sys/netinet6/nd6_nbr.c Sat Dec 13 10:19:28 2008 (r186035)
@@ -41,6 +41,8 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/rwlock.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
@@ -603,7 +605,7 @@ nd6_na_input(struct mbuf *m, int off, in
char *lladdr = NULL;
int lladdrlen = 0;
struct ifaddr *ifa;
- struct llentry *ln;
+ struct llentry *ln = NULL;
union nd_opts ndopts;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
@@ -699,7 +701,7 @@ nd6_na_input(struct mbuf *m, int off, in
* discarded.
*/
IF_AFDATA_LOCK(ifp);
- ln = nd6_lookup(&taddr6, 0, ifp);
+ ln = nd6_lookup(&taddr6, LLE_EXCLUSIVE, ifp);
IF_AFDATA_UNLOCK(ifp);
if (ln == NULL) {
goto freeit;
@@ -723,12 +725,12 @@ nd6_na_input(struct mbuf *m, int off, in
ln->ln_state = ND6_LLINFO_REACHABLE;
ln->ln_byhint = 0;
if (!ND6_LLINFO_PERMANENT(ln)) {
- nd6_llinfo_settimer(ln,
+ nd6_llinfo_settimer_locked(ln,
(long)ND_IFINFO(ln->lle_tbl->llt_ifp)->reachable * hz);
}
} else {
ln->ln_state = ND6_LLINFO_STALE;
- nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
+ nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz);
}
if ((ln->ln_router = is_router) != 0) {
/*
@@ -782,7 +784,7 @@ nd6_na_input(struct mbuf *m, int off, in
*/
if (ln->ln_state == ND6_LLINFO_REACHABLE) {
ln->ln_state = ND6_LLINFO_STALE;
- nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
+ nd6_llinfo_settimer_locked(ln, (long)V_nd6_gctimer * hz);
}
goto freeit;
} else if (is_override /* (2a) */
@@ -805,13 +807,13 @@ nd6_na_input(struct mbuf *m, int off, in
ln->ln_state = ND6_LLINFO_REACHABLE;
ln->ln_byhint = 0;
if (!ND6_LLINFO_PERMANENT(ln)) {
- nd6_llinfo_settimer(ln,
+ nd6_llinfo_settimer_locked(ln,
(long)ND_IFINFO(ifp)->reachable * hz);
}
} else {
if (lladdr != NULL && llchange) {
ln->ln_state = ND6_LLINFO_STALE;
- nd6_llinfo_settimer(ln,
+ nd6_llinfo_settimer_locked(ln,
(long)V_nd6_gctimer * hz);
}
}
@@ -825,7 +827,6 @@ nd6_na_input(struct mbuf *m, int off, in
*/
struct nd_defrouter *dr;
struct in6_addr *in6;
-/* int s;*/
in6 = &L3_ADDR_SIN6(ln)->sin6_addr;
@@ -835,9 +836,6 @@ nd6_na_input(struct mbuf *m, int off, in
* is only called under the network software interrupt
* context. However, we keep it just for safety.
*/
-/* Qing - removing
- s = splnet();
-*/
dr = defrouter_lookup(in6, ln->lle_tbl->llt_ifp);
if (dr)
defrtrlist_del(dr);
@@ -851,15 +849,13 @@ nd6_na_input(struct mbuf *m, int off, in
*/
rt6_flush(&ip6->ip6_src, ifp);
}
-/* Qing - removing
- splx(s);
-*/
}
ln->ln_router = is_router;
}
- /* Qing - do we care ?
- rt->rt_flags &= ~RTF_REJECT;
- */
+ /* XXX - QL
+ * Does this matter?
+ * rt->rt_flags &= ~RTF_REJECT;
+ */
ln->la_asked = 0;
if (ln->la_hold) {
struct mbuf *m_hold, *m_hold_next;
@@ -877,14 +873,20 @@ nd6_na_input(struct mbuf *m, int off, in
* we assume ifp is not a loopback here, so just set
* the 2nd argument as the 1st one.
*/
- nd6_output(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL);
+ nd6_output_lle(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL, ln);
}
}
freeit:
+ if (ln)
+ LLE_WUNLOCK(ln);
+
m_freem(m);
return;
bad:
+ if (ln)
+ LLE_WUNLOCK(ln);
+
V_icmp6stat.icp6s_badna++;
m_freem(m);
}
More information about the svn-src-projects
mailing list