Skip to content

Commit d2ad689

Browse files
vladimirolteandavem330
authored andcommitted
net/sched: taprio: calculate budgets per traffic class
Currently taprio assumes that the budget for a traffic class expires at the end of the current interval as if the next interval contains a "gate close" event for this traffic class. This is, however, an unfounded assumption. Allow schedule entry intervals to be fused together for a particular traffic class by calculating the budget until the gate *actually* closes. This means we need to keep budgets per traffic class, and we also need to update the budget consumption procedure. Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Kurt Kanzenbach <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e551755 commit d2ad689

File tree

1 file changed

+46
-8
lines changed

1 file changed

+46
-8
lines changed

net/sched/sch_taprio.c

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct sched_entry {
4343
* respective traffic class gate closes
4444
*/
4545
u64 gate_duration[TC_MAX_QUEUE];
46+
atomic_t budget[TC_MAX_QUEUE];
4647
struct list_head list;
4748

4849
/* The instant that this entry ends and the next one
@@ -51,7 +52,6 @@ struct sched_entry {
5152
*/
5253
ktime_t end_time;
5354
ktime_t next_txtime;
54-
atomic_t budget;
5555
int index;
5656
u32 gate_mask;
5757
u32 interval;
@@ -563,11 +563,48 @@ static struct sk_buff *taprio_peek(struct Qdisc *sch)
563563
return NULL;
564564
}
565565

566-
static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry)
566+
static void taprio_set_budgets(struct taprio_sched *q,
567+
struct sched_gate_list *sched,
568+
struct sched_entry *entry)
567569
{
568-
atomic_set(&entry->budget,
569-
div64_u64((u64)entry->interval * PSEC_PER_NSEC,
570-
atomic64_read(&q->picos_per_byte)));
570+
struct net_device *dev = qdisc_dev(q->root);
571+
int num_tc = netdev_get_num_tc(dev);
572+
int tc, budget;
573+
574+
for (tc = 0; tc < num_tc; tc++) {
575+
/* Traffic classes which never close have infinite budget */
576+
if (entry->gate_duration[tc] == sched->cycle_time)
577+
budget = INT_MAX;
578+
else
579+
budget = div64_u64((u64)entry->gate_duration[tc] * PSEC_PER_NSEC,
580+
atomic64_read(&q->picos_per_byte));
581+
582+
atomic_set(&entry->budget[tc], budget);
583+
}
584+
}
585+
586+
/* When an skb is sent, it consumes from the budget of all traffic classes */
587+
static int taprio_update_budgets(struct sched_entry *entry, size_t len,
588+
int tc_consumed, int num_tc)
589+
{
590+
int tc, budget, new_budget = 0;
591+
592+
for (tc = 0; tc < num_tc; tc++) {
593+
budget = atomic_read(&entry->budget[tc]);
594+
/* Don't consume from infinite budget */
595+
if (budget == INT_MAX) {
596+
if (tc == tc_consumed)
597+
new_budget = budget;
598+
continue;
599+
}
600+
601+
if (tc == tc_consumed)
602+
new_budget = atomic_sub_return(len, &entry->budget[tc]);
603+
else
604+
atomic_sub(len, &entry->budget[tc]);
605+
}
606+
607+
return new_budget;
571608
}
572609

573610
static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq,
@@ -577,6 +614,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq,
577614
struct taprio_sched *q = qdisc_priv(sch);
578615
struct net_device *dev = qdisc_dev(sch);
579616
struct Qdisc *child = q->qdiscs[txq];
617+
int num_tc = netdev_get_num_tc(dev);
580618
struct sk_buff *skb;
581619
ktime_t guard;
582620
int prio;
@@ -611,7 +649,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq,
611649

612650
/* ... and no budget. */
613651
if (gate_mask != TAPRIO_ALL_GATES_OPEN &&
614-
atomic_sub_return(len, &entry->budget) < 0)
652+
taprio_update_budgets(entry, len, tc, num_tc) < 0)
615653
return NULL;
616654

617655
skip_peek_checks:
@@ -832,7 +870,7 @@ static enum hrtimer_restart advance_sched(struct hrtimer *timer)
832870
}
833871

834872
next->end_time = end_time;
835-
taprio_set_budget(q, next);
873+
taprio_set_budgets(q, oper, next);
836874

837875
first_run:
838876
rcu_assign_pointer(q->current_entry, next);
@@ -1091,7 +1129,7 @@ static void setup_first_end_time(struct taprio_sched *q,
10911129
sched->cycle_end_time = ktime_add_ns(base, cycle);
10921130

10931131
first->end_time = ktime_add_ns(base, first->interval);
1094-
taprio_set_budget(q, first);
1132+
taprio_set_budgets(q, sched, first);
10951133
rcu_assign_pointer(q->current_entry, NULL);
10961134
}
10971135

0 commit comments

Comments
 (0)