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