summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2015-08-08 17:48:54 +0000
committermelifaro <melifaro@FreeBSD.org>2015-08-08 17:48:54 +0000
commit20bb5966e2075bde042b8b62c236e29d6e8934da (patch)
tree731dce9358d789a8c3034ce0eea54d4f64dad724
parent2039dd9ad41e9d94f6bf6471ffcf42c381368b69 (diff)
downloadFreeBSD-src-20bb5966e2075bde042b8b62c236e29d6e8934da.zip
FreeBSD-src-20bb5966e2075bde042b8b62c236e29d6e8934da.tar.gz
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
-rw-r--r--sys/net/if_llatbl.c125
-rw-r--r--sys/net/if_llatbl.h47
-rw-r--r--sys/netinet/if_ether.c28
-rw-r--r--sys/netinet/in.c174
-rw-r--r--sys/netinet/toecore.c3
-rw-r--r--sys/netinet6/in6.c171
-rw-r--r--sys/netinet6/nd6.c43
-rw-r--r--sys/netinet6/nd6.h4
8 files changed, 371 insertions, 224 deletions
diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c
index 84ea6c6..3f4e737 100644
--- a/sys/net/if_llatbl.c
+++ b/sys/net/if_llatbl.c
@@ -147,8 +147,7 @@ llentry_alloc(struct ifnet *ifp, struct lltable *lt,
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, struct rt_addrinfo *info)
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, struct rt_addrinfo *info)
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, struct rt_addrinfo *info)
LLTABLE_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_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;
+ error = 0;
+
+ 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);
}
diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h
index 4f21fde..69c340c 100644
--- a/sys/net/if_llatbl.h
+++ b/sys/net/if_llatbl.h
@@ -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 ifnet *, struct lltable *,
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 <sys/eventhandler.h>
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index 1012e93..8006226 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -152,8 +152,7 @@ arp_ifscrub(struct ifnet *ifp, uint32_t addr)
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, struct mbuf *m,
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 ifaddr *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;
}
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index c2c7ce0..f4eab74 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -1107,6 +1107,117 @@ in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr
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_int flags, const struct sockaddr *l3add
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;
diff --git a/sys/netinet/toecore.c b/sys/netinet/toecore.c
index 5ca4604..ec73f91 100644
--- a/sys/netinet/toecore.c
+++ b/sys/netinet/toecore.c
@@ -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. */
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 754a5f3..f82fbbd 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -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);
+}
+
+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;
- 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);
+ 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;
}
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index bcb2d0b..4cfe818 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -937,16 +937,33 @@ nd6_lookup(struct in6_addr *addr6, int flags, struct ifnet *ifp)
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, struct in6_addr *from, char *lladdr,
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 ifnet *origifp, struct mbuf *m,
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 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.
*/
- 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 */
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 0b061df..d148a0b 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -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_in6 *, struct ifnet *);
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);
OpenPOWER on IntegriCloud