Commit 1e42f73f authored by Willem de Bruijn's avatar Willem de Bruijn Committed by Jakub Kicinski

selftests/net: packetdrill: import tcp/zerocopy

Same as initial tests, import verbatim from
github.com/google/packetdrill, aside from:

- update `source ./defaults.sh` path to adjust for flat dir
- add SPDX headers
- remove author statements if any
- drop blank lines at EOF (new)

Also import set_sysctls.py, which many scripts depend on to set
sysctls and then restore them later. This is no longer strictly needed
for namespacified sysctl. But not all sysctls are namespacified, and
doesn't hurt if they are.
Signed-off-by: default avatarWillem de Bruijn <willemb@google.com>
Acked-by: default avatarMatthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20240912005317.1253001-3-willemdebruijn.kernel@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent cded7e04
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
TEST_INCLUDES := ksft_runner.sh \ TEST_INCLUDES := ksft_runner.sh \
defaults.sh \ defaults.sh \
set_sysctls.py \
../../kselftest/ktap_helpers.sh ../../kselftest/ktap_helpers.sh
TEST_PROGS := $(wildcard *.pkt) TEST_PROGS := $(wildcard *.pkt)
......
#!/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)
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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`
// 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
// 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment