svn commit: r185785 - in user/kmacy/head_arpv2/sys: net netinet netinet6

Kip Macy kmacy at FreeBSD.org
Mon Dec 8 20:54:18 PST 2008


Author: kmacy
Date: Tue Dec  9 04:54:17 2008
New Revision: 185785
URL: http://svn.freebsd.org/changeset/base/185785

Log:
  - remove a number of cases of IF_AFDATA_LOCK recursion
  - implement LLE_EXCLUSIVE
  - implement LLE_FREE

Modified:
  user/kmacy/head_arpv2/sys/net/if_llatbl.c
  user/kmacy/head_arpv2/sys/net/if_llatbl.h
  user/kmacy/head_arpv2/sys/net/if_var.h
  user/kmacy/head_arpv2/sys/netinet/if_ether.c
  user/kmacy/head_arpv2/sys/netinet/in.c
  user/kmacy/head_arpv2/sys/netinet/ip_output.c
  user/kmacy/head_arpv2/sys/netinet6/icmp6.c
  user/kmacy/head_arpv2/sys/netinet6/in6.c
  user/kmacy/head_arpv2/sys/netinet6/nd6.c
  user/kmacy/head_arpv2/sys/netinet6/nd6_nbr.c

Modified: user/kmacy/head_arpv2/sys/net/if_llatbl.c
==============================================================================
--- user/kmacy/head_arpv2/sys/net/if_llatbl.c	Tue Dec  9 04:30:47 2008	(r185784)
+++ user/kmacy/head_arpv2/sys/net/if_llatbl.c	Tue Dec  9 04:54:17 2008	(r185785)
@@ -213,10 +213,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;
 			}

Modified: user/kmacy/head_arpv2/sys/net/if_llatbl.h
==============================================================================
--- user/kmacy/head_arpv2/sys/net/if_llatbl.h	Tue Dec  9 04:30:47 2008	(r185784)
+++ user/kmacy/head_arpv2/sys/net/if_llatbl.h	Tue Dec  9 04:54:17 2008	(r185785)
@@ -77,6 +77,7 @@ struct llentry {
 #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)
 
@@ -105,6 +106,18 @@ struct llentry {
 	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

Modified: user/kmacy/head_arpv2/sys/net/if_var.h
==============================================================================
--- user/kmacy/head_arpv2/sys/net/if_var.h	Tue Dec  9 04:30:47 2008	(r185784)
+++ user/kmacy/head_arpv2/sys/net/if_var.h	Tue Dec  9 04:54:17 2008	(r185785)
@@ -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: user/kmacy/head_arpv2/sys/netinet/if_ether.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet/if_ether.c	Tue Dec  9 04:30:47 2008	(r185784)
+++ user/kmacy/head_arpv2/sys/netinet/if_ether.c	Tue Dec  9 04:54:17 2008	(r185785)
@@ -156,15 +156,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);
 }
 
 
@@ -251,6 +258,7 @@ arpresolve(struct ifnet *ifp, struct rte
 	u_int flags;
 	int error;
 
+	log(LOG_DEBUG, "arpesolve called\n");
 	*lle = NULL;
 	if (m != NULL) {
 		if (m->m_flags & M_BCAST) {
@@ -280,11 +288,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,
@@ -297,12 +306,18 @@ arpresolve(struct ifnet *ifp, struct rte
 			    &SIN(dst)->sin_addr, IF_LLADDR(ifp));
 
 			la->la_preempt--;
-		} 
+		}
+		log(LOG_DEBUG, "arpresolve: success\n");
+		
 		*lle = la;
 		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));
