Skip to content

Commit 5caa328

Browse files
Michal Kaziorjmberg-intel
authored andcommitted
mac80211: implement codel on fair queuing flows
There is no other limit other than a global packet count limit when using software queuing. This means a single flow queue can grow insanely long. This is particularly bad for TCP congestion algorithms which requires a little more sophisticated frame dropping scheme than a mere headdrop on limit overflow. Hence apply (a slighly modified, to fit the knobs) CoDel5 on flow queues. This improves TCP convergence and stability when combined with wireless driver which keeps its own tx queue/fifo at a minimum fill level for given link conditions. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
1 parent 9399b86 commit 5caa328

File tree

3 files changed

+126
-2
lines changed

3 files changed

+126
-2
lines changed

include/net/mac80211.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/skbuff.h>
2222
#include <linux/ieee80211.h>
2323
#include <net/cfg80211.h>
24+
#include <net/codel.h>
2425
#include <asm/unaligned.h>
2526

2627
/**
@@ -895,7 +896,18 @@ struct ieee80211_tx_info {
895896
unsigned long jiffies;
896897
};
897898
/* NB: vif can be NULL for injected frames */
898-
struct ieee80211_vif *vif;
899+
union {
900+
/* NB: vif can be NULL for injected frames */
901+
struct ieee80211_vif *vif;
902+
903+
/* When packets are enqueued on txq it's easy
904+
* to re-construct the vif pointer. There's no
905+
* more space in tx_info so it can be used to
906+
* store the necessary enqueue time for packet
907+
* sojourn time computation.
908+
*/
909+
codel_time_t enqueue_time;
910+
};
899911
struct ieee80211_key_conf *hw_key;
900912
u32 flags;
901913
/* 4 bytes free */

