aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPaolo Valente <paolo.valente@unimore.it>2013-03-05 03:05:00 -0500
committerDavid S. Miller <davem@davemloft.net>2013-03-06 02:47:05 -0500
commita0143efa96671dc51dab9bba776a66f9bfa1757f (patch)
tree7e690ce2c71fa569c7d18b70ee889695e8877d26 /net
parent2f3b89a1fe0823fceb544856c9eeb036a75ff091 (diff)
pkt_sched: sch_qfq: prevent budget from wrapping around after a dequeue
Aggregate budgets are computed so as to guarantee that, after an aggregate has been selected for service, that aggregate has enough budget to serve at least one maximum-size packet for the classes it contains. For this reason, after a new aggregate has been selected for service, its next packet is immediately dequeued, without any further control. The maximum packet size for a class, lmax, can be changed through qfq_change_class(). In case the user sets lmax to a lower value than the the size of some of the still-to-arrive packets, QFQ+ will automatically push up lmax as it enqueues these packets. This automatic push up is likely to happen with TSO/GSO. In any case, if lmax is assigned a lower value than the size of some of the packets already enqueued for the class, then the following problem may occur: the size of the next packet to dequeue for the class may happen to be larger than lmax, after the aggregate to which the class belongs has been just selected for service. In this case, even the budget of the aggregate, which is an unsigned value, may be lower than the size of the next packet to dequeue. After dequeueing this packet and subtracting its size from the budget, the latter would wrap around. This fix prevents the budget from wrapping around after any packet dequeue. Signed-off-by: Paolo Valente <paolo.valente@unimore.it> Reviewed-by: Fabio Checconi <fchecconi@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/sched/sch_qfq.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index 8c5172c7f193..c34af93ddfe2 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -1068,7 +1068,15 @@ static struct sk_buff *qfq_dequeue(struct Qdisc *sch)
1068 qdisc_bstats_update(sch, skb); 1068 qdisc_bstats_update(sch, skb);
1069 1069
1070 agg_dequeue(in_serv_agg, cl, len); 1070 agg_dequeue(in_serv_agg, cl, len);
1071 in_serv_agg->budget -= len; 1071 /* If lmax is lowered, through qfq_change_class, for a class
1072 * owning pending packets with larger size than the new value
1073 * of lmax, then the following condition may hold.
1074 */
1075 if (unlikely(in_serv_agg->budget < len))
1076 in_serv_agg->budget = 0;
1077 else
1078 in_serv_agg->budget -= len;
1079
1072 q->V += (u64)len * IWSUM; 1080 q->V += (u64)len * IWSUM;
1073 pr_debug("qfq dequeue: len %u F %lld now %lld\n", 1081 pr_debug("qfq dequeue: len %u F %lld now %lld\n",
1074 len, (unsigned long long) in_serv_agg->F, 1082 len, (unsigned long long) in_serv_agg->F,