svn commit: r185738 - in user/kmacy/head_arpv2/sys: net netinet
netinet6
Kip Macy
kmacy at FreeBSD.org
Sat Dec 6 23:02:27 PST 2008
Author: kmacy
Date: Sun Dec 7 07:02:26 2008
New Revision: 185738
URL: http://svn.freebsd.org/changeset/base/185738
Log:
- add refcount and rwlock to llentry
- reduce coverage of AFDATA lock
Modified:
user/kmacy/head_arpv2/sys/net/if_llatbl.c
user/kmacy/head_arpv2/sys/net/if_llatbl.h
user/kmacy/head_arpv2/sys/netinet/if_ether.c
user/kmacy/head_arpv2/sys/netinet/in.c
user/kmacy/head_arpv2/sys/netinet6/in6.c
user/kmacy/head_arpv2/sys/netinet6/ip6_input.c
user/kmacy/head_arpv2/sys/netinet6/nd6.c
user/kmacy/head_arpv2/sys/netinet6/nd6.h
Modified: user/kmacy/head_arpv2/sys/net/if_llatbl.c
==============================================================================
--- user/kmacy/head_arpv2/sys/net/if_llatbl.c Sun Dec 7 06:34:50 2008 (r185737)
+++ user/kmacy/head_arpv2/sys/net/if_llatbl.c Sun Dec 7 07:02:26 2008 (r185738)
@@ -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);
}
/*
Modified: user/kmacy/head_arpv2/sys/net/if_llatbl.h
==============================================================================
--- user/kmacy/head_arpv2/sys/net/if_llatbl.h Sun Dec 7 06:34:50 2008 (r185737)
+++ user/kmacy/head_arpv2/sys/net/if_llatbl.h Sun Dec 7 07:02:26 2008 (r185738)
@@ -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,40 @@ 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_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 ln_timer_ch lle_timer.ln_timer_ch
#define la_timer lle_timer.la_timer
@@ -105,8 +147,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: user/kmacy/head_arpv2/sys/netinet/if_ether.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet/if_ether.c Sun Dec 7 06:34:50 2008 (r185737)
+++ user/kmacy/head_arpv2/sys/netinet/if_ether.c Sun Dec 7 07:02:26 2008 (r185738)
@@ -130,20 +130,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
@@ -257,7 +252,6 @@ arpresolve(struct ifnet *ifp, struct rte
int error;
*lle = NULL;
-
if (m != NULL) {
if (m->m_flags & M_BCAST) {
/* broadcast */
@@ -273,6 +267,7 @@ arpresolve(struct ifnet *ifp, struct rte
}
flags = (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) ? 0 : LLE_CREATE;
+ flags |= (m ? LLE_EXCLUSIVE : 0);
/* XXXXX
* Since this function returns an llentry, the
@@ -304,14 +299,16 @@ arpresolve(struct ifnet *ifp, struct rte
la->la_preempt--;
}
*lle = la;
- return (0);
+ error = 0;
+ goto done;
}
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;
}
/*
* There is an arptab entry, but no ethernet address
@@ -322,6 +319,7 @@ arpresolve(struct ifnet *ifp, struct rte
if (la->la_hold)
m_freem(la->la_hold);
la->la_hold = m;
+ LLE_DOWNGRADE(la);
}
/*
* Return EWOULDBLOCK if we have tried less than arp_maxtries. It
@@ -344,7 +342,9 @@ arpresolve(struct ifnet *ifp, struct rte
IF_LLADDR(ifp));
}
- return (EWOULDBLOCK);
+done:
+ LLE_RUNLOCK(la);
+ return (error);
}
/*
@@ -434,7 +434,7 @@ in_arpinput(struct mbuf *m)
struct sockaddr sa;
struct in_addr isaddr, itaddr, myaddr;
u_int8_t *enaddr = NULL;
- int op, flag;
+ int op, flags;
/*
, rif_len;
*/
@@ -561,9 +561,11 @@ 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);
- 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) {
/* the following is not an error when doing bridging */
if (!bridged && la->lle_tbl->llt_ifp != ifp
@@ -698,8 +700,8 @@ reply:
}
}
- IF_AFDATA_UNLOCK(ifp);
-
+ 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. */
@@ -725,7 +727,8 @@ reply:
return;
drop:
- IF_AFDATA_UNLOCK(ifp);
+ if (la)
+ LLE_WUNLOCK(la);
m_freem(m);
}
#endif
@@ -750,6 +753,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: user/kmacy/head_arpv2/sys/netinet/in.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet/in.c Sun Dec 7 06:34:50 2008 (r185737)
+++ user/kmacy/head_arpv2/sys/netinet/in.c Sun Dec 7 07:02:26 2008 (r185738)
@@ -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;
}
@@ -1083,6 +1084,11 @@ in_lltable_rtcheck(struct ifnet *ifp, co
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)
{
@@ -1104,7 +1110,22 @@ in_lltable_lookup(struct lltable *llt, u
break;
}
- if (lle == NULL) {
+ if (lle != NULL ) {
+ 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;
+ } else
+ LLE_RLOCK(lle);
+ } else {
+#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 +1135,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)) {
@@ -1129,12 +1150,11 @@ in_lltable_lookup(struct lltable *llt, u
lle->lle_tbl = llt;
lle->lle_head = lleh;
+ LLE_RLOCK(lle);
LIST_INSERT_HEAD(lleh, lle, lle_next);
- } else {
- if (flags & LLE_DELETE)
- lle->la_flags = LLE_DELETED;
- }
- return lle;
+ }
+done:
+ return (lle);
}
static int
Modified: user/kmacy/head_arpv2/sys/netinet6/in6.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet6/in6.c Sun Dec 7 06:34:50 2008 (r185737)
+++ user/kmacy/head_arpv2/sys/netinet6/in6.c Sun Dec 7 07:02:26 2008 (r185738)
@@ -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;
}
Modified: user/kmacy/head_arpv2/sys/netinet6/ip6_input.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet6/ip6_input.c Sun Dec 7 06:34:50 2008 (r185737)
+++ user/kmacy/head_arpv2/sys/netinet6/ip6_input.c Sun Dec 7 07:02:26 2008 (r185738)
@@ -554,13 +554,13 @@ 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);
if (ip6_forward_rt.ro_rt != NULL &&
(ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 &&
Modified: user/kmacy/head_arpv2/sys/netinet6/nd6.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet6/nd6.c Sun Dec 7 06:34:50 2008 (r185737)
+++ user/kmacy/head_arpv2/sys/netinet6/nd6.c Sun Dec 7 07:02:26 2008 (r185738)
@@ -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>
@@ -434,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,
@@ -450,6 +454,7 @@ nd6_llinfo_settimer(struct llentry *ln,
nd6_llinfo_timer, ln);
}
}
+ LLE_WUNLOCK(ln);
}
static void
@@ -472,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) {
@@ -483,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);
@@ -491,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) {
@@ -567,6 +576,8 @@ nd6_llinfo_timer(void *arg)
}
IF_AFDATA_UNLOCK(ifp);
CURVNET_RESTORE();
+done:
+ LLE_FREE_LOCKED(ln);
}
@@ -853,27 +864,28 @@ nd6_purge(struct ifnet *ifp)
#endif
}
-
-
/* Qing
* the caller acquires and releases the lock on the lltbls
*/
struct llentry *
-nd6_lookup(struct in6_addr *addr6, int create, struct ifnet *ifp)
+nd6_lookup(struct in6_addr *addr6, int flags, struct ifnet *ifp)
{
INIT_VNET_INET6(curvnet);
struct sockaddr_in6 sin6;
struct llentry *ln;
- int flags = 0;
-
+ int llflags = 0;
+
bzero(&sin6, sizeof(sin6));
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_family = AF_INET6;
sin6.sin6_addr = *addr6;
- if (create)
- flags |= LLE_CREATE;
- ln = lla_lookup(LLTABLE6(ifp), flags, (struct sockaddr *)&sin6);
+ if (flags & ND6_CREATE)
+ llflags |= LLE_CREATE;
+ if (flags & ND6_EXCLUSIVE)
+ llflags |= LLE_EXCLUSIVE;
+
+ ln = lla_lookup(LLTABLE6(ifp), llflags, (struct sockaddr *)&sin6);
if ((ln != NULL) && (flags & LLE_CREATE)) {
ln->ln_state = ND6_LLINFO_NOSTATE;
callout_init(&ln->ln_timer_ch, 0);
@@ -964,7 +976,9 @@ nd6_is_new_addr_neighbor(struct sockaddr
int
nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
{
-
+ struct llentry *lle;
+ int rc = 0;
+
if (nd6_is_new_addr_neighbor(addr, ifp))
return (1);
@@ -973,12 +987,12 @@ nd6_is_addr_neighbor(struct sockaddr_in6
* in the neighbor cache.
*/
IF_AFDATA_LOCK(ifp);
- if (nd6_lookup(&addr->sin6_addr, 0, ifp) != NULL) {
- IF_AFDATA_UNLOCK(ifp);
- return (1);
+ if ((lle = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) {
+ LLE_RUNLOCK(lle);
+ rc = 1;
}
IF_AFDATA_UNLOCK(ifp);
- return (0);
+ return (rc);
}
/*
@@ -1104,15 +1118,13 @@ nd6_nud_hint(struct rtentry *rt, struct
return;
IF_AFDATA_LOCK(ifp);
- if ((ln = nd6_lookup(dst6, 0, NULL)) == NULL) {
- IF_AFDATA_UNLOCK(ifp);
+ ln = nd6_lookup(dst6, ND6_EXCLUSIVE, NULL);
+ IF_AFDATA_UNLOCK(ifp);
+ if (ln == NULL)
return;
- }
- if (ln->ln_state < ND6_LLINFO_REACHABLE) {
- IF_AFDATA_UNLOCK(ifp);
- return;
- }
+ if (ln->ln_state < ND6_LLINFO_REACHABLE)
+ goto done;
/*
* if we get upper-layer reachability confirmation many times,
@@ -1121,17 +1133,17 @@ nd6_nud_hint(struct rtentry *rt, struct
if (!force) {
ln->ln_byhint++;
if (ln->ln_byhint > V_nd6_maxnudhint) {
- IF_AFDATA_UNLOCK(ifp);
- return;
+ goto done;
}
}
- ln->ln_state = ND6_LLINFO_REACHABLE;
+ ln->ln_state = ND6_LLINFO_REACHABLE;
if (!ND6_LLINFO_PERMANENT(ln)) {
nd6_llinfo_settimer(ln,
(long)ND_IFINFO(rt->rt_ifp)->reachable * hz);
}
- IF_AFDATA_UNLOCK(ifp);
+done:
+ LLE_WUNLOCK(ln);
}
@@ -1342,17 +1354,18 @@ nd6_ioctl(u_long cmd, caddr_t data, stru
return (error);
IF_AFDATA_LOCK(ifp);
- if ((ln = nd6_lookup(&nb_addr, 0, ifp)) == NULL) {
+ ln = nd6_lookup(&nb_addr, 0, ifp);
+ IF_AFDATA_UNLOCK(ifp);
+
+ if (ln == NULL) {
error = EINVAL;
- IF_AFDATA_UNLOCK(ifp);
break;
}
nbi->state = ln->ln_state;
nbi->asked = ln->la_asked;
nbi->isrouter = ln->ln_router;
nbi->expire = ln->la_expire;
- IF_AFDATA_UNLOCK(ifp);
-
+ LLE_RUNLOCK(ln);
break;
}
case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */
@@ -1385,6 +1398,7 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
int do_update;
int olladdr;
int llchange;
+ int flags = 0;
int newstate = 0;
if (ifp == NULL)
@@ -1405,27 +1419,25 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
* Spec says nothing in sections for RA, RS and NA. There's small
* description on it in NS section (RFC 2461 7.2.3).
*/
- ln = nd6_lookup(from, 0, ifp);
+ flags |= lladdr ? ND6_EXCLUSIVE : 0;
+ ln = nd6_lookup(from, flags, ifp);
if (ln == NULL) {
- ln = nd6_lookup(from, 1, ifp);
+ ln = nd6_lookup(from, flags |ND6_CREATE, ifp);
is_newentry = 1;
} else {
/* do nothing if static ndp is set */
if (ln->la_flags & LLE_STATIC)
- return NULL;
+ goto done;
is_newentry = 0;
}
- if (ln == NULL) {
- return NULL;
- }
+ if (ln == NULL)
+ return (NULL);
olladdr = (ln->la_flags & LLE_VALID) ? 1 : 0;
if (olladdr && lladdr) {
- if (bcmp(lladdr, &ln->ll_addr, ifp->if_addrlen))
- llchange = 1;
- else
- llchange = 0;
+ llchange = bcmp(lladdr, &ln->ll_addr,
+ ifp->if_addrlen);
} else
llchange = 0;
@@ -1588,8 +1600,16 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
*/
if (do_update && ln->ln_router && !V_ip6_forwarding && V_ip6_accept_rtadv)
defrouter_select();
-
- return ln;
+done:
+ if (ln) {
+ if (ln->la_flags & LLE_STATIC)
+ ln = NULL;
+ if (lladdr)
+ LLE_WUNLOCK(ln);
+ else
+ LLE_RUNLOCK(ln);
+ }
+ return (ln);
}
static void
@@ -1623,6 +1643,14 @@ nd6_slowtimo(void *arg)
CURVNET_RESTORE();
}
+/*
+ * Note that I'm not enforcing any global serialization
+ * lle state or asked changes here as the logic is too
+ * complicated to avoid having to always acquire an exclusive
+ * lock
+ * KMM
+ *
+ */
#define senderr(e) { error = (e); goto bad;}
int
nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
@@ -1633,6 +1661,7 @@ nd6_output(struct ifnet *ifp, struct ifn
struct rtentry *rt = rt0;
struct llentry *ln = NULL;
int error = 0;
+ int flags = 0;
if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
goto sendpkt;
@@ -1650,6 +1679,7 @@ 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;
ln = lla_lookup(LLTABLE6(ifp), 0, (struct sockaddr *)dst);
if ((ln == NULL) && nd6_is_addr_neighbor(dst, ifp)) {
/*
@@ -1657,7 +1687,8 @@ nd6_output(struct ifnet *ifp, struct ifn
* the condition below is not very efficient. But we believe
* it is tolerable, because this should be a rare case.
*/
- ln = nd6_lookup(&dst->sin6_addr, 1, ifp);
+ flags = ND6_CREATE | (m ? ND6_EXCLUSIVE : 0);
+ ln = nd6_lookup(&dst->sin6_addr, flags, ifp);
}
if (ln == NULL) {
if ((ifp->if_flags & IFF_POINTOPOINT) == 0 &&
@@ -1742,6 +1773,11 @@ nd6_output(struct ifnet *ifp, struct ifn
(long)ND_IFINFO(ifp)->retrans * hz / 1000);
nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0);
}
+ if (m0)
+ LLE_WUNLOCK(ln);
+ else
+ LLE_RUNLOCK(ln);
+
return (0);
sendpkt:
@@ -1762,6 +1798,12 @@ nd6_output(struct ifnet *ifp, struct ifn
return (error);
bad:
+ if (ln) {
+ if (m0)
+ LLE_WUNLOCK(ln);
+ else
+ LLE_RUNLOCK(ln);
+ }
if (m)
m_freem(m);
return (error);
Modified: user/kmacy/head_arpv2/sys/netinet6/nd6.h
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet6/nd6.h Sun Dec 7 06:34:50 2008 (r185737)
+++ user/kmacy/head_arpv2/sys/netinet6/nd6.h Sun Dec 7 07:02:26 2008 (r185738)
@@ -85,6 +85,9 @@ struct nd_ifinfo {
*/
#define ND6_IFF_DONT_SET_IFROUTE 0x10
+#define ND6_CREATE 0x1
+#define ND6_EXCLUSIVE 0x2
+
#ifdef _KERNEL
#define ND_IFINFO(ifp) \
(((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->nd_ifinfo)
More information about the svn-src-user
mailing list