svn commit: r185839 - in projects/arpv2_merge_1/sys: net netinet
netinet6
Kip Macy
kmacy at FreeBSD.org
Tue Dec 9 22:01:28 PST 2008
Author: kmacy
Date: Wed Dec 10 06:01:27 2008
New Revision: 185839
URL: http://svn.freebsd.org/changeset/base/185839
Log:
merge changes from head_arpv2 branch:
- substantially reduce the scope of the IF_AFDATA_LOCK
- make the IF_AFDATA_LOCK not recursive
- add rwlock and refcount to llentry
Modified:
projects/arpv2_merge_1/sys/net/if.c
projects/arpv2_merge_1/sys/net/if_llatbl.c
projects/arpv2_merge_1/sys/net/if_llatbl.h
projects/arpv2_merge_1/sys/net/if_var.h
projects/arpv2_merge_1/sys/netinet/if_ether.c
projects/arpv2_merge_1/sys/netinet/in.c
projects/arpv2_merge_1/sys/netinet/ip_output.c
projects/arpv2_merge_1/sys/netinet6/icmp6.c
projects/arpv2_merge_1/sys/netinet6/in6.c
projects/arpv2_merge_1/sys/netinet6/in6_rmx.c
projects/arpv2_merge_1/sys/netinet6/ip6_input.c
projects/arpv2_merge_1/sys/netinet6/ip6_mroute.c
projects/arpv2_merge_1/sys/netinet6/ip6_output.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
projects/arpv2_merge_1/sys/netinet6/nd6_rtr.c
Modified: projects/arpv2_merge_1/sys/net/if.c
==============================================================================
--- projects/arpv2_merge_1/sys/net/if.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/net/if.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -71,7 +71,6 @@
#include <net/radix.h>
#include <net/route.h>
#include <net/vnet.h>
-#include <net/if_llatbl.h>
#if defined(INET) || defined(INET6)
/*XXX*/
@@ -1345,6 +1344,9 @@ done:
return (ifa);
}
+#include <net/route.h>
+#include <net/if_llatbl.h>
+
/*
* Default action when installing a route with a Link Level gateway.
* Lookup an appropriate real ifa to point to.
Modified: projects/arpv2_merge_1/sys/net/if_llatbl.c
==============================================================================
--- projects/arpv2_merge_1/sys/net/if_llatbl.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/net/if_llatbl.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <sys/kernel.h>
#include <sys/mutex.h>
+#include <sys/rwlock.h>
#include <sys/vimage.h>
#include <vm/uma.h>
@@ -89,13 +90,14 @@ done:
void
llentry_free(struct llentry *lle)
{
- struct lltable *llt = lle->lle_tbl;
+ LLE_WLOCK(lle);
LIST_REMOVE(lle, lle_next);
if (lle->la_hold != NULL)
m_freem(lle->la_hold);
- llt->llt_free(llt, lle);
+
+ LLE_FREE_LOCKED(lle);
}
/*
@@ -186,7 +188,8 @@ lla_rt_output(struct rt_msghdr *rtm, str
struct ifnet *ifp;
struct lltable *llt;
struct llentry *lle;
- u_int flags = 0;
+ u_int laflags = 0, flags = 0;
+ int error = 0;
if (dl == NULL || dl->sdl_family != AF_LINK) {
log(LOG_INFO, "%s: invalid dl\n", __func__);
@@ -211,10 +214,10 @@ lla_rt_output(struct rt_msghdr *rtm, str
log(LOG_INFO, "%s: RTM_ADD publish "
"(proxy only) is invalid\n",
__func__);
- rtfree(rt);
+ RTFREE(rt);
return EINVAL;
}
- rtfree(rt);
+ RTFREE(rt);
flags |= LLE_PROXY;
}
@@ -238,17 +241,21 @@ lla_rt_output(struct rt_msghdr *rtm, str
* XXXXXXXX:
* REVISE this approach if possible.
*/
- IFNET_WLOCK();
+ IFNET_RLOCK();
SLIST_FOREACH(llt, &lltables, llt_link) {
if (llt->llt_af == dst->sa_family &&
llt->llt_ifp == ifp)
break;
}
- IFNET_WUNLOCK();
+ IFNET_RUNLOCK();
KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n"));
+ if (flags && LLE_CREATE)
+ flags |= LLE_EXCLUSIVE;
+
IF_AFDATA_LOCK(ifp);
lle = lla_lookup(llt, flags, dst);
+ IF_AFDATA_UNLOCK(ifp);
if (lle != NULL) {
if (flags & LLE_CREATE) {
/* qing: if we delay the delete, then if a subsequent
@@ -268,31 +275,32 @@ lla_rt_output(struct rt_msghdr *rtm, str
/*
* "arp" and "ndp" always sets the (RTF_STATIC | RTF_HOST) flags
*/
+
if (rtm->rtm_rmx.rmx_expire == 0) {
lle->la_flags |= LLE_STATIC;
lle->la_expire = 0;
} else
lle->la_expire = rtm->rtm_rmx.rmx_expire;
+ laflags = lle->la_flags;
+ LLE_WUNLOCK(lle);
#ifdef INET
/* gratuious ARP */
- if ((lle->la_flags & LLE_PUB) &&
+ if ((laflags & LLE_PUB) &&
dst->sa_family == AF_INET) {
arprequest(ifp,
&((struct sockaddr_in *)dst)->sin_addr,
&((struct sockaddr_in *)dst)->sin_addr,
- ((lle->la_flags & LLE_PROXY) ?
+ ((laflags & LLE_PROXY) ?
(u_char *)IF_LLADDR(ifp) :
(u_char *)LLADDR(dl)));
}
#endif
- }
+ } else
+ LLE_RUNLOCK(lle);
} else {
- if (flags & LLE_DELETE) {
- IF_AFDATA_UNLOCK(ifp);
- return EINVAL;
- }
+ if (flags & LLE_DELETE)
+ error = EINVAL;
}
- IF_AFDATA_UNLOCK(ifp);
- return 0;
+ return (error);
}
Modified: projects/arpv2_merge_1/sys/net/if_llatbl.h
==============================================================================
--- projects/arpv2_merge_1/sys/net/if_llatbl.h Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/net/if_llatbl.h Wed Dec 10 06:01:27 2008 (r185839)
@@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$");
#ifndef _NET_IF_LLATBL_H_
#define _NET_IF_LLATBL_H_
+#include <sys/_rwlock.h>
#include <netinet/in.h>
struct ifnet;
@@ -38,8 +39,13 @@ struct rt_addrinfo;
struct llentry;
LIST_HEAD(llentries, llentry);
+/*
+ * Code referencing llentry must at least hold
+ * a shared lock
+ */
struct llentry {
LIST_ENTRY(llentry) lle_next;
+ struct rwlock lle_lock;
struct lltable *lle_tbl;
struct llentries *lle_head;
struct mbuf *la_hold;
@@ -51,6 +57,8 @@ struct llentry {
int16_t ln_state; /* IPv6 has ND6_LLINFO_NOSTATE == -2 */
uint16_t ln_router;
time_t ln_ntick;
+ int lle_refcnt;
+
union {
uint64_t mac_aligned;
uint16_t mac16[3];
@@ -64,6 +72,53 @@ struct llentry {
/* NB: struct sockaddr must immediately follow */
};
+#define LLE_WLOCK(lle) rw_wlock(&(lle)->lle_lock)
+#define LLE_RLOCK(lle) rw_rlock(&(lle)->lle_lock)
+#define LLE_WUNLOCK(lle) rw_wunlock(&(lle)->lle_lock)
+#define LLE_RUNLOCK(lle) rw_runlock(&(lle)->lle_lock)
+#define LLE_DOWNGRADE(lle) rw_downgrade(&(lle)->lle_lock)
+#define LLE_TRY_UPGRADE(lle) rw_try_upgrade(&(lle)->lle_lock)
+#define LLE_LOCK_INIT(lle) rw_init_flags(&(lle)->lle_lock, "lle", RW_DUPOK)
+#define LLE_WLOCK_ASSERT(lle) rw_assert(&(lle)->lle_lock, RA_WLOCKED)
+
+#define LLE_ADDREF(lle) do { \
+ LLE_WLOCK_ASSERT(lle); \
+ KASSERT((lle)->lle_refcnt >= 0, \
+ ("negative refcnt %d", (lle)->lle_refcnt)); \
+ (lle)->lle_refcnt++; \
+} while (0)
+
+#define LLE_REMREF(lle) do { \
+ LLE_WLOCK_ASSERT(lle); \
+ KASSERT((lle)->rt_refcnt > 0, \
+ ("bogus refcnt %ld", (lle)->rt_refcnt)); \
+ (lle)->rt_refcnt--; \
+} while (0)
+
+#define LLE_FREE_LOCKED(lle) do { \
+ if ((lle)->lle_refcnt <= 1) \
+ (lle)->lle_tbl->llt_free((lle)->lle_tbl, (lle));\
+ else { \
+ (lle)->lle_refcnt--; \
+ LLE_WUNLOCK(lle); \
+ } \
+ /* guard against invalid refs */ \
+ lle = 0; \
+} while (0)
+
+#define LLE_FREE(lle) do { \
+ LLE_WLOCK(lle); \
+ if ((lle)->lle_refcnt <= 1) \
+ (lle)->lle_tbl->llt_free((lle)->lle_tbl, (lle));\
+ else { \
+ (lle)->lle_refcnt--; \
+ LLE_WUNLOCK(lle); \
+ } \
+ /* guard against invalid refs */ \
+ lle = 0; \
+} while (0)
+
+
#define ln_timer_ch lle_timer.ln_timer_ch
#define la_timer lle_timer.la_timer
@@ -105,8 +160,9 @@ MALLOC_DECLARE(M_LLTABLE);
#define LLE_VALID 0x0008 /* ll_addr is valid */
#define LLE_PROXY 0x0010 /* proxy entry ??? */
#define LLE_PUB 0x0020 /* publish entry ??? */
-#define LLE_CREATE 0x8000 /* create on a lookup miss */
#define LLE_DELETE 0x4000 /* delete on a lookup - match LLE_IFADDR */
+#define LLE_CREATE 0x8000 /* create on a lookup miss */
+#define LLE_EXCLUSIVE 0x2000 /* return lle xlocked */
#define LLATBL_HASH(key, mask) \
(((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask)
Modified: projects/arpv2_merge_1/sys/net/if_var.h
==============================================================================
--- projects/arpv2_merge_1/sys/net/if_var.h Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/net/if_var.h Wed Dec 10 06:01:27 2008 (r185839)
@@ -359,13 +359,15 @@ typedef void (*group_change_event_handle
EVENTHANDLER_DECLARE(group_change_event, group_change_event_handler_t);
#define IF_AFDATA_LOCK_INIT(ifp) \
- mtx_init(&(ifp)->if_afdata_mtx, "if_afdata", NULL, \
- (MTX_DEF | MTX_RECURSE))
+ mtx_init(&(ifp)->if_afdata_mtx, "if_afdata", NULL, MTX_DEF)
#define IF_AFDATA_LOCK(ifp) mtx_lock(&(ifp)->if_afdata_mtx)
#define IF_AFDATA_TRYLOCK(ifp) mtx_trylock(&(ifp)->if_afdata_mtx)
#define IF_AFDATA_UNLOCK(ifp) mtx_unlock(&(ifp)->if_afdata_mtx)
#define IF_AFDATA_DESTROY(ifp) mtx_destroy(&(ifp)->if_afdata_mtx)
+#define IF_AFDATA_LOCK_ASSERT(ifp) mtx_assert(&(ifp)->if_afdata_mtx, MA_OWNED)
+#define IF_AFDATA_UNLOCK_ASSERT(ifp) mtx_assert(&(ifp)->if_afdata_mtx, MA_NOTOWNED)
+
#define IFF_LOCKGIANT(ifp) do { \
if ((ifp)->if_flags & IFF_NEEDSGIANT) \
mtx_lock(&Giant); \
Modified: projects/arpv2_merge_1/sys/netinet/if_ether.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet/if_ether.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/netinet/if_ether.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -128,20 +128,15 @@ void
arp_ifscrub(struct ifnet *ifp, uint32_t addr)
{
struct sockaddr_in addr4;
- struct llentry *lle;
bzero((void *)&addr4, sizeof(addr4));
addr4.sin_len = sizeof(addr4);
addr4.sin_family = AF_INET;
addr4.sin_addr.s_addr = addr;
IF_AFDATA_LOCK(ifp);
- lle = lla_lookup(LLTABLE(ifp), (LLE_DELETE | LLE_IFADDR),
+ lla_lookup(LLTABLE(ifp), (LLE_DELETE | LLE_IFADDR),
(struct sockaddr *)&addr4);
IF_AFDATA_UNLOCK(ifp);
-#if 0
- if (lle == NULL)
- log(LOG_INFO, "arp_ifscrub: interface address is missing from cache\n");
-#endif
}
#endif
@@ -159,15 +154,22 @@ arptimer(void *arg)
return;
}
ifp = lle->lle_tbl->llt_ifp;
- IF_AFDATA_LOCK(ifp);
if ((lle->la_flags & LLE_DELETED) ||
(time_second >= lle->la_expire)) {
+ printf("deleting entry\n");
+
+ IF_AFDATA_LOCK(ifp);
if (!callout_pending(&lle->la_timer) &&
(callout_active(&lle->la_timer))) {
(void)llentry_free(lle);
}
+ IF_AFDATA_UNLOCK(ifp);
+ } else {
+ /*
+ * Still valid, just drop our reference
+ */
+ LLE_FREE(lle);
}
- IF_AFDATA_UNLOCK(ifp);
}
@@ -252,10 +254,10 @@ arpresolve(struct ifnet *ifp, struct rte
INIT_VNET_INET(ifp->if_vnet);
struct llentry *la = 0;
u_int flags;
- int error;
+ int error, renew;
+ log(LOG_DEBUG, "arpesolve called\n");
*lle = NULL;
-
if (m != NULL) {
if (m->m_flags & M_BCAST) {
/* broadcast */
@@ -276,6 +278,7 @@ arpresolve(struct ifnet *ifp, struct rte
* Since this function returns an llentry, the
* lock is held by the caller.
*/
+retry:
la = lla_lookup(LLTABLE(ifp), flags, dst);
if (la == NULL) {
if (flags & LLE_CREATE)
@@ -283,11 +286,12 @@ arpresolve(struct ifnet *ifp, struct rte
"arpresolve: can't allocate llinfo for %s\n",
inet_ntoa(SIN(dst)->sin_addr));
m_freem(m);
+ log(LOG_DEBUG, "arpesolve: lla_lookup fail\n");
return (EINVAL);
}
- if (la->la_flags & LLE_VALID &&
- (la->la_flags & LLE_STATIC || la->la_expire > time_uptime)) {
+ if ((la->la_flags & LLE_VALID) &&
+ ((la->la_flags & LLE_STATIC) || (la->la_expire > time_uptime))) {
bcopy(&la->ll_addr, desten, ifp->if_addrlen);
/*
* If entry has an expiry time and it is approaching,
@@ -300,26 +304,46 @@ arpresolve(struct ifnet *ifp, struct rte
&SIN(dst)->sin_addr, IF_LLADDR(ifp));
la->la_preempt--;
- }
+ }
+ log(LOG_DEBUG, "arpresolve: success\n");
+
*lle = la;
- return (0);
- }
-
+ error = 0;
+ goto done;
+ } else
+ log(LOG_DEBUG,
+ "la=%p valid=%d static=%d expire=%ld uptime=%ld\n", la,
+ !!(la->la_flags & LLE_VALID), !!(la->la_flags & LLE_STATIC),
+ la->la_expire, time_uptime);
+
if (la->la_flags & LLE_STATIC) { /* should not happen! */
log(LOG_DEBUG, "arpresolve: ouch, empty static llinfo for %s\n",
inet_ntoa(SIN(dst)->sin_addr));
m_freem(m);
- return (EINVAL);
+ error = EINVAL;
+ goto done;
}
+
+ renew = (la->la_asked == 0 || la->la_expire != time_uptime);
/*
* There is an arptab entry, but no ethernet address
* response yet. Replace the held mbuf with this
* latest one.
*/
if (m) {
+ if ((flags & LLE_EXCLUSIVE) == 0) {
+ flags |= LLE_EXCLUSIVE;
+ LLE_RUNLOCK(la);
+ goto retry;
+ }
if (la->la_hold)
m_freem(la->la_hold);
la->la_hold = m;
+ if (renew == 0 && (flags & LLE_EXCLUSIVE)) {
+ flags &= ~LLE_EXCLUSIVE;
+ LLE_DOWNGRADE(la);
+ }
+
}
/*
* Return EWOULDBLOCK if we have tried less than arp_maxtries. It
@@ -333,16 +357,26 @@ arpresolve(struct ifnet *ifp, struct rte
error =
(rt0->rt_flags & RTF_GATEWAY) ? EHOSTDOWN : EHOSTUNREACH;
- if (la->la_asked == 0 || la->la_expire != time_uptime) {
+ if (renew) {
+ log(LOG_DEBUG,
+ "arpresolve: kicking off new resolve expire=%ld\n",
+ la->la_expire);
+ LLE_ADDREF(la);
la->la_expire = time_uptime;
callout_reset(&la->la_timer, hz, arptimer, la);
la->la_asked++;
-
+ LLE_WUNLOCK(la);
arprequest(ifp, NULL, &SIN(dst)->sin_addr,
IF_LLADDR(ifp));
+ return (error);
}
- return (EWOULDBLOCK);
+done:
+ if (flags & LLE_EXCLUSIVE)
+ LLE_WUNLOCK(la);
+ else
+ LLE_RUNLOCK(la);
+ return (error);
}
/*
@@ -432,7 +466,8 @@ in_arpinput(struct mbuf *m)
struct sockaddr sa;
struct in_addr isaddr, itaddr, myaddr;
u_int8_t *enaddr = NULL;
- int op, flag, lock_owned = 0;
+ int op, flags;
+ struct mbuf *m0;
/*
, rif_len;
*/
@@ -527,6 +562,7 @@ in_arpinput(struct mbuf *m)
if (!bridged || (ia = TAILQ_FIRST(&V_in_ifaddrhead)) == NULL)
goto drop;
match:
+ log(LOG_DEBUG,"in_arpinput: match\n");
if (!enaddr)
enaddr = (u_int8_t *)IF_LLADDR(ifp);
myaddr = ia->ia_addr.sin_addr;
@@ -559,17 +595,19 @@ match:
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_family = AF_INET;
sin.sin_addr = isaddr;
- flag = (itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0;
+ flags = (itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0;
+ flags |= LLE_EXCLUSIVE;
IF_AFDATA_LOCK(ifp);
- lock_owned = 1;
- la = lla_lookup(LLTABLE(ifp), flag, (struct sockaddr *)&sin);
+ la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin);
+ IF_AFDATA_UNLOCK(ifp);
if (la != NULL) {
+ log(LOG_DEBUG, "in_arpinput: la found\n");
/* the following is not an error when doing bridging */
if (!bridged && la->lle_tbl->llt_ifp != ifp
#ifdef DEV_CARP
&& (ifp->if_type != IFT_CARP || !carp_match)
#endif
- ) {
+ ) {
if (log_arp_wrong_iface)
log(LOG_ERR, "arp: %s is on %s "
"but got reply from %*D on %s\n",
@@ -579,9 +617,9 @@ match:
ifp->if_xname);
goto reply;
}
-
- if (la->la_flags & LLE_VALID &&
+ if ((la->la_flags & LLE_VALID) &&
bcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) {
+ log(LOG_DEBUG, "LLE_VALID and match\n");
if (la->la_flags & LLE_STATIC) {
log(LOG_ERR,
"arp: %*D attempts to modify permanent "
@@ -600,6 +638,7 @@ match:
ifp->if_xname);
}
}
+
if (ifp->if_addrlen != ah->ar_hln) {
log(LOG_WARNING,
"arp from %*D: addr len: new %d, i/f %d (ignored)",
@@ -610,6 +649,7 @@ match:
(void)memcpy(&la->ll_addr, ar_sha(ah), ifp->if_addrlen);
la->la_flags |= LLE_VALID;
+ log(LOG_DEBUG, "in_arpinput: la=%p valid set\n", la);
if (!(la->la_flags & LLE_STATIC)) {
la->la_expire = time_uptime + arpt_keep;
callout_reset(&la->la_timer, hz * V_arpt_keep,
@@ -618,8 +658,13 @@ match:
la->la_asked = 0;
la->la_preempt = V_arp_maxtries;
if (la->la_hold) {
- (*ifp->if_output)(ifp, la->la_hold, L3_ADDR(la), NULL);
+ m0 = la->la_hold;
la->la_hold = 0;
+ memcpy(&sa, L3_ADDR(la), sizeof(sa));
+ LLE_WUNLOCK(la);
+
+ (*ifp->if_output)(ifp, m0, &sa, NULL);
+ return;
}
}
reply:
@@ -636,7 +681,6 @@ reply:
goto drop;
sin.sin_addr = itaddr;
-
/* XXX MRT use table 0 for arp reply */
rt = in_rtalloc1((struct sockaddr *)&sin, 0, 0UL, 0);
if (!rt)
@@ -697,11 +741,8 @@ reply:
}
}
- if (lock_owned != 0) {
- IF_AFDATA_UNLOCK(ifp);
- lock_owned = 0;
- }
-
+ if (la)
+ LLE_WUNLOCK(la);
if (itaddr.s_addr == myaddr.s_addr &&
IN_LINKLOCAL(ntohl(itaddr.s_addr))) {
/* RFC 3927 link-local IPv4; always reply by broadcast. */
@@ -727,8 +768,8 @@ reply:
return;
drop:
- if (lock_owned != 0)
- IF_AFDATA_UNLOCK(ifp);
+ if (la)
+ LLE_WUNLOCK(la);
m_freem(m);
}
#endif
@@ -753,6 +794,7 @@ arp_ifinit(struct ifnet *ifp, struct ifa
if (lle == NULL)
log(LOG_INFO, "arp_ifinit: cannot create arp "
"entry for interface address\n");
+ LLE_RUNLOCK(lle);
ifa->ifa_rtrequest = NULL;
}
Modified: projects/arpv2_merge_1/sys/netinet/in.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet/in.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/netinet/in.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -1046,7 +1046,8 @@ in_lltable_new(const struct sockaddr *l3
*/
lle->base.la_expire = time_second; /* mark expired */
lle->l3_addr4 = *(const struct sockaddr_in *)l3addr;
-
+ lle->base.lle_refcnt = 1;
+ LLE_LOCK_INIT(&lle->base);
return &lle->base;
}
@@ -1076,13 +1077,18 @@ in_lltable_rtcheck(struct ifnet *ifp, co
log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n",
inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr));
if (rt != NULL)
- rtfree(rt);
- return EINVAL;
+ RTFREE_LOCKED(rt);
+ return (EINVAL);
}
- rtfree(rt);
+ RTFREE_LOCKED(rt);
return 0;
}
+/*
+ * Returns NULL if not found or marked for deletion
+ * if found returns lle read locked
+ *
+ */
static struct llentry *
in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
{
@@ -1103,8 +1109,11 @@ in_lltable_lookup(struct lltable *llt, u
if (bcmp(L3_ADDR(lle), l3addr, sizeof(struct sockaddr_in)) == 0)
break;
}
-
if (lle == NULL) {
+#ifdef INVARIANTS
+ if (flags & LLE_DELETE)
+ log(LOG_INFO, "interface address is missing from cache = %p in delete\n", lle);
+#endif
if (!(flags & LLE_CREATE))
return (NULL);
/*
@@ -1114,12 +1123,12 @@ in_lltable_lookup(struct lltable *llt, u
*/
if (!(flags & LLE_IFADDR) &&
in_lltable_rtcheck(ifp, l3addr) != 0)
- return NULL;
+ goto done;
lle = in_lltable_new(l3addr, flags);
if (lle == NULL) {
log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
- return NULL;
+ goto done;
}
lle->la_flags = flags & ~LLE_CREATE;
if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) {
@@ -1130,11 +1139,23 @@ in_lltable_lookup(struct lltable *llt, u
lle->lle_tbl = llt;
lle->lle_head = lleh;
LIST_INSERT_HEAD(lleh, lle, lle_next);
- } else {
- if (flags & LLE_DELETE)
- lle->la_flags = LLE_DELETED;
+ } else if (flags & LLE_DELETE) {
+ LLE_WLOCK(lle);
+ lle->la_flags = LLE_DELETED;
+ LLE_WUNLOCK(lle);
+#ifdef INVARIANTS
+ log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
+#endif
+ lle = NULL;
+ }
+ if (lle) {
+ if (flags & LLE_EXCLUSIVE)
+ LLE_WLOCK(lle);
+ else
+ LLE_RLOCK(lle);
}
- return lle;
+done:
+ return (lle);
}
static int
Modified: projects/arpv2_merge_1/sys/netinet/ip_output.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet/ip_output.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/netinet/ip_output.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -567,11 +567,8 @@ passout:
* to avoid confusing lower layers.
*/
m->m_flags &= ~(M_PROTOFLAGS);
-
- IF_AFDATA_LOCK(ifp);
error = (*ifp->if_output)(ifp, m,
(struct sockaddr *)dst, ro->ro_rt);
- IF_AFDATA_UNLOCK(ifp);
goto done;
}
@@ -604,10 +601,8 @@ passout:
*/
m->m_flags &= ~(M_PROTOFLAGS);
- IF_AFDATA_LOCK(ifp);
error = (*ifp->if_output)(ifp, m,
(struct sockaddr *)dst, ro->ro_rt);
- IF_AFDATA_UNLOCK(ifp);
} else
m_freem(m);
}
Modified: projects/arpv2_merge_1/sys/netinet6/icmp6.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/icmp6.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/netinet6/icmp6.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -85,10 +85,10 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/if_dl.h>
+#include <net/if_llatbl.h>
#include <net/if_types.h>
#include <net/route.h>
#include <net/vnet.h>
-#include <net/if_llatbl.h>
#include <netinet/in.h>
#include <netinet/in_pcb.h>
@@ -2397,10 +2397,8 @@ icmp6_redirect_input(struct mbuf *m, int
}
/* RFC 2461 8.3 */
- IF_AFDATA_LOCK(ifp);
nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT,
is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER);
- IF_AFDATA_UNLOCK(ifp);
if (!is_onlink) { /* better router case. perform rtredirect. */
/* perform rtredirect */
@@ -2583,17 +2581,16 @@ icmp6_redirect_output(struct mbuf *m0, s
IF_AFDATA_LOCK(ifp);
ln = nd6_lookup(router_ll6, 0, ifp);
- if (!ln) {
- IF_AFDATA_UNLOCK(ifp);
+ IF_AFDATA_UNLOCK(ifp);
+ if (!ln)
goto nolladdropt;
- }
+
len = sizeof(*nd_opt) + ifp->if_addrlen;
len = (len + 7) & ~7; /* round by 8 */
/* safety check */
- if (len + (p - (u_char *)ip6) > maxlen) {
- IF_AFDATA_UNLOCK(ifp);
+ if (len + (p - (u_char *)ip6) > maxlen)
goto nolladdropt;
- }
+
if (ln->la_flags & LLE_VALID) {
nd_opt = (struct nd_opt_hdr *)p;
nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
@@ -2602,7 +2599,7 @@ icmp6_redirect_output(struct mbuf *m0, s
bcopy(&ln->ll_addr, lladdr, ifp->if_addrlen);
p += len;
}
- IF_AFDATA_UNLOCK(ifp);
+ LLE_RUNLOCK(ln);
}
nolladdropt:;
Modified: projects/arpv2_merge_1/sys/netinet6/in6.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/in6.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/netinet6/in6.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -1143,21 +1143,16 @@ in6_purgeaddr(struct ifaddr *ifa)
{
struct ifnet *ifp = ifa->ifa_ifp;
struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
- struct llentry *ln = NULL;
struct in6_multi_mship *imm;
/* stop DAD processing */
nd6_dad_stop(ifa);
IF_AFDATA_LOCK(ifp);
- ln = lla_lookup(LLTABLE6(ifp), (LLE_DELETE | LLE_IFADDR),
+ lla_lookup(LLTABLE6(ifp), (LLE_DELETE | LLE_IFADDR),
(struct sockaddr *)&ia->ia_addr);
- if (ln == NULL)
- log(LOG_INFO, "nd6_purgeaddr: interface address is missing from cache\n");
- else
- log(LOG_INFO, "nd6_purgeaddr: ifaddr cache = %p is deleted\n", ln);
IF_AFDATA_UNLOCK(ifp);
-
+
/*
* leave from multicast groups we have joined for the interface
*/
@@ -1609,13 +1604,14 @@ in6_ifinit(struct ifnet *ifp, struct in6
/* Qing
* we need to report rt_newaddrmsg
*/
- ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR),
+ ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | LLE_EXCLUSIVE),
(struct sockaddr *)&ia->ia_addr);
+ IF_AFDATA_UNLOCK(ifp);
if (ln) {
ln->la_expire = 0; /* for IPv6 this means permanent */
ln->ln_state = ND6_LLINFO_REACHABLE;
+ LLE_WUNLOCK(ln);
}
- IF_AFDATA_UNLOCK(ifp);
}
return (error);
@@ -2119,7 +2115,8 @@ in6_lltable_new(const struct sockaddr *l
callout_init(&lle->base.ln_timer_ch, CALLOUT_MPSAFE);
lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr;
-
+ lle->base.lle_refcnt = 1;
+ LLE_LOCK_INIT(&lle->base);
return &lle->base;
}
@@ -2217,11 +2214,22 @@ in6_lltable_lookup(struct lltable *llt,
lle->lle_tbl = llt;
lle->lle_head = lleh;
LIST_INSERT_HEAD(lleh, lle, lle_next);
- } else {
- if (flags & LLE_DELETE)
- lle->la_flags = LLE_DELETED;
+ } else if (flags & LLE_DELETE) {
+ LLE_WLOCK(lle);
+ lle->la_flags = LLE_DELETED;
+ LLE_WUNLOCK(lle);
+#ifdef INVARIANTS
+ log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
+#endif
+ lle = NULL;
+ }
+ if (lle) {
+ if (flags & LLE_EXCLUSIVE)
+ LLE_WLOCK(lle);
+ else
+ LLE_RLOCK(lle);
}
- return lle;
+ return (lle);
}
static int
Modified: projects/arpv2_merge_1/sys/netinet6/in6_rmx.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/in6_rmx.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/netinet6/in6_rmx.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -307,7 +307,7 @@ in6_rtqkill(struct radix_node *rn, void
err = rtrequest(RTM_DELETE,
(struct sockaddr *)rt_key(rt),
rt->rt_gateway, rt_mask(rt),
- rt->rt_flags, 0);
+ rt->rt_flags|RTF_RNH_LOCKED, 0);
if (err) {
log(LOG_WARNING, "in6_rtqkill: error %d", err);
} else {
Modified: projects/arpv2_merge_1/sys/netinet6/ip6_input.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/ip6_input.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/netinet6/ip6_input.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -554,13 +554,14 @@ passin:
IF_AFDATA_LOCK(ifp);
lle = lla_lookup(LLTABLE6(ifp), 0,
(struct sockaddr *)&dst6);
+ IF_AFDATA_UNLOCK(ifp);
if ((lle != NULL) && (lle->la_flags & LLE_IFADDR)) {
ours = 1;
deliverifp = ifp;
- IF_AFDATA_UNLOCK(ifp);
+ LLE_RUNLOCK(lle);
goto hbhcheck;
}
- IF_AFDATA_UNLOCK(ifp);
+ LLE_RUNLOCK(lle);
if (ip6_forward_rt.ro_rt != NULL &&
(ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 &&
Modified: projects/arpv2_merge_1/sys/netinet6/ip6_mroute.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/ip6_mroute.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/netinet6/ip6_mroute.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -1612,10 +1612,8 @@ phyint_send(struct ip6_hdr *ip6, struct
* We just call if_output instead of nd6_output here, since
* we need no ND for a multicast forwarded packet...right?
*/
- IF_AFDATA_LOCK(ifp);
error = (*ifp->if_output)(ifp, mb_copy,
(struct sockaddr *)&ro.ro_dst, NULL);
- IF_AFDATA_UNLOCK(ifp);
#ifdef MRT6DEBUG
if (V_mrt6debug & DEBUG_XMIT)
log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
Modified: projects/arpv2_merge_1/sys/netinet6/ip6_output.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/ip6_output.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/netinet6/ip6_output.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -949,9 +949,7 @@ passout:
ia6->ia_ifa.if_opackets++;
ia6->ia_ifa.if_obytes += m->m_pkthdr.len;
}
- IF_AFDATA_LOCK(ifp);
error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
- IF_AFDATA_UNLOCK(ifp);
goto done;
}
@@ -1090,9 +1088,7 @@ sendorfree:
ia->ia_ifa.if_opackets++;
ia->ia_ifa.if_obytes += m->m_pkthdr.len;
}
- IF_AFDATA_LOCK(ifp);
error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
- IF_AFDATA_UNLOCK(ifp);
} else
m_freem(m);
}
Modified: projects/arpv2_merge_1/sys/netinet6/nd6.c
==============================================================================
--- projects/arpv2_merge_1/sys/netinet6/nd6.c Wed Dec 10 05:50:07 2008 (r185838)
+++ projects/arpv2_merge_1/sys/netinet6/nd6.c Wed Dec 10 06:01:27 2008 (r185839)
@@ -48,6 +48,8 @@ __FBSDID("$FreeBSD$");
#include <sys/protosw.h>
#include <sys/errno.h>
#include <sys/syslog.h>
+#include <sys/lock.h>
+#include <sys/rwlock.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
@@ -99,6 +101,11 @@ int nd6_maxqueuelen;
int nd6_debug;
+/* for debugging? */
+#if 0
+static int nd6_inuse, nd6_allocated;
+#endif
+
struct nd_drhead nd_defrouter;
struct nd_prhead nd_prefix;
@@ -160,6 +167,13 @@ nd6_init(void)
V_dad_ignore_ns = 0; /* ignore NS in DAD - specwise incorrect*/
V_dad_maxtry = 15; /* max # of *tries* to transmit DAD packet */
+ /*
+ * XXX just to get this to compile KMM
+ */
+#ifdef notyet
+ V_llinfo_nd6.ln_next = &V_llinfo_nd6;
+ V_llinfo_nd6.ln_prev = &V_llinfo_nd6;
+#endif
LIST_INIT(&V_nd_prefix);
ip6_use_tempaddr = 0;
@@ -422,12 +436,14 @@ skip1:
void
nd6_llinfo_settimer(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);
} else {
ln->la_expire = time_second + tick / hz;
+ LLE_ADDREF(ln);
if (tick > INT_MAX) {
ln->ln_ntick = tick - INT_MAX;
callout_reset(&ln->ln_timer_ch, INT_MAX,
@@ -438,6 +454,7 @@ nd6_llinfo_settimer(struct llentry *ln,
nd6_llinfo_timer, ln);
}
}
+ LLE_WUNLOCK(ln);
}
static void
@@ -460,6 +477,10 @@ 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) {
@@ -471,7 +492,7 @@ nd6_llinfo_timer(void *arg)
nd6_llinfo_settimer(ln, ln->ln_ntick);
}
IF_AFDATA_UNLOCK(ifp);
- return;
+ goto done;
}
ndi = ND_IFINFO(ifp);
@@ -479,13 +500,13 @@ nd6_llinfo_timer(void *arg)
if ((ln->la_flags & LLE_STATIC) || (ln->la_expire > time_second)) {
IF_AFDATA_UNLOCK(ifp);
- return;
+ goto done;
}
if (ln->la_flags & LLE_DELETED) {
(void)nd6_free(ln, 0);
IF_AFDATA_UNLOCK(ifp);
- return;
+ goto done;
}
switch (ln->ln_state) {
@@ -555,6 +576,8 @@ nd6_llinfo_timer(void *arg)
}
IF_AFDATA_UNLOCK(ifp);
CURVNET_RESTORE();
+done:
+ LLE_FREE_LOCKED(ln);
}
@@ -817,8 +840,12 @@ nd6_purge(struct ifnet *ifp)
nd6_setdefaultiface(0);
if (!V_ip6_forwarding && V_ip6_accept_rtadv) { /* XXX: too restrictive? */
- /* refresh default router list */
+ /* refresh default router list
+ *
+ *
+ */
defrouter_select();
+
}
/* XXXXX
@@ -828,44 +855,38 @@ nd6_purge(struct ifnet *ifp)
* from if_detach() where everything gets purged. So let
* in6_domifdetach() do the actual L2 table purging work.
*/
-#if 0
- /*
- * Nuke neighbor cache entries for the ifp.
- * Note that rt->rt_ifp may not be the same as ifp,
- * due to KAME goto ours hack. See RTM_RESOLVE case in
- * nd6_rtrequest(), and ip6_input().
- */
- IF_AFDATA_LOCK(ifp);
- lltable_free(LLTABLE6(ifp));
- IF_AFDATA_UNLOCK(ifp);
-#endif
}
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list