Merge branch 'selftests-net-packetdrill-netns-and-two-imports'

Willem de Bruijn says:

====================
selftests/net: packetdrill: netns and two imports

From: Willem de Bruijn <willemb@google.com>

1/3: run in nets, as discussed, and add missing CONFIGs
2/3: import tcp/zerocopy
3/3: import tcp/slow_start
====================

Link: https://patch.msgid.link/20240912005317.1253001-1-willemdebruijn.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-09-12 19:04:39 -07:00
commit f1bcd486c8
25 changed files with 1108 additions and 2 deletions

View File

@ -2,6 +2,7 @@
TEST_INCLUDES := ksft_runner.sh \
defaults.sh \
set_sysctls.py \
../../kselftest/ktap_helpers.sh
TEST_PROGS := $(wildcard *.pkt)

View File

@ -1,5 +1,11 @@
CONFIG_IPV6=y
CONFIG_HZ_1000=y
CONFIG_HZ=1000
CONFIG_NET_NS=y
CONFIG_NET_SCH_FIFO=y
CONFIG_NET_SCH_FQ=y
CONFIG_PROC_SYSCTL=y
CONFIG_SYN_COOKIES=y
CONFIG_TCP_CONG_CUBIC=y
CONFIG_TCP_MD5SIG=y
CONFIG_TUN=y

View File

@ -33,9 +33,9 @@ fi
ktap_print_header
ktap_set_plan 2
packetdrill ${ipv4_args[@]} $(basename $script) > /dev/null \
unshare -n packetdrill ${ipv4_args[@]} $(basename $script) > /dev/null \
&& ktap_test_pass "ipv4" || ktap_test_fail "ipv4"
packetdrill ${ipv6_args[@]} $(basename $script) > /dev/null \
unshare -n packetdrill ${ipv6_args[@]} $(basename $script) > /dev/null \
&& ktap_test_pass "ipv6" || ktap_test_fail "ipv6"
ktap_finished

View File

@ -0,0 +1,38 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
"""Sets sysctl values and writes a file that restores them.
The arguments are of the form "<proc-file>=<val>" separated by spaces.
The program first reads the current value of the proc-file and creates
a shell script named "/tmp/sysctl_restore_${PACKETDRILL_PID}.sh" which
restores the values when executed. It then sets the new values.
PACKETDRILL_PID is set by packetdrill to the pid of itself, so a .pkt
file could restore sysctls by running `/tmp/sysctl_restore_${PPID}.sh`
at the end.
"""
import os
import subprocess
import sys
filename = '/tmp/sysctl_restore_%s.sh' % os.environ['PACKETDRILL_PID']
# Open file for restoring sysctl values
restore_file = open(filename, 'w')
print('#!/bin/bash', file=restore_file)
for a in sys.argv[1:]:
sysctl = a.split('=')
# sysctl[0] contains the proc-file name, sysctl[1] the new value
# read current value and add restore command to file
cur_val = subprocess.check_output(['cat', sysctl[0]], universal_newlines=True)
print('echo "%s" > %s' % (cur_val.strip(), sysctl[0]), file=restore_file)
# set new value
cmd = 'echo "%s" > %s' % (sysctl[1], sysctl[0])
os.system(cmd)
os.system('chmod u+x %s' % filename)

View File

