Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/net: integrate packetdrill with ksft

Lay the groundwork to import into kselftests the over 150 packetdrill
TCP/IP conformance tests on github.com/google/packetdrill.

Florian recently added support for packetdrill tests in nf_conntrack,
in commit a8a388c2aae49 ("selftests: netfilter: add packetdrill based
conntrack tests").

This patch takes a slightly different approach. It relies on
ksft_runner.sh to run every *.pkt file in the directory.

Any future imports of packetdrill tests should require no additional
coding. Just add the *.pkt files.

Initially import only two features/directories from github. One with a
single script, and one with two. This was the only reason to pick
tcp/inq and tcp/md5.

The path replaces the directory hierarchy in github with a flat space
of files: $(subst /,_,$(wildcard tcp/**/*.pkt)). This is the most
straightforward option to integrate with kselftests. The Linked thread
reviewed two ways to maintain the hierarchy: TEST_PROGS_RECURSE and
PRESERVE_TEST_DIRS. But both introduce significant changes to
kselftest infra and with that risk to existing tests.

Implementation notes:
- restore alphabetical order when adding the new directory to
tools/testing/selftests/Makefile
- imported *.pkt files and support verbatim from the github project,
except for
- update `source ./defaults.sh` path (to adjust for flat dir)
- add SPDX headers
- remove one author statement
- Acknowledgment: drop an e (checkpatch)

Tested:
make -C tools/testing/selftests \
TARGETS=net/packetdrill \
run_tests

make -C tools/testing/selftests \
TARGETS=net/packetdrill \
install INSTALL_PATH=$KSFT_INSTALL_PATH

# in virtme-ng
./run_kselftest.sh -c net/packetdrill
./run_kselftest.sh -t net/packetdrill:tcp_inq_client.pkt

Link: https://lore.kernel.org/netdev/20240827193417.2792223-1-willemdebruijn.kernel@gmail.com/
Signed-off-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20240905231653.2427327-3-willemdebruijn.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Willem de Bruijn and committed by
Jakub Kicinski
8a405552 dbd61921

+251 -2
+3 -2
tools/testing/selftests/Makefile
··· 65 65 TARGETS += net/forwarding 66 66 TARGETS += net/hsr 67 67 TARGETS += net/mptcp 68 - TARGETS += net/openvswitch 69 - TARGETS += net/tcp_ao 70 68 TARGETS += net/netfilter 69 + TARGETS += net/openvswitch 70 + TARGETS += net/packetdrill 71 71 TARGETS += net/rds 72 + TARGETS += net/tcp_ao 72 73 TARGETS += nsfs 73 74 TARGETS += perf_events 74 75 TARGETS += pidfd
+9
tools/testing/selftests/net/packetdrill/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + TEST_INCLUDES := ksft_runner.sh \ 4 + defaults.sh \ 5 + ../../kselftest/ktap_helpers.sh 6 + 7 + TEST_PROGS := $(wildcard *.pkt) 8 + 9 + include ../../lib.mk
+5
tools/testing/selftests/net/packetdrill/config
··· 1 + CONFIG_IPV6=y 2 + CONFIG_NET_SCH_FIFO=y 3 + CONFIG_PROC_SYSCTL=y 4 + CONFIG_TCP_MD5SIG=y 5 + CONFIG_TUN=y
+63
tools/testing/selftests/net/packetdrill/defaults.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # 4 + # Set standard production config values that relate to TCP behavior. 5 + 6 + # Flush old cached data (fastopen cookies). 7 + ip tcp_metrics flush all > /dev/null 2>&1 8 + 9 + # TCP min, default, and max receive and send buffer sizes. 10 + sysctl -q net.ipv4.tcp_rmem="4096 540000 $((15*1024*1024))" 11 + sysctl -q net.ipv4.tcp_wmem="4096 $((256*1024)) 4194304" 12 + 13 + # TCP timestamps. 14 + sysctl -q net.ipv4.tcp_timestamps=1 15 + 16 + # TCP SYN(ACK) retry thresholds 17 + sysctl -q net.ipv4.tcp_syn_retries=5 18 + sysctl -q net.ipv4.tcp_synack_retries=5 19 + 20 + # TCP Forward RTO-Recovery, RFC 5682. 21 + sysctl -q net.ipv4.tcp_frto=2 22 + 23 + # TCP Selective Acknowledgements (SACK) 24 + sysctl -q net.ipv4.tcp_sack=1 25 + 26 + # TCP Duplicate Selective Acknowledgements (DSACK) 27 + sysctl -q net.ipv4.tcp_dsack=1 28 + 29 + # TCP FACK (Forward Acknowldgement) 30 + sysctl -q net.ipv4.tcp_fack=0 31 + 32 + # TCP reordering degree ("dupthresh" threshold for entering Fast Recovery). 33 + sysctl -q net.ipv4.tcp_reordering=3 34 + 35 + # TCP congestion control. 36 + sysctl -q net.ipv4.tcp_congestion_control=cubic 37 + 38 + # TCP slow start after idle. 39 + sysctl -q net.ipv4.tcp_slow_start_after_idle=0 40 + 41 + # TCP RACK and TLP. 42 + sysctl -q net.ipv4.tcp_early_retrans=4 net.ipv4.tcp_recovery=1 43 + 44 + # TCP method for deciding when to defer sending to accumulate big TSO packets. 45 + sysctl -q net.ipv4.tcp_tso_win_divisor=3 46 + 47 + # TCP Explicit Congestion Notification (ECN) 48 + sysctl -q net.ipv4.tcp_ecn=0 49 + 50 + sysctl -q net.ipv4.tcp_pacing_ss_ratio=200 51 + sysctl -q net.ipv4.tcp_pacing_ca_ratio=120 52 + sysctl -q net.ipv4.tcp_notsent_lowat=4294967295 > /dev/null 2>&1 53 + 54 + sysctl -q net.ipv4.tcp_fastopen=0x70403 55 + sysctl -q net.ipv4.tcp_fastopen_key=a1a1a1a1-b2b2b2b2-c3c3c3c3-d4d4d4d4 56 + 57 + sysctl -q net.ipv4.tcp_syncookies=1 58 + 59 + # Override the default qdisc on the tun device. 60 + # Many tests fail with timing errors if the default 61 + # is FQ and that paces their flows. 62 + tc qdisc add dev tun0 root pfifo 63 +
+41
tools/testing/selftests/net/packetdrill/ksft_runner.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + source "$(dirname $(realpath $0))/../../kselftest/ktap_helpers.sh" 5 + 6 + readonly ipv4_args=('--ip_version=ipv4 ' 7 + '--local_ip=192.168.0.1 ' 8 + '--gateway_ip=192.168.0.1 ' 9 + '--netmask_ip=255.255.0.0 ' 10 + '--remote_ip=192.0.2.1 ' 11 + '-D CMSG_LEVEL_IP=SOL_IP ' 12 + '-D CMSG_TYPE_RECVERR=IP_RECVERR ') 13 + 14 + readonly ipv6_args=('--ip_version=ipv6 ' 15 + '--mtu=1520 ' 16 + '--local_ip=fd3d:0a0b:17d6::1 ' 17 + '--gateway_ip=fd3d:0a0b:17d6:8888::1 ' 18 + '--remote_ip=fd3d:fa7b:d17d::1 ' 19 + '-D CMSG_LEVEL_IP=SOL_IPV6 ' 20 + '-D CMSG_TYPE_RECVERR=IPV6_RECVERR ') 21 + 22 + if [ $# -ne 1 ]; then 23 + ktap_exit_fail_msg "usage: $0 <script>" 24 + exit "$KSFT_FAIL" 25 + fi 26 + script="$1" 27 + 28 + if [ -z "$(which packetdrill)" ]; then 29 + ktap_skip_all "packetdrill not found in PATH" 30 + exit "$KSFT_SKIP" 31 + fi 32 + 33 + ktap_print_header 34 + ktap_set_plan 2 35 + 36 + packetdrill ${ipv4_args[@]} $(basename $script) > /dev/null \ 37 + && ktap_test_pass "ipv4" || ktap_test_fail "ipv4" 38 + packetdrill ${ipv6_args[@]} $(basename $script) > /dev/null \ 39 + && ktap_test_pass "ipv6" || ktap_test_fail "ipv6" 40 + 41 + ktap_finished
+51
tools/testing/selftests/net/packetdrill/tcp_inq_client.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Test TCP_INQ and TCP_CM_INQ on the client side. 3 + `./defaults.sh 4 + ` 5 + 6 + // Create a socket and set it to non-blocking. 7 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 8 + +0 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) 9 + +0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 10 + 11 + // Connect to the server and enable TCP_INQ. 12 + +0 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) 13 + +0 setsockopt(3, SOL_TCP, TCP_INQ, [1], 4) = 0 14 + 15 + +0 > S 0:0(0) <mss 1460,sackOK,TS val 100 ecr 0,nop,wscale 8> 16 + +.01 < S. 0:0(0) ack 1 win 5792 <mss 1460,sackOK,TS val 700 ecr 100,nop,wscale 7> 17 + +0 > . 1:1(0) ack 1 <nop,nop,TS val 200 ecr 700> 18 + 19 + // Now we have 10K of data ready on the socket. 20 + +0 < . 1:10001(10000) ack 1 win 514 21 + +0 > . 1:1(0) ack 10001 <nop,nop,TS val 200 ecr 700> 22 + 23 + // We read 1K and we should have 9K ready to read. 24 + +0 recvmsg(3, {msg_name(...)=..., 25 + msg_iov(1)=[{..., 1000}], 26 + msg_flags=0, 27 + msg_control=[{cmsg_level=SOL_TCP, 28 + cmsg_type=TCP_CM_INQ, 29 + cmsg_data=9000}]}, 0) = 1000 30 + // We read 9K and we should have no further data ready to read. 31 + +0 recvmsg(3, {msg_name(...)=..., 32 + msg_iov(1)=[{..., 9000}], 33 + msg_flags=0, 34 + msg_control=[{cmsg_level=SOL_TCP, 35 + cmsg_type=TCP_CM_INQ, 36 + cmsg_data=0}]}, 0) = 9000 37 + 38 + // Server sends more data and closes the connections. 39 + +0 < F. 10001:20001(10000) ack 1 win 514 40 + +0 > . 1:1(0) ack 20002 <nop,nop,TS val 200 ecr 700> 41 + 42 + // We read 10K and we should have one "fake" byte because the connection is 43 + // closed. 44 + +0 recvmsg(3, {msg_name(...)=..., 45 + msg_iov(1)=[{..., 10000}], 46 + msg_flags=0, 47 + msg_control=[{cmsg_level=SOL_TCP, 48 + cmsg_type=TCP_CM_INQ, 49 + cmsg_data=1}]}, 0) = 10000 50 + // Now, receive EOF. 51 + +0 read(3, ..., 2000) = 0
+51
tools/testing/selftests/net/packetdrill/tcp_inq_server.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Test TCP_INQ and TCP_CM_INQ on the server side. 3 + `./defaults.sh 4 + ` 5 + 6 + // Initialize connection 7 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 8 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 9 + +0 bind(3, ..., ...) = 0 10 + +0 listen(3, 1) = 0 11 + 12 + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 10> 13 + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> 14 + +.01 < . 1:1(0) ack 1 win 514 15 + 16 + // Accept the connection and enable TCP_INQ. 17 + +0 accept(3, ..., ...) = 4 18 + +0 setsockopt(4, SOL_TCP, TCP_INQ, [1], 4) = 0 19 + 20 + // Now we have 10K of data ready on the socket. 21 + +0 < . 1:10001(10000) ack 1 win 514 22 + +0 > . 1:1(0) ack 10001 23 + 24 + // We read 2K and we should have 8K ready to read. 25 + +0 recvmsg(4, {msg_name(...)=..., 26 + msg_iov(1)=[{..., 2000}], 27 + msg_flags=0, 28 + msg_control=[{cmsg_level=SOL_TCP, 29 + cmsg_type=TCP_CM_INQ, 30 + cmsg_data=8000}]}, 0) = 2000 31 + // We read 8K and we should have no further data ready to read. 32 + +0 recvmsg(4, {msg_name(...)=..., 33 + msg_iov(1)=[{..., 8000}], 34 + msg_flags=0, 35 + msg_control=[{cmsg_level=SOL_TCP, 36 + cmsg_type=TCP_CM_INQ, 37 + cmsg_data=0}]}, 0) = 8000 38 + // Client sends more data and closes the connections. 39 + +0 < F. 10001:20001(10000) ack 1 win 514 40 + +0 > . 1:1(0) ack 20002 41 + 42 + // We read 10K and we should have one "fake" byte because the connection is 43 + // closed. 44 + +0 recvmsg(4, {msg_name(...)=..., 45 + msg_iov(1)=[{..., 10000}], 46 + msg_flags=0, 47 + msg_control=[{cmsg_level=SOL_TCP, 48 + cmsg_type=TCP_CM_INQ, 49 + cmsg_data=1}]}, 0) = 10000 50 + // Now, receive error. 51 + +0 read(3, ..., 2000) = -1 ENOTCONN (Transport endpoint is not connected)
+28
tools/testing/selftests/net/packetdrill/tcp_md5_md5-only-on-client-ack.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Test what happens when client does not provide MD5 on SYN, 3 + // but then does on the ACK that completes the three-way handshake. 4 + 5 + `./defaults.sh` 6 + 7 + // Establish a connection. 8 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 9 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 10 + +0 bind(3, ..., ...) = 0 11 + +0 listen(3, 1) = 0 12 + 13 + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 10> 14 + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> 15 + // Ooh, weird: client provides MD5 option on the ACK: 16 + +.01 < . 1:1(0) ack 1 win 514 <md5 000102030405060708090a0b0c0d0e0f,nop,nop> 17 + +.01 < . 1:1(0) ack 1 win 514 <md5 000102030405060708090a0b0c0d0e0f,nop,nop> 18 + 19 + // The TCP listener refcount should be 2, but on buggy kernels it can be 0: 20 + +0 `grep " 0A " /proc/net/tcp /proc/net/tcp6 | grep ":1F90"` 21 + 22 + // Now here comes the legit ACK: 23 + +.01 < . 1:1(0) ack 1 win 514 24 + 25 + // Make sure the connection is OK: 26 + +0 accept(3, ..., ...) = 4 27 + 28 + +.01 write(4, ..., 1000) = 1000