From owner-svn-src-all@freebsd.org Sat Aug 8 17:48:58 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7C1C09B561A; Sat, 8 Aug 2015 17:48:58 +0000 (UTC) (envelope-from melifaro@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 6BDD117D9; Sat, 8 Aug 2015 17:48:58 +0000 (UTC) (envelope-from melifaro@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.70]) by repo.freebsd.org (8.14.9/8.14.9) with ESMTP id t78Hmw22068797; Sat, 8 Aug 2015 17:48:58 GMT (envelope-from melifaro@FreeBSD.org) Received: (from melifaro@localhost) by repo.freebsd.org (8.14.9/8.14.9/Submit) id t78HmtxL068784; Sat, 8 Aug 2015 17:48:55 GMT (envelope-from melifaro@FreeBSD.org) Message-Id: <201508081748.t78HmtxL068784@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: melifaro set sender to melifaro@FreeBSD.org using -f From: "Alexander V. Chernikov" Date: Sat, 8 Aug 2015 17:48:55 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r286457 - in head/sys: net netinet netinet6 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 08 Aug 2015 17:48:58 -0000 Author: melifaro Date: Sat Aug 8 17:48:54 2015 New Revision: 286457 URL: https://svnweb.freebsd.org/changeset/base/286457 Log: MFP r274553: * Move lle creation/deletion from lla_lookup to separate functions: lla_lookup(LLE_CREATE) -> lla_create lla_lookup(LLE_DELETE) -> lla_delete lla_create now returns with LLE_EXCLUSIVE lock for lle. * Provide typedefs for new/existing lltable callbacks. Reviewed by: ae Modified: head/sys/net/if_llatbl.c head/sys/net/if_llatbl.h head/sys/netinet/if_ether.c head/sys/netinet/in.c head/sys/netinet/toecore.c head/sys/netinet6/in6.c head/sys/netinet6/nd6.c head/sys/netinet6/nd6.h Directory Properties: head/sys/ (props changed) Modified: head/sys/net/if_llatbl.c ============================================================================== --- head/sys/net/if_llatbl.c Sat Aug 8 16:39:28 2015 (r286456) +++ head/sys/net/if_llatbl.c Sat Aug 8 17:48:54 2015 (r286457) @@ -147,8 +147,7 @@ llentry_alloc(struct ifnet *ifp, struct if ((la == NULL) && (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { IF_AFDATA_WLOCK(ifp); - la = lla_lookup(lt, (LLE_CREATE | LLE_EXCLUSIVE), - (struct sockaddr *)dst); + la = lla_create(lt, 0, (struct sockaddr *)dst); IF_AFDATA_WUNLOCK(ifp); } @@ -259,7 +258,7 @@ lltable_init(struct ifnet *ifp, int af) } /* - * Called in route_output when adding/deleting a route to an interface. + * Called in route_output when rtm_flags contains RTF_LLDATA. */ int lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) @@ -270,8 +269,8 @@ lla_rt_output(struct rt_msghdr *rtm, str struct ifnet *ifp; struct lltable *llt; struct llentry *lle; - u_int laflags = 0, flags = 0; - int error = 0; + u_int laflags = 0; + int error; KASSERT(dl != NULL && dl->sdl_family == AF_LINK, ("%s: invalid dl\n", __func__)); @@ -283,24 +282,6 @@ lla_rt_output(struct rt_msghdr *rtm, str return EINVAL; } - switch (rtm->rtm_type) { - case RTM_ADD: - if (rtm->rtm_flags & RTF_ANNOUNCE) - flags |= LLE_PUB; - flags |= LLE_CREATE; - break; - - case RTM_DELETE: - flags |= LLE_DELETE; - break; - - case RTM_CHANGE: - break; - - default: - return EINVAL; /* XXX not implemented yet */ - } - /* XXX linked list may be too expensive */ LLTABLE_RLOCK(); SLIST_FOREACH(llt, &V_lltables, llt_link) { @@ -311,58 +292,62 @@ lla_rt_output(struct rt_msghdr *rtm, str LLTABLE_RUNLOCK(); KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n")); - if (flags & LLE_CREATE) - flags |= LLE_EXCLUSIVE; + error = 0; - IF_AFDATA_LOCK(ifp); - lle = lla_lookup(llt, flags, dst); - IF_AFDATA_UNLOCK(ifp); - if (LLE_IS_VALID(lle)) { - if (flags & LLE_CREATE) { - /* - * If we delay the delete, then a subsequent - * "arp add" should look up this entry, reset the - * LLE_DELETED flag, and reset the expiration timer - */ - bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen); - lle->la_flags |= (flags & LLE_PUB); - lle->la_flags |= LLE_VALID; - lle->la_flags &= ~LLE_DELETED; + switch (rtm->rtm_type) { + case RTM_ADD: + /* Add static LLE */ + IF_AFDATA_WLOCK(ifp); + lle = lla_create(llt, 0, dst); + if (lle == NULL) { + IF_AFDATA_WUNLOCK(ifp); + return (ENOMEM); + } + + + bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen); + if ((rtm->rtm_flags & RTF_ANNOUNCE)) + lle->la_flags |= LLE_PUB; + lle->la_flags |= LLE_VALID; #ifdef INET6 - /* - * ND6 - */ - if (dst->sa_family == AF_INET6) - lle->ln_state = ND6_LLINFO_REACHABLE; + /* + * ND6 + */ + if (dst->sa_family == AF_INET6) + lle->ln_state = ND6_LLINFO_REACHABLE; #endif - /* - * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) - */ - - 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); + /* + * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) + */ + + 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); + IF_AFDATA_WUNLOCK(ifp); #ifdef INET - /* gratuitous ARP */ - if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) - arprequest(ifp, - &((struct sockaddr_in *)dst)->sin_addr, - &((struct sockaddr_in *)dst)->sin_addr, - (u_char *)LLADDR(dl)); + /* gratuitous ARP */ + if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) + arprequest(ifp, + &((struct sockaddr_in *)dst)->sin_addr, + &((struct sockaddr_in *)dst)->sin_addr, + (u_char *)LLADDR(dl)); #endif - } else { - if (flags & LLE_EXCLUSIVE) - LLE_WUNLOCK(lle); - else - LLE_RUNLOCK(lle); - } - } else if ((lle == NULL) && (flags & LLE_DELETE)) - error = EINVAL; + break; + + case RTM_DELETE: + IF_AFDATA_WLOCK(ifp); + error = lla_delete(llt, 0, dst); + IF_AFDATA_WUNLOCK(ifp); + return (error == 0 ? 0 : ENOENT); + + default: + error = EINVAL; + } return (error); } Modified: head/sys/net/if_llatbl.h ============================================================================== --- head/sys/net/if_llatbl.h Sat Aug 8 16:39:28 2015 (r286456) +++ head/sys/net/if_llatbl.h Sat Aug 8 17:48:54 2015 (r286457) @@ -144,25 +144,33 @@ struct llentry { #define LLTBL_HASHMASK (LLTBL_HASHTBL_SIZE - 1) #endif +typedef struct llentry *(llt_lookup_t)(struct lltable *, u_int flags, + const struct sockaddr *l3addr); +typedef struct llentry *(llt_create_t)(struct lltable *, u_int flags, + const struct sockaddr *l3addr); +typedef int (llt_delete_t)(struct lltable *, u_int flags, + const struct sockaddr *l3addr); +typedef void (llt_prefix_free_t)(struct lltable *, + const struct sockaddr *prefix, const struct sockaddr *mask, u_int flags); +typedef int (llt_dump_t)(struct lltable *, struct sysctl_req *); + struct lltable { SLIST_ENTRY(lltable) llt_link; struct llentries lle_head[LLTBL_HASHTBL_SIZE]; int llt_af; struct ifnet *llt_ifp; - void (*llt_prefix_free)(struct lltable *, - const struct sockaddr *prefix, - const struct sockaddr *mask, - u_int flags); - struct llentry * (*llt_lookup)(struct lltable *, u_int flags, - const struct sockaddr *l3addr); - int (*llt_dump)(struct lltable *, - struct sysctl_req *); + llt_lookup_t *llt_lookup; + llt_create_t *llt_create; + llt_delete_t *llt_delete; + llt_prefix_free_t *llt_prefix_free; + llt_dump_t *llt_dump; }; + MALLOC_DECLARE(M_LLTABLE); /* - * flags to be passed to arplookup. + * LLentry flags */ #define LLE_DELETED 0x0001 /* entry must be deleted */ #define LLE_STATIC 0x0002 /* entry is static */ @@ -170,9 +178,8 @@ MALLOC_DECLARE(M_LLTABLE); #define LLE_VALID 0x0008 /* ll_addr is valid */ #define LLE_PUB 0x0020 /* publish entry ??? */ #define LLE_LINKED 0x0040 /* linked to lookup structure */ +/* LLE request flags */ #define LLE_EXCLUSIVE 0x2000 /* return lle xlocked */ -#define LLE_DELETE 0x4000 /* delete on a lookup - match LLE_IFADDR */ -#define LLE_CREATE 0x8000 /* create on a lookup miss */ #define LLATBL_HASH(key, mask) \ (((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask) @@ -196,9 +203,25 @@ struct llentry *llentry_alloc(struct if static __inline struct llentry * lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) { - return llt->llt_lookup(llt, flags, l3addr); + + return (llt->llt_lookup(llt, flags, l3addr)); } +static __inline struct llentry * +lla_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +{ + + return (llt->llt_create(llt, flags, l3addr)); +} + +static __inline int +lla_delete(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +{ + + return (llt->llt_delete(llt, flags, l3addr)); +} + + int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *); #include Modified: head/sys/netinet/if_ether.c ============================================================================== --- head/sys/netinet/if_ether.c Sat Aug 8 16:39:28 2015 (r286456) +++ head/sys/netinet/if_ether.c Sat Aug 8 17:48:54 2015 (r286457) @@ -152,8 +152,7 @@ arp_ifscrub(struct ifnet *ifp, uint32_t addr4.sin_family = AF_INET; addr4.sin_addr.s_addr = addr; IF_AFDATA_WLOCK(ifp); - lla_lookup(LLTABLE(ifp), (LLE_DELETE | LLE_IFADDR), - (struct sockaddr *)&addr4); + lla_delete(LLTABLE(ifp), LLE_IFADDR, (struct sockaddr *)&addr4); IF_AFDATA_WUNLOCK(ifp); } #endif @@ -325,11 +324,12 @@ arpresolve(struct ifnet *ifp, int is_gw, u_int flags = 0; struct mbuf *curr = NULL; struct mbuf *next = NULL; - int error, renew; + int create, error, renew; if (pflags != NULL) *pflags = 0; + create = 0; if (m != NULL) { if (m->m_flags & M_BCAST) { /* broadcast */ @@ -349,13 +349,14 @@ retry: IF_AFDATA_RUNLOCK(ifp); if ((la == NULL) && ((flags & LLE_EXCLUSIVE) == 0) && ((ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0)) { - flags |= (LLE_CREATE | LLE_EXCLUSIVE); + create = 1; + flags |= LLE_EXCLUSIVE; IF_AFDATA_WLOCK(ifp); - la = lla_lookup(LLTABLE(ifp), flags, dst); + la = lla_create(LLTABLE(ifp), flags, dst); IF_AFDATA_WUNLOCK(ifp); } if (la == NULL) { - if (flags & LLE_CREATE) + if (create != 0) log(LOG_DEBUG, "arpresolve: can't allocate llinfo for %s on %s\n", inet_ntoa(SIN(dst)->sin_addr), ifp->if_xname); @@ -578,7 +579,7 @@ in_arpinput(struct mbuf *m) int op, flags; int req_len; int bridged = 0, is_bridge = 0; - int carped; + int carped, create; struct sockaddr_in sin; sin.sin_len = sizeof(struct sockaddr_in); sin.sin_family = AF_INET; @@ -729,10 +730,13 @@ match: sin.sin_len = sizeof(struct sockaddr_in); sin.sin_family = AF_INET; sin.sin_addr = isaddr; - flags = (itaddr.s_addr == myaddr.s_addr) ? LLE_CREATE : 0; - flags |= LLE_EXCLUSIVE; + create = (itaddr.s_addr == myaddr.s_addr) ? 1 : 0; + flags = LLE_EXCLUSIVE; IF_AFDATA_LOCK(ifp); - la = lla_lookup(LLTABLE(ifp), flags, (struct sockaddr *)&sin); + if (create != 0) + la = lla_create(LLTABLE(ifp), 0, (struct sockaddr *)&sin); + else + 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 */ @@ -947,14 +951,14 @@ arp_ifinit(struct ifnet *ifp, struct ifa * that L2 entry as permanent */ IF_AFDATA_LOCK(ifp); - lle = lla_lookup(LLTABLE(ifp), (LLE_CREATE | LLE_IFADDR | LLE_STATIC), + lle = lla_create(LLTABLE(ifp), LLE_IFADDR | LLE_STATIC, (struct sockaddr *)IA_SIN(ifa)); IF_AFDATA_UNLOCK(ifp); if (lle == NULL) log(LOG_INFO, "arp_ifinit: cannot create arp " "entry for interface address\n"); else - LLE_RUNLOCK(lle); + LLE_WUNLOCK(lle); } ifa->ifa_rtrequest = NULL; } Modified: head/sys/netinet/in.c ============================================================================== --- head/sys/netinet/in.c Sat Aug 8 16:39:28 2015 (r286456) +++ head/sys/netinet/in.c Sat Aug 8 17:48:54 2015 (r286457) @@ -1107,6 +1107,117 @@ in_lltable_rtcheck(struct ifnet *ifp, u_ return (0); } +static inline struct llentry * +in_lltable_find_dst(struct lltable *llt, struct in_addr dst) +{ + struct llentry *lle; + struct llentries *lleh; + struct sockaddr_in *sin; + u_int hashkey; + + hashkey = dst.s_addr; + lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; + LIST_FOREACH(lle, lleh, lle_next) { + sin = satosin(L3_ADDR(lle)); + if (lle->la_flags & LLE_DELETED) + continue; + if (sin->sin_addr.s_addr == dst.s_addr) + break; + } + + return (lle); +} + +static int +in_lltable_delete(struct lltable *llt, u_int flags, + const struct sockaddr *l3addr) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + + IF_AFDATA_WLOCK_ASSERT(ifp); + KASSERT(l3addr->sa_family == AF_INET, + ("sin_family %d", l3addr->sa_family)); + + lle = in_lltable_find_dst(llt, sin->sin_addr); + if (lle == NULL) { +#ifdef DIAGNOSTIC + log(LOG_INFO, "interface address is missing from cache = %p in delete\n", lle); +#endif + return (ENOENT); + } + + if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) { + LLE_WLOCK(lle); + lle->la_flags |= LLE_DELETED; + EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED); +#ifdef DIAGNOSTIC + log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); +#endif + if ((lle->la_flags & (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC) + llentry_free(lle); + else + LLE_WUNLOCK(lle); + } + + return (0); +} + +static struct llentry * +in_lltable_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + struct llentries *lleh; + u_int hashkey; + + IF_AFDATA_WLOCK_ASSERT(ifp); + KASSERT(l3addr->sa_family == AF_INET, + ("sin_family %d", l3addr->sa_family)); + + lle = in_lltable_find_dst(llt, sin->sin_addr); + + if (lle != NULL) { + LLE_WLOCK(lle); + return (lle); + } + + /* no existing record, we need to create new one */ + + /* + * A route that covers the given address must have + * been installed 1st because we are doing a resolution, + * verify this. + */ + if (!(flags & LLE_IFADDR) && + in_lltable_rtcheck(ifp, flags, l3addr) != 0) + return (NULL); + + lle = in_lltable_new(l3addr, flags); + if (lle == NULL) { + log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); + 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); + } + + hashkey = sin->sin_addr.s_addr; + lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; + + lle->lle_tbl = llt; + lle->lle_head = lleh; + lle->la_flags |= LLE_LINKED; + LIST_INSERT_HEAD(lleh, lle, lle_next); + LLE_WLOCK(lle); + + return (lle); +} + /* * Return NULL if not found or marked for deletion. * If found return lle read locked. @@ -1133,62 +1244,15 @@ in_lltable_lookup(struct lltable *llt, u if (sa2->sin_addr.s_addr == sin->sin_addr.s_addr) break; } - if (lle == NULL) { -#ifdef DIAGNOSTIC - 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); - IF_AFDATA_WLOCK_ASSERT(ifp); - /* - * A route that covers the given address must have - * been installed 1st because we are doing a resolution, - * verify this. - */ - if (!(flags & LLE_IFADDR) && - in_lltable_rtcheck(ifp, flags, l3addr) != 0) - goto done; - - lle = in_lltable_new(l3addr, flags); - if (lle == NULL) { - log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); - goto done; - } - lle->la_flags = flags & ~LLE_CREATE; - if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { - bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); - lle->la_flags |= (LLE_VALID | LLE_STATIC); - } - lle->lle_tbl = llt; - lle->lle_head = lleh; - lle->la_flags |= LLE_LINKED; - LIST_INSERT_HEAD(lleh, lle, lle_next); - } else if (flags & LLE_DELETE) { - if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) { - LLE_WLOCK(lle); - lle->la_flags |= LLE_DELETED; - EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED); -#ifdef DIAGNOSTIC - log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); -#endif - if ((lle->la_flags & - (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC) - llentry_free(lle); - else - LLE_WUNLOCK(lle); - } - lle = (void *)-1; + if (lle == NULL) + return (NULL); + + if (flags & LLE_EXCLUSIVE) + LLE_WLOCK(lle); + else + LLE_RLOCK(lle); - } - if (LLE_IS_VALID(lle)) { - if (flags & LLE_EXCLUSIVE) - LLE_WLOCK(lle); - else - LLE_RLOCK(lle); - } -done: return (lle); } @@ -1279,6 +1343,8 @@ in_domifattach(struct ifnet *ifp) if (llt != NULL) { llt->llt_prefix_free = in_lltable_prefix_free; llt->llt_lookup = in_lltable_lookup; + llt->llt_create = in_lltable_create; + llt->llt_delete = in_lltable_delete; llt->llt_dump = in_lltable_dump; } ii->ii_llt = llt; Modified: head/sys/netinet/toecore.c ============================================================================== --- head/sys/netinet/toecore.c Sat Aug 8 16:39:28 2015 (r286456) +++ head/sys/netinet/toecore.c Sat Aug 8 17:48:54 2015 (r286457) @@ -463,8 +463,7 @@ restart: IF_AFDATA_RUNLOCK(ifp); if (lle == NULL) { IF_AFDATA_LOCK(ifp); - lle = nd6_lookup(&sin6->sin6_addr, ND6_CREATE | ND6_EXCLUSIVE, - ifp); + lle = nd6_create(&sin6->sin6_addr, 0, ifp); IF_AFDATA_UNLOCK(ifp); if (lle == NULL) return (ENOMEM); /* Couldn't create entry in cache. */ Modified: head/sys/netinet6/in6.c ============================================================================== --- head/sys/netinet6/in6.c Sat Aug 8 16:39:28 2015 (r286456) +++ head/sys/netinet6/in6.c Sat Aug 8 17:48:54 2015 (r286457) @@ -2152,81 +2152,134 @@ in6_lltable_rtcheck(struct ifnet *ifp, return 0; } -static struct llentry * -in6_lltable_lookup(struct lltable *llt, u_int flags, - const struct sockaddr *l3addr) +static inline struct llentry * +in6_lltable_find_dst(struct lltable *llt, const struct in6_addr *dst) { - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; - struct ifnet *ifp = llt->llt_ifp; struct llentry *lle; struct llentries *lleh; + const struct sockaddr_in6 *sin6; u_int hashkey; - IF_AFDATA_LOCK_ASSERT(ifp); - KASSERT(l3addr->sa_family == AF_INET6, - ("sin_family %d", l3addr->sa_family)); - - hashkey = sin6->sin6_addr.s6_addr32[3]; + hashkey = dst->s6_addr32[3]; lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; LIST_FOREACH(lle, lleh, lle_next) { - struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)L3_ADDR(lle); + sin6 = (const struct sockaddr_in6 *)L3_ADDR(lle); if (lle->la_flags & LLE_DELETED) continue; - if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr, - sizeof(struct in6_addr)) == 0) + if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, dst)) break; } - if (lle == NULL) { - if (!(flags & LLE_CREATE)) - return (NULL); - IF_AFDATA_WLOCK_ASSERT(ifp); - /* - * A route that covers the given address must have - * been installed 1st because we are doing a resolution, - * verify this. - */ - if (!(flags & LLE_IFADDR) && - in6_lltable_rtcheck(ifp, flags, l3addr) != 0) - return NULL; - - lle = in6_lltable_new(l3addr, flags); - if (lle == NULL) { - log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); - return NULL; - } - lle->la_flags = flags & ~LLE_CREATE; - if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { - bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); - lle->la_flags |= (LLE_VALID | LLE_STATIC); - } + return (lle); +} - lle->lle_tbl = llt; - lle->lle_head = lleh; - lle->la_flags |= LLE_LINKED; - LIST_INSERT_HEAD(lleh, lle, lle_next); - } else if (flags & LLE_DELETE) { - if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) { - LLE_WLOCK(lle); - lle->la_flags |= LLE_DELETED; - EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED); +static int +in6_lltable_delete(struct lltable *llt, u_int flags, + const struct sockaddr *l3addr) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + + IF_AFDATA_LOCK_ASSERT(ifp); + KASSERT(l3addr->sa_family == AF_INET6, + ("sin_family %d", l3addr->sa_family)); + + lle = in6_lltable_find_dst(llt, &sin6->sin6_addr); + + if (lle == NULL) + return (ENOENT); + + if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) { + LLE_WLOCK(lle); + lle->la_flags |= LLE_DELETED; + EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED); #ifdef DIAGNOSTIC - log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); + log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); #endif - if ((lle->la_flags & - (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC) - llentry_free(lle); - else - LLE_WUNLOCK(lle); - } - lle = (void *)-1; - } - if (LLE_IS_VALID(lle)) { - if (flags & LLE_EXCLUSIVE) - LLE_WLOCK(lle); + if ((lle->la_flags & (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC) + llentry_free(lle); else - LLE_RLOCK(lle); + LLE_WUNLOCK(lle); } + + return (0); +} + +static struct llentry * +in6_lltable_create(struct lltable *llt, u_int flags, + const struct sockaddr *l3addr) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + struct llentries *lleh; + u_int hashkey; + + IF_AFDATA_WLOCK_ASSERT(ifp); + KASSERT(l3addr->sa_family == AF_INET6, + ("sin_family %d", l3addr->sa_family)); + + lle = in6_lltable_find_dst(llt, &sin6->sin6_addr); + + if (lle != NULL) { + LLE_WLOCK(lle); + return (lle); + } + + /* + * A route that covers the given address must have + * been installed 1st because we are doing a resolution, + * verify this. + */ + if (!(flags & LLE_IFADDR) && + in6_lltable_rtcheck(ifp, flags, l3addr) != 0) + return (NULL); + + lle = in6_lltable_new(l3addr, flags); + if (lle == NULL) { + log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); + 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); + } + + hashkey = sin6->sin6_addr.s6_addr32[3]; + lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; + + lle->lle_tbl = llt; + lle->lle_head = lleh; + lle->la_flags |= LLE_LINKED; + LIST_INSERT_HEAD(lleh, lle, lle_next); + LLE_WLOCK(lle); + + return (lle); +} + +static struct llentry * +in6_lltable_lookup(struct lltable *llt, u_int flags, + const struct sockaddr *l3addr) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; + struct ifnet *ifp = llt->llt_ifp; + struct llentry *lle; + + IF_AFDATA_LOCK_ASSERT(ifp); + KASSERT(l3addr->sa_family == AF_INET6, + ("sin_family %d", l3addr->sa_family)); + + lle = in6_lltable_find_dst(llt, &sin6->sin6_addr); + + if (lle == NULL) + return (NULL); + + if (flags & LLE_EXCLUSIVE) + LLE_WLOCK(lle); + else + LLE_RLOCK(lle); return (lle); } @@ -2340,6 +2393,8 @@ in6_domifattach(struct ifnet *ifp) if (ext->lltable != NULL) { ext->lltable->llt_prefix_free = in6_lltable_prefix_free; ext->lltable->llt_lookup = in6_lltable_lookup; + ext->lltable->llt_create = in6_lltable_create; + ext->lltable->llt_delete = in6_lltable_delete; ext->lltable->llt_dump = in6_lltable_dump; } Modified: head/sys/netinet6/nd6.c ============================================================================== --- head/sys/netinet6/nd6.c Sat Aug 8 16:39:28 2015 (r286456) +++ head/sys/netinet6/nd6.c Sat Aug 8 17:48:54 2015 (r286457) @@ -937,16 +937,33 @@ nd6_lookup(struct in6_addr *addr6, int f IF_AFDATA_LOCK_ASSERT(ifp); - llflags = 0; - if (flags & ND6_CREATE) - llflags |= LLE_CREATE; - if (flags & ND6_EXCLUSIVE) - llflags |= LLE_EXCLUSIVE; - + llflags = (flags & ND6_EXCLUSIVE) ? LLE_EXCLUSIVE : 0; ln = lla_lookup(LLTABLE6(ifp), llflags, (struct sockaddr *)&sin6); - if ((ln != NULL) && (llflags & LLE_CREATE)) + + return (ln); +} + +/* + * the caller acquires and releases the lock on the lltbls + * Returns the llentry wlocked + */ +struct llentry * +nd6_create(struct in6_addr *addr6, int flags, struct ifnet *ifp) +{ + struct sockaddr_in6 sin6; + struct llentry *ln; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = *addr6; + + IF_AFDATA_WLOCK_ASSERT(ifp); + + ln = lla_create(LLTABLE6(ifp), 0, (struct sockaddr *)&sin6); + if (ln != NULL) ln->ln_state = ND6_LLINFO_NOSTATE; - + return (ln); } @@ -1664,7 +1681,7 @@ nd6_cache_lladdr(struct ifnet *ifp, stru if (ln == NULL) { flags |= ND6_EXCLUSIVE; IF_AFDATA_LOCK(ifp); - ln = nd6_lookup(from, flags | ND6_CREATE, ifp); + ln = nd6_create(from, 0, ifp); IF_AFDATA_UNLOCK(ifp); is_newentry = 1; } else { @@ -2020,7 +2037,6 @@ nd6_output_lle(struct ifnet *ifp, struct struct sockaddr_in6 *dst) { struct llentry *lle = NULL; - int flags = 0; KASSERT(m != NULL, ("NULL mbuf, nothing to send")); /* discard the packet if IPv6 operation is disabled on the interface */ @@ -2051,9 +2067,8 @@ nd6_output_lle(struct ifnet *ifp, struct * the condition below is not very efficient. But we believe * it is tolerable, because this should be a rare case. */ - flags = ND6_CREATE | ND6_EXCLUSIVE; IF_AFDATA_LOCK(ifp); - lle = nd6_lookup(&dst->sin6_addr, flags, ifp); + lle = nd6_create(&dst->sin6_addr, 0, ifp); IF_AFDATA_UNLOCK(ifp); } } @@ -2237,8 +2252,8 @@ nd6_add_ifa_lle(struct in6_ifaddr *ia) return (0); IF_AFDATA_LOCK(ifp); ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; - ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | - LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr); + ln = lla_create(LLTABLE6(ifp), LLE_IFADDR, + (struct sockaddr *)&ia->ia_addr); IF_AFDATA_UNLOCK(ifp); if (ln != NULL) { ln->la_expire = 0; /* for IPv6 this means permanent */ Modified: head/sys/netinet6/nd6.h ============================================================================== --- head/sys/netinet6/nd6.h Sat Aug 8 16:39:28 2015 (r286456) +++ head/sys/netinet6/nd6.h Sat Aug 8 17:48:54 2015 (r286457) @@ -89,7 +89,6 @@ struct nd_ifinfo { #define ND6_IFF_NO_PREFER_IFACE 0x80 /* XXX: not related to ND. */ #define ND6_IFF_NO_DAD 0x100 -#define ND6_CREATE LLE_CREATE #define ND6_EXCLUSIVE LLE_EXCLUSIVE #ifdef _KERNEL @@ -407,7 +406,8 @@ int nd6_is_addr_neighbor(struct sockaddr void nd6_option_init(void *, int, union nd_opts *); struct nd_opt_hdr *nd6_option(union nd_opts *); int nd6_options(union nd_opts *); -struct llentry *nd6_lookup(struct in6_addr *, int, struct ifnet *); +struct llentry *nd6_lookup(struct in6_addr *, int, struct ifnet *); +struct llentry *nd6_create(struct in6_addr *, int, struct ifnet *); void nd6_setmtu(struct ifnet *); void nd6_llinfo_settimer(struct llentry *, long); void nd6_llinfo_settimer_locked(struct llentry *, long);