@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-2.0
// Test of slow start when not application-limited, so that
// the cwnd continues to grow.
// In this variant, the receiver ACKs every packet.
// Set up config. To keep things simple, disable the
// mechanism that defers sending in order to send bigger TSO packets.
`./defaults.sh
sysctl -q net.ipv4.tcp_tso_win_divisor=100`
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
+.1 < 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
+0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0
+0 write(4, ..., 30000) = 30000
+0 > P. 1:10001(10000) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
+.105 < . 1:1(0) ack 1001 win 257
+0 > P. 10001:12001(2000) ack 1
+0 < . 1:1(0) ack 2001 win 257
+0 > P. 12001:14001(2000) ack 1
+.005 < . 1:1(0) ack 3001 win 257
+0 > P. 14001:16001(2000) ack 1
+0 < . 1:1(0) ack 4001 win 257
+0 > P. 16001:18001(2000) ack 1
+.005 < . 1:1(0) ack 5001 win 257
+0 > P. 18001:20001(2000) ack 1
+0 < . 1:1(0) ack 6001 win 257
+0 > P. 20001:22001(2000) ack 1
+.005 < . 1:1(0) ack 7001 win 257
+0 > P. 22001:24001(2000) ack 1
+0 < . 1:1(0) ack 8001 win 257
+0 > P. 24001:26001(2000) ack 1
+.005 < . 1:1(0) ack 9001 win 257
+0 > P. 26001:28001(2000) ack 1
+0 < . 1:1(0) ack 10001 win 257
+0 > P. 28001:30001(2000) ack 1
+0 %{ assert tcpi_snd_cwnd == 20, tcpi_snd_cwnd }%

View File

@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0
// Test of slow start when an outstanding flight of packets is
// less than the current cwnd, and not big enough to bump up cwnd.
//
// In this variant, the receiver ACKs every other packet,
// approximating standard delayed ACKs.
// Set up config.
`./defaults.sh`
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>
+0 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
// Only send 5 packets.
+0 write(4, ..., 5000) = 5000
+0 > P. 1:5001(5000) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
+0 < . 1:1(0) ack 2001 win 257
+0 %{ assert tcpi_snd_cwnd == 10, 'cwnd=%d' % tcpi_snd_cwnd }%
+0 < . 1:1(0) ack 4001 win 257
+0 %{ assert tcpi_snd_cwnd == 10, 'cwnd=%d' % tcpi_snd_cwnd }%
+0 < . 1:1(0) ack 5001 win 257
+0 %{ assert tcpi_snd_cwnd == 10, 'cwnd=%d' % tcpi_snd_cwnd }%

View File

@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-2.0
// Test of slow start when an outstanding flight of packets is
// less than the current cwnd, but still big enough that in slow
// start we want to increase our cwnd a little.
//
// In this variant, the receiver ACKs every other packet,
// approximating standard delayed ACKs.
// Set up config.
`./defaults.sh`
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>
+0 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
// Only send 6 packets.
+0 write(4, ..., 6000) = 6000
+0 > P. 1:6001(6000) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
+0 < . 1:1(0) ack 2001 win 257
+0 %{ assert tcpi_snd_cwnd == 12, 'cwnd=%d' % tcpi_snd_cwnd }%
+0 < . 1:1(0) ack 4001 win 257
+0 %{ assert tcpi_snd_cwnd == 12, 'cwnd=%d' % tcpi_snd_cwnd }%
+0 < . 1:1(0) ack 6001 win 257
+0 %{ assert tcpi_snd_cwnd == 12, 'cwnd=%d' % tcpi_snd_cwnd }%

View File

@ -0,0 +1,42 @@
// SPDX-License-Identifier: GPL-2.0
// Test of slow start when not application-limited, so that
// the cwnd continues to grow.
// In this variant, the receiver ACKs every other packet,
// approximating standard delayed ACKs.
// Set up config. To keep things simple, disable the
// mechanism that defers sending in order to send bigger TSO packets.
`./defaults.sh
sysctl -q net.ipv4.tcp_tso_win_divisor=100`
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
+.1 < 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
+0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0
+0 write(4, ..., 30000) = 30000
+0 > P. 1:10001(10000) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
+.105 < . 1:1(0) ack 2001 win 257
+0 > P. 10001:14001(4000) ack 1
+.005 < . 1:1(0) ack 4001 win 257
+0 > P. 14001:18001(4000) ack 1
+.005 < . 1:1(0) ack 6001 win 257
+0 > P. 18001:22001(4000) ack 1
+.005 < . 1:1(0) ack 8001 win 257
+0 > P. 22001:26001(4000) ack 1
+.005 < . 1:1(0) ack 10001 win 257
+0 > P. 26001:30001(4000) ack 1
+0 %{ assert tcpi_snd_cwnd == 20, tcpi_snd_cwnd }%