@@ -319,7 +334,8 @@ arpresolve(struct ifnet *ifp, struct rte
 		if (la->la_hold)
 			m_freem(la->la_hold);
 		la->la_hold = m;
-		LLE_DOWNGRADE(la);
+		if (!(la->la_asked == 0 || la->la_expire != time_uptime))
+			LLE_DOWNGRADE(la);
 	}
 	/*
 	 * Return EWOULDBLOCK if we have tried less than arp_maxtries. It
@@ -334,12 +350,17 @@ arpresolve(struct ifnet *ifp, struct rte
 		    (rt0->rt_flags & RTF_GATEWAY) ? EHOSTDOWN : EHOSTUNREACH;
 
 	if (la->la_asked == 0 || la->la_expire != time_uptime) {
+		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);
 	}
 
 done:
@@ -435,6 +456,7 @@ in_arpinput(struct mbuf *m)
 	struct in_addr isaddr, itaddr, myaddr;
 	u_int8_t *enaddr = NULL;
 	int op, flags;
+	struct mbuf *m0;
 /*
 , rif_len;
 */
@@ -529,6 +551,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;
@@ -567,12 +590,13 @@ match:
 	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",
@@ -582,9 +606,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 "
@@ -603,6 +627,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)",
@@ -613,6 +638,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,
@@ -621,8 +647,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:
@@ -639,7 +670,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)
@@ -650,12 +680,12 @@ reply:
 			 * over who claims what Ether address.
 			 */
 			if (rt->rt_ifp == ifp) {
-				rtfree(rt);
+				RTFREE(rt);
 				goto drop;
 			}
 			(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
 			(void)memcpy(ar_sha(ah), enaddr, ah->ar_hln);
-			rtfree(rt);
+			RTFREE(rt);
 
 			/*
 			 * Also check that the node which sent the ARP packet
@@ -674,10 +704,10 @@ reply:
 				    " from %s via %s, expecting %s\n",
 				    inet_ntoa(isaddr), ifp->if_xname,
 				    rt->rt_ifp->if_xname);
-				rtfree(rt);
+				RTFREE(rt);
 				goto drop;
 			}
-			rtfree(rt);
+			RTFREE(rt);
 
 #ifdef DEBUG_PROXY
 			printf("arp: proxying for %s\n",

Modified: user/kmacy/head_arpv2/sys/netinet/in.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet/in.c	Tue Dec  9 04:30:47 2008	(r185784)
+++ user/kmacy/head_arpv2/sys/netinet/in.c	Tue Dec  9 04:54:17 2008	(r185785)
@@ -1077,10 +1077,10 @@ 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;
 }
 
@@ -1110,17 +1110,14 @@ in_lltable_lookup(struct lltable *llt, u
 			break;
 	}
 
-	if (lle != NULL ) {
-		if (flags & LLE_DELETE) {
-			LLE_WLOCK(lle);
-			lle->la_flags = LLE_DELETED;
-			LLE_WUNLOCK(lle);
+	if ((lle != NULL) && (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);	
+		log(LOG_INFO, "ifaddr cache = %p  is deleted\n", lle);	
 #endif
-			lle = NULL;
-		} else 
-			LLE_RLOCK(lle);
+		lle = NULL;
 	} else {
 #ifdef INVARIANTS
 		if (flags & LLE_DELETE)
@@ -1150,9 +1147,14 @@ 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);
 	} 
+	if (lle) {
+		if (flags & LLE_EXCLUSIVE)
+			LLE_WLOCK(lle);
+		else
+			LLE_RLOCK(lle);
+	}
 done:
 	return (lle);
 }

Modified: user/kmacy/head_arpv2/sys/netinet/ip_output.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet/ip_output.c	Tue Dec  9 04:30:47 2008	(r185784)
+++ user/kmacy/head_arpv2/sys/netinet/ip_output.c	Tue Dec  9 04:54:17 2008	(r185785)
@@ -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: user/kmacy/head_arpv2/sys/netinet6/icmp6.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet6/icmp6.c	Tue Dec  9 04:30:47 2008	(r185784)
+++ user/kmacy/head_arpv2/sys/netinet6/icmp6.c	Tue Dec  9 04:54:17 2008	(r185785)
@@ -2583,17 +2583,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 +2601,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: user/kmacy/head_arpv2/sys/netinet6/in6.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet6/in6.c	Tue Dec  9 04:30:47 2008	(r185784)
+++ user/kmacy/head_arpv2/sys/netinet6/in6.c	Tue Dec  9 04:54:17 2008	(r185785)
@@ -2215,10 +2215,23 @@ in6_lltable_lookup(struct lltable *llt, 
 		lle->lle_head = lleh;
 		LIST_INSERT_HEAD(lleh, lle, lle_next);
 	} else {
-		if (flags & LLE_DELETE)
+		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: user/kmacy/head_arpv2/sys/netinet6/nd6.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet6/nd6.c	Tue Dec  9 04:30:47 2008	(r185784)
+++ user/kmacy/head_arpv2/sys/netinet6/nd6.c	Tue Dec  9 04:54:17 2008	(r185785)
@@ -840,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
@@ -851,21 +855,11 @@ 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
 }
 
 /* Qing
  * the caller acquires and releases the lock on the lltbls
+ * Returns the llentry locked
  */
 struct llentry *
 nd6_lookup(struct in6_addr *addr6, int flags, struct ifnet *ifp)
@@ -880,6 +874,8 @@ nd6_lookup(struct in6_addr *addr6, int f
 	sin6.sin6_family = AF_INET6;
 	sin6.sin6_addr = *addr6;
 
+	IF_AFDATA_LOCK_ASSERT(ifp);
+
 	if (flags & ND6_CREATE)
 	    llflags |= LLE_CREATE;
 	if (flags & ND6_EXCLUSIVE)
@@ -890,6 +886,7 @@ nd6_lookup(struct in6_addr *addr6, int f
 		ln->ln_state = ND6_LLINFO_NOSTATE;
 		callout_init(&ln->ln_timer_ch, 0);
 	}
+	
 	return (ln);
 }
 
@@ -978,7 +975,8 @@ nd6_is_addr_neighbor(struct sockaddr_in6
 {
 	struct llentry *lle;
 	int rc = 0;
-	
+
+	IF_AFDATA_UNLOCK_ASSERT(ifp);
 	if (nd6_is_new_addr_neighbor(addr, ifp))
 		return (1);
 
@@ -1401,6 +1399,8 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
 	int flags = 0;
 	int newstate = 0;
 
+	IF_AFDATA_LOCK_ASSERT(ifp);
+
 	if (ifp == NULL)
 		panic("ifp == NULL in nd6_cache_lladdr");
 	if (from == NULL)
@@ -1598,16 +1598,27 @@ nd6_cache_lladdr(struct ifnet *ifp, stru
 	 * for those are not autoconfigured hosts, we explicitly avoid such
 	 * cases for safety.
 	 */
-	if (do_update && ln->ln_router && !V_ip6_forwarding && V_ip6_accept_rtadv)
+	if (do_update && ln->ln_router && !V_ip6_forwarding && V_ip6_accept_rtadv) {
+#ifdef notyet
+		/*
+		 * XXX implement the boiler plate
+		 */
+		taskqueue_enqueue(ipv6_taskq, defrouter_select_task);
+#endif
+		/*
+		 * guaranteed recursion
+		 */
 		defrouter_select();
+	}
+	
 done:	
 	if (ln) {
-		if (ln->la_flags & LLE_STATIC)
-			ln = NULL;
 		if (lladdr)
 			LLE_WUNLOCK(ln);
 		else
 			LLE_RUNLOCK(ln);
+		if (ln->la_flags & LLE_STATIC)
+			ln = NULL;
 	}
 	return (ln);
 }
@@ -1680,7 +1691,9 @@ nd6_output(struct ifnet *ifp, struct ifn
 	 * or an anycast address(i.e. not a multicast).
 	 */
 	flags = m ? LLE_EXCLUSIVE : 0;
+	IF_AFDATA_LOCK(rt->rt_ifp);
 	ln = lla_lookup(LLTABLE6(ifp), 0, (struct sockaddr *)dst);
+	IF_AFDATA_UNLOCK(rt->rt_ifp);
 	if ((ln == NULL) && nd6_is_addr_neighbor(dst, ifp))  {
 		/*
 		 * Since nd6_is_addr_neighbor() internally calls nd6_lookup(),
@@ -1688,7 +1701,9 @@ nd6_output(struct ifnet *ifp, struct ifn
 		 * it is tolerable, because this should be a rare case.
 		 */
 		flags = ND6_CREATE | (m ? ND6_EXCLUSIVE : 0);
+		IF_AFDATA_LOCK(rt->rt_ifp);
 		ln = nd6_lookup(&dst->sin6_addr, flags, ifp);
+		IF_AFDATA_UNLOCK(rt->rt_ifp);
 	}
 	if (ln == NULL) {
 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0 &&
@@ -1700,7 +1715,6 @@ nd6_output(struct ifnet *ifp, struct ifn
 			    ip6_sprintf(ip6buf, &dst->sin6_addr), ln, rt);
 			senderr(EIO);	/* XXX: good error? */
 		}
-
 		goto sendpkt;	/* send anyway */
 	}
 
@@ -1786,6 +1800,12 @@ nd6_output(struct ifnet *ifp, struct ifn
 		error = ENETDOWN; /* better error? */
 		goto bad;
 	}
+	if (ln) {
+		if (m0)
+			LLE_WUNLOCK(ln);
+		else
+			LLE_RUNLOCK(ln);
+	}
 
 #ifdef MAC
 	mac_netinet6_nd6_send(ifp, m);

Modified: user/kmacy/head_arpv2/sys/netinet6/nd6_nbr.c
==============================================================================
--- user/kmacy/head_arpv2/sys/netinet6/nd6_nbr.c	Tue Dec  9 04:30:47 2008	(r185784)
+++ user/kmacy/head_arpv2/sys/netinet6/nd6_nbr.c	Tue Dec  9 04:54:17 2008	(r185785)
@@ -115,7 +115,7 @@ nd6_ns_input(struct mbuf *m, int off, in
 	struct ifaddr *ifa = NULL;
 	int lladdrlen = 0;
 	int anycast = 0, proxy = 0, tentative = 0;
-	int tlladdr;
+	int tlladdr, error;
 	union nd_opts ndopts;
 	struct sockaddr_dl *proxydl = NULL;
 	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
@@ -169,7 +169,8 @@ nd6_ns_input(struct mbuf *m, int off, in
 		src_sa6.sin6_family = AF_INET6;
 		src_sa6.sin6_len = sizeof(src_sa6);
 		src_sa6.sin6_addr = saddr6;
-		if (!nd6_is_addr_neighbor(&src_sa6, ifp)) {
+		error = nd6_is_addr_neighbor(&src_sa6, ifp);
+		if (error) {
 			nd6log((LOG_INFO, "nd6_ns_input: "
 				"NS packet from non-neighbor\n"));
 			goto bad;
@@ -701,8 +702,8 @@ nd6_na_input(struct mbuf *m, int off, in
 	 */
 	IF_AFDATA_LOCK(ifp);
 	ln = nd6_lookup(&taddr6, 0, ifp);
+	IF_AFDATA_UNLOCK(ifp);
 	if (ln == NULL) {
-		IF_AFDATA_UNLOCK(ifp);
 		goto freeit;
 	}
 
@@ -712,7 +713,6 @@ nd6_na_input(struct mbuf *m, int off, in
 		 * discard the packet.
 		 */
 		if (ifp->if_addrlen && lladdr == NULL) {
-			IF_AFDATA_UNLOCK(ifp);
 			goto freeit;
 		}
 
@@ -786,7 +786,6 @@ nd6_na_input(struct mbuf *m, int off, in
 				ln->ln_state = ND6_LLINFO_STALE;
 				nd6_llinfo_settimer(ln, (long)V_nd6_gctimer * hz);
 			}
-			IF_AFDATA_UNLOCK(ifp);
 			goto freeit;
 		} else if (is_override				   /* (2a) */
 			|| (!is_override && (lladdr != NULL && !llchange)) /* (2b) */
@@ -883,8 +882,6 @@ nd6_na_input(struct mbuf *m, int off, in
 			nd6_output(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL);
 		}
 	}
-	IF_AFDATA_UNLOCK(ifp);
-
  freeit:
 	m_freem(m);
 	return;


More information about the svn-src-user mailing list