Run the tests: # ./ksft_runner.sh ./tcp_purge_receive_queue_disabled.pkt TAP version 13 1..3 ok 1 ipv4 ok 2 ipv6 ok 3 ipv4-mapped-ipv6 # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0
# ./ksft_runner.sh ./tcp_purge_receive_queue_enabled.pkt TAP version 13 1..3 ok 1 ipv4 ok 2 ipv6 ok 3 ipv4-mapped-ipv6 # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0 Assisted-by: Codex:gpt-5.5 Signed-off-by: Leon Hwang <[email protected]> --- .../tcp_purge_receive_queue_disabled.pkt | 40 ++++++++++++++++++ .../tcp_purge_receive_queue_enabled.pkt | 42 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_disabled.pkt create mode 100644 tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_enabled.pkt diff --git a/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_disabled.pkt b/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_disabled.pkt new file mode 100644 index 000000000000..a46f93eaab1f --- /dev/null +++ b/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_disabled.pkt @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +// Test: with tcp_purge_receive_queue disabled (default), receiving RST +// in CLOSE_WAIT state does NOT purge the receive queue. +// The unread data in the receive queue is still accessible to the +// application. + +`./defaults.sh +./set_sysctls.py /proc/sys/net/ipv4/tcp_purge_receive_queue=0` + +// Establish a connection (server side). + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 + + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> + +.1 < . 1:1(0) ack 1 win 257 + + +0 accept(3, ..., ...) = 4 + +// Remote sends 4KiB data so that receive queue is populated. + +.1 < . 1:4097(4096) ack 1 win 257 + +0 > . 1:1(0) ack 4097 + +// Remote sends FIN -> socket enters CLOSE_WAIT. + +.1 < F. 4097:4097(0) ack 1 win 257 + +0~+.04 > . 1:1(0) ack 4098 + +// Inject RST directly while in CLOSE_WAIT. + +.1 < R. 4098:4098(0) ack 1 win 257 + +// With tcp_purge_receive_queue=0, the receive queue is NOT purged. +// Data is still in the receive queue; read returns data. + +0 read(4, ..., 1) = 1 + + +0 close(4) = 0 + +// Restore sysctls. +`/tmp/sysctl_restore_${PPID}.sh` diff --git a/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_enabled.pkt b/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_enabled.pkt new file mode 100644 index 000000000000..b1d1dff28f50 --- /dev/null +++ b/tools/testing/selftests/net/packetdrill/tcp_purge_receive_queue_enabled.pkt @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +// Test: with tcp_purge_receive_queue enabled, receiving RST in +// CLOSE_WAIT state purges the receive queue immediately. +// The unread data is discarded, so read() observes EOF. +// +// RFC 9293 Section 3.10.7.4: +// "all segment queues should be flushed" + +`./defaults.sh +./set_sysctls.py /proc/sys/net/ipv4/tcp_purge_receive_queue=1` + +// Establish a connection (server side). + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0 bind(3, ..., ...) = 0 + +0 listen(3, 1) = 0 + + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> + +.1 < . 1:1(0) ack 1 win 257 + + +0 accept(3, ..., ...) = 4 + +// Remote sends 4KiB data so that receive queue is populated. + +.1 < . 1:4097(4096) ack 1 win 257 + +0 > . 1:1(0) ack 4097 + +// Remote sends FIN -> socket enters CLOSE_WAIT. + +.1 < F. 4097:4097(0) ack 1 win 257 + +0~+.04 > . 1:1(0) ack 4098 + +// Inject RST directly while in CLOSE_WAIT. + +.1 < R. 4098:4098(0) ack 1 win 257 + +// With tcp_purge_receive_queue=1, the receive queue IS purged. +// Queue was purged by RST handler; read returns EOF. + +0 read(4, ..., 1) = 0 + + +0 close(4) = 0 + +// Restore sysctls. +`/tmp/sysctl_restore_${PPID}.sh` -- 2.55.0

