> On Wed, 12 Aug 2026 10:33:19 +0000 Chia-Yu Chang (Nokia) wrote:
> > > > -     /* This indicates the tcp segment has CWR set. */
> > > > +     /* For TX, this indicates that the first TCP segment has CWR set, 
> > > > and
> > > > +      * any subsequent segment in the same skb has CWR cleared. This 
> > > > flag
> > > > +      * must not be used in RX, because the connection to which the 
> > > > segment
> > > > +      * belongs is not tracked to use RFC3168 or AccECN. Using RFC3168 
> > > > ECN
> > > > +      * offload may clear CWR and corrupt ACE signal (CWR is part of 
> > > > it).
> > > > +      * Instead, SKB_GSO_TCP_ACCECN shall be used to avoid CWR 
> > > > corruption.
> > > > +      */
> > >
> > > I still can't wrap my head around this TBH.
> > >
> > > SKB_GSO_TCP_ECN means RFC3168
> > > SKB_GSO_TCP_ACCECN means AccECN
> > >
> > > If the HW can correctly detect cwr on first frame and then no cwr and 
> > > report that as ECN/RFC3168 - what's the problem? TSO will produce the 
> > > exact expected segment sequence.
> > >
> > > Is the program that if we re-GRO that frame in SW we end up with
> > > ECN+ACCECN on the same skb?
> >
> > Yes, this is the problem.
> > The HW does not know whether the received packets belong to an RFC3168 ECN 
> > flow or an AccECN flow on the RX path.
> > For example, HW GRO may set SKB_GSO_TCP_ECN after observing that the first 
> > packet has CWR=1:
> >
> > +===================+==========+=================+================+
> > |     Packet id     | CWR flag |       Flag      | Flushed as SKB |
> > +===================+==========+=================+================+
> > |         0         |     1    | SKB_GSO_TCP_ECN |        0       |
> > |         1         |     0    |         -       |        0       |
> > |         2         |     1    |         -       |        0       |
> > |         3         |     1    |         -       |        1       |
> > +===================+==========+=================+================+
> >
> > If the aggregated skb is forwarded through a device using GSO, e.g., 
> > HW RX (GRO) -> veth TX (GSO), the SKB_GSO_TCP_ECN applies RFC3168 
> > semantics. This means that only the 1st segment keeps the CWR flag 
> > while all subsequent segments have CWR cleared:
> >
> > +===================+==========+
> > |     Packet id     | CWR flag |
> > +===================+==========+
> > |         0         |     1    |
> > |         1         |     0    |
> > |         2         |     0    |
> > |         3         |     0    |
> > +===================+==========+
> >
> > This behavior is ok for RFC3168, since CWR is expected to appear only 
> > once. However, for AccECN, CWR is part of the ACE signal and must be 
> > preserved across all segments.
> 
> But this would be obviously a buggy HW-GRO implementation.
> The rules for HW-GRO RFC3168 are -- ignore CWR on first segment (host 
> responsible for populating SKB_GSO_TCP_ECN), and CWR _must be 0_ for all 
> subsequent segments.
> 
> > In the example above, the original CWR sequence was 1,0,1,1.
> > But after re-segmentation it becomes: 1,0,0,0.
> > This is why SKB_GSO_TCP_ECN should not be used in RX/GRO paths.
> 
> We have extensive gro tests under
> tools/testing/selftests/drivers/net/gro.py
> 
> If you want to catch bad devices - add appropriate test cases there.
>

I added a test case in patch 6f74bc8b6e8d related to the CWR flag.
In that case, there are 5 packets with CWR values of 0, 1, 1, 0, and 0, and 
packets are flushed after the 1st, 3rd, and 5th packets.
The gro.py uses this case in tools/testing/selftests/net/lib/gro.c to verify 
CWR behavior.
But indeed, that does not cover whether SKB_GSO_TCP_ECN or SKB_GSO_TCP_ACCECN 
shall be set during the GRO.
So, a test might be added to verify the SKB_GSO_TCP_ECN or SKB_GSO_TCP_ACCECN 
flags (if there is another suggested way, please let me know)?

> The comment as stated seems to be misleading - there's nothing wrong with 
> using the flag if the device follows the RFC3168 semantics correctly.
> 
> And of course, adding a comment and hoping people will find it is much weaker 
> than adding tests.
>
> Again, maybe I'm missing what _actually_ doesn't work here.

Before adding an extra test, we need to clarify the definition and usages of 
these flags.
At the TX path, in tcp_gso_segment() of net/ipv4/tcp_offload.c, the 
SKB_GSO_TCP_ACCECN flag is used to preserve the CWR flags for AccECN flows.
Otherwise, when without SKB_GSO_TCP_ACCECN (RFC3168 ECN or Non-ECN flows), cwr 
will be cleared from the following packets.

For the RX path, unfortunately I do not find a clear rule of when 
SKB_GSO_TCP_ECN shall be set except in include/linux/skbuff.h.
Plus, the device usually does not track packets belonging to RFC3168 ECN or 
ACCECN flows.
So, my previous thought is to always use SKB_GSO_TCP_ACCECN in the RX path to 
avoid any potential CWR bleaching.

And FYI we will further include the related changes on the virtio-net after we 
get an approval in the virtio-spec.

Reply via email to