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