Date: Wed, 10 Dec 2008 06:01:27 +0000 (UTC) From: Kip Macy <kmacy@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r185839 - in projects/arpv2_merge_1/sys: net netinet netinet6 Message-ID: <200812100601.mBA61RqB020268@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200812100601.mBA61RqB020268>