Skip to content

Commit f52ed89

Browse files
edumazetdavem330
authored andcommitted
pkt_sched: fq: fix pacing for small frames
For performance reasons, sch_fq tried hard to not setup timers for every sent packet, using a quantum based heuristic : A delay is setup only if the flow exhausted its credit. Problem is that application limited flows can refill their credit for every queued packet, and they can evade pacing. This problem can also be triggered when TCP flows use small MSS values, as TSO auto sizing builds packets that are smaller than the default fq quantum (3028 bytes) This patch adds a 40 ms delay to guard flow credit refill. Fixes: afe4fd0 ("pkt_sched: fq: Fair Queue packet scheduler") Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Maciej Żenczykowski <maze@google.com> Cc: Willem de Bruijn <willemb@google.com> Cc: Yuchung Cheng <ycheng@google.com> Cc: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 65c5189 commit f52ed89

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

include/uapi/linux/pkt_sched.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,9 @@ enum {
768768
TCA_FQ_FLOW_MAX_RATE, /* per flow max rate */
769769

770770
TCA_FQ_BUCKETS_LOG, /* log2(number of buckets) */
771+
772+
TCA_FQ_FLOW_REFILL_DELAY, /* flow credit refill delay in usec */
773+
771774
__TCA_FQ_MAX
772775
};
773776

net/sched/sch_fq.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ struct fq_sched_data {
8888
struct fq_flow internal; /* for non classified or high prio packets */
8989
u32 quantum;
9090
u32 initial_quantum;
91+
u32 flow_refill_delay;
9192
u32 flow_max_rate; /* optional max rate per flow */
9293
u32 flow_plimit; /* max packets per flow */
9394
struct rb_root *fq_root;
@@ -114,6 +115,7 @@ static struct fq_flow detached, throttled;
114115
static void fq_flow_set_detached(struct fq_flow *f)
115116
{
116117
f->next = &detached;
118+
f->age = jiffies;
117119
}
118120

119121
static bool fq_flow_is_detached(const struct fq_flow *f)
@@ -366,17 +368,20 @@ static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
366368
}
367369

368370
f->qlen++;
369-
flow_queue_add(f, skb);
370371
if (skb_is_retransmit(skb))
371372
q->stat_tcp_retrans++;
372373
sch->qstats.backlog += qdisc_pkt_len(skb);
373374
if (fq_flow_is_detached(f)) {
374375
fq_flow_add_tail(&q->new_flows, f);
375-
if (q->quantum > f->credit)
376-
f->credit = q->quantum;
376+
if (time_after(jiffies, f->age + q->flow_refill_delay))
377+
f->credit = max_t(u32, f->credit, q->quantum);
377378
q->inactive_flows--;
378379
qdisc_unthrottled(sch);
379380
}
381+
382+
/* Note: this overwrites f->age */
383+
flow_queue_add(f, skb);
384+
380385
if (unlikely(f == &q->internal)) {
381386
q->stat_internal_packets++;
382387
qdisc_unthrottled(sch);
@@ -454,7 +459,6 @@ static struct sk_buff *fq_dequeue(struct Qdisc *sch)
454459
fq_flow_add_tail(&q->old_flows, f);
455460
} else {
456461
fq_flow_set_detached(f);
457-
f->age = jiffies;
458462
q->inactive_flows++;
459463
}
460464
goto begin;
@@ -608,6 +612,7 @@ static const struct nla_policy fq_policy[TCA_FQ_MAX + 1] = {
608612
[TCA_FQ_FLOW_DEFAULT_RATE] = { .type = NLA_U32 },
609613
[TCA_FQ_FLOW_MAX_RATE] = { .type = NLA_U32 },
610614
[TCA_FQ_BUCKETS_LOG] = { .type = NLA_U32 },
615+
[TCA_FQ_FLOW_REFILL_DELAY] = { .type = NLA_U32 },
611616
};
612617

613618
static int fq_change(struct Qdisc *sch, struct nlattr *opt)
@@ -664,6 +669,12 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
664669
err = -EINVAL;
665670
}
666671

672+
if (tb[TCA_FQ_FLOW_REFILL_DELAY]) {
673+
u32 usecs_delay = nla_get_u32(tb[TCA_FQ_FLOW_REFILL_DELAY]) ;
674+
675+
q->flow_refill_delay = usecs_to_jiffies(usecs_delay);
676+
}
677+
667678
if (!err)
668679
err = fq_resize(q, fq_log);
669680

@@ -699,6 +710,7 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt)
699710
q->flow_plimit = 100;
700711
q->quantum = 2 * psched_mtu(qdisc_dev(sch));
701712
q->initial_quantum = 10 * psched_mtu(qdisc_dev(sch));
713+
q->flow_refill_delay = msecs_to_jiffies(40);
702714
q->flow_max_rate = ~0U;
703715
q->rate_enable = 1;
704716
q->new_flows.first = NULL;
@@ -733,6 +745,8 @@ static int fq_dump(struct Qdisc *sch, struct sk_buff *skb)
733745
nla_put_u32(skb, TCA_FQ_INITIAL_QUANTUM, q->initial_quantum) ||
734746
nla_put_u32(skb, TCA_FQ_RATE_ENABLE, q->rate_enable) ||
735747
nla_put_u32(skb, TCA_FQ_FLOW_MAX_RATE, q->flow_max_rate) ||
748+
nla_put_u32(skb, TCA_FQ_FLOW_REFILL_DELAY,
749+
jiffies_to_usecs(q->flow_refill_delay)) ||
736750
nla_put_u32(skb, TCA_FQ_BUCKETS_LOG, q->fq_trees_log))
737751
goto nla_put_failure;
738752

0 commit comments

Comments
 (0)