mac80211: Fix station rx-packets counters.
Subsystems (2)
PATCH 1/3 mac80211: Fix station rx-packets counters.
From: Ben Greear <[email protected]>
I noticed 'iw dev wlan6 station dump' showed almost no rx-packets one one of my radios. The rx-amsdu path did not appear to gather any stats, and after code inspection, neither did the rx-data handler.
Add common method to deal with these stats. Verified in AX and /a mode, stats look at least generally correct now.
--- net/mac80211/rx.c | 54 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 17 deletions(-)
net/mac80211/rx.c +37 -17
@@ -1713,6 +1713,27 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx)return RX_CONTINUE ; } +static void ieee80211_update_data_rx_stats (struct ieee80211_rx_data *rx, +struct ieee80211_sta_rx_stats *stats, +struct ieee80211_rx_status *status, +int skb_len) +{ + stats->fragments++; + stats->packets++; + stats->last_rx = jiffies; + stats->last_rate =sta_stats_encode_rate (status); + +/* The seqno index has the same property as needed +* for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS +* for non-QoS-data frames. Here we know it's a data +* frame, so count MSDUs. +*/ +u64_stats_update_begin (&stats->syncp); + stats->msdu[rx->seqno_idx]++; + stats->bytes += skb_len; +u64_stats_update_end (&stats->syncp); +} + static ieee80211_rx_result debug_noinlineieee80211_rx_h_sta_process (struct ieee80211_rx_data *rx) {
@@ -2706,6 +2727,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)struct ieee80211_rx_status *status =IEEE80211_SKB_RXCB (skb);struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;__le16 fc = hdr->frame_control; +ieee80211_rx_result rv; +int orig_len = skb->len;if (!(status->rx_flags &IEEE80211_RX_AMSDU ))return RX_CONTINUE ;
@@ -2734,7 +2757,12 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)if (is_multicast_ether_addr (hdr->addr1))return RX_DROP_UNUSABLE ; -return __ieee80211_rx_h_amsdu (rx,0 ); + rv =__ieee80211_rx_h_amsdu (rx,0 ); +if ((rv ==RX_QUEUED ) && (rx->sta)) { +struct ieee80211_sta_rx_stats *stats = &rx->sta->rx_stats; +ieee80211_update_data_rx_stats (rx, stats, status, orig_len); + } +return rv; }#ifdef CONFIG_MAC80211_MESH
@@ -2958,6 +2986,13 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)mod_timer (&local->dynamic_ps_timer, jiffies +msecs_to_jiffies (local->hw.conf.dynamic_ps_timeout)); + +if (rx->sta) { +struct ieee80211_sta_rx_stats *stats = &rx->sta->rx_stats; +struct ieee80211_rx_status *status =IEEE80211_SKB_RXCB (rx->skb); +ieee80211_update_data_rx_stats (rx, stats, status, rx->skb->len); + } +ieee80211_deliver_skb (rx);return RX_QUEUED ;
@@ -4400,12 +4435,6 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,return true; } - stats->last_rx = jiffies; - stats->last_rate =sta_stats_encode_rate (status); - - stats->fragments++; - stats->packets++; -/* do the header conversion - first grab the addresses */ ether_addr_copy (addrs.da, skb->data + fast_rx->da_offs);ether_addr_copy (addrs.sa, skb->data + fast_rx->sa_offs);
@@ -4416,18 +4445,9 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, skb->dev = fast_rx->dev; +ieee80211_update_data_rx_stats (rx, stats, status, orig_len);dev_sw_netstats_rx_add (fast_rx->dev, skb->len); -/* The seqno index has the same property as needed -* for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS -* for non-QoS-data frames. Here we know it's a data -* frame, so count MSDUs. -*/ -u64_stats_update_begin (&stats->syncp); - stats->msdu[rx->seqno_idx]++; - stats->bytes += orig_len; -u64_stats_update_end (&stats->syncp); -if (fast_rx->internal_forward) {struct sk_buff *xmit_skb =NULL ;if (is_multicast_ether_addr (addrs.da)) {
Signature · 1 line
2.20.1
PATCH 2/3 mac80211: Provide per-station stats in debugfs
From: Ben Greear <[email protected]>
Including per tid and per acs stats.
Nice for those who like to peer deep into the guts of a system.
--- net/mac80211/debugfs_sta.c | 88 ++++++++++++++++++++++++++++++++++++++ net/mac80211/sta_info.c | 33 ++++++++++++++ net/mac80211/sta_info.h | 4 ++ 3 files changed, 125 insertions(+)
net/mac80211/debugfs_sta.c +88 -0
@@ -102,6 +102,93 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, }STA_OPS (flags); +static ssize_t sta_stats_read (struct file *file,char __user *userbuf, +size_t count,loff_t *ppos) +{ +struct sta_info *sta = file->private_data; +unsigned int len =0 ; +const int buf_len =8000 ; +char *buf =kzalloc (buf_len,GFP_KERNEL ); +unsigned long sum; +char tmp[60 ]; +int i; +struct ieee80211_sta_rx_stats rx_stats = {0 }; + +if (!buf) +return -ENOMEM ; + +sta_accum_rx_stats (sta, &rx_stats); + +#define PRINT_MY_STATS (a, b) do { \ + len += scnprintf(buf + len, buf_len - len, "%30s %18lu\n", a, (unsigned long)(b)); \ + if (len >= buf_len) { \ + goto done; \ + } \ + } while (0) + +#define PRINT_MY_STATS_S (a, b) do { \ + len += scnprintf(buf + len, buf_len - len, "%30s %18ld\n", a, (long)(b)); \ + if (len >= buf_len) { \ + goto done; \ + } \ + } while (0) + +PRINT_MY_STATS ("rx-packets" , rx_stats.packets); +PRINT_MY_STATS ("rx-bytes" , rx_stats.bytes); +PRINT_MY_STATS ("rx-dup" , rx_stats.num_duplicates); +PRINT_MY_STATS ("rx-fragments" , rx_stats.fragments); +PRINT_MY_STATS ("rx-dropped" , rx_stats.dropped); +PRINT_MY_STATS_S ("rx-last-signal" , rx_stats.last_signal); + +for (i =0 ; i<IEEE80211_MAX_CHAINS ; i++) { +if (rx_stats.chains & (1 <<i)) { +sprintf (tmp,"rx-last-signal-chain[%i]" , i); +PRINT_MY_STATS_S (tmp, rx_stats.chain_signal_last[i]); + } + } +PRINT_MY_STATS ("rx-last-rate-encoded" , rx_stats.last_rate); + + len +=scnprintf (buf + len, buf_len - len,"\n" ); + + sum = sta->tx_stats.packets[0 ] + sta->tx_stats.packets[1 ] + + sta->tx_stats.packets[2 ] + sta->tx_stats.packets[3 ]; +PRINT_MY_STATS ("tx-packets" , sum); + + sum = sta->tx_stats.bytes[0 ] + sta->tx_stats.bytes[1 ] + + sta->tx_stats.bytes[2 ] + sta->tx_stats.bytes[3 ]; +PRINT_MY_STATS ("tx-bytes" , sum); + +/* per txq stats */ +PRINT_MY_STATS ("tx-packets-acs[VO]" , sta->tx_stats.packets[IEEE80211_AC_VO ]); +PRINT_MY_STATS ("tx-packets-acs[VI]" , sta->tx_stats.packets[IEEE80211_AC_VI ]); +PRINT_MY_STATS ("tx-packets-acs[BE]" , sta->tx_stats.packets[IEEE80211_AC_BE ]); +PRINT_MY_STATS ("tx-packets-acs[BK]" , sta->tx_stats.packets[IEEE80211_AC_BK ]); + +PRINT_MY_STATS ("tx-bytes-acs[VO]" , sta->tx_stats.bytes[IEEE80211_AC_VO ]); +PRINT_MY_STATS ("tx-bytes-acs[VI]" , sta->tx_stats.bytes[IEEE80211_AC_VI ]); +PRINT_MY_STATS ("tx-bytes-acs[BE]" , sta->tx_stats.bytes[IEEE80211_AC_BE ]); +PRINT_MY_STATS ("tx-bytes-acs[BK]" , sta->tx_stats.bytes[IEEE80211_AC_BK ]); + + len +=scnprintf (buf + len, buf_len - len,"\n" ); +for (i =0 ; i<=IEEE80211_NUM_TIDS ; i++) { +sprintf (tmp,"tx-msdu-tid[%2i]" , i); +PRINT_MY_STATS (tmp, sta->tx_stats.msdu[i]); + } + + len +=scnprintf (buf + len, buf_len - len,"\n" ); +for (i =0 ; i<=IEEE80211_NUM_TIDS ; i++) { +sprintf (tmp,"rx-msdu-tid[%2i]" , i); +PRINT_MY_STATS (tmp, rx_stats.msdu[i]); + } + +#undef PRINT_MY_STATS +done: + i =simple_read_from_buffer (userbuf, count, ppos, buf,strlen (buf)); +kfree (buf); +return i; +} +STA_OPS (stats); +static ssize_t sta_num_ps_buf_frames_read (struct file *file,char __user *userbuf,size_t count,loff_t *ppos)
@@ -1073,6 +1160,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) sta->debugfs_dir =debugfs_create_dir (mac, stations_dir);DEBUGFS_ADD (flags); +DEBUGFS_ADD (stats);DEBUGFS_ADD (aid);DEBUGFS_ADD (num_ps_buf_frames);DEBUGFS_ADD (last_seq_ctrl);
net/mac80211/sta_info.c +33 -0
@@ -2650,6 +2650,39 @@ static void sta_update_codel_params(struct sta_info *sta, u32 thr) } } +void sta_accum_rx_stats (struct sta_info *sta, +struct ieee80211_sta_rx_stats *rx_stats) +{ +int cpu; +int i; + +memcpy (rx_stats, &sta->rx_stats,sizeof (*rx_stats)); + +if (!sta->pcpu_rx_stats) +return ; + +for_each_possible_cpu (cpu) { +struct ieee80211_sta_rx_stats *cpurxs; + + cpurxs =per_cpu_ptr (sta->pcpu_rx_stats, cpu); + rx_stats->packets += cpurxs->packets; +if (time_after (cpurxs->last_rx, rx_stats->last_rx)) { + rx_stats->last_rx = cpurxs->last_rx; + rx_stats->last_signal = cpurxs->last_signal; +for (i =0 ; i<IEEE80211_MAX_CHAINS ; i++) + rx_stats->chain_signal_last[i] = cpurxs->chain_signal_last[i]; + rx_stats->last_rate = cpurxs->last_rate; + } + rx_stats->num_duplicates += cpurxs->num_duplicates; + rx_stats->fragments += cpurxs->fragments; + rx_stats->dropped += cpurxs->dropped; + rx_stats->bytes +=sta_get_stats_bytes (cpurxs); +for (i =0 ; i<=IEEE80211_NUM_TIDS ; i++) { + rx_stats->msdu[i] +=sta_get_tidstats_msdu (cpurxs, i); + } + } +} +void ieee80211_sta_set_expected_throughput (struct ieee80211_sta *pubsta,u32 thr) {
net/mac80211/sta_info.h +4 -0
@@ -422,6 +422,7 @@ struct mesh_sta {DECLARE_EWMA (signal,10 ,8 ) +/* Update sta_accum_rx_stats if you change this structure. */struct ieee80211_sta_rx_stats {unsigned long packets;unsigned long last_rx;
@@ -907,4 +908,7 @@ static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s) return r; } +void sta_accum_rx_stats (struct sta_info *sta, +struct ieee80211_sta_rx_stats *rx_stats); +#endif /* STA_INFO_H */
Signature · 1 line
2.20.1
PATCH 3/3 mac80211: Provide detailed station rx stats.
In reply to [email protected]From: Ben Greear <[email protected]>
This provides histograms of different encoding types, nss, rate-idx, and some ofdma related stats. The goal is general visibility into what is going on with rate control, ofdma, etc.
--- include/uapi/linux/nl80211.h | 1 + net/mac80211/Kconfig | 11 +++++++++ net/mac80211/debugfs_sta.c | 31 ++++++++++++++++++++++++ net/mac80211/rx.c | 46 ++++++++++++++++++++++++++++++++++++ net/mac80211/sta_info.c | 17 +++++++++++++ net/mac80211/sta_info.h | 18 ++++++++++++++ 6 files changed, 124 insertions(+)
include/uapi/linux/nl80211.h +1 -0
@@ -3269,6 +3269,7 @@ enum nl80211_he_ru_alloc {NL80211_RATE_INFO_HE_RU_ALLOC_484 ,NL80211_RATE_INFO_HE_RU_ALLOC_996 , NL80211_RATE_INFO_HE_RU_ALLOC_2x996, + NL80211_RATE_INFO_HE_RU_ALLOC_LAST /* new entries before this */ };/**
net/mac80211/Kconfig +11 -0
@@ -295,6 +295,17 @@ config MAC80211_DEBUG_COUNTERS If unsure, say N. +config MAC80211_DEBUG_STA_COUNTERS + bool "Extra Station TX/RX statistics" + depends on MAC80211_DEBUG_MENU + depends on MAC80211_DEBUGFS + help + Selecting this option causes mac80211 to keep additional + and very verbose station-specific TX and RX statistics + These will be exposed in debugfs. + + If unsure, say N. + config MAC80211_STA_HASH_MAX_SIZE int "Station hash table maximum size" if MAC80211_DEBUG_MENU default 0
net/mac80211/debugfs_sta.c +31 -0
@@ -181,6 +181,37 @@ static ssize_t sta_stats_read(struct file *file, char __user *userbuf,PRINT_MY_STATS (tmp, rx_stats.msdu[i]); } +#ifdef CONFIG_MAC80211_DEBUG_STA_COUNTERS +PRINT_MY_STATS ("rx-bw-20" , rx_stats.msdu_20); +PRINT_MY_STATS ("rx-bw-40" , rx_stats.msdu_40); +PRINT_MY_STATS ("rx-bw-80" , rx_stats.msdu_80); +PRINT_MY_STATS ("rx-bw-160" , rx_stats.msdu_160); + +PRINT_MY_STATS ("rx-he-total" , rx_stats.msdu_he_tot); +PRINT_MY_STATS ("rx-he-mu" , rx_stats.msdu_he_mu); +PRINT_MY_STATS ("rx-vht" , rx_stats.msdu_vht); +PRINT_MY_STATS ("rx-ht" , rx_stats.msdu_ht); +PRINT_MY_STATS ("rx-legacy" , rx_stats.msdu_legacy); + +PRINT_MY_STATS ("rx-he-ru-alloc[ 26]" , rx_stats.msdu_he_ru_alloc[NL80211_RATE_INFO_HE_RU_ALLOC_26 ]); +PRINT_MY_STATS ("rx-he-ru-alloc[ 52]" , rx_stats.msdu_he_ru_alloc[NL80211_RATE_INFO_HE_RU_ALLOC_52 ]); +PRINT_MY_STATS ("rx-he-ru-alloc[ 106]" , rx_stats.msdu_he_ru_alloc[NL80211_RATE_INFO_HE_RU_ALLOC_106 ]); +PRINT_MY_STATS ("rx-he-ru-alloc[ 242]" , rx_stats.msdu_he_ru_alloc[NL80211_RATE_INFO_HE_RU_ALLOC_242 ]); +PRINT_MY_STATS ("rx-he-ru-alloc[ 484]" , rx_stats.msdu_he_ru_alloc[NL80211_RATE_INFO_HE_RU_ALLOC_484 ]); +PRINT_MY_STATS ("rx-he-ru-alloc[ 996]" , rx_stats.msdu_he_ru_alloc[NL80211_RATE_INFO_HE_RU_ALLOC_996 ]); +PRINT_MY_STATS ("rx-he-ru-alloc[2x996]" , rx_stats.msdu_he_ru_alloc[NL80211_RATE_INFO_HE_RU_ALLOC_2x996]); + +for (i =0 ; i<8 ; i++) { +sprintf (tmp,"rx-msdu-nss[%i]" , i); +PRINT_MY_STATS (tmp, rx_stats.msdu_nss[i]); + } + +for (i =0 ; i<32 ; i++) { +sprintf (tmp,"rx-rate-idx[%3i]" , i); +PRINT_MY_STATS (tmp, rx_stats.msdu_rate_idx[i]); + } +#endif +#undef PRINT_MY_STATS done: i =simple_read_from_buffer (userbuf, count, ppos, buf,strlen (buf));
net/mac80211/rx.c +46 -0
52 lines not on this page · raw message
net/mac80211/sta_info.c +17 -0
@@ -2680,6 +2680,23 @@ void sta_accum_rx_stats(struct sta_info *sta,for (i =0 ; i<=IEEE80211_NUM_TIDS ; i++) { rx_stats->msdu[i] +=sta_get_tidstats_msdu (cpurxs, i); } +#ifdef CONFIG_MAC80211_DEBUG_STA_COUNTERS + rx_stats->msdu_20 += cpurxs->msdu_20; + rx_stats->msdu_40 += cpurxs->msdu_40; + rx_stats->msdu_80 += cpurxs->msdu_80; + rx_stats->msdu_160 += cpurxs->msdu_160; +for (i =0 ; i<NL80211_RATE_INFO_HE_RU_ALLOC_LAST ; i++) + rx_stats->msdu_he_ru_alloc[i] += cpurxs->msdu_he_ru_alloc[i]; + rx_stats->msdu_he_tot += cpurxs->msdu_he_tot; + rx_stats->msdu_he_mu += cpurxs->msdu_he_mu; + rx_stats->msdu_vht += cpurxs->msdu_vht; + rx_stats->msdu_ht += cpurxs->msdu_ht; + rx_stats->msdu_legacy += cpurxs->msdu_legacy; +for (i =0 ; i<8 ; i++) + rx_stats->msdu_nss[i] += cpurxs->msdu_nss[i]; +for (i =0 ; i<32 ; i++) + rx_stats->msdu_rate_idx[i] += cpurxs->msdu_rate_idx[i]; +#endif } }
net/mac80211/sta_info.h +18 -0
@@ -436,6 +436,24 @@ struct ieee80211_sta_rx_stats {struct u64_stats_sync syncp;u64 bytes;u64 msdu[IEEE80211_NUM_TIDS +1 ]; + +#ifdef CONFIG_MAC80211_DEBUG_STA_COUNTERS +/* these take liberty with how things are defined, and are +* designed to give a rough idea of how things are going. +*/ +u32 msdu_20; +u32 msdu_40; +u32 msdu_80; +u32 msdu_160; +u32 msdu_he_ru_alloc[NL80211_RATE_INFO_HE_RU_ALLOC_LAST ]; +u32 msdu_he_tot; +u32 msdu_he_mu; +u32 msdu_vht; +u32 msdu_ht; +u32 msdu_legacy; +u32 msdu_nss[8 ]; +u32 msdu_rate_idx[32 ]; +#endif };/*
Signature · 1 line
2.20.1