View File

@ -0,0 +1,35 @@
// SPDX-License-Identifier: GPL-2.0
// Test of slow start when not application-limited, so that
// the cwnd continues to grow.
// In this variant, the receiver sends one ACK per 4 packets.
// Set up config. To keep things simple, disable the
// mechanism that defers sending in order to send bigger TSO packets.
`./defaults.sh
sysctl -q net.ipv4.tcp_tso_win_divisor=100`
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
+.1 < 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
+0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0
+0 write(4, ..., 30000) = 30000
+0 > P. 1:10001(10000) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
+.11 < . 1:1(0) ack 4001 win 257
+0 > P. 10001:18001(8000) ack 1
+.01 < . 1:1(0) ack 8001 win 257
+0 > P. 18001:26001(8000) ack 1
+.005 < . 1:1(0) ack 10001 win 257
+0 > P. 26001:30001(4000) ack 1
+0 %{ assert tcpi_snd_cwnd == 20, tcpi_snd_cwnd }%

View File

@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0
// Test of slow start after idle
// This test expects tso size to be at least initial cwnd * mss
`./defaults.sh
./set_sysctls.py /proc/sys/net/ipv4/tcp_slow_start_after_idle=1 \
/proc/sys/net/ipv4/tcp_min_tso_segs=10`
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 65535 <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 511
+0 accept(3, ..., ...) = 4
+0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0
+0 write(4, ..., 26000) = 26000
+0 > P. 1:5001(5000) ack 1
+0 > P. 5001:10001(5000) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
+.1 < . 1:1(0) ack 10001 win 511
+0 %{ assert tcpi_snd_cwnd == 20, tcpi_snd_cwnd }%
+0 > P. 10001:20001(10000) ack 1
+0 > P. 20001:26001(6000) ack 1
+.1 < . 1:1(0) ack 26001 win 511
+0 %{ assert tcpi_snd_cwnd == 36, tcpi_snd_cwnd }%
+2 write(4, ..., 20000) = 20000
// If slow start after idle works properly, we should send 5 MSS here (cwnd/2)
+0 > P. 26001:31001(5000) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
// Reset sysctls
`/tmp/sysctl_restore_${PPID}.sh`

View File

@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0
// Test of slow start after window update
// This test expects tso size to be at least initial cwnd * mss
`./defaults.sh
./set_sysctls.py /proc/sys/net/ipv4/tcp_slow_start_after_idle=1 \
/proc/sys/net/ipv4/tcp_min_tso_segs=10`
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 65535 <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 511
+0 accept(3, ..., ...) = 4
+0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0
+0 write(4, ..., 26000) = 26000
+0 > P. 1:5001(5000) ack 1
+0 > P. 5001:10001(5000) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
+.1 < . 1:1(0) ack 10001 win 511
+0 %{ assert tcpi_snd_cwnd == 20, tcpi_snd_cwnd }%
+0 > P. 10001:20001(10000) ack 1
+0 > P. 20001:26001(6000) ack 1
+.1 < . 1:1(0) ack 26001 win 0
+0 %{ assert tcpi_snd_cwnd == 36, tcpi_snd_cwnd }%
+0 write(4, ..., 20000) = 20000
// 1st win0 probe
+.3~+.310 > . 26000:26000(0) ack 1
+0 %{ assert tcpi_snd_cwnd == 36, tcpi_snd_cwnd }%
// 2nd win0 probe
+.6~+.620 > . 26000:26000(0) ack 1
+0 %{ assert tcpi_snd_cwnd == 36, tcpi_snd_cwnd }%
// 3rd win0 probe
+1.2~+1.240 > . 26000:26000(0) ack 1
+0 %{ assert tcpi_snd_cwnd == 36, tcpi_snd_cwnd }%
+.9 < . 1:1(0) ack 26001 win 511
+0 > P. 26001:31001(5000) ack 1
// Reset sysctls
`/tmp/sysctl_restore_${PPID}.sh`

