From owner-svn-src-user@FreeBSD.ORG Sun Dec 7 07:02:27 2008 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 7E1D2106564A; Sun, 7 Dec 2008 07:02:27 +0000 (UTC) (envelope-from kmacy@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 6C3AC8FC12; Sun, 7 Dec 2008 07:02:27 +0000 (UTC) (envelope-from kmacy@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id mB772RjU017238; Sun, 7 Dec 2008 07:02:27 GMT (envelope-from kmacy@svn.freebsd.org) Received: (from kmacy@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id mB772Qdp017229; Sun, 7 Dec 2008 07:02:26 GMT (envelope-from kmacy@svn.freebsd.org) Message-Id: <200812070702.mB772Qdp017229@svn.freebsd.org> From: Kip Macy Date: Sun, 7 Dec 2008 07:02:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r185738 - in user/kmacy/head_arpv2/sys: net netinet netinet6 X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 07 Dec 2008 07:02:27 -0000 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 #include #include +#include #include #include @@ -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 #include 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 #include #include +#include +#include #include #include @@ -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)