Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: Dynamically set CoDel parameters per station

CoDel can be too aggressive if a station sends at a very low rate,
leading reduced throughput. This gets worse the more stations are
present, as each station gets more bursty the longer the round-robin
scheduling between stations takes.

This adds dynamic adjustment of CoDel parameters per station. It uses
the rate selection information to estimate throughput and sets more
lenient CoDel parameters if the estimated throughput is below a
threshold (modified by the number of active stations).

A new callback is added that drivers can use to notify mac80211 about
changes in expected throughput, so the same adjustment can be made for
cards that implement rate control in firmware. Drivers that don't use
this will just get the default parameters.

Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
[remove currently unnecessary EXPORT_SYMBOL, fix kernel-doc, remove
inline annotation]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Toke Høiland-Jørgensen and committed by
Johannes Berg
484a54c2 ca8fe250

+73 -2
+16
include/net/mac80211.h
··· 4205 4205 int max_rates); 4206 4206 4207 4207 /** 4208 + * ieee80211_sta_set_expected_throughput - set the expected tpt for a station 4209 + * 4210 + * Call this function to notify mac80211 about a change in expected throughput 4211 + * to a station. A driver for a device that does rate control in firmware can 4212 + * call this function when the expected throughput estimate towards a station 4213 + * changes. The information is used to tune the CoDel AQM applied to traffic 4214 + * going towards that station (which can otherwise be too aggressive and cause 4215 + * slow stations to starve). 4216 + * 4217 + * @pubsta: the station to set throughput for. 4218 + * @thr: the current expected throughput in kbps. 4219 + */ 4220 + void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta, 4221 + u32 thr); 4222 + 4223 + /** 4208 4224 * ieee80211_tx_status - transmit status callback 4209 4225 * 4210 4226 * Call this function for all transmitted frames after they have been
+6
net/mac80211/debugfs_sta.c
··· 154 154 155 155 p += scnprintf(p, 156 156 bufsz+buf-p, 157 + "target %uus interval %uus ecn %s\n", 158 + codel_time_to_us(sta->cparams.target), 159 + codel_time_to_us(sta->cparams.interval), 160 + sta->cparams.ecn ? "yes" : "no"); 161 + p += scnprintf(p, 162 + bufsz+buf-p, 157 163 "tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n"); 158 164 159 165 for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+2 -1
net/mac80211/rate.c
··· 943 943 944 944 drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta); 945 945 946 + ieee80211_sta_set_expected_throughput(pubsta, sta_get_expected_throughput(sta)); 947 + 946 948 return 0; 947 949 } 948 950 EXPORT_SYMBOL(rate_control_set_rates); ··· 993 991 local->rate_ctrl = NULL; 994 992 rate_control_free(local, ref); 995 993 } 996 -
+30
net/mac80211/sta_info.c
··· 20 20 #include <linux/timer.h> 21 21 #include <linux/rtnetlink.h> 22 22 23 + #include <net/codel.h> 23 24 #include <net/mac80211.h> 24 25 #include "ieee80211_i.h" 25 26 #include "driver-ops.h" ··· 425 424 } 426 425 427 426 sta->sta.max_rc_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_BA; 427 + 428 + sta->cparams.ce_threshold = CODEL_DISABLED_THRESHOLD; 429 + sta->cparams.target = MS2TIME(20); 430 + sta->cparams.interval = MS2TIME(100); 431 + sta->cparams.ecn = true; 428 432 429 433 sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); 430 434 ··· 2315 2309 if (time_after(stats->last_rx, sta->status_stats.last_ack)) 2316 2310 return stats->last_rx; 2317 2311 return sta->status_stats.last_ack; 2312 + } 2313 + 2314 + static void sta_update_codel_params(struct sta_info *sta, u32 thr) 2315 + { 2316 + if (!sta->sdata->local->ops->wake_tx_queue) 2317 + return; 2318 + 2319 + if (thr && thr < STA_SLOW_THRESHOLD * sta->local->num_sta) { 2320 + sta->cparams.target = MS2TIME(50); 2321 + sta->cparams.interval = MS2TIME(300); 2322 + sta->cparams.ecn = false; 2323 + } else { 2324 + sta->cparams.target = MS2TIME(20); 2325 + sta->cparams.interval = MS2TIME(100); 2326 + sta->cparams.ecn = true; 2327 + } 2328 + } 2329 + 2330 + void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta, 2331 + u32 thr) 2332 + { 2333 + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); 2334 + 2335 + sta_update_codel_params(sta, thr); 2318 2336 }
+11
net/mac80211/sta_info.h
··· 394 394 }; 395 395 396 396 /** 397 + * The bandwidth threshold below which the per-station CoDel parameters will be 398 + * scaled to be more lenient (to prevent starvation of slow stations). This 399 + * value will be scaled by the number of active stations when it is being 400 + * applied. 401 + */ 402 + #define STA_SLOW_THRESHOLD 6000 /* 6 Mbps */ 403 + 404 + /** 397 405 * struct sta_info - STA information 398 406 * 399 407 * This structure collects information about a station that ··· 454 446 * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for 455 447 * AP only. 456 448 * @cipher_scheme: optional cipher scheme for this station 449 + * @cparams: CoDel parameters for this station. 457 450 * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) 458 451 * @fast_tx: TX fastpath information 459 452 * @fast_rx: RX fastpath information ··· 557 548 558 549 enum ieee80211_smps_mode known_smps_mode; 559 550 const struct ieee80211_cipher_scheme *cipher_scheme; 551 + 552 + struct codel_params cparams; 560 553 561 554 u8 reserved_tid; 562 555
+8 -1
net/mac80211/tx.c
··· 1340 1340 1341 1341 local = container_of(fq, struct ieee80211_local, fq); 1342 1342 txqi = container_of(tin, struct txq_info, tin); 1343 - cparams = &local->cparams; 1344 1343 cstats = &txqi->cstats; 1344 + 1345 + if (txqi->txq.sta) { 1346 + struct sta_info *sta = container_of(txqi->txq.sta, 1347 + struct sta_info, sta); 1348 + cparams = &sta->cparams; 1349 + } else { 1350 + cparams = &local->cparams; 1351 + } 1345 1352 1346 1353 if (flow == &txqi->def_flow) 1347 1354 cvars = &txqi->def_cvars;