[openwrt/openwrt] mac80211: fix spurious disconnect issues with disassoc_low_ack=1 (default)

LEDE Commits lede-commits at lists.infradead.org
Sun Aug 9 08:02:26 EDT 2020


nbd pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/eff8c76aa02275a7b325e0fa93cc349380299fde

commit eff8c76aa02275a7b325e0fa93cc349380299fde
Author: Felix Fietkau <nbd at nbd.name>
AuthorDate: Sat Aug 8 19:28:07 2020 +0200

    mac80211: fix spurious disconnect issues with disassoc_low_ack=1 (default)
    
    mac80211 reports a packet loss event to user space when 50 consecutive packets
    were not acked. On a high throughput link with long aggregates and sudden
    link changes, this can trigger way too easily.
    Mitigate false positives by only triggering the event on a packet loss if
    no ACK was received for at least a second
    
    Signed-off-by: Felix Fietkau <nbd at nbd.name>
---
 ...-reduce-packet-loss-event-false-positives.patch | 116 +++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/package/kernel/mac80211/patches/subsys/310-mac80211-reduce-packet-loss-event-false-positives.patch b/package/kernel/mac80211/patches/subsys/310-mac80211-reduce-packet-loss-event-false-positives.patch
new file mode 100644
index 0000000000..85094389a8
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/310-mac80211-reduce-packet-loss-event-false-positives.patch
@@ -0,0 +1,116 @@
+From: Felix Fietkau <nbd at nbd.name>
+Date: Sat, 8 Aug 2020 19:20:02 +0200
+Subject: [PATCH] mac80211: reduce packet loss event false positives
+
+When running a large number of packets per second with a high data rate
+and long A-MPDUs, the packet loss threshold can be reached very quickly
+when the link conditions change. This frequently shows up as spurious
+disconnects.
+Mitigate false positives by using a similar logic for regular stations
+as the one being used for TDLS, though with a more aggressive timeout.
+Packet loss events are only reported if no ACK was received for a second.
+
+Signed-off-by: Felix Fietkau <nbd at nbd.name>
+---
+
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -522,7 +522,7 @@ struct ieee80211_sta_rx_stats {
+  * @status_stats.retry_failed: # of frames that failed after retry
+  * @status_stats.retry_count: # of retries attempted
+  * @status_stats.lost_packets: # of lost packets
+- * @status_stats.last_tdls_pkt_time: timestamp of last TDLS packet
++ * @status_stats.last_pkt_time: timestamp of last ACKed packet
+  * @status_stats.msdu_retries: # of MSDU retries
+  * @status_stats.msdu_failed: # of failed MSDUs
+  * @status_stats.last_ack: last ack timestamp (jiffies)
+@@ -595,7 +595,7 @@ struct sta_info {
+ 		unsigned long filtered;
+ 		unsigned long retry_failed, retry_count;
+ 		unsigned int lost_packets;
+-		unsigned long last_tdls_pkt_time;
++		unsigned long last_pkt_time;
+ 		u64 msdu_retries[IEEE80211_NUM_TIDS + 1];
+ 		u64 msdu_failed[IEEE80211_NUM_TIDS + 1];
+ 		unsigned long last_ack;
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -749,12 +749,16 @@ static void ieee80211_report_used_skb(st
+  *  - current throughput (higher value for higher tpt)?
+  */
+ #define STA_LOST_PKT_THRESHOLD	50
++#define STA_LOST_PKT_TIME	HZ		/* 1 sec since last ACK */
+ #define STA_LOST_TDLS_PKT_THRESHOLD	10
+ #define STA_LOST_TDLS_PKT_TIME		(10*HZ) /* 10secs since last ACK */
+ 
+ static void ieee80211_lost_packet(struct sta_info *sta,
+ 				  struct ieee80211_tx_info *info)
+ {
++	unsigned long pkt_time = STA_LOST_PKT_TIME;
++	unsigned int pkt_thr = STA_LOST_PKT_THRESHOLD;
++
+ 	/* If driver relies on its own algorithm for station kickout, skip
+ 	 * mac80211 packet loss mechanism.
+ 	 */
+@@ -767,21 +771,20 @@ static void ieee80211_lost_packet(struct
+ 		return;
+ 
+ 	sta->status_stats.lost_packets++;
+-	if (!sta->sta.tdls &&
+-	    sta->status_stats.lost_packets < STA_LOST_PKT_THRESHOLD)
+-		return;
++	if (sta->sta.tdls) {
++		pkt_time = STA_LOST_TDLS_PKT_TIME;
++		pkt_thr = STA_LOST_PKT_THRESHOLD;
++	}
+ 
+ 	/*
+ 	 * If we're in TDLS mode, make sure that all STA_LOST_TDLS_PKT_THRESHOLD
+ 	 * of the last packets were lost, and that no ACK was received in the
+ 	 * last STA_LOST_TDLS_PKT_TIME ms, before triggering the CQM packet-loss
+ 	 * mechanism.
++	 * For non-TDLS, use STA_LOST_PKT_THRESHOLD and STA_LOST_PKT_TIME
+ 	 */
+-	if (sta->sta.tdls &&
+-	    (sta->status_stats.lost_packets < STA_LOST_TDLS_PKT_THRESHOLD ||
+-	     time_before(jiffies,
+-			 sta->status_stats.last_tdls_pkt_time +
+-			 STA_LOST_TDLS_PKT_TIME)))
++	if (sta->status_stats.lost_packets < pkt_thr ||
++	    !time_after(jiffies, sta->status_stats.last_pkt_time + pkt_time))
+ 		return;
+ 
+ 	cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
+@@ -1034,9 +1037,7 @@ static void __ieee80211_tx_status(struct
+ 					sta->status_stats.lost_packets = 0;
+ 
+ 				/* Track when last TDLS packet was ACKed */
+-				if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
+-					sta->status_stats.last_tdls_pkt_time =
+-						jiffies;
++				sta->status_stats.last_pkt_time = jiffies;
+ 			} else if (noack_success) {
+ 				/* nothing to do here, do not account as lost */
+ 			} else {
+@@ -1169,9 +1170,8 @@ void ieee80211_tx_status_ext(struct ieee
+ 			if (sta->status_stats.lost_packets)
+ 				sta->status_stats.lost_packets = 0;
+ 
+-			/* Track when last TDLS packet was ACKed */
+-			if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
+-				sta->status_stats.last_tdls_pkt_time = jiffies;
++			/* Track when last packet was ACKed */
++			sta->status_stats.last_pkt_time = jiffies;
+ 		} else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
+ 			return;
+ 		} else if (noack_success) {
+@@ -1260,8 +1260,7 @@ void ieee80211_tx_status_8023(struct iee
+ 			if (sta->status_stats.lost_packets)
+ 				sta->status_stats.lost_packets = 0;
+ 
+-			if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
+-				sta->status_stats.last_tdls_pkt_time = jiffies;
++			sta->status_stats.last_pkt_time = jiffies;
+ 		} else {
+ 			ieee80211_lost_packet(sta, info);
+ 		}



More information about the lede-commits mailing list