View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0
// Test of slow start when application-limited: in this case,
// with IW10, if we don't fully use our cwnd but instead
// send just 9 packets, then cwnd should grow to twice that
// value, or 18 packets.
// Set up config.
`./defaults.sh`
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
+.1 < 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
+0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0
+0 write(4, ..., 9000) = 9000
+0 > P. 1:9001(9000) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
+.105 < . 1:1(0) ack 2001 win 257
+0 %{ assert tcpi_snd_cwnd == 12, tcpi_snd_cwnd }%
+.005 < . 1:1(0) ack 4001 win 257
+0 %{ assert tcpi_snd_cwnd == 14, tcpi_snd_cwnd }%
+.005 < . 1:1(0) ack 6001 win 257
+0 %{ assert tcpi_snd_cwnd == 16, tcpi_snd_cwnd }%
+.005 < . 1:1(0) ack 8001 win 257
+0 %{ assert tcpi_snd_cwnd == 18, tcpi_snd_cwnd }%
+.005 < . 1:1(0) ack 9001 win 257
+0 %{ assert tcpi_snd_cwnd == 18, tcpi_snd_cwnd }%

View File

@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0
// Test of slow start when application-limited: in this case,
// with IW10, if we send exactly 10 packets then cwnd should grow to 20.
// Set up config.
`./defaults.sh`
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
+.1 < 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
+0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0
+0 write(4, ..., 10000) = 10000
+0 > P. 1:10001(10000) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
+.105 < . 1:1(0) ack 2001 win 257
+0 %{ assert tcpi_snd_cwnd == 12, tcpi_snd_cwnd }%
+.005 < . 1:1(0) ack 4001 win 257
+0 %{ assert tcpi_snd_cwnd == 14, tcpi_snd_cwnd }%
+.005 < . 1:1(0) ack 6001 win 257
+0 %{ assert tcpi_snd_cwnd == 16, tcpi_snd_cwnd }%
+.005 < . 1:1(0) ack 8001 win 257
+0 %{ assert tcpi_snd_cwnd == 18, tcpi_snd_cwnd }%
+.005 < . 1:1(0) ack 10001 win 257
+0 %{ assert tcpi_snd_cwnd == 20, tcpi_snd_cwnd }%

View File

@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0
// Test of slow start when not application-limited, so that
// the cwnd continues to grow, even if TSQ triggers.
// In this variant, the receiver ACKs every other packet,
// approximating standard delayed ACKs.
// Note we use FQ/pacing to check if TCP Small Queues is not hurting
`./defaults.sh
tc qdisc replace dev tun0 root fq
sysctl -q net/ipv4/tcp_pacing_ss_ratio=200
sysctl -e -q net.ipv4.tcp_min_tso_segs=2`
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
+.1 < S 0:0(0) win 32792 <mss 1460,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 500
+0 accept(3, ..., ...) = 4
+0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0
+0 write(4, ..., 40000) = 40000
// This might change if we cook the initial packet with 10 MSS.
+0 > P. 1:2921(2920) ack 1
+0 > P. 2921:5841(2920) ack 1
+0 > P. 5841:8761(2920) ack 1
+0 > P. 8761:11681(2920) ack 1
+0 > P. 11681:14601(2920) ack 1
+0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }%
+.105 < . 1:1(0) ack 2921 win 500
+0 %{ assert tcpi_snd_cwnd == 12, tcpi_snd_cwnd }%
// Note: after this commit : "net_sched: sch_fq: account for schedule/timers drifts"
// FQ notices that this packet missed the 'time to send next packet' computed
// when prior packet (11681:14601(2920)) was sent.
// So FQ will allow following packet to be sent a bit earlier (quantum/2)
// (FQ commit allows an application/cwnd limited flow to get at most quantum/2 extra credit)
+0 > P. 14601:17521(2920) ack 1
+.003 < . 1:1(0) ack 5841 win 500
+0 %{ assert tcpi_snd_cwnd == 14, tcpi_snd_cwnd }%
+.001 > P. 17521:20441(2920) ack 1
+.001 < . 1:1(0) ack 8761 win 500
+0 %{ assert tcpi_snd_cwnd == 16, tcpi_snd_cwnd }%
// remaining packets are delivered at a constant rate.
+.007 > P. 20441:23361(2920) ack 1
+.002 < . 1:1(0) ack 11681 win 500
+0 %{ assert tcpi_snd_cwnd == 18, tcpi_snd_cwnd }%
+.001 < . 1:1(0) ack 14601 win 500
+.004 > P. 23361:26281(2920) ack 1
+.007 > P. 26281:29201(2920) ack 1
+0 %{ assert tcpi_snd_cwnd == 20, 'cwnd=%d' % tcpi_snd_cwnd }%

View File

@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-2.0
// basic zerocopy test:
//
// send a packet with MSG_ZEROCOPY and receive the notification ID
// repeat and verify IDs are consecutive
`./defaults.sh`
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [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>
+0 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 1:4001(4000) ack 1
+0 < . 1:1(0) ack 4001 win 257
+0 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=0}}
]}, MSG_ERRQUEUE) = 0
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 4001:8001(4000) ack 1
+0 < . 1:1(0) ack 8001 win 257
+0 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=1,
ee_data=1}}
]}, MSG_ERRQUEUE) = 0

View File

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0
// batch zerocopy test:
//
// send multiple packets, then read one range of all notifications.
`./defaults.sh`
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [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>
+0 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
+0 setsockopt(4, SOL_SOCKET, SO_MARK, [666], 4) = 0
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 1:4001(4000) ack 1
+0 < . 1:1(0) ack 4001 win 257
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 4001:8001(4000) ack 1
+0 < . 1:1(0) ack 8001 win 257
+0 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=1}}
]}, MSG_ERRQUEUE) = 0

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0
// Minimal client-side zerocopy test
`./defaults.sh`
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 4
+0 setsockopt(4, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0
+0...0 connect(4, ..., ...) = 0
+0 > S 0:0(0) <mss 1460,sackOK,TS val 0 ecr 0,nop,wscale 8>
+0 < S. 0:0(0) ack 1 win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
+0 > . 1:1(0) ack 1
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 1:4001(4000) ack 1
+0 < . 1:1(0) ack 4001 win 257
+0 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=0}}
]}, MSG_ERRQUEUE) = 0

View File

@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0
// send with MSG_ZEROCOPY on a non-established socket
//
// verify that a send in state TCP_CLOSE correctly aborts the zerocopy
// operation, specifically it does not increment the zerocopy counter.
//
// First send on a closed socket and wait for (absent) notification.
// Then connect and send and verify that notification nr. is zero.
`./defaults.sh`
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 4
+0 setsockopt(4, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0
+0 send(4, ..., 4000, MSG_ZEROCOPY) = -1 EPIPE (Broken pipe)
+0.1 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[]}, MSG_ERRQUEUE) = -1 EAGAIN (Resource temporarily unavailable)
+0...0 connect(4, ..., ...) = 0
+0 > S 0:0(0) <mss 1460,sackOK,TS val 0 ecr 0,nop,wscale 8>
+0 < S. 0:0(0) ack 1 win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
+0 > . 1:1(0) ack 1
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 1:4001(4000) ack 1
+0 < . 1:1(0) ack 4001 win 257
+0 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=0}}
]}, MSG_ERRQUEUE) = 0

