From patchwork Thu Apr 6 09:38:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Toke_H=C3=B8iland-J=C3=B8rgensen?= X-Patchwork-Id: 9666759 X-Patchwork-Delegate: johannes@sipsolutions.net Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 93EA0601EB for ; Thu, 6 Apr 2017 09:38:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9872D204C1 for ; Thu, 6 Apr 2017 09:38:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8C77526E8A; Thu, 6 Apr 2017 09:38:46 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 79C7D204C1 for ; Thu, 6 Apr 2017 09:38:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932347AbdDFJio (ORCPT ); Thu, 6 Apr 2017 05:38:44 -0400 Received: from mail.toke.dk ([52.28.52.200]:46871 "EHLO mail.toke.dk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933847AbdDFJid (ORCPT ); Thu, 6 Apr 2017 05:38:33 -0400 Received: from mail.toke.dk (localhost.localdomain [127.0.0.1]) by mail.toke.dk (Postfix) with ESMTPS id 11E66B360D; Thu, 6 Apr 2017 11:38:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=toke.dk; s=20161023; t=1491471510; bh=3IfaDQJ/c8qmgZvmxPyVwU8baCQOQl/NJe/oKlkkhTQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pdzdTn9lbMYwIxRlRBEEMR86pyxVVh1kfKkpTXtfRMIviNC0dc4yGC/xb4SqGieAA oIoTIof/giY5uU538dXaTkWuxo2uG7+SLegcrbvKpMfVToId1INjBggakTWq6hA1/C rYpokmyjRn+KUGnnRx3+QClMnfdML+8FLbWiHir1VFnUUpE5735MnCy/ZSFyzscRVR Zou2njSez+vbbTK03gOPc3dAfglyJGEgrkGx2osAZwkgUiT4NwLoM6dutjX0WA2625 o1Jim+pHo6192qAx1qUuP5IXH8r0CAIMyUZbDw8Oz1NaAyzRuB5pVZ808MRXVLufDC gd0t0G9VQB2Dg== Received: by alrua-kau.kau.toke.dk (Postfix, from userid 1000) id BF3A5C40276; Thu, 6 Apr 2017 11:38:28 +0200 (CEST) From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= To: make-wifi-fast@lists.bufferbloat.net, linux-wireless@vger.kernel.org Cc: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= Subject: [PATCH v3] mac80211: Dynamically set CoDel parameters per station Date: Thu, 6 Apr 2017 11:38:26 +0200 Message-Id: <20170406093826.16626-1-toke@toke.dk> In-Reply-To: <20170405161810.30671-1-toke@toke.dk> References: <20170405161810.30671-1-toke@toke.dk> MIME-Version: 1.0 Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- Changes since v2: - Messed up the rebase and squash in v2; this one actually compiles... include/net/mac80211.h | 17 +++++++++++++++++ net/mac80211/debugfs_sta.c | 6 ++++++ net/mac80211/rate.c | 3 ++- net/mac80211/sta_info.c | 31 +++++++++++++++++++++++++++++++ net/mac80211/sta_info.h | 11 +++++++++++ net/mac80211/tx.c | 9 ++++++++- 6 files changed, 75 insertions(+), 2 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a3bab3c5ecfb..8cd546cbcabc 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -4181,6 +4181,23 @@ void ieee80211_get_tx_rates(struct ieee80211_vif *vif, int max_rates); /** + * ieee80211_sta_set_expected_throughput - set the expected throughput for a + * station + * + * Call this function to notify mac80211 about a change in expected throughput + * to a station. A driver for a device that does rate control in firmware can + * call this function when the expected throughput estimate towards a station + * changes. The information is used to tune the CoDel AQM applied to traffic + * going towards that station (which can otherwise be too aggressive and cause + * slow stations to starve). + * + * @pubsta: the station to set throughput for. + * @thr: the current expected throughput in kbps. + */ +void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta, + u32 thr); + +/** * ieee80211_tx_status - transmit status callback * * Call this function for all transmitted frames after they have been diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 42601820db20..b15412c21ac9 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -154,6 +154,12 @@ static ssize_t sta_aqm_read(struct file *file, char __user *userbuf, p += scnprintf(p, bufsz+buf-p, + "target %uus interval %uus ecn %s\n", + codel_time_to_us(sta->cparams.target), + codel_time_to_us(sta->cparams.interval), + sta->cparams.ecn ? "yes" : "no"); + p += scnprintf(p, + bufsz+buf-p, "tid ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n"); for (i = 0; i < IEEE80211_NUM_TIDS; i++) { diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 206698bc93f4..233c23ba2b98 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -890,6 +890,8 @@ int rate_control_set_rates(struct ieee80211_hw *hw, drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta); + ieee80211_sta_set_expected_throughput(pubsta, sta_get_expected_throughput(sta)); + return 0; } EXPORT_SYMBOL(rate_control_set_rates); @@ -938,4 +940,3 @@ void rate_control_deinitialize(struct ieee80211_local *local) local->rate_ctrl = NULL; rate_control_free(ref); } - diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 3323a2fb289b..d5d54e84620f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "ieee80211_i.h" #include "driver-ops.h" @@ -420,6 +421,11 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->sta.max_rc_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_BA; + sta->cparams.ce_threshold = CODEL_DISABLED_THRESHOLD; + sta->cparams.target = MS2TIME(20); + sta->cparams.interval = MS2TIME(100); + sta->cparams.ecn = true; + sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); return sta; @@ -2298,3 +2304,28 @@ unsigned long ieee80211_sta_last_active(struct sta_info *sta) return stats->last_rx; return sta->status_stats.last_ack; } + +static inline void sta_update_codel_params(struct sta_info *sta, u32 thr) +{ + if (!sta->sdata->local->ops->wake_tx_queue) + return; + + if (thr && thr < STA_SLOW_THRESHOLD * sta->local->num_sta) { + sta->cparams.target = MS2TIME(50); + sta->cparams.interval = MS2TIME(300); + sta->cparams.ecn = false; + } else { + sta->cparams.target = MS2TIME(20); + sta->cparams.interval = MS2TIME(100); + sta->cparams.ecn = true; + } +} + +void ieee80211_sta_set_expected_throughput(struct ieee80211_sta *pubsta, + u32 thr) +{ + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + + sta_update_codel_params(sta, thr); +} +EXPORT_SYMBOL(ieee80211_sta_set_expected_throughput); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index e65cda34d2bc..e3b07e019df1 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -390,6 +390,14 @@ struct ieee80211_sta_rx_stats { }; /** + * The bandwidth threshold below which the per-station CoDel parameters will be + * scaled to be more lenient (to prevent starvation of slow stations). This + * value will be scaled by the number of active stations when it is being + * applied. + */ +#define STA_SLOW_THRESHOLD 6000 /* 6 Mbps */ + +/** * struct sta_info - STA information * * This structure collects information about a station that @@ -442,6 +450,7 @@ struct ieee80211_sta_rx_stats { * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for * AP only. * @cipher_scheme: optional cipher scheme for this station + * @cparams: CoDel parameters for this station. * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED) * @fast_tx: TX fastpath information * @fast_rx: RX fastpath information @@ -545,6 +554,8 @@ struct sta_info { enum ieee80211_smps_mode known_smps_mode; const struct ieee80211_cipher_scheme *cipher_scheme; + struct codel_params cparams; + u8 reserved_tid; struct cfg80211_chan_def tdls_chandef; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ba8d7db0a071..dab60a165059 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1344,9 +1344,16 @@ static struct sk_buff *fq_tin_dequeue_func(struct fq *fq, local = container_of(fq, struct ieee80211_local, fq); txqi = container_of(tin, struct txq_info, tin); - cparams = &local->cparams; cstats = &txqi->cstats; + if (txqi->txq.sta) { + struct sta_info *sta = container_of(txqi->txq.sta, + struct sta_info, sta); + cparams = &sta->cparams; + } else { + cparams = &local->cparams; + } + if (flow == &txqi->def_flow) cvars = &txqi->def_cvars; else