summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2015-12-13 07:39:49 +0000
committermelifaro <melifaro@FreeBSD.org>2015-12-13 07:39:49 +0000
commit5acc305ae04293e9f5d59d5b6782bdf9c72ba05b (patch)
tree251c656de71547c45363d25809b11a40e2698fdb /sys/net
parentd5e50bf50f68836c9aab5f197ee9eacfec020d8c (diff)
downloadFreeBSD-src-5acc305ae04293e9f5d59d5b6782bdf9c72ba05b.zip
FreeBSD-src-5acc305ae04293e9f5d59d5b6782bdf9c72ba05b.tar.gz
Remove LLE read lock from IPv6 fast path.
LLE structure is mostly unchanged during its lifecycle: there are only 2 things relevant for fast path lookup code: 1) link-level address change. Since r286722, these updates are performed under AFDATA WLOCK. 2) Some sort of feedback indicating that this particular entry is used so we send NS to perform reachability verification instead of expiring entry. The only signal that is needed from fast path is something like binary yes/no. The latter is solved by the following changes: Special r_skip_req (introduced in D3688) value is used for fast path feedback. It is read lockless by fast path, but updated under req_mutex mutex. If this field is non-zero, then fast path will acquire lock and set it back to 0. After transitioning to STALE state, callout timer is armed to run each V_nd6_delay seconds to make sure that if packet was transmitted at the start of given interval, we would be able to switch to PROBE state in V_nd6_delay seconds as user expects. (in STALE state) timer is rescheduled until original V_nd6_gctimer expires keeping lle in STALE state (remaining timer value stored in lle_remtime). (in STALE state) timer is rescheduled if packet was transmitted less that V_nd6_delay seconds ago to make sure we transition to PROBE state exactly after V_n6_delay seconds. As a result, all packets towards lle in REACHABLE/STALE/PROBE states are handled by fast path without acquiring lle read lock. Differential Revision: https://reviews.freebsd.org/D3780
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if_llatbl.c41
-rw-r--r--sys/net/if_llatbl.h4
2 files changed, 45 insertions, 0 deletions
diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c
index c7b1042..f2749e5 100644
--- a/sys/net/if_llatbl.c
+++ b/sys/net/if_llatbl.c
@@ -288,6 +288,47 @@ lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
}
/*
+ * 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 *lladdr)
+{
+
+ /* 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);
+
+ /*
+ * Since we droppped LLE lock, other thread might have deleted
+ * this lle. Check and return
+ */
+ if ((lle->la_flags & LLE_DELETED) != 0) {
+ IF_AFDATA_WUNLOCK(ifp);
+ LLE_FREE_LOCKED(lle);
+ return (0);
+ }
+
+ /* Update data */
+ lltable_set_entry_addr(ifp, lle, lladdr);
+
+ IF_AFDATA_WUNLOCK(ifp);
+
+ LLE_REMREF(lle);
+
+ return (1);
+}
+
+/*
*
* Performes generic cleanup routines and frees lle.
*
diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h
index 044959e..8a300c3 100644
--- a/sys/net/if_llatbl.h
+++ b/sys/net/if_llatbl.h
@@ -79,6 +79,8 @@ struct llentry {
int16_t ln_state; /* IPv6 has ND6_LLINFO_NOSTATE == -2 */
uint16_t ln_router;
time_t ln_ntick;
+ time_t lle_remtime; /* Real time remaining */
+ time_t lle_hittime; /* Time when r_skip_req was unset */
int lle_refcnt;
LIST_ENTRY(llentry) lle_chain; /* chain of deleted items */
@@ -222,6 +224,8 @@ struct llentry *llentry_alloc(struct ifnet *, struct lltable *,
size_t lltable_drop_entry_queue(struct llentry *);
void lltable_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
const char *lladdr);
+int lltable_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle,
+ const char *lladdr);
struct llentry *lltable_alloc_entry(struct lltable *llt, u_int flags,
const struct sockaddr *l4addr);
OpenPOWER on IntegriCloud