View File

@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0
// epoll zerocopy test:
//
// EPOLLERR is known to be not edge-triggered unlike EPOLLIN and EPOLLOUT but
// it is not level-triggered either.
//
// fire two sends with MSG_ZEROCOPY and receive the acks. confirm that EPOLLERR
// is correctly fired only once, when EPOLLET is set. send another packet with
// MSG_ZEROCOPY. confirm that EPOLLERR is correctly fired again only once.
`./defaults.sh`
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [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>
+0 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
+0 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
+0 epoll_create(1) = 5
+0 epoll_ctl(5, EPOLL_CTL_ADD, 4, {events=EPOLLOUT|EPOLLET, fd=4}) = 0
+0 epoll_wait(5, {events=EPOLLOUT, fd=4}, 1, 0) = 1
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 1:4001(4000) ack 1
+0 < . 1:1(0) ack 4001 win 257
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 4001:8001(4000) ack 1
+0 < . 1:1(0) ack 8001 win 257
// receive only one EPOLLERR for the two sends above.
+0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1
+0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 8001:12001(4000) ack 1
+0 < . 1:1(0) ack 12001 win 257
// receive only one EPOLLERR for the third send above.
+0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1
+0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0
+0 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=2}}
]}, MSG_ERRQUEUE) = 0

View File

@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0
// epoll zerocopy test:
//
// EPOLLERR is known to be not edge-triggered unlike EPOLLIN and EPOLLOUT but
// it is not level-triggered either. this tests verify that the same behavior is
// maintained when we have EPOLLEXCLUSIVE.
//
// fire two sends with MSG_ZEROCOPY and receive the acks. confirm that EPOLLERR
// is correctly fired only once, when EPOLLET is set. send another packet with
// MSG_ZEROCOPY. confirm that EPOLLERR is correctly fired again only once.
`./defaults.sh`
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [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>
+0 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
+0 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
+0 epoll_create(1) = 5
+0 epoll_ctl(5, EPOLL_CTL_ADD, 4,
{events=EPOLLOUT|EPOLLET|EPOLLEXCLUSIVE, fd=4}) = 0
+0 epoll_wait(5, {events=EPOLLOUT, fd=4}, 1, 0) = 1
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 1:4001(4000) ack 1
+0 < . 1:1(0) ack 4001 win 257
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 4001:8001(4000) ack 1
+0 < . 1:1(0) ack 8001 win 257
// receive only one EPOLLERR for the two sends above.
+0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1
+0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 8001:12001(4000) ack 1
+0 < . 1:1(0) ack 12001 win 257
// receive only one EPOLLERR for the third send above.
+0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1
+0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0
+0 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=2}}
]}, MSG_ERRQUEUE) = 0

View File

@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0
// epoll zerocopy test:
//
// This is a test to confirm that EPOLLERR is only fired once for an FD when
// EPOLLONESHOT is set.
//
// fire two sends with MSG_ZEROCOPY and receive the acks. confirm that EPOLLERR
// is correctly fired only once, when EPOLLONESHOT is set. send another packet
// with MSG_ZEROCOPY. confirm that EPOLLERR is not fired. Rearm the FD and
// confirm that EPOLLERR is correctly set.
`./defaults.sh`
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [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>
+0 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
+0 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
+0 epoll_create(1) = 5
+0 epoll_ctl(5, EPOLL_CTL_ADD, 4,
{events=EPOLLOUT|EPOLLET|EPOLLONESHOT, fd=4}) = 0
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 1:4001(4000) ack 1
+0 < . 1:1(0) ack 4001 win 257
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 4001:8001(4000) ack 1
+0 < . 1:1(0) ack 8001 win 257
// receive only one EPOLLERR for the two sends above.
+0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1
+0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0
+0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000
+0 > P. 8001:12001(4000) ack 1
+0 < . 1:1(0) ack 12001 win 257
// receive no EPOLLERR for the third send above.
+0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0
// rearm the FD and verify the EPOLLERR is fired again.
+0 epoll_ctl(5, EPOLL_CTL_MOD, 4, {events=EPOLLOUT|EPOLLONESHOT, fd=4}) = 0
+0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1
+0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0
+0 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=2}}
]}, MSG_ERRQUEUE) = 0

