summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2020-07-21 08:39:00 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2020-07-21 08:39:00 +0000
commita02431f689b429b7a00c5292661a7cc298f19b3d (patch)
tree898adc0e5e0eb70c37782ef8f878a95f650bc590
parentf0129c6f60ba44937b9aef20e315408ed4927e29 (diff)
Improve processing of lost frames during 802.11 Rx aggregation.
Make ieee80211_input_ba() skip one missing frame at the head of the Rx block ack (BA) window once the rest of the window has filled up with pending frames. This avoids having to wait for the BA window gap timeout handler to run in order to make progress in such situations. Simplify the BA gap timeout handler by deferring the actual flushing of the BA window buffer to the regular input path. The timeout handler now simply advances the BA window across any missing frames at the head of the window, and if_input() is no longer called from the context of this timeout handler. The window will be flushed once another frame arrives. Packet loss under streamy traffic conditions and during Rx bursts is reduced. Much less stuttering, more stable tcpbench, and easier flight in Minecraft. tested by phessler@, Martin Vahlensieck, jmc@, Uwe Werler, and myself
-rw-r--r--sys/net80211/ieee80211_input.c65
-rw-r--r--sys/net80211/ieee80211_node.h9
2 files changed, 54 insertions, 20 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 6ea9bfe3d3a..f65a1892194 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_input.c,v 1.219 2020/07/20 07:45:44 stsp Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.220 2020/07/21 08:38:59 stsp Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
@@ -67,6 +67,7 @@ void ieee80211_input_ba(struct ieee80211com *, struct mbuf *,
struct mbuf_list *);
void ieee80211_input_ba_flush(struct ieee80211com *, struct ieee80211_node *,
struct ieee80211_rx_ba *, struct mbuf_list *);
+int ieee80211_input_ba_gap_skip(struct ieee80211_rx_ba *);
void ieee80211_input_ba_gap_timeout(void *arg);
void ieee80211_ba_move_window(struct ieee80211com *,
struct ieee80211_node *, u_int8_t, u_int16_t, struct mbuf_list *);
@@ -837,10 +838,29 @@ ieee80211_input_ba(struct ieee80211com *ic, struct mbuf *m,
rxi->rxi_flags |= IEEE80211_RXI_AMPDU_DONE;
ba->ba_buf[idx].rxi = *rxi;
- if (ba->ba_buf[ba->ba_head].m == NULL)
- timeout_add_msec(&ba->ba_gap_to, IEEE80211_BA_GAP_TIMEOUT);
- else if (timeout_pending(&ba->ba_gap_to))
- timeout_del(&ba->ba_gap_to);
+ if (ba->ba_buf[ba->ba_head].m == NULL) {
+ if (ba->ba_gapwait < (ba->ba_winsize - 1)) {
+ if (ba->ba_gapwait == 0) {
+ timeout_add_msec(&ba->ba_gap_to,
+ IEEE80211_BA_GAP_TIMEOUT);
+ }
+ ba->ba_gapwait++;
+ } else {
+ /*
+ * A full BA window worth of frames is now waiting.
+ * Skip the missing frame at the head of the window.
+ */
+ int skipped = ieee80211_input_ba_gap_skip(ba);
+ ic->ic_stats.is_ht_rx_ba_frame_lost += skipped;
+ ba->ba_gapwait = 0;
+ if (timeout_pending(&ba->ba_gap_to))
+ timeout_del(&ba->ba_gap_to);
+ }
+ } else {
+ ba->ba_gapwait = 0;
+ if (timeout_pending(&ba->ba_gap_to))
+ timeout_del(&ba->ba_gap_to);
+ }
ieee80211_input_ba_flush(ic, ni, ba, ml);
}
@@ -908,10 +928,26 @@ ieee80211_input_ba_flush(struct ieee80211com *ic, struct ieee80211_node *ni,
* A leading gap will occur if a particular A-MPDU subframe never arrives
* or if a bug in the sender causes sequence numbers to jump forward by > 1.
*/
+int
+ieee80211_input_ba_gap_skip(struct ieee80211_rx_ba *ba)
+{
+ int skipped = 0;
+
+ while (skipped < ba->ba_winsize && ba->ba_buf[ba->ba_head].m == NULL) {
+ /* move window forward */
+ ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
+ ba->ba_winstart = (ba->ba_winstart + 1) & 0xfff;
+ skipped++;
+ }
+ if (skipped > 0)
+ ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff;
+
+ return skipped;
+}
+
void
ieee80211_input_ba_gap_timeout(void *arg)
{
- struct mbuf_list ml = MBUF_LIST_INITIALIZER();
struct ieee80211_rx_ba *ba = arg;
struct ieee80211_node *ni = ba->ba_ni;
struct ieee80211com *ic = ni->ni_ic;
@@ -921,19 +957,8 @@ ieee80211_input_ba_gap_timeout(void *arg)
s = splnet();
- skipped = 0;
- while (skipped < ba->ba_winsize && ba->ba_buf[ba->ba_head].m == NULL) {
- /* move window forward */
- ba->ba_head = (ba->ba_head + 1) % IEEE80211_BA_MAX_WINSZ;
- ba->ba_winstart = (ba->ba_winstart + 1) & 0xfff;
- skipped++;
- ic->ic_stats.is_ht_rx_ba_frame_lost++;
- }
- if (skipped > 0)
- ba->ba_winend = (ba->ba_winstart + ba->ba_winsize - 1) & 0xfff;
-
- ieee80211_input_ba_flush(ic, ni, ba, &ml);
- if_input(&ic->ic_if, &ml);
+ skipped = ieee80211_input_ba_gap_skip(ba);
+ ic->ic_stats.is_ht_rx_ba_frame_lost += skipped;
splx(s);
}
@@ -2716,6 +2741,7 @@ ieee80211_recv_addba_req(struct ieee80211com *ic, struct mbuf *m,
ba->ba_token = token;
timeout_set(&ba->ba_to, ieee80211_rx_ba_timeout, ba);
timeout_set(&ba->ba_gap_to, ieee80211_input_ba_gap_timeout, ba);
+ ba->ba_gapwait = 0;
ba->ba_winsize = bufsz;
if (ba->ba_winsize == 0 || ba->ba_winsize > IEEE80211_BA_MAX_WINSZ)
ba->ba_winsize = IEEE80211_BA_MAX_WINSZ;
@@ -2956,6 +2982,7 @@ ieee80211_recv_delba(struct ieee80211com *ic, struct mbuf *m,
/* stop Block Ack inactivity timer */
timeout_del(&ba->ba_to);
timeout_del(&ba->ba_gap_to);
+ ba->ba_gapwait = 0;
if (ba->ba_buf != NULL) {
/* free all MSDUs stored in reordering buffer */
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index 4256a8add05..510eb534ae7 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_node.h,v 1.86 2020/05/31 09:11:12 stsp Exp $ */
+/* $OpenBSD: ieee80211_node.h,v 1.87 2020/07/21 08:38:59 stsp Exp $ */
/* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */
/*-
@@ -226,6 +226,13 @@ struct ieee80211_rx_ba {
u_int16_t ba_head;
struct timeout ba_gap_to;
#define IEEE80211_BA_GAP_TIMEOUT 300 /* msec */
+
+ /*
+ * Counter for frames forced to wait in the reordering buffer
+ * due to a leading gap caused by one or more missing frames.
+ */
+ int ba_gapwait;
+
/* Counter for consecutive frames which missed the BA window. */
int ba_winmiss;
/* Sequence number of previous frame which missed the BA window. */