On Fri, Nov 18, 2016 at 03:01:34PM +0100, Stefan Sperling wrote:
> On Fri, Nov 18, 2016 at 02:37:18PM +0100, Stefan Sperling wrote:
> > While playing around with rate scaling, and testing behaviour when
> > increasing the distance to the AP, I noticed that a lot of successfully
> > received frames end up getting stuck or discarded in the block ack
> > buffer logic.
> > 
> > In this situation, I see icmp echo replies arrive in the output
> > of tcpdump -i iwm0 -y IEEE802_11_RADIO -v, but those replies don't
> > reach the ping program in userspace. And when they do, they arrive
> > with a huge delay (up to several seconds).
> > 
> > This diff tunes block ack parameters to vastly reduce buffering timeout.
> > With this, as long as we receive echo replies, they are very likely to
> > reach the ping program. In my testing, some pings still get lost and
> > some get delayed, but it seems latency now depends mostly on how fast
> > the AP chooses a lower data rate -- and once the incoming rate settles
> > at 1Mbit/s, traffic flows smoothly again.
> > 
> > Under ideal wifi signal conditions, this diff should make no difference.
> > 
> > OK?
> 
> A bit of more testing has shown that a 5 msec gap timeout is a bit
> too aggressive when other traffic is passed besides ping. It can
> cause frames to arrive behind the BA window, and we're dropping those.
> In such cases 10 msec seems to work better.

And another diff, which adds another idea on top:

Resync the block ack window backwards (as well as forwards), when we
lose synchronization. The 802.11n standard commands we drop all packets
"before" the window, but well... several details of this standards were
"well intended".
This change should address a situation I saw where echo replies were
received but dropped because they were counted as arriving "before"
the window, and not "after" the window.

However, it comes at a cost of occasional dupes during normal operation,
e.g. in case the sender did not receive our block ack and sends the whole
aggregate again.

Contrary to previous diffs, I'm not changing the MAX_WINMISS threshold
in this diff (currently set to 8 frames). This seems to work alright
and not cause many dupes.

Index: ieee80211_node.h
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_node.h,v
retrieving revision 1.63
diff -u -p -r1.63 ieee80211_node.h
--- ieee80211_node.h    21 Sep 2016 12:21:27 -0000      1.63
+++ ieee80211_node.h    18 Nov 2016 15:15:45 -0000
@@ -146,7 +146,7 @@ struct ieee80211_rx_ba {
        u_int16_t               ba_winsize;
        u_int16_t               ba_head;
        struct timeout          ba_gap_to;
-#define IEEE80211_BA_GAP_TIMEOUT       300 /* msec */
+#define IEEE80211_BA_GAP_TIMEOUT       10 /* msec */
        /* Counter for consecutive frames which missed the BA window. */
        int                     ba_winmiss;
        /* Sequence number of previous frame which missed the BA window. */
Index: ieee80211_input.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v
retrieving revision 1.180
diff -u -p -r1.180 ieee80211_input.c
--- ieee80211_input.c   21 Sep 2016 12:21:27 -0000      1.180
+++ ieee80211_input.c   18 Nov 2016 15:14:23 -0000
@@ -708,10 +708,31 @@ ieee80211_input_ba(struct ieee80211com *
 
        if (SEQ_LT(sn, ba->ba_winstart)) {      /* SN < WinStartB */
                ic->ic_stats.is_ht_rx_frame_below_ba_winstart++;
-               m_freem(m);     /* discard the MPDU */
-               return;
-       }
-       if (SEQ_LT(ba->ba_winend, sn)) {        /* WinEndB < SN */
+               /* 
+                * Check whether we're consistently ahead of the window,
+                * and let the window jump backwards if neccessary.
+                */
+               if (ba->ba_winmiss < IEEE80211_BA_MAX_WINMISS) { 
+                       if (ba->ba_missedsn == ((sn - 1) & 0xfff))
+                               ba->ba_winmiss++;
+                       else
+                               ba->ba_winmiss = 0;
+                       ba->ba_missedsn = sn;
+                       ifp->if_ierrors++;
+                       m_freem(m);     /* discard the MPDU */
+                       return;
+               } else {
+                       /* It appears the window has moved for real. */
+                       ic->ic_stats.is_ht_rx_ba_window_jump++;
+                       ba->ba_winmiss = 0;
+                       ba->ba_missedsn = 0;
+                       /* Flush our current window. */
+                       ieee80211_ba_move_window(ic, ni, tid, ba->ba_winend);
+                       /* Reset the window. */
+                       ba->ba_winstart = sn;
+                       ieee80211_input_ba_flush(ic, ni, ba);
+               }
+       } else if (SEQ_LT(ba->ba_winend, sn)) { /* WinEndB < SN */
                ic->ic_stats.is_ht_rx_frame_above_ba_winend++;
                count = (sn - ba->ba_winend) & 0xfff;
                if (count > ba->ba_winsize) {

Reply via email to