net/mac80211/ieee80211_i.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,10 +812,12 @@ enum txq_info_flags {
812812
* @tin: contains packets split into multiple flows
813813
* @def_flow: used as a fallback flow when a packet destined to @tin hashes to
814814
* a fq_flow which is already owned by a different tin
815+
* @def_cvars: codel vars for @def_flow
815816
*/
816817
struct txq_info {
817818
struct fq_tin tin;
818819
struct fq_flow def_flow;
820+
struct codel_vars def_cvars;
819821
unsigned long flags;
820822

821823
/* keep last! */
@@ -1108,6 +1110,9 @@ struct ieee80211_local {
11081110
struct ieee80211_hw hw;
11091111

11101112
struct fq fq;
1113+
struct codel_vars *cvars;
1114+
struct codel_params cparams;
1115+
struct codel_stats cstats;
11111116

11121117
const struct ieee80211_ops *ops;
11131118

net/mac80211/tx.c

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
#include <net/ieee80211_radiotap.h>
2525
#include <net/cfg80211.h>
2626
#include <net/mac80211.h>
27+
#include <net/codel.h>
28+
#include <net/codel_impl.h>
2729
#include <asm/unaligned.h>
2830
#include <net/fq_impl.h>
2931

@@ -1267,11 +1269,92 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
12671269
return to_txq_info(txq);
12681270
}
12691271

1272+
static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
1273+
{
1274+
IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
1275+
}
1276+
1277+
static void ieee80211_set_skb_vif(struct sk_buff *skb, struct txq_info *txqi)
1278+
{
1279+
IEEE80211_SKB_CB(skb)->control.vif = txqi->txq.vif;
1280+
}
1281+
1282+
static u32 codel_skb_len_func(const struct sk_buff *skb)
1283+
{
1284+
return skb->len;
1285+
}
1286+
1287+
static codel_time_t codel_skb_time_func(const struct sk_buff *skb)
1288+
{
1289+
const struct ieee80211_tx_info *info;
1290+
1291+
info = (const struct ieee80211_tx_info *)skb->cb;
1292+
return info->control.enqueue_time;
1293+
}
1294+
1295+
static struct sk_buff *codel_dequeue_func(struct codel_vars *cvars,
1296+
void *ctx)
1297+
{
1298+
struct ieee80211_local *local;
1299+
struct txq_info *txqi;
1300+
struct fq *fq;
1301+
struct fq_flow *flow;
1302+
1303+
txqi = ctx;
1304+
local = vif_to_sdata(txqi->txq.vif)->local;
1305+
fq = &local->fq;
1306+
1307+
if (cvars == &txqi->def_cvars)
1308+
flow = &txqi->def_flow;
1309+
else
1310+
flow = &fq->flows[cvars - local->cvars];
1311+
1312+
return fq_flow_dequeue(fq, flow);
1313+
}
1314+
1315+
static void codel_drop_func(struct sk_buff *skb,
1316+
void *ctx)
1317+
{
1318+
struct ieee80211_local *local;
1319+
struct ieee80211_hw *hw;
1320+
struct txq_info *txqi;
1321+
1322+
txqi = ctx;
1323+
local = vif_to_sdata(txqi->txq.vif)->local;
1324+
hw = &local->hw;
1325+
1326+
ieee80211_free_txskb(hw, skb);
1327+
}
1328+
12701329
static struct sk_buff *fq_tin_dequeue_func(struct fq *fq,
12711330
struct fq_tin *tin,
12721331
struct fq_flow *flow)
12731332
{
1274-
return fq_flow_dequeue(fq, flow);
1333+
struct ieee80211_local *local;
1334+
struct txq_info *txqi;
1335+
struct codel_vars *cvars;
1336+
struct codel_params *cparams;
1337+
struct codel_stats *cstats;
1338+
1339+
local = container_of(fq, struct ieee80211_local, fq);
1340+
txqi = container_of(tin, struct txq_info, tin);
1341+
cparams = &local->cparams;
1342+
cstats = &local->cstats;
1343+
1344+
if (flow == &txqi->def_flow)
1345+
cvars = &txqi->def_cvars;
1346+
else
1347+
cvars = &local->cvars[flow - fq->flows];
1348+
1349+
return codel_dequeue(txqi,
1350+
&flow->backlog,
1351+
cparams,
1352+
cvars,
1353+
cstats,
1354+
codel_skb_len_func,
1355+
codel_skb_time_func,
1356+
codel_drop_func,
1357+
codel_dequeue_func);
12751358
}
12761359

12771360
static void fq_skb_free_func(struct fq *fq,
@@ -1303,6 +1386,7 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local,
13031386
struct fq *fq = &local->fq;
13041387
struct fq_tin *tin = &txqi->tin;
13051388

1389+
ieee80211_set_skb_enqueue_time(skb);
13061390
fq_tin_enqueue(fq, tin, skb,
13071391
fq_skb_free_func,
13081392
fq_flow_get_default_func);
@@ -1314,6 +1398,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
13141398
{
13151399
fq_tin_init(&txqi->tin);
13161400
fq_flow_init(&txqi->def_flow);
1401+
codel_vars_init(&txqi->def_cvars);
13171402

13181403
txqi->txq.vif = &sdata->vif;
13191404

@@ -1342,6 +1427,7 @@ int ieee80211_txq_setup_flows(struct ieee80211_local *local)
13421427
{
13431428
struct fq *fq = &local->fq;
13441429
int ret;
1430+
int i;
13451431

13461432
if (!local->ops->wake_tx_queue)
13471433
return 0;
@@ -1350,6 +1436,22 @@ int ieee80211_txq_setup_flows(struct ieee80211_local *local)
13501436
if (ret)
13511437
return ret;
13521438

1439+
codel_params_init(&local->cparams);
1440+
codel_stats_init(&local->cstats);
1441+
local->cparams.interval = MS2TIME(100);
1442+
local->cparams.target = MS2TIME(20);
1443+
local->cparams.ecn = true;
1444+
1445+
local->cvars = kcalloc(fq->flows_cnt, sizeof(local->cvars[0]),
1446+
GFP_KERNEL);
1447+
if (!local->cvars) {
1448+
fq_reset(fq, fq_skb_free_func);
1449+
return -ENOMEM;
1450+
}
1451+
1452+
for (i = 0; i < fq->flows_cnt; i++)
1453+
codel_vars_init(&local->cvars[i]);
1454+
13531455
return 0;
13541456
}
13551457

@@ -1360,6 +1462,9 @@ void ieee80211_txq_teardown_flows(struct ieee80211_local *local)
13601462
if (!local->ops->wake_tx_queue)
13611463
return;
13621464

1465+
kfree(local->cvars);
1466+
local->cvars = NULL;
1467+
13631468
fq_reset(fq, fq_skb_free_func);
13641469
}
13651470

@@ -1382,6 +1487,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
13821487
if (!skb)
13831488
goto out;
13841489

1490+
ieee80211_set_skb_vif(skb, txqi);
1491+
13851492
hdr = (struct ieee80211_hdr *)skb->data;
13861493
if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) {
13871494
struct sta_info *sta = container_of(txq->sta, struct sta_info,

0 commit comments

Comments
 (0)