Skip to content

Commit a878fd4

Browse files
vladimirolteandavem330
authored andcommitted
net/sched: keep the max_frm_len information inside struct sched_gate_list
I have one practical reason for doing this and one concerning correctness. The practical reason has to do with a follow-up patch, which aims to mix 2 sources of max_sdu (one coming from the user and the other automatically calculated based on TC gate durations @current link speed). Among those 2 sources of input, we must always select the smaller max_sdu value, but this can change at various link speeds. So the max_sdu coming from the user must be kept separated from the value that is operationally used (the minimum of the 2), because otherwise we overwrite it and forget what the user asked us to do. To solve that, this patch proposes that struct sched_gate_list contains the operationally active max_frm_len, and q->max_sdu contains just what was requested by the user. The reason having to do with correctness is based on the following observation: the admin sched_gate_list becomes operational at a given base_time in the future. Until then, it is inactive and applies no shaping, all gates are open, etc. So the queueMaxSDU dropping shouldn't apply either (this is a mechanism to ensure that packets smaller than the largest gate duration for that TC don't hang the port; clearly it makes little sense if the gates are always open). Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Kurt Kanzenbach <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a3d91b2 commit a878fd4

File tree

1 file changed

+40
-13
lines changed

1 file changed

+40
-13
lines changed

net/sched/sch_taprio.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ struct sched_gate_list {
6363
* or 0 if a traffic class gate never opens during the schedule.
6464
*/
6565
u64 max_open_gate_duration[TC_MAX_QUEUE];
66+
u32 max_frm_len[TC_MAX_QUEUE]; /* for the fast path */
6667
struct rcu_head rcu;
6768
struct list_head entries;
6869
size_t num_entries;
@@ -93,7 +94,6 @@ struct taprio_sched {
9394
struct hrtimer advance_timer;
9495
struct list_head taprio_list;
9596
int cur_txq[TC_MAX_QUEUE];
96-
u32 max_frm_len[TC_MAX_QUEUE]; /* for the fast path */
9797
u32 max_sdu[TC_MAX_QUEUE]; /* for dump and offloading */
9898
u32 txtime_delay;
9999
};
@@ -246,6 +246,21 @@ static int length_to_duration(struct taprio_sched *q, int len)
246246
return div_u64(len * atomic64_read(&q->picos_per_byte), PSEC_PER_NSEC);
247247
}
248248

249+
static void taprio_update_queue_max_sdu(struct taprio_sched *q,
250+
struct sched_gate_list *sched)
251+
{
252+
struct net_device *dev = qdisc_dev(q->root);
253+
int num_tc = netdev_get_num_tc(dev);
254+
int tc;
255+
256+
for (tc = 0; tc < num_tc; tc++) {
257+
if (q->max_sdu[tc])
258+
sched->max_frm_len[tc] = q->max_sdu[tc] + dev->hard_header_len;
259+
else
260+
sched->max_frm_len[tc] = U32_MAX; /* never oversized */
261+
}
262+
}
263+
249264
/* Returns the entry corresponding to next available interval. If
250265
* validate_interval is set, it only validates whether the timestamp occurs
251266
* when the gate corresponding to the skb's traffic class is open.
@@ -479,14 +494,33 @@ static long get_packet_txtime(struct sk_buff *skb, struct Qdisc *sch)
479494
return txtime;
480495
}
481496

482-
static int taprio_enqueue_one(struct sk_buff *skb, struct Qdisc *sch,
483-
struct Qdisc *child, struct sk_buff **to_free)
497+
/* Devices with full offload are expected to honor this in hardware */
498+
static bool taprio_skb_exceeds_queue_max_sdu(struct Qdisc *sch,
499+
struct sk_buff *skb)
484500
{
485501
struct taprio_sched *q = qdisc_priv(sch);
486502
struct net_device *dev = qdisc_dev(sch);
503+
struct sched_gate_list *sched;
487504
int prio = skb->priority;
505+
bool exceeds = false;
488506
u8 tc;
489507

508+
tc = netdev_get_prio_tc_map(dev, prio);
509+
510+
rcu_read_lock();
511+
sched = rcu_dereference(q->oper_sched);
512+
if (sched && skb->len > sched->max_frm_len[tc])
513+
exceeds = true;
514+
rcu_read_unlock();
515+
516+
return exceeds;
517+
}
518+
519+
static int taprio_enqueue_one(struct sk_buff *skb, struct Qdisc *sch,
520+
struct Qdisc *child, struct sk_buff **to_free)
521+
{
522+
struct taprio_sched *q = qdisc_priv(sch);
523+
490524
/* sk_flags are only safe to use on full sockets. */
491525
if (skb->sk && sk_fullsock(skb->sk) && sock_flag(skb->sk, SOCK_TXTIME)) {
492526
if (!is_valid_interval(skb, sch))
@@ -497,9 +531,7 @@ static int taprio_enqueue_one(struct sk_buff *skb, struct Qdisc *sch,
497531
return qdisc_drop(skb, sch, to_free);
498532
}
499533

500-
/* Devices with full offload are expected to honor this in hardware */
501-
tc = netdev_get_prio_tc_map(dev, prio);
502-
if (skb->len > q->max_frm_len[tc])
534+
if (taprio_skb_exceeds_queue_max_sdu(sch, skb))
503535
return qdisc_drop(skb, sch, to_free);
504536

505537
qdisc_qstats_backlog_inc(sch, skb);
@@ -1609,7 +1641,6 @@ static int taprio_parse_tc_entries(struct Qdisc *sch,
16091641
struct netlink_ext_ack *extack)
16101642
{
16111643
struct taprio_sched *q = qdisc_priv(sch);
1612-
struct net_device *dev = qdisc_dev(sch);
16131644
u32 max_sdu[TC_QOPT_MAX_QUEUE];
16141645
unsigned long seen_tcs = 0;
16151646
struct nlattr *n;
@@ -1628,13 +1659,8 @@ static int taprio_parse_tc_entries(struct Qdisc *sch,
16281659
goto out;
16291660
}
16301661

1631-
for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++) {
1662+
for (tc = 0; tc < TC_QOPT_MAX_QUEUE; tc++)
16321663
q->max_sdu[tc] = max_sdu[tc];
1633-
if (max_sdu[tc])
1634-
q->max_frm_len[tc] = max_sdu[tc] + dev->hard_header_len;
1635-
else
1636-
q->max_frm_len[tc] = U32_MAX; /* never oversized */
1637-
}
16381664

16391665
out:
16401666
return err;
@@ -1758,6 +1784,7 @@ static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
17581784
goto free_sched;
17591785

17601786
taprio_set_picos_per_byte(dev, q);
1787+
taprio_update_queue_max_sdu(q, new_admin);
17611788

17621789
if (mqprio) {
17631790
err = netdev_set_num_tc(dev, mqprio->num_tc);

0 commit comments

Comments
 (0)