View File

@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-2.0
// Fastopen client zerocopy test:
//
// send data with MSG_FASTOPEN | MSG_ZEROCOPY and verify that the
// kernel returns the notification ID.
//
// Fastopen requires a stored cookie. Create two sockets. The first
// one will have no data in the initial send. On return 0 the
// zerocopy notification counter is not incremented. Verify this too.
`./defaults.sh`
// Send a FastOpen request, no cookie yet so no data in SYN
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
+0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0
+0 sendto(3, ..., 500, MSG_FASTOPEN|MSG_ZEROCOPY, ..., ...) = -1 EINPROGRESS (Operation now in progress)
+0 > S 0:0(0) <mss 1460,sackOK,TS val 1000 ecr 0,nop,wscale 8,FO,nop,nop>
+.01 < S. 123:123(0) ack 1 win 14600 <mss 940,TS val 2000 ecr 1000,sackOK,nop,wscale 6, FO abcd1234,nop,nop>
+0 > . 1:1(0) ack 1 <nop,nop,TS val 1001 ecr 2000>
// Read from error queue: no zerocopy notification
+1 recvmsg(3, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[]}, MSG_ERRQUEUE) = -1 EAGAIN (Resource temporarily unavailable)
+.01 close(3) = 0
+0 > F. 1:1(0) ack 1 <nop,nop,TS val 1002 ecr 2000>
+.01 < F. 1:1(0) ack 2 win 92 <nop,nop,TS val 2001 ecr 1002>
+0 > . 2:2(0) ack 2 <nop,nop,TS val 1003 ecr 2001>
// Send another Fastopen request, now SYN will have data
+.07 `sysctl -q net.ipv4.tcp_timestamps=0`
+.1 socket(..., SOCK_STREAM, IPPROTO_TCP) = 5
+0 fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0
+0 setsockopt(5, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0
+0 sendto(5, ..., 500, MSG_FASTOPEN|MSG_ZEROCOPY, ..., ...) = 500
+0 > S 0:500(500) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO abcd1234,nop,nop>
+.05 < S. 5678:5678(0) ack 501 win 14600 <mss 1460,nop,nop,sackOK,nop,wscale 6>
+0 > . 501:501(0) ack 1
// Read from error queue: now has first zerocopy notification
+0.5 recvmsg(5, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=0}}
]}, MSG_ERRQUEUE) = 0

View File

@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0
// Fastopen server zerocopy test:
//
// send data with MSG_FASTOPEN | MSG_ZEROCOPY and verify that the
// kernel returns the notification ID.
`./defaults.sh
./set_sysctls.py /proc/sys/net/ipv4/tcp_fastopen=0x207`
// Set up a TFO server listening socket.
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+.1 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 setsockopt(3, SOL_TCP, TCP_FASTOPEN, [2], 4) = 0
+0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0
// Client sends a SYN with data.
+.1 < S 0:1000(1000) win 32792 <mss 1460,sackOK,nop,nop>
+0 > S. 0:0(0) ack 1001 <mss 1460,nop,nop,sackOK>
// Server accepts and replies with data.
+.005 accept(3, ..., ...) = 4
+0 read(4, ..., 1024) = 1000
+0 sendto(4, ..., 1000, MSG_ZEROCOPY, ..., ...) = 1000
+0 > P. 1:1001(1000) ack 1001
+.05 < . 1001:1001(0) ack 1001 win 32792
// Read from error queue: now has first zerocopy notification
+0.1 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=0}}
]}, MSG_ERRQUEUE) = 0
`/tmp/sysctl_restore_${PPID}.sh`

View File

@ -0,0 +1,118 @@
// SPDX-License-Identifier: GPL-2.0
// tcp_MAX_SKB_FRAGS test
//
// Verify that sending an iovec of tcp_MAX_SKB_FRAGS + 1 elements will
// 1) fit in a single packet without zerocopy
// 2) spill over into a second packet with zerocopy,
// because each iovec element becomes a frag
// 3) the PSH bit is set on an skb when it runs out of fragments
`./defaults.sh`
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0
// Each pinned zerocopy page is fully accounted to skb->truesize.
// This test generates a worst case packet with each frag storing
// one byte, but increasing truesize with a page (64KB on PPC).
+0 setsockopt(3, SOL_SOCKET, SO_SNDBUF, [2000000], 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>
+0 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
// send an iov of 18 elements: just becomes a linear skb
+0 sendmsg(4, {msg_name(...)=...,
msg_iov(18)=[{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}],
msg_flags=0}, 0) = 18
+0 > P. 1:19(18) ack 1
+0 < . 1:1(0) ack 19 win 257
// send a zerocopy iov of 18 elements:
+1 sendmsg(4, {msg_name(...)=...,
msg_iov(18)=[{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}],
msg_flags=0}, MSG_ZEROCOPY) = 18
// verify that it is split in one skb of 17 frags + 1 of 1 frag
// verify that both have the PSH bit set
+0 > P. 19:36(17) ack 1
+0 < . 1:1(0) ack 36 win 257
+0 > P. 36:37(1) ack 1
+0 < . 1:1(0) ack 37 win 257
+1 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=0}}
]}, MSG_ERRQUEUE) = 0
// send a zerocopy iov of 64 elements:
+0 sendmsg(4, {msg_name(...)=...,
msg_iov(64)=[{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1},
{..., 1}, {..., 1}, {..., 1}, {..., 1}],
msg_flags=0}, MSG_ZEROCOPY) = 64
// verify that it is split in skbs with 17 frags
+0 > P. 37:54(17) ack 1
+0 < . 1:1(0) ack 54 win 257
+0 > P. 54:71(17) ack 1
+0 < . 1:1(0) ack 71 win 257
+0 > P. 71:88(17) ack 1
+0 < . 1:1(0) ack 88 win 257
+0 > P. 88:101(13) ack 1
+0 < . 1:1(0) ack 101 win 257
+1 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=1,
ee_data=1}}
]}, MSG_ERRQUEUE) = 0

View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
// small packet zerocopy test:
//
// verify that SO_EE_CODE_ZEROCOPY_COPIED is set on zerocopy
// packets of all sizes, including the smallest payload, 1B.
`./defaults.sh`
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [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>
+0 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
// send 1B
+0 send(4, ..., 1, MSG_ZEROCOPY) = 1
+0 > P. 1:2(1) ack 1
+0 < . 1:1(0) ack 2 win 257
+1 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=0,
ee_data=0}}
]}, MSG_ERRQUEUE) = 0
// send 1B again
+0 send(4, ..., 1, MSG_ZEROCOPY) = 1
+0 > P. 2:3(1) ack 1
+0 < . 1:1(0) ack 3 win 257
+1 recvmsg(4, {msg_name(...)=...,
msg_iov(1)=[{...,0}],
msg_flags=MSG_ERRQUEUE,
msg_control=[
{cmsg_level=CMSG_LEVEL_IP,
cmsg_type=CMSG_TYPE_RECVERR,
cmsg_data={ee_errno=0,
ee_origin=SO_EE_ORIGIN_ZEROCOPY,
ee_type=0,
ee_code=SO_EE_CODE_ZEROCOPY_COPIED,
ee_info=1,
ee_data=1}}
]}, MSG_ERRQUEUE) = 0