Re: [bug, bisected] pfifo_fast causes packet reordering

From: John Fastabend
Date: Wed Mar 21 2018 - 16:53:16 EST


On 03/21/2018 12:44 PM, Jakob Unterwurzacher wrote:
> On 21.03.18 19:43, John Fastabend wrote:
>> Thats my theory at least. Are you able to test a patch if I generate
>> one to fix this?
>
> Yes, no problem.

Can you try this,

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index d4907b5..1e596bd 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -30,6 +30,7 @@ struct qdisc_rate_table {
enum qdisc_state_t {
__QDISC_STATE_SCHED,
__QDISC_STATE_DEACTIVATED,
+ __QDISC_STATE_RUNNING,
};

struct qdisc_size_table {
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 190570f..cf7c37d 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -377,20 +377,26 @@ static inline bool qdisc_restart(struct Qdisc *q, int *packets)
struct netdev_queue *txq;
struct net_device *dev;
struct sk_buff *skb;
- bool validate;
+ bool more, validate;

/* Dequeue packet */
+ if (test_and_set_bit(__QDISC_STATE_RUNNING, &q->state))
+ return false;
+
skb = dequeue_skb(q, &validate, packets);
- if (unlikely(!skb))
+ if (unlikely(!skb)) {
+ clear_bit(__QDISC_STATE_RUNNING, &q->state);
return false;
+ }

if (!(q->flags & TCQ_F_NOLOCK))
root_lock = qdisc_lock(q);

dev = qdisc_dev(q);
txq = skb_get_tx_queue(dev, skb);
-
- return sch_direct_xmit(skb, q, dev, txq, root_lock, validate);
+ more = sch_direct_xmit(skb, q, dev, txq, root_lock, validate);
+ clear_bit(__QDISC_STATE_RUNNING, &q->state);
+ return more;
}


>
> I just tested with the flag change you suggested (see below, I had to keep TCQ_F_CPUSTATS to prevent a crash) and I have NOT seen OOO so far.
>

Right because the code expects per cpu stats if the CPUSTATS flag is
removed it will crash.

> Thanks,
> Jakob
>
>
> diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
> index 190570f21b20..51b68ef4977b 100644
> --- a/net/sched/sch_generic.c
> +++ b/net/sched/sch_generic.c
> @@ -792,7 +792,7 @@ struct Qdisc_ops pfifo_fast_ops __read_mostly = {
> ÂÂÂÂÂÂÂ .dumpÂÂÂÂÂÂÂÂÂÂ =ÂÂÂÂÂÂ pfifo_fast_dump,
> ÂÂÂÂÂÂÂ .change_tx_queue_len =Â pfifo_fast_change_tx_queue_len,
> ÂÂÂÂÂÂÂ .ownerÂÂÂÂÂÂÂÂÂ =ÂÂÂÂÂÂ THIS_MODULE,
> -ÂÂÂÂÂÂ .static_flagsÂÂ =ÂÂÂÂÂÂ TCQ_F_NOLOCK | TCQ_F_CPUSTATS,
> +ÂÂÂÂÂÂ .static_flagsÂÂ =ÂÂÂÂÂÂ TCQ_F_CPUSTATS,
> Â};
> ÂEXPORT_SYMBOL(pfifo_fast_ops);