Do more fine-grained lltable locking: use table runtime lock as rare

as we can.
This commit is contained in:
Alexander V. Chernikov 2014-11-23 15:38:06 +00:00
parent 9479029b1f
commit 73d770287d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/routing/; revision=274917
10 changed files with 157 additions and 134 deletions

View File

@ -774,16 +774,16 @@ if_attachdomain1(struct ifnet *ifp)
* Since dp->dom_ifattach calls malloc() with M_WAITOK, we
* cannot lock ifp->if_afdata initialization, entirely.
*/
if (IF_AFDATA_TRY_WLOCK(ifp) == 0)
if (IF_AFDATA_CFG_TRY_WLOCK(ifp) == 0)
return;
if (ifp->if_afdata_initialized >= domain_init_status) {
IF_AFDATA_UNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
log(LOG_WARNING, "%s called more than once on %s\n",
__func__, ifp->if_xname);
return;
}
ifp->if_afdata_initialized = domain_init_status;
IF_AFDATA_UNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
/* address family dependent data region */
bzero(ifp->if_afdata, sizeof(ifp->if_afdata));
@ -961,10 +961,10 @@ if_detach_internal(struct ifnet *ifp, int vmove)
* sleep, for example trying to drain a callout, thus open up the
* theoretical race with re-attaching.
*/
IF_AFDATA_LOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
i = ifp->if_afdata_initialized;
ifp->if_afdata_initialized = 0;
IF_AFDATA_UNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
for (dp = domains; i > 0 && dp; dp = dp->dom_next) {
if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
(*dp->dom_ifdetach)(ifp,
@ -3967,36 +3967,10 @@ if_afdata_cfg_wunlock(struct ifnet *ifp)
rw_wunlock(&ifp->if_afdata_cfg_lock);
}
void
if_afdata_cfg_lock_assert(struct ifnet *ifp, int what)
{
rw_assert(&ifp->if_afdata_cfg_lock, what);
}
void
if_afdata_wlock(struct ifnet *ifp)
{
if_afdata_cfg_wlock(ifp);
IF_AFDATA_RUN_WLOCK(ifp);
}
void
if_afdata_wunlock(struct ifnet *ifp)
{
if_afdata_cfg_wunlock(ifp);
IF_AFDATA_RUN_WUNLOCK(ifp);
}
int
if_afdata_try_wlock(struct ifnet *ifp)
if_afdata_cfg_try_wlock(struct ifnet *ifp)
{
if (rw_try_wlock(&ifp->if_afdata_cfg_lock) == 0)
return (0);
IF_AFDATA_RUN_WLOCK(ifp);
return (1);
return (rw_try_wlock(&ifp->if_afdata_cfg_lock));
}

View File

@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/rwlock.h>
#include <sys/rmlock.h>
#ifdef DDB
#include <ddb/ddb.h>
@ -99,6 +100,11 @@ llentry_link(struct lltable *llt, struct llentry *lle)
struct llentries *lleh;
uint32_t hashkey;
if ((lle->la_flags & LLE_LINKED) != 0)
return;
IF_AFDATA_RUN_WLOCK_ASSERT(llt->llt_ifp);
hashkey = llt->llt_hash(lle);
lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
@ -112,11 +118,14 @@ void
llentry_unlink(struct llentry *lle)
{
if ((lle->la_flags & LLE_LINKED) != 0) {
IF_AFDATA_RUN_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
LIST_REMOVE(lle, lle_next);
lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
lle->lle_tbl = NULL;
lle->lle_head = NULL;
}
}
void
llentries_unlink(struct llentries *head)
@ -143,12 +152,7 @@ llentry_free(struct llentry *lle)
struct mbuf *next;
LLE_WLOCK_ASSERT(lle);
if ((lle->la_flags & LLE_LINKED) != 0) {
IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
LIST_REMOVE(lle, lle_next);
lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
}
KASSERT((lle->la_flags & LLE_LINKED) == 0, ("Freeing linked lle"));
pkts_dropped = 0;
while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
@ -172,6 +176,8 @@ llentry_free(struct llentry *lle)
* (al)locate an llentry for address dst (equivalent to rtalloc for new-arp).
*
* If found the llentry * is returned referenced and unlocked.
*
* XXX: Remove after converting flowtable
*/
struct llentry *
llentry_alloc(struct ifnet *ifp, struct lltable *lt,
@ -184,9 +190,14 @@ llentry_alloc(struct ifnet *ifp, struct lltable *lt,
IF_AFDATA_RUNLOCK(ifp);
if ((la == NULL) &&
(ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
IF_AFDATA_WLOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
la = lla_create(lt, 0, (struct sockaddr *)dst);
IF_AFDATA_WUNLOCK(ifp);
if (la != NULL) {
IF_AFDATA_RUN_WLOCK(ifp);
llentry_link(lt, la);
IF_AFDATA_RUN_WUNLOCK(ifp);
}
IF_AFDATA_CFG_WUNLOCK(ifp);
}
if (la != NULL) {
@ -204,6 +215,7 @@ void
lltable_free(struct lltable *llt)
{
struct llentry *lle, *next;
struct llentries dchain;
int i;
KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
@ -212,7 +224,8 @@ lltable_free(struct lltable *llt)
SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
LLTABLE_WUNLOCK();
IF_AFDATA_WLOCK(llt->llt_ifp);
LIST_INIT(&dchain);
IF_AFDATA_CFG_WLOCK(llt->llt_ifp);
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
LLE_WLOCK(lle);
@ -220,10 +233,15 @@ lltable_free(struct lltable *llt)
LLE_REMREF(lle);
lle->la_flags &= ~LLE_CALLOUTREF;
}
LIST_INSERT_HEAD(&dchain, lle, lle_chain);
}
}
IF_AFDATA_RUN_WLOCK(llt->llt_ifp);
llentries_unlink(&dchain);
IF_AFDATA_RUN_WUNLOCK(llt->llt_ifp);
LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next)
llentry_free(lle);
}
}
IF_AFDATA_WUNLOCK(llt->llt_ifp);
IF_AFDATA_CFG_WUNLOCK(llt->llt_ifp);
free(llt, M_LLTABLE);
}
@ -337,14 +355,15 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
switch (rtm->rtm_type) {
case RTM_ADD:
/* Add static LLE */
IF_AFDATA_WLOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
lle = lla_create(llt, 0, dst);
if (lle == NULL) {
IF_AFDATA_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
return (ENOMEM);
}
IF_AFDATA_RUN_WLOCK(ifp);
bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen);
if ((rtm->rtm_flags & RTF_ANNOUNCE))
lle->la_flags |= LLE_PUB;
@ -366,9 +385,11 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
lle->la_expire = 0;
} else
lle->la_expire = rtm->rtm_rmx.rmx_expire;
llentry_link(llt, lle);
IF_AFDATA_RUN_WUNLOCK(ifp);
laflags = lle->la_flags;
LLE_WUNLOCK(lle);
IF_AFDATA_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
#ifdef INET
/* gratuitous ARP */
if ((laflags & LLE_PUB) && dst->sa_family == AF_INET)
@ -381,9 +402,9 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
break;
case RTM_DELETE:
IF_AFDATA_WLOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
error = lla_delete(llt, 0, dst);
IF_AFDATA_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
return (error == 0 ? 0 : ENOENT);
default:

View File

@ -355,17 +355,26 @@ EVENTHANDLER_DECLARE(group_change_event, group_change_event_handler_t);
#define IF_AFDATA_CFG_RUNLOCK(ifp) if_afdata_cfg_runlock(ifp)
#define IF_AFDATA_CFG_WLOCK(ifp) if_afdata_cfg_wlock(ifp)
#define IF_AFDATA_CFG_WUNLOCK(ifp) if_afdata_cfg_wunlock(ifp)
#define IF_AFDATA_CFG_TRY_WLOCK(ifp) if_afdata_cfg_try_wlock(ifp)
#define IF_AFDATA_CFG_LOCK_ASSERT(i) if_afdata_cfg_lock_assert(i, RA_LOCKED)
#define IF_AFDATA_CFG_RLOCK_ASSERT(i) if_afdata_cfg_lock_assert(i, RA_RLOCKED)
#define IF_AFDATA_CFG_WLOCK_ASSERT(i) if_afdata_cfg_lock_assert(i, RA_WLOCKED)
#define IF_AFDATA_CFG_UNLOCK_ASSERT(i) if_afdata_cfg_lock_assert(i,RA_UNLOCKED)
#define if_afdata_cfg_lock_assert(ifp, what) \
rw_assert(&(ifp)->if_afdata_cfg_lock, what)
void if_afdata_cfg_rlock(struct ifnet *ifp);
void if_afdata_cfg_runlock(struct ifnet *ifp);
void if_afdata_cfg_wlock(struct ifnet *ifp);
void if_afdata_cfg_wunlock(struct ifnet *ifp);
void if_afdata_cfg_lock_assert(struct ifnet *ifp, int what);
int if_afdata_cfg_try_wlock(struct ifnet *ifp);
/* Wrappers */
#define IF_AFDATA_RLOCK IF_AFDATA_CFG_RLOCK
#define IF_AFDATA_RUNLOCK IF_AFDATA_CFG_RUNLOCK
/* if_afdata lock: fast path */
#define IF_AFDATA_RUN_WLOCK(ifp) rm_wlock(&(ifp)->if_afdata_run_lock)
@ -376,23 +385,8 @@ void if_afdata_cfg_lock_assert(struct ifnet *ifp, int what);
rm_runlock(&(ifp)->if_afdata_run_lock, &if_afdata_tracker)
#define IF_AFDATA_RUN_TRACKER struct rm_priotracker if_afdata_tracker
/* Common wrappers */
#define IF_AFDATA_RLOCK(ifp) IF_AFDATA_CFG_RLOCK(ifp)
#define IF_AFDATA_RUNLOCK(ifp) IF_AFDATA_CFG_RUNLOCK(ifp)
#define IF_AFDATA_WLOCK(ifp) if_afdata_wlock(ifp)
#define IF_AFDATA_WUNLOCK(ifp) if_afdata_wunlock(ifp)
#define IF_AFDATA_TRY_WLOCK(ifp) if_afdata_try_wlock(ifp)
#define IF_AFDATA_LOCK(ifp) IF_AFDATA_WLOCK(ifp)
#define IF_AFDATA_UNLOCK(ifp) IF_AFDATA_WUNLOCK(ifp)
void if_afdata_wlock(struct ifnet *ifp);
void if_afdata_wunlock(struct ifnet *ifp);
int if_afdata_try_wlock(struct ifnet *ifp);
#define IF_AFDATA_LOCK_ASSERT(ifp) IF_AFDATA_CFG_LOCK_ASSERT(ifp)
#define IF_AFDATA_RLOCK_ASSERT(ifp) IF_AFDATA_CFG_RLOCK_ASSERT(ifp)
#define IF_AFDATA_WLOCK_ASSERT(ifp) IF_AFDATA_CFG_WLOCK_ASSERT(ifp)
#define IF_AFDATA_UNLOCK_ASSERT(ifp) IF_AFDATA_CFG_UNLOCK_ASSERT(ifp)
#define IF_AFDATA_RUN_WLOCK_ASSERT(ifp) \
rm_assert(&(ifp)->if_afdata_run_lock, RA_WLOCKED)
/*
* 72 was chosen below because it is the size of a TCP/IP

View File

@ -699,7 +699,7 @@ fib6_storelladdr(struct ifnet *ifp, struct in6_addr *dst, int mm_flags,
* the entry should have been created in nd6_store_lladdr
*/
IF_AFDATA_RUN_RLOCK(ifp);
ln = lla_lookup(LLTABLE6(ifp), 0, (struct sockaddr *)&dst_sa);
ln = lla_lookup(LLTABLE6(ifp), LLE_UNLOCKED, (struct sockaddr *)&dst_sa);
/*
* Perform fast path for the following cases:

View File

@ -164,9 +164,9 @@ arp_ifscrub(struct ifnet *ifp, uint32_t addr)
addr4.sin_len = sizeof(addr4);
addr4.sin_family = AF_INET;
addr4.sin_addr.s_addr = addr;
IF_AFDATA_WLOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
lla_delete(LLTABLE(ifp), LLE_IFADDR, (struct sockaddr *)&addr4);
IF_AFDATA_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
}
#endif
@ -247,7 +247,7 @@ arptimer(void *arg)
/* XXX: LOR avoidance. We still have ref on lle. */
LLE_WUNLOCK(lle);
IF_AFDATA_LOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
LLE_WLOCK(lle);
/*
@ -262,7 +262,7 @@ arptimer(void *arg)
pkts_dropped = llentry_free(lle);
ARPSTAT_ADD(dropped, pkts_dropped);
IF_AFDATA_UNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
ARPSTAT_INC(timeouts);
@ -492,9 +492,14 @@ arpresolve_slow(struct ifnet *ifp, int is_gw, struct mbuf *m,
IF_AFDATA_RUNLOCK(ifp);
if (la == NULL && (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
create = 1;
IF_AFDATA_WLOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
la = lla_create(LLTABLE(ifp), 0, dst);
IF_AFDATA_WUNLOCK(ifp);
if (la != NULL) {
IF_AFDATA_RUN_WLOCK(ifp);
llentry_link(LLTABLE(ifp), la);
IF_AFDATA_RUN_WUNLOCK(ifp);
}
IF_AFDATA_CFG_WUNLOCK(ifp);
}
if (la == NULL) {
if (create != 0)
@ -508,6 +513,7 @@ arpresolve_slow(struct ifnet *ifp, int is_gw, struct mbuf *m,
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 0
/*
* If entry has an expiry time and it is approaching,
* see if we need to send an ARP request within this
@ -518,7 +524,7 @@ arpresolve_slow(struct ifnet *ifp, int is_gw, struct mbuf *m,
arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL);
la->la_preempt--;
}
#endif
*lle = la;
error = 0;
goto done;
@ -851,15 +857,15 @@ in_arpinput(struct mbuf *m)
sin.sin_addr = isaddr;
create = (itaddr.s_addr == myaddr.s_addr) ? 1 : 0;
flags = LLE_EXCLUSIVE;
IF_AFDATA_LOCK(ifp);
if (create != 0)
IF_AFDATA_CFG_WLOCK(ifp);
if (create != 0) {
la = lla_create(LLTABLE(ifp), 0, (struct sockaddr *)&sin);
else
} else
la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin);
IF_AFDATA_UNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
if (la != NULL) {
/* the following is not an error when doing bridging */
if (!bridged && la->lle_tbl->llt_ifp != ifp) {
if (!bridged && la->lle_tbl && la->lle_tbl->llt_ifp != ifp) {
if (log_arp_wrong_iface)
ARP_LOG(LOG_WARNING, "%s is on %s "
"but got reply from %*D on %s\n",
@ -910,17 +916,20 @@ in_arpinput(struct mbuf *m)
/* use afdata WLOCK to update fields */
LLE_ADDREF(la);
LLE_WUNLOCK(la);
IF_AFDATA_WLOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
LLE_WLOCK(la);
/* Update data */
IF_AFDATA_RUN_WLOCK(ifp);
memcpy(&la->ll_addr, ar_sha(ah), ifp->if_addrlen);
la->la_flags |= LLE_VALID;
la->r_flags |= RLLE_VALID;
if ((la->la_flags & LLE_STATIC) == 0)
la->la_expire = time_uptime + V_arpt_keep;
llentry_link(LLTABLE(ifp), la);
IF_AFDATA_RUN_WUNLOCK(ifp);
IF_AFDATA_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
LLE_REMREF(la);
}
@ -1084,12 +1093,18 @@ arp_ifinit(struct ifnet *ifp, struct ifaddr *ifa)
* because the output of the arp utility shows
* that L2 entry as permanent
*/
IF_AFDATA_LOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
lle = lla_create(LLTABLE(ifp), LLE_IFADDR | LLE_STATIC,
(struct sockaddr *)IA_SIN(ifa));
if (lle != NULL)
if (lle != NULL) {
IF_AFDATA_RUN_WLOCK(ifp);
bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
lle->la_flags |= (LLE_VALID | LLE_STATIC);
lle->r_flags |= RLLE_VALID;
IF_AFDATA_UNLOCK(ifp);
llentry_link(LLTABLE(ifp), lle);
IF_AFDATA_RUN_WUNLOCK(ifp);
}
IF_AFDATA_CFG_WUNLOCK(ifp);
if (lle == NULL)
log(LOG_INFO, "arp_ifinit: cannot create arp "
"entry for interface address\n");

View File

@ -1050,7 +1050,7 @@ in_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
size_t pkts_dropped;
LIST_INIT(&dchain);
IF_AFDATA_WLOCK(llt->llt_ifp);
IF_AFDATA_CFG_WLOCK(llt->llt_ifp);
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
/*
@ -1070,12 +1070,14 @@ in_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
}
}
/* Unlink chain */
IF_AFDATA_RUN_WLOCK(llt->llt_ifp);
llentries_unlink(&dchain);
IF_AFDATA_RUN_WUNLOCK(llt->llt_ifp);
LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
pkts_dropped = llentry_free(lle);
ARPSTAT_ADD(dropped, pkts_dropped);
}
IF_AFDATA_WUNLOCK(llt->llt_ifp);
IF_AFDATA_CFG_WUNLOCK(llt->llt_ifp);
}
@ -1159,7 +1161,7 @@ in_lltable_delete(struct lltable *llt, u_int flags,
struct ifnet *ifp = llt->llt_ifp;
struct llentry *lle;
IF_AFDATA_WLOCK_ASSERT(ifp);
IF_AFDATA_CFG_WLOCK_ASSERT(ifp);
KASSERT(l3addr->sa_family == AF_INET,
("sin_family %d", l3addr->sa_family));
@ -1175,7 +1177,9 @@ in_lltable_delete(struct lltable *llt, u_int flags,
LLE_WLOCK(lle);
lle->la_flags |= LLE_DELETED;
EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED);
IF_AFDATA_RUN_WLOCK(ifp);
llentry_unlink(lle);
IF_AFDATA_RUN_WUNLOCK(ifp);
#ifdef DIAGNOSTIC
log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
#endif
@ -1195,7 +1199,7 @@ in_lltable_create(struct lltable *llt, u_int flags, const struct sockaddr *l3add
struct ifnet *ifp = llt->llt_ifp;
struct llentry *lle;
IF_AFDATA_WLOCK_ASSERT(ifp);
IF_AFDATA_CFG_WLOCK_ASSERT(ifp);
KASSERT(l3addr->sa_family == AF_INET,
("sin_family %d", l3addr->sa_family));
@ -1223,12 +1227,6 @@ in_lltable_create(struct lltable *llt, u_int flags, const struct sockaddr *l3add
return (NULL);
}
lle->la_flags = flags;
if ((flags & LLE_IFADDR) == LLE_IFADDR) {
bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
lle->la_flags |= (LLE_VALID | LLE_STATIC);
}
llentry_link(llt, lle);
LLE_WLOCK(lle);
return (lle);

View File

@ -462,9 +462,9 @@ toe_nd6_resolve(struct ifnet *ifp, struct sockaddr *sa, uint8_t *lladdr)
lle = lla_lookup(LLTABLE6(ifp), flags, sa);
IF_AFDATA_RUNLOCK(ifp);
if (lle == NULL) {
IF_AFDATA_LOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
lle = nd6_create(&sin6->sin6_addr, 0, ifp);
IF_AFDATA_UNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
if (lle == NULL)
return (ENOMEM); /* Couldn't create entry in cache. */
lle->ln_state = ND6_LLINFO_INCOMPLETE;

View File

@ -72,6 +72,8 @@ __FBSDID("$FreeBSD$");
#include <sys/errno.h>
#include <sys/jail.h>
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/rmlock.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sockio.h>
@ -2100,7 +2102,7 @@ in6_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
* including static ND6 entries.
*/
LIST_INIT(&dchain);
IF_AFDATA_WLOCK(llt->llt_ifp);
IF_AFDATA_CFG_WLOCK(llt->llt_ifp);
for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
if (IN6_ARE_MASKED_ADDR_EQUAL(
@ -2117,10 +2119,12 @@ in6_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
}
}
}
IF_AFDATA_RUN_WLOCK(llt->llt_ifp);
llentries_unlink(&dchain);
IF_AFDATA_RUN_WUNLOCK(llt->llt_ifp);
LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next)
llentry_free(lle);
IF_AFDATA_WUNLOCK(llt->llt_ifp);
IF_AFDATA_CFG_WUNLOCK(llt->llt_ifp);
}
static int
@ -2198,7 +2202,7 @@ in6_lltable_delete(struct lltable *llt, u_int flags,
const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
struct llentry *lle;
IF_AFDATA_LOCK_ASSERT(llt->llt_ifp);
IF_AFDATA_CFG_WLOCK_ASSERT(llt->llt_ifp);
KASSERT(l3addr->sa_family == AF_INET6,
("sin_family %d", l3addr->sa_family));
@ -2210,7 +2214,9 @@ in6_lltable_delete(struct lltable *llt, u_int flags,
if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) {
LLE_WLOCK(lle);
lle->la_flags |= LLE_DELETED;
IF_AFDATA_RUN_WLOCK(llt->llt_ifp);
llentry_unlink(lle);
IF_AFDATA_RUN_WUNLOCK(llt->llt_ifp);
#ifdef DIAGNOSTIC
log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle);
#endif
@ -2231,7 +2237,7 @@ in6_lltable_create(struct lltable *llt, u_int flags,
struct ifnet *ifp = llt->llt_ifp;
struct llentry *lle;
IF_AFDATA_WLOCK_ASSERT(ifp);
IF_AFDATA_CFG_WLOCK_ASSERT(ifp);
KASSERT(l3addr->sa_family == AF_INET6,
("sin_family %d", l3addr->sa_family));
@ -2257,12 +2263,6 @@ in6_lltable_create(struct lltable *llt, u_int flags,
return NULL;
}
lle->la_flags = flags;
if ((flags & LLE_IFADDR) == LLE_IFADDR) {
bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
lle->la_flags |= (LLE_VALID | LLE_STATIC);
}
llentry_link(llt, lle);
LLE_WLOCK(lle);
return (lle);
@ -2290,7 +2290,7 @@ in6_lltable_lookup(struct lltable *llt, u_int flags,
if (flags & LLE_EXCLUSIVE)
LLE_WLOCK(lle);
else
else if ((flags & LLE_UNLOCKED) == 0)
LLE_RLOCK(lle);
return (lle);
}

View File

@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <sys/syslog.h>
#include <sys/lock.h>
#include <sys/rwlock.h>
#include <sys/rmlock.h>
#include <sys/queue.h>
#include <sys/sdt.h>
#include <sys/sysctl.h>
@ -854,7 +855,9 @@ nd6_lookup(struct in6_addr *addr6, int flags, struct ifnet *ifp)
sin6.sin6_family = AF_INET6;
sin6.sin6_addr = *addr6;
IF_AFDATA_LOCK_ASSERT(ifp);
/*
* IF_AFDATA_LOCK_ASSERT(ifp);
*/
llflags = (flags & ND6_EXCLUSIVE) ? LLE_EXCLUSIVE : 0;
ln = lla_lookup(LLTABLE6(ifp), llflags, (struct sockaddr *)&sin6);
@ -877,11 +880,15 @@ nd6_create(struct in6_addr *addr6, int flags, struct ifnet *ifp)
sin6.sin6_family = AF_INET6;
sin6.sin6_addr = *addr6;
IF_AFDATA_WLOCK_ASSERT(ifp);
IF_AFDATA_CFG_WLOCK_ASSERT(ifp);
ln = lla_create(LLTABLE6(ifp), 0, (struct sockaddr *)&sin6);
if (ln != NULL)
if (ln != NULL) {
IF_AFDATA_RUN_WLOCK(ifp);
ln->ln_state = ND6_LLINFO_NOSTATE;
llentry_link(LLTABLE6(ifp), ln);
IF_AFDATA_RUN_WUNLOCK(ifp);
}
return (ln);
}
@ -998,7 +1005,7 @@ nd6_is_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
struct llentry *lle;
int rc = 0;
IF_AFDATA_UNLOCK_ASSERT(ifp);
IF_AFDATA_CFG_UNLOCK_ASSERT(ifp);
if (nd6_is_new_addr_neighbor(addr, ifp))
return (1);
@ -1137,7 +1144,7 @@ nd6_free(struct llentry *ln, int gc)
* free(9) in llentry_free() if someone else holds one as well.
*/
LLE_WUNLOCK(ln);
IF_AFDATA_LOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
LLE_WLOCK(ln);
/*
@ -1149,9 +1156,13 @@ nd6_free(struct llentry *ln, int gc)
ln->la_flags &= ~LLE_CALLOUTREF;
}
IF_AFDATA_RUN_WLOCK(ifp);
llentry_unlink(ln);
IF_AFDATA_RUN_WUNLOCK(ifp);
llentry_free(ln);
IF_AFDATA_UNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
return (next);
}
@ -1579,7 +1590,7 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
struct mbuf *chain = NULL;
int static_route = 0;
IF_AFDATA_UNLOCK_ASSERT(ifp);
IF_AFDATA_CFG_UNLOCK_ASSERT(ifp);
KASSERT(ifp != NULL, ("%s: ifp == NULL", __func__));
KASSERT(from != NULL, ("%s: from == NULL", __func__));
@ -1598,14 +1609,14 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
* description on it in NS section (RFC 2461 7.2.3).
*/
flags = lladdr ? ND6_EXCLUSIVE : 0;
IF_AFDATA_RLOCK(ifp);
IF_AFDATA_CFG_RLOCK(ifp);
ln = nd6_lookup(from, flags, ifp);
IF_AFDATA_RUNLOCK(ifp);
IF_AFDATA_CFG_RUNLOCK(ifp);
if (ln == NULL) {
flags |= ND6_EXCLUSIVE;
IF_AFDATA_LOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
ln = nd6_create(from, 0, ifp);
IF_AFDATA_UNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
is_newentry = 1;
} else {
/* do nothing if static ndp is set */
@ -2004,9 +2015,9 @@ nd6_output_lle(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
* the condition below is not very efficient. But we believe
* it is tolerable, because this should be a rare case.
*/
IF_AFDATA_LOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
lle = nd6_create(&dst->sin6_addr, 0, ifp);
IF_AFDATA_UNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
}
}
if (lle == NULL) {
@ -2257,14 +2268,23 @@ nd6_add_ifa_lle(struct in6_ifaddr *ia)
struct llentry *ln;
ifp = ia->ia_ifa.ifa_ifp;
IF_AFDATA_LOCK(ifp);
ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
IF_AFDATA_CFG_WLOCK(ifp);
ln = lla_create(LLTABLE6(ifp), LLE_IFADDR,
(struct sockaddr *)&ia->ia_addr);
IF_AFDATA_UNLOCK(ifp);
if (ln != NULL) {
IF_AFDATA_RUN_WLOCK(ifp);
bcopy(IF_LLADDR(ifp), &ln->ll_addr, ifp->if_addrlen);
ln->la_flags |= (LLE_VALID | LLE_STATIC);
ln->r_flags |= RLLE_VALID;
ln->la_expire = 0; /* for IPv6 this means permanent */
ln->ln_state = ND6_LLINFO_REACHABLE;
llentry_link(LLTABLE6(ifp), ln);
IF_AFDATA_RUN_WUNLOCK(ifp);
}
ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
IF_AFDATA_CFG_WUNLOCK(ifp);
if (ln != NULL) {
LLE_WUNLOCK(ln);
in6_newaddrmsg(ia, RTM_ADD);
return (0);
@ -2306,7 +2326,7 @@ nd6_storelladdr(struct ifnet *ifp, struct mbuf *m,
struct llentry *ln;
*lle = NULL;
IF_AFDATA_UNLOCK_ASSERT(ifp);
IF_AFDATA_CFG_UNLOCK_ASSERT(ifp);
if (m != NULL && m->m_flags & M_MCAST) {
int i;

View File

@ -148,11 +148,11 @@ scope6_set(struct ifnet *ifp, struct scope6_id *idlist)
int error = 0;
struct scope6_id *sid = NULL;
IF_AFDATA_WLOCK(ifp);
IF_AFDATA_CFG_WLOCK(ifp);
sid = SID(ifp);
if (!sid) { /* paranoid? */
IF_AFDATA_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
return (EINVAL);
}
@ -175,7 +175,7 @@ scope6_set(struct ifnet *ifp, struct scope6_id *idlist)
*/
if (i == IPV6_ADDR_SCOPE_INTFACELOCAL &&
idlist->s6id_list[i] != ifp->if_index) {
IF_AFDATA_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
return (EINVAL);
}
@ -187,7 +187,7 @@ scope6_set(struct ifnet *ifp, struct scope6_id *idlist)
* IDs, but we check the consistency for
* safety in later use.
*/
IF_AFDATA_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
return (EINVAL);
}
@ -196,10 +196,11 @@ scope6_set(struct ifnet *ifp, struct scope6_id *idlist)
* but we simply set the new value in this initial
* implementation.
*/
/* XXX: Use runtime lock? */
sid->s6id_list[i] = idlist->s6id_list[i];
}
}
IF_AFDATA_WUNLOCK(ifp);
IF_AFDATA_CFG_WUNLOCK(ifp);
return (error);
}