The ETF pass the TX sending hardware timestamp to the network interface driver. - Add new flag to the ETF Qdisc setting that mandate the use of the hardware timestamp in a socket's buffer. - The ETF Qdisc pass the TX sending hardware timestamp to the network interface driver. Signed-off-by: Erez Geva <erez.geva.ext@xxxxxxxxxxx> --- include/uapi/linux/pkt_sched.h | 1 + net/sched/sch_etf.c | 59 +++++++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 9e7c2c607845..51e2b57bfa81 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -1056,6 +1056,7 @@ struct tc_etf_qopt { #define TC_ETF_DEADLINE_MODE_ON _BITUL(0) #define TC_ETF_OFFLOAD_ON _BITUL(1) #define TC_ETF_SKIP_SOCK_CHECK _BITUL(2) +#define TC_ETF_USE_HW_TIMESTAMP _BITUL(3) }; enum { diff --git a/net/sched/sch_etf.c b/net/sched/sch_etf.c index c48f91075b5c..67eace3e180f 100644 --- a/net/sched/sch_etf.c +++ b/net/sched/sch_etf.c @@ -23,11 +23,13 @@ #define DEADLINE_MODE_IS_ON(x) ((x)->flags & TC_ETF_DEADLINE_MODE_ON) #define OFFLOAD_IS_ON(x) ((x)->flags & TC_ETF_OFFLOAD_ON) #define SKIP_SOCK_CHECK_IS_SET(x) ((x)->flags & TC_ETF_SKIP_SOCK_CHECK) +#define USE_HW_TIMESTAMP(x) ((x)->flags & TC_ETF_USE_HW_TIMESTAMP) struct etf_sched_data { bool offload; bool deadline_mode; bool skip_sock_check; + bool use_hw_timestamp; int clockid; int queue; s32 delta; /* in ns */ @@ -75,7 +77,7 @@ static inline int validate_input_params(struct tc_etf_qopt *qopt, static bool is_packet_valid(struct Qdisc *sch, struct sk_buff *nskb) { struct etf_sched_data *q = qdisc_priv(sch); - ktime_t txtime = nskb->tstamp; + ktime_t hwtxtime, txtime = nskb->tstamp; struct sock *sk = nskb->sk; ktime_t now; @@ -88,6 +90,9 @@ static bool is_packet_valid(struct Qdisc *sch, struct sk_buff *nskb) if (!sock_flag(sk, SOCK_TXTIME)) return false; + if (!q->use_hw_timestamp != !sock_flag(sk, SOCK_HW_TXTIME)) + return false; + /* We don't perform crosstimestamping. * Drop if packet's clockid differs from qdisc's. */ @@ -99,7 +104,11 @@ static bool is_packet_valid(struct Qdisc *sch, struct sk_buff *nskb) skip: now = q->get_time(); - if (ktime_before(txtime, now) || ktime_before(txtime, q->last)) + if (q->use_hw_timestamp) + hwtxtime = skb_hwtstamps(nskb)->hwtstamp; + else + hwtxtime = txtime; + if (ktime_before(txtime, now) || ktime_before(hwtxtime, q->last)) return false; return true; @@ -173,16 +182,33 @@ static int etf_enqueue_timesortedlist(struct sk_buff *nskb, struct Qdisc *sch, return qdisc_drop(nskb, sch, to_free); } - while (*p) { - struct sk_buff *skb; + if (q->use_hw_timestamp) { + ktime_t hwtxtime = skb_hwtstamps(nskb)->hwtstamp; + + while (*p) { + struct sk_buff *skb; - parent = *p; - skb = rb_to_skb(parent); - if (ktime_compare(txtime, skb->tstamp) >= 0) { - p = &parent->rb_right; - leftmost = false; - } else { - p = &parent->rb_left; + parent = *p; + skb = rb_to_skb(parent); + if (ktime_compare(hwtxtime, skb_hwtstamps(skb)->hwtstamp) >= 0) { + p = &parent->rb_right; + leftmost = false; + } else { + p = &parent->rb_left; + } + } + } else { + while (*p) { + struct sk_buff *skb; + + parent = *p; + skb = rb_to_skb(parent); + if (ktime_compare(txtime, skb->tstamp) >= 0) { + p = &parent->rb_right; + leftmost = false; + } else { + p = &parent->rb_left; + } } } rb_link_node(&nskb->rbnode, parent, p); @@ -245,6 +271,10 @@ static void timesortedlist_remove(struct Qdisc *sch, struct sk_buff *skb) qdisc_bstats_update(sch, skb); + /* Pass hardware time to driver and to last */ + if (q->use_hw_timestamp) + skb->tstamp = skb_hwtstamps(skb)->hwtstamp; + q->last = skb->tstamp; sch->q.qlen--; @@ -393,6 +423,10 @@ static int etf_init(struct Qdisc *sch, struct nlattr *opt, q->offload = OFFLOAD_IS_ON(qopt); q->deadline_mode = DEADLINE_MODE_IS_ON(qopt); q->skip_sock_check = SKIP_SOCK_CHECK_IS_SET(qopt); + q->use_hw_timestamp = USE_HW_TIMESTAMP(qopt); + /* deadline mode can not coexist with using hardware time */ + if (q->use_hw_timestamp && q->deadline_mode) + return -EOPNOTSUPP; switch (q->clockid) { case CLOCK_REALTIME: @@ -484,6 +518,9 @@ static int etf_dump(struct Qdisc *sch, struct sk_buff *skb) if (q->skip_sock_check) opt.flags |= TC_ETF_SKIP_SOCK_CHECK; + if (q->use_hw_timestamp) + opt.flags |= TC_ETF_USE_HW_TIMESTAMP; + if (nla_put(skb, TCA_ETF_PARMS, sizeof(opt), &opt)) goto nla_put_failure; -- 2.20.1