From: Simon Baatz <gmbnomis@gmail.com>
The test ensures we correctly apply the maximum advertised window limit
when rcv_nxt advances past rcv_mwnd_seq, so that the "usable window"
is properly clamped to zero rather than becoming negative.
Signed-off-by: Simon Baatz <gmbnomis@gmail.com>
---
.../net/packetdrill/tcp_rcv_neg_window.pkt | 26 ++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
new file mode 100644
index 0000000000000000000000000000000000000000..15a9b4938f16d175ac54f3fd192ed2b59b0a4399
--- /dev/null
+++ b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+
+--mss=1000
+
+`./defaults.sh`
+
+// Establish a connection.
+ +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+ +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+ +0 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [20000], 4) = 0
+ +0 bind(3, ..., ...) = 0
+ +0 listen(3, 1) = 0
+
+ +0 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7>
+ +0 > S. 0:0(0) ack 1 win 18980 <mss 1460,nop,wscale 0>
+ +.1 < . 1:1(0) ack 1 win 257
+
+ +0 accept(3, ..., ...) = 4
+
+// A too big packet is accepted if the receive queue is empty
+ +0 < P. 1:20001(20000) ack 1 win 257
+// Send a RST immediately so that there is no rcv_wup/rcv_mwnd_seq update yet
+ +0 < R. 20001:20001(0) ack 1 win 257
+
+ +.1 %{ assert tcpi_state == TCP_CLOSE, tcpi_state }%
+
--
2.53.0
On Mon, Mar 9, 2026 at 9:03 AM Simon Baatz via B4 Relay
<devnull+gmbnomis.gmail.com@kernel.org> wrote:
>
> From: Simon Baatz <gmbnomis@gmail.com>
>
> The test ensures we correctly apply the maximum advertised window limit
> when rcv_nxt advances past rcv_mwnd_seq, so that the "usable window"
> is properly clamped to zero rather than becoming negative.
>
> Signed-off-by: Simon Baatz <gmbnomis@gmail.com>
> ---
> .../net/packetdrill/tcp_rcv_neg_window.pkt | 26 ++++++++++++++++++++++
> 1 file changed, 26 insertions(+)
>
> diff --git a/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
> new file mode 100644
> index 0000000000000000000000000000000000000000..15a9b4938f16d175ac54f3fd192ed2b59b0a4399
> --- /dev/null
> +++ b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
> @@ -0,0 +1,26 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +--mss=1000
> +
> +`./defaults.sh`
> +
> +// Establish a connection.
> + +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
> + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
> + +0 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [20000], 4) = 0
> + +0 bind(3, ..., ...) = 0
> + +0 listen(3, 1) = 0
> +
> + +0 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7>
> + +0 > S. 0:0(0) ack 1 win 18980 <mss 1460,nop,wscale 0>
> + +.1 < . 1:1(0) ack 1 win 257
> +
> + +0 accept(3, ..., ...) = 4
> +
> +// A too big packet is accepted if the receive queue is empty
> + +0 < P. 1:20001(20000) ack 1 win 257
We do not see the answer, it seems this test is not complete ?
> +// Send a RST immediately so that there is no rcv_wup/rcv_mwnd_seq update yet
> + +0 < R. 20001:20001(0) ack 1 win 257
> +
> + +.1 %{ assert tcpi_state == TCP_CLOSE, tcpi_state }%
> +
>
> --
> 2.53.0
>
>
Hi Eric,
On Tue, Mar 10, 2026 at 09:54:58AM +0100, Eric Dumazet wrote:
> On Mon, Mar 9, 2026 at 9:03???AM Simon Baatz via B4 Relay
> <devnull+gmbnomis.gmail.com@kernel.org> wrote:
> >
> > From: Simon Baatz <gmbnomis@gmail.com>
> >
> > The test ensures we correctly apply the maximum advertised window limit
> > when rcv_nxt advances past rcv_mwnd_seq, so that the "usable window"
> > is properly clamped to zero rather than becoming negative.
> >
> > Signed-off-by: Simon Baatz <gmbnomis@gmail.com>
> > ---
> > .../net/packetdrill/tcp_rcv_neg_window.pkt | 26 ++++++++++++++++++++++
> > 1 file changed, 26 insertions(+)
> >
> > diff --git a/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
> > new file mode 100644
> > index 0000000000000000000000000000000000000000..15a9b4938f16d175ac54f3fd192ed2b59b0a4399
> > --- /dev/null
> > +++ b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
> > @@ -0,0 +1,26 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +
> > +--mss=1000
> > +
> > +`./defaults.sh`
> > +
> > +// Establish a connection.
> > + +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
> > + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
> > + +0 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [20000], 4) = 0
> > + +0 bind(3, ..., ...) = 0
> > + +0 listen(3, 1) = 0
> > +
> > + +0 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7>
> > + +0 > S. 0:0(0) ack 1 win 18980 <mss 1460,nop,wscale 0>
> > + +.1 < . 1:1(0) ack 1 win 257
> > +
> > + +0 accept(3, ..., ...) = 4
> > +
> > +// A too big packet is accepted if the receive queue is empty
> > + +0 < P. 1:20001(20000) ack 1 win 257
>
> We do not see the answer, it seems this test is not complete ?
Actually we do not want to see an answer. The packet won't trigger
an immediate ACK (it is larger than the advertised window, but does
not cause immediate memory pressure).
When we then send a RST before the delayed ACK would be generated:
> > +// Send a RST immediately so that there is no rcv_wup/rcv_mwnd_seq update yet
> > + +0 < R. 20001:20001(0) ack 1 win 257
We are in a state where rcv_wup, rcv_wnd, and rcv_mwnd_seq have not
been updated yet, but we must still accept the RST
(rcv_nxt == 20001 > rcv_mwnd_seq, tcp_max_receive_window() == 0)
> > +
> > + +.1 %{ assert tcpi_state == TCP_CLOSE, tcpi_state }%
And we verify that we accepted the RST here.
Given how subtle this sequence is, and considering the limited value
of this test, I am also fine with dropping it if it is too fragile or
confusing.
On Wed, Mar 11, 2026 at 12:09 AM Simon Baatz <gmbnomis@gmail.com> wrote:
>
> Hi Eric,
>
> On Tue, Mar 10, 2026 at 09:54:58AM +0100, Eric Dumazet wrote:
> > On Mon, Mar 9, 2026 at 9:03???AM Simon Baatz via B4 Relay
> > <devnull+gmbnomis.gmail.com@kernel.org> wrote:
> > >
> > > From: Simon Baatz <gmbnomis@gmail.com>
> > >
> > > The test ensures we correctly apply the maximum advertised window limit
> > > when rcv_nxt advances past rcv_mwnd_seq, so that the "usable window"
> > > is properly clamped to zero rather than becoming negative.
> > >
> > > Signed-off-by: Simon Baatz <gmbnomis@gmail.com>
> > > ---
> > > .../net/packetdrill/tcp_rcv_neg_window.pkt | 26 ++++++++++++++++++++++
> > > 1 file changed, 26 insertions(+)
> > >
> > > diff --git a/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
> > > new file mode 100644
> > > index 0000000000000000000000000000000000000000..15a9b4938f16d175ac54f3fd192ed2b59b0a4399
> > > --- /dev/null
> > > +++ b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
> > > @@ -0,0 +1,26 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +
> > > +--mss=1000
> > > +
> > > +`./defaults.sh`
> > > +
> > > +// Establish a connection.
> > > + +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
> > > + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
> > > + +0 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [20000], 4) = 0
> > > + +0 bind(3, ..., ...) = 0
> > > + +0 listen(3, 1) = 0
> > > +
> > > + +0 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7>
> > > + +0 > S. 0:0(0) ack 1 win 18980 <mss 1460,nop,wscale 0>
> > > + +.1 < . 1:1(0) ack 1 win 257
> > > +
> > > + +0 accept(3, ..., ...) = 4
> > > +
> > > +// A too big packet is accepted if the receive queue is empty
> > > + +0 < P. 1:20001(20000) ack 1 win 257
> >
> > We do not see the answer, it seems this test is not complete ?
>
> Actually we do not want to see an answer. The packet won't trigger
> an immediate ACK (it is larger than the advertised window, but does
> not cause immediate memory pressure).
>
> When we then send a RST before the delayed ACK would be generated:
>
> > > +// Send a RST immediately so that there is no rcv_wup/rcv_mwnd_seq update yet
> > > + +0 < R. 20001:20001(0) ack 1 win 257
>
> We are in a state where rcv_wup, rcv_wnd, and rcv_mwnd_seq have not
> been updated yet, but we must still accept the RST
> (rcv_nxt == 20001 > rcv_mwnd_seq, tcp_max_receive_window() == 0)
>
> > > +
> > > + +.1 %{ assert tcpi_state == TCP_CLOSE, tcpi_state }%
>
> And we verify that we accepted the RST here.
>
> Given how subtle this sequence is, and considering the limited value
> of this test, I am also fine with dropping it if it is too fragile or
> confusing.
Sorry I missed your answer.
Ok then please use :
// A too big packet is accepted if the receive queue is empty
+0 < P. 1:20001(20000) ack 1 win 257
+0 %{ assert tcpi_bytes_received == 20000, tcpi_bytes_received;
assert tcpi_bytes_acked == 0, tcpi_bytes_acked }%
// Send a RST immediately so that there is no rcv_wup/rcv_mwnd_seq update yet
+0 < R. 20001:20001(0) ack 1 win 257
+.1 %{ assert tcpi_state == TCP_CLOSE, tcpi_state }%
Then add my
Reviewed-by: Eric Dumazet <edumazet@google.com>
Hi Eric,
On Sat, Mar 14, 2026 at 04:58:28AM +0100, Eric Dumazet wrote:
> On Wed, Mar 11, 2026 at 12:09???AM Simon Baatz <gmbnomis@gmail.com> wrote:
> >
> > Hi Eric,
> >
> > On Tue, Mar 10, 2026 at 09:54:58AM +0100, Eric Dumazet wrote:
> > > On Mon, Mar 9, 2026 at 9:03???AM Simon Baatz via B4 Relay
> > > <devnull+gmbnomis.gmail.com@kernel.org> wrote:
> > > >
> > > > From: Simon Baatz <gmbnomis@gmail.com>
> > > >
> > > > The test ensures we correctly apply the maximum advertised window limit
> > > > when rcv_nxt advances past rcv_mwnd_seq, so that the "usable window"
> > > > is properly clamped to zero rather than becoming negative.
> > > >
> > > > Signed-off-by: Simon Baatz <gmbnomis@gmail.com>
> > > > ---
> > > > .../net/packetdrill/tcp_rcv_neg_window.pkt | 26 ++++++++++++++++++++++
> > > > 1 file changed, 26 insertions(+)
> > > >
> > > > diff --git a/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
> > > > new file mode 100644
> > > > index 0000000000000000000000000000000000000000..15a9b4938f16d175ac54f3fd192ed2b59b0a4399
> > > > --- /dev/null
> > > > +++ b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
> > > > @@ -0,0 +1,26 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +
> > > > +--mss=1000
> > > > +
> > > > +`./defaults.sh`
> > > > +
> > > > +// Establish a connection.
> > > > + +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
> > > > + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
> > > > + +0 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [20000], 4) = 0
> > > > + +0 bind(3, ..., ...) = 0
> > > > + +0 listen(3, 1) = 0
> > > > +
> > > > + +0 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7>
> > > > + +0 > S. 0:0(0) ack 1 win 18980 <mss 1460,nop,wscale 0>
> > > > + +.1 < . 1:1(0) ack 1 win 257
> > > > +
> > > > + +0 accept(3, ..., ...) = 4
> > > > +
> > > > +// A too big packet is accepted if the receive queue is empty
> > > > + +0 < P. 1:20001(20000) ack 1 win 257
> > >
> > > We do not see the answer, it seems this test is not complete ?
> >
> > Actually we do not want to see an answer. The packet won't trigger
> > an immediate ACK (it is larger than the advertised window, but does
> > not cause immediate memory pressure).
> >
> > When we then send a RST before the delayed ACK would be generated:
> >
> > > > +// Send a RST immediately so that there is no rcv_wup/rcv_mwnd_seq update yet
> > > > + +0 < R. 20001:20001(0) ack 1 win 257
> >
> > We are in a state where rcv_wup, rcv_wnd, and rcv_mwnd_seq have not
> > been updated yet, but we must still accept the RST
> > (rcv_nxt == 20001 > rcv_mwnd_seq, tcp_max_receive_window() == 0)
> >
> > > > +
> > > > + +.1 %{ assert tcpi_state == TCP_CLOSE, tcpi_state }%
> >
> > And we verify that we accepted the RST here.
> >
> > Given how subtle this sequence is, and considering the limited value
> > of this test, I am also fine with dropping it if it is too fragile or
> > confusing.
>
> Sorry I missed your answer.
>
> Ok then please use :
>
> // A too big packet is accepted if the receive queue is empty
> +0 < P. 1:20001(20000) ack 1 win 257
> +0 %{ assert tcpi_bytes_received == 20000, tcpi_bytes_received;
> assert tcpi_bytes_acked == 0, tcpi_bytes_acked }%
Unfortunately, tcpi_bytes_acked is the TX direction, it will always
be 0 here.
Instead, we can still test that the oversized packet is accepted and
indirectly verify that no immediate ACK is sent by eliciting and
checking a RST:
// A too big packet is accepted if the receive queue is empty, but does not trigger
// an immediate ACK.
+0 < P. 1:20001(20000) ack 1 win 257
+0 %{ assert tcpi_bytes_received == 20000, tcpi_bytes_received; }%
// Send a RST immediately so that there is no rcv_wup/rcv_mwnd_seq update yet
+0 < R. 20001:20001(0) ack 1 win 257
// Verify that the RST was accepted. Indirectly this also verifies that no immediate
// ACK was sent for the data packet above.
+0 < . 20001:20001(0) ack 1 win 257
* > R 1:1(0)
As the series is merged now (thank you!), I will send this
separately, as suggested.
- Simon
--
Simon Baatz <gmbnomis@gmail.com>
On Sat, Mar 14, 2026 at 06:07:05PM +0100, Simon Baatz wrote:
> Hi Eric,
>
> On Sat, Mar 14, 2026 at 04:58:28AM +0100, Eric Dumazet wrote:
> > On Wed, Mar 11, 2026 at 12:09???AM Simon Baatz <gmbnomis@gmail.com> wrote:
> > >
> > > Hi Eric,
> > >
> > > On Tue, Mar 10, 2026 at 09:54:58AM +0100, Eric Dumazet wrote:
> > > > On Mon, Mar 9, 2026 at 9:03???AM Simon Baatz via B4 Relay
> > > > <devnull+gmbnomis.gmail.com@kernel.org> wrote:
> > > > >
> > > > > From: Simon Baatz <gmbnomis@gmail.com>
> > > > >
> > > > > The test ensures we correctly apply the maximum advertised window limit
> > > > > when rcv_nxt advances past rcv_mwnd_seq, so that the "usable window"
> > > > > is properly clamped to zero rather than becoming negative.
> > > > >
> > > > > Signed-off-by: Simon Baatz <gmbnomis@gmail.com>
> > > > > ---
> > > > > .../net/packetdrill/tcp_rcv_neg_window.pkt | 26 ++++++++++++++++++++++
> > > > > 1 file changed, 26 insertions(+)
> > > > >
> > > > > diff --git a/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
> > > > > new file mode 100644
> > > > > index 0000000000000000000000000000000000000000..15a9b4938f16d175ac54f3fd192ed2b59b0a4399
> > > > > --- /dev/null
> > > > > +++ b/tools/testing/selftests/net/packetdrill/tcp_rcv_neg_window.pkt
> > > > > @@ -0,0 +1,26 @@
> > > > > +// SPDX-License-Identifier: GPL-2.0
> > > > > +
> > > > > +--mss=1000
> > > > > +
> > > > > +`./defaults.sh`
> > > > > +
> > > > > +// Establish a connection.
> > > > > + +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
> > > > > + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
> > > > > + +0 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [20000], 4) = 0
> > > > > + +0 bind(3, ..., ...) = 0
> > > > > + +0 listen(3, 1) = 0
> > > > > +
> > > > > + +0 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7>
> > > > > + +0 > S. 0:0(0) ack 1 win 18980 <mss 1460,nop,wscale 0>
> > > > > + +.1 < . 1:1(0) ack 1 win 257
> > > > > +
> > > > > + +0 accept(3, ..., ...) = 4
> > > > > +
> > > > > +// A too big packet is accepted if the receive queue is empty
> > > > > + +0 < P. 1:20001(20000) ack 1 win 257
> > > >
> > > > We do not see the answer, it seems this test is not complete ?
> > >
> > > Actually we do not want to see an answer. The packet won't trigger
> > > an immediate ACK (it is larger than the advertised window, but does
> > > not cause immediate memory pressure).
> > >
> > > When we then send a RST before the delayed ACK would be generated:
> > >
> > > > > +// Send a RST immediately so that there is no rcv_wup/rcv_mwnd_seq update yet
> > > > > + +0 < R. 20001:20001(0) ack 1 win 257
> > >
> > > We are in a state where rcv_wup, rcv_wnd, and rcv_mwnd_seq have not
> > > been updated yet, but we must still accept the RST
> > > (rcv_nxt == 20001 > rcv_mwnd_seq, tcp_max_receive_window() == 0)
> > >
> > > > > +
> > > > > + +.1 %{ assert tcpi_state == TCP_CLOSE, tcpi_state }%
> > >
> > > And we verify that we accepted the RST here.
> > >
> > > Given how subtle this sequence is, and considering the limited value
> > > of this test, I am also fine with dropping it if it is too fragile or
> > > confusing.
> >
> > Sorry I missed your answer.
> >
> > Ok then please use :
> >
> > // A too big packet is accepted if the receive queue is empty
> > +0 < P. 1:20001(20000) ack 1 win 257
> > +0 %{ assert tcpi_bytes_received == 20000, tcpi_bytes_received;
> > assert tcpi_bytes_acked == 0, tcpi_bytes_acked }%
>
> Unfortunately, tcpi_bytes_acked is the TX direction, it will always
> be 0 here.
>
> Instead, we can still test that the oversized packet is accepted and
> indirectly verify that no immediate ACK is sent by eliciting and
> checking a RST:
>
> // A too big packet is accepted if the receive queue is empty, but does not trigger
> // an immediate ACK.
> +0 < P. 1:20001(20000) ack 1 win 257
> +0 %{ assert tcpi_bytes_received == 20000, tcpi_bytes_received; }%
>
> // Send a RST immediately so that there is no rcv_wup/rcv_mwnd_seq update yet
> +0 < R. 20001:20001(0) ack 1 win 257
>
> // Verify that the RST was accepted. Indirectly this also verifies that no immediate
> // ACK was sent for the data packet above.
> +0 < . 20001:20001(0) ack 1 win 257
> * > R 1:1(0)
>
> As the series is merged now (thank you!), I will send this
> separately, as suggested.
Patch is at: https://lore.kernel.org/netdev/20260316-improve_tcp_neg_usable_wnd_test-v1-1-f16d5e365107@gmail.com/
--
Simon Baatz <gmbnomis@gmail.com>
On Sat, Mar 14, 2026 at 4:58 AM Eric Dumazet <edumazet@google.com> wrote: > > > Then add my > Reviewed-by: Eric Dumazet <edumazet@google.com> BTW, this can be done in a followup. Jakub/Paolo feel free to apply v3 series if this is still possible. Thanks !
On Sat, 14 Mar 2026 15:55:35 +0100 Eric Dumazet wrote: > On Sat, Mar 14, 2026 at 4:58 AM Eric Dumazet <edumazet@google.com> wrote: > > Then add my > > Reviewed-by: Eric Dumazet <edumazet@google.com> > > BTW, this can be done in a followup. > > Jakub/Paolo feel free to apply v3 series if this is still possible. Roger that! For the record I'll fix the trailing white space on patch 4 when applying.
© 2016 - 2026 Red Hat, Inc.