Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F138034814
D31432.id93367.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D31432.id93367.diff
View Options
diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h
--- a/sys/net/if_llatbl.h
+++ b/sys/net/if_llatbl.h
@@ -238,6 +238,8 @@
struct ifnet *lltable_get_ifp(const struct lltable *llt);
int lltable_get_af(const struct lltable *llt);
+bool lltable_acquire_wlock(struct ifnet *ifp, struct llentry *lle);
+
int lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
void *farg);
/*
diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c
--- a/sys/net/if_llatbl.c
+++ b/sys/net/if_llatbl.c
@@ -318,22 +318,18 @@
}
/*
- * Tries to update @lle link-level address.
- * Since update requires AFDATA WLOCK, function
- * drops @lle lock, acquires AFDATA lock and then acquires
- * @lle lock to maintain lock order.
+ * Acquires lltable write lock.
*
- * Returns 1 on success.
+ * Returns true on success, with both lltable and lle lock held.
+ * On failure, false is returned and lle wlock is still held.
*/
-int
-lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
- const char *linkhdr, size_t linkhdrsize, int lladdr_off)
+bool
+lltable_acquire_wlock(struct ifnet *ifp, struct llentry *lle)
{
+ NET_EPOCH_ASSERT();
/* Perform real LLE update */
/* use afdata WLOCK to update fields */
- LLE_WLOCK_ASSERT(lle);
- LLE_ADDREF(lle);
LLE_WUNLOCK(lle);
IF_AFDATA_WLOCK(ifp);
LLE_WLOCK(lle);
@@ -344,17 +340,33 @@
*/
if ((lle->la_flags & LLE_DELETED) != 0) {
IF_AFDATA_WUNLOCK(ifp);
- LLE_FREE_LOCKED(lle);
- return (0);
+ return (false);
}
+ return (true);
+}
+
+/*
+ * Tries to update @lle link-level address.
+ * Since update requires AFDATA WLOCK, function
+ * drops @lle lock, acquires AFDATA lock and then acquires
+ * @lle lock to maintain lock order.
+ *
+ * Returns 1 on success.
+ */
+int
+lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
+ const char *linkhdr, size_t linkhdrsize, int lladdr_off)
+{
+
+ if (!lltable_acquire_wlock(ifp, lle))
+ return (0);
+
/* Update data */
lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off);
IF_AFDATA_WUNLOCK(ifp);
- LLE_REMREF(lle);
-
return (1);
}
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -376,6 +376,7 @@
int nd6_ioctl(u_long, caddr_t, struct ifnet *);
void nd6_cache_lladdr(struct ifnet *, struct in6_addr *,
char *, int, int, int);
+bool nd6_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, char *lladdr);
struct mbuf *nd6_grab_holdchain(struct llentry *);
int nd6_flush_holdchain(struct ifnet *, struct llentry *, struct mbuf *);
int nd6_add_ifa_lle(struct in6_ifaddr *);
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -1382,6 +1382,35 @@
return (rc);
}
+/*
+ * Tries to update @lle address/prepend data with new @lladdr.
+ *
+ * Returns true on success.
+ * In any case, @lle is returned wlocked.
+ */
+bool
+nd6_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, char *lladdr)
+{
+ u_char linkhdr[LLE_MAX_LINKHDR];
+ size_t linkhdrsize;
+ int lladdr_off;
+
+ LLE_WLOCK_ASSERT(lle);
+
+ linkhdrsize = sizeof(linkhdr);
+ if (lltable_calc_llheader(ifp, AF_INET6, lladdr,
+ linkhdr, &linkhdrsize, &lladdr_off) != 0) {
+ return (false);
+ }
+
+ if (!lltable_acquire_wlock(ifp, lle))
+ return (false);
+ lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off);
+ IF_AFDATA_WUNLOCK(ifp);
+
+ return (true);
+}
+
/*
* Free an nd6 llinfo entry.
* Since the function would cause significant changes in the kernel, DO NOT
@@ -2027,14 +2056,9 @@
* Record source link-layer address
* XXX is it dependent to ifp->if_type?
*/
- linkhdrsize = sizeof(linkhdr);
- if (lltable_calc_llheader(ifp, AF_INET6, lladdr,
- linkhdr, &linkhdrsize, &lladdr_off) != 0)
- return;
-
- if (lltable_try_set_entry_addr(ifp, ln, linkhdr, linkhdrsize,
- lladdr_off) == 0) {
+ if (!nd6_try_set_entry_addr(ifp, ln, lladdr)) {
/* Entry was deleted */
+ LLE_WUNLOCK(ln);
return;
}
@@ -2257,6 +2281,39 @@
return (nd6_resolve_slow(ifp, 0, m, dst6, desten, pflags, plle));
}
+/*
+ * Finds or creates a new llentry for @addr.
+ * Returns wlocked llentry or NULL.
+ */
+static __noinline struct llentry *
+nd6_get_llentry(struct ifnet *ifp, const struct in6_addr *addr)
+{
+ struct llentry *lle, *lle_tmp;
+
+ lle = nd6_alloc(addr, 0, ifp);
+ if (lle == NULL) {
+ char ip6buf[INET6_ADDRSTRLEN];
+ log(LOG_DEBUG,
+ "nd6_get_llentry: can't allocate llinfo for %s "
+ "(ln=%p)\n",
+ ip6_sprintf(ip6buf, addr), lle);
+ return (NULL);
+ }
+
+ IF_AFDATA_WLOCK(ifp);
+ LLE_WLOCK(lle);
+ /* Prefer any existing entry over newly-created one */
+ lle_tmp = nd6_lookup(addr, LLE_EXCLUSIVE, ifp);
+ if (lle_tmp == NULL)
+ lltable_link_entry(LLTABLE6(ifp), lle);
+ IF_AFDATA_WUNLOCK(ifp);
+ if (lle_tmp != NULL) {
+ lltable_free_entry(LLTABLE6(ifp), lle);
+ return (lle_tmp);
+ } else
+ return (lle);
+}
+
/*
* Do L2 address resolution for @sa_dst address. Stores found
* address in @desten buffer. Copy of lle ln_flags can be also
@@ -2273,7 +2330,7 @@
const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags,
struct llentry **plle)
{
- struct llentry *lle = NULL, *lle_tmp;
+ struct llentry *lle = NULL;
struct in6_addr *psrc, src;
int send_ns, ll_len;
char *lladdr;
@@ -2286,39 +2343,16 @@
* At this point, the destination of the packet must be a unicast
* or an anycast address(i.e. not a multicast).
*/
- if (lle == NULL) {
- lle = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp);
- if ((lle == NULL) && nd6_is_addr_neighbor(dst, ifp)) {
- /*
- * Since nd6_is_addr_neighbor() internally calls nd6_lookup(),
- * the condition below is not very efficient. But we believe
- * it is tolerable, because this should be a rare case.
- */
- lle = nd6_alloc(&dst->sin6_addr, 0, ifp);
- if (lle == NULL) {
- char ip6buf[INET6_ADDRSTRLEN];
- log(LOG_DEBUG,
- "nd6_output: can't allocate llinfo for %s "
- "(ln=%p)\n",
- ip6_sprintf(ip6buf, &dst->sin6_addr), lle);
- m_freem(m);
- return (ENOBUFS);
- }
+ lle = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp);
+ if ((lle == NULL) && nd6_is_addr_neighbor(dst, ifp)) {
+ /*
+ * Since nd6_is_addr_neighbor() internally calls nd6_lookup(),
+ * the condition below is not very efficient. But we believe
+ * it is tolerable, because this should be a rare case.
+ */
+ lle = nd6_get_llentry(ifp, &dst->sin6_addr);
+ }
- IF_AFDATA_WLOCK(ifp);
- LLE_WLOCK(lle);
- /* Prefer any existing entry over newly-created one */
- lle_tmp = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp);
- if (lle_tmp == NULL)
- lltable_link_entry(LLTABLE6(ifp), lle);
- IF_AFDATA_WUNLOCK(ifp);
- if (lle_tmp != NULL) {
- lltable_free_entry(LLTABLE6(ifp), lle);
- lle = lle_tmp;
- lle_tmp = NULL;
- }
- }
- }
if (lle == NULL) {
m_freem(m);
return (ENOBUFS);
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -770,16 +770,9 @@
/*
* Record link-layer address, and update the state.
*/
- linkhdrsize = sizeof(linkhdr);
- if (lltable_calc_llheader(ifp, AF_INET6, lladdr,
- linkhdr, &linkhdrsize, &lladdr_off) != 0)
- return;
-
- if (lltable_try_set_entry_addr(ifp, ln, linkhdr, linkhdrsize,
- lladdr_off) == 0) {
- ln = NULL;
+ if (!nd6_try_set_entry_addr(ifp, ln, lladdr))
goto freeit;
- }
+
EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_RESOLVED);
if (is_solicited)
nd6_llinfo_setstate(ln, ND6_LLINFO_REACHABLE);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 29, 9:29 AM (4 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26325115
Default Alt Text
D31432.id93367.diff (7 KB)
Attached To
Mode
D31432: [lltable] Restructure nd6 code
Attached
Detach File
Event Timeline
Log In to Comment