diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index a27bcc4f7e9a..dc18bafd13d0 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -951,6 +951,8 @@ struct sk_buff { unsigned int truesize; refcount_t users; + unsigned long enqueue_jiffies; + #ifdef CONFIG_SKB_EXTENSIONS /* only useable after checking ->active_extensions != 0 */ struct skb_ext *extensions; diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index f893d9a81b01..cb09b0f165ce 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -109,8 +109,10 @@ static inline struct sk_buff *qdisc_dequeue_skb_bad_txq(struct Qdisc *q) { struct sk_buff *skb = skb_peek(&q->skb_bad_txq); - if (unlikely(skb)) + if (unlikely(skb)) { skb = __skb_dequeue_bad_txq(q); + net_err_ratelimited("dequeuing bad txq skb: %px\n", skb); + } return skb; } @@ -251,6 +253,8 @@ static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate, goto validate; } + net_err_ratelimited("dequeuing gso skb: %px\n", skb); + /* skb in gso_skb were already validated */ *validate = false; if (xfrm_offload(skb)) @@ -737,6 +741,8 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc, return qdisc_drop_cpu(skb, qdisc, to_free); else return qdisc_drop(skb, qdisc, to_free); + } else { + skb->enqueue_jiffies = jiffies; } qdisc_update_stats_at_enqueue(qdisc, pkt_len); @@ -760,6 +766,12 @@ static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc) skb = __skb_array_consume(q); } if (likely(skb)) { + unsigned int delay_ms; + + delay_ms = jiffies_to_msecs(jiffies - skb->enqueue_jiffies); + if (delay_ms > 500) + netdev_err(qdisc_dev(qdisc), "delay: %u ms, skb: %px\n", delay_ms, skb); + qdisc_update_stats_at_dequeue(qdisc, skb); } else if (need_retry && READ_ONCE(qdisc->state) & QDISC_STATE_NON_EMPTY) {