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

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: Willem de Bruijn <willemb@google.com>
Acked-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20240912005317.1253001-3-willemdebruijn.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Willem de Bruijn and committed by
Jakub Kicinski
1e42f73f cded7e04

+674
+1
tools/testing/selftests/net/packetdrill/Makefile
··· 2 2 3 3 TEST_INCLUDES := ksft_runner.sh \ 4 4 defaults.sh \ 5 + set_sysctls.py \ 5 6 ../../kselftest/ktap_helpers.sh 6 7 7 8 TEST_PROGS := $(wildcard *.pkt)
+38
tools/testing/selftests/net/packetdrill/set_sysctls.py
··· 1 + #!/usr/bin/env python3 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + """Sets sysctl values and writes a file that restores them. 5 + 6 + The arguments are of the form "<proc-file>=<val>" separated by spaces. 7 + The program first reads the current value of the proc-file and creates 8 + a shell script named "/tmp/sysctl_restore_${PACKETDRILL_PID}.sh" which 9 + restores the values when executed. It then sets the new values. 10 + 11 + PACKETDRILL_PID is set by packetdrill to the pid of itself, so a .pkt 12 + file could restore sysctls by running `/tmp/sysctl_restore_${PPID}.sh` 13 + at the end. 14 + """ 15 + 16 + import os 17 + import subprocess 18 + import sys 19 + 20 + filename = '/tmp/sysctl_restore_%s.sh' % os.environ['PACKETDRILL_PID'] 21 + 22 + # Open file for restoring sysctl values 23 + restore_file = open(filename, 'w') 24 + print('#!/bin/bash', file=restore_file) 25 + 26 + for a in sys.argv[1:]: 27 + sysctl = a.split('=') 28 + # sysctl[0] contains the proc-file name, sysctl[1] the new value 29 + 30 + # read current value and add restore command to file 31 + cur_val = subprocess.check_output(['cat', sysctl[0]], universal_newlines=True) 32 + print('echo "%s" > %s' % (cur_val.strip(), sysctl[0]), file=restore_file) 33 + 34 + # set new value 35 + cmd = 'echo "%s" > %s' % (sysctl[1], sysctl[0]) 36 + os.system(cmd) 37 + 38 + os.system('chmod u+x %s' % filename)
+55
tools/testing/selftests/net/packetdrill/tcp_zerocopy_basic.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // basic zerocopy test: 3 + // 4 + // send a packet with MSG_ZEROCOPY and receive the notification ID 5 + // repeat and verify IDs are consecutive 6 + 7 + `./defaults.sh` 8 + 9 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 10 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 11 + +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 12 + +0 bind(3, ..., ...) = 0 13 + +0 listen(3, 1) = 0 14 + 15 + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> 16 + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> 17 + +0 < . 1:1(0) ack 1 win 257 18 + 19 + +0 accept(3, ..., ...) = 4 20 + 21 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 22 + +0 > P. 1:4001(4000) ack 1 23 + +0 < . 1:1(0) ack 4001 win 257 24 + 25 + +0 recvmsg(4, {msg_name(...)=..., 26 + msg_iov(1)=[{...,0}], 27 + msg_flags=MSG_ERRQUEUE, 28 + msg_control=[ 29 + {cmsg_level=CMSG_LEVEL_IP, 30 + cmsg_type=CMSG_TYPE_RECVERR, 31 + cmsg_data={ee_errno=0, 32 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 33 + ee_type=0, 34 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 35 + ee_info=0, 36 + ee_data=0}} 37 + ]}, MSG_ERRQUEUE) = 0 38 + 39 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 40 + +0 > P. 4001:8001(4000) ack 1 41 + +0 < . 1:1(0) ack 8001 win 257 42 + 43 + +0 recvmsg(4, {msg_name(...)=..., 44 + msg_iov(1)=[{...,0}], 45 + msg_flags=MSG_ERRQUEUE, 46 + msg_control=[ 47 + {cmsg_level=CMSG_LEVEL_IP, 48 + cmsg_type=CMSG_TYPE_RECVERR, 49 + cmsg_data={ee_errno=0, 50 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 51 + ee_type=0, 52 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 53 + ee_info=1, 54 + ee_data=1}} 55 + ]}, MSG_ERRQUEUE) = 0
+41
tools/testing/selftests/net/packetdrill/tcp_zerocopy_batch.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // batch zerocopy test: 3 + // 4 + // send multiple packets, then read one range of all notifications. 5 + 6 + `./defaults.sh` 7 + 8 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 9 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 10 + +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 11 + +0 bind(3, ..., ...) = 0 12 + +0 listen(3, 1) = 0 13 + 14 + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> 15 + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> 16 + +0 < . 1:1(0) ack 1 win 257 17 + 18 + +0 accept(3, ..., ...) = 4 19 + +0 setsockopt(4, SOL_SOCKET, SO_MARK, [666], 4) = 0 20 + 21 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 22 + +0 > P. 1:4001(4000) ack 1 23 + +0 < . 1:1(0) ack 4001 win 257 24 + 25 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 26 + +0 > P. 4001:8001(4000) ack 1 27 + +0 < . 1:1(0) ack 8001 win 257 28 + 29 + +0 recvmsg(4, {msg_name(...)=..., 30 + msg_iov(1)=[{...,0}], 31 + msg_flags=MSG_ERRQUEUE, 32 + msg_control=[ 33 + {cmsg_level=CMSG_LEVEL_IP, 34 + cmsg_type=CMSG_TYPE_RECVERR, 35 + cmsg_data={ee_errno=0, 36 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 37 + ee_type=0, 38 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 39 + ee_info=0, 40 + ee_data=1}} 41 + ]}, MSG_ERRQUEUE) = 0
+30
tools/testing/selftests/net/packetdrill/tcp_zerocopy_client.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Minimal client-side zerocopy test 3 + 4 + `./defaults.sh` 5 + 6 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 4 7 + +0 setsockopt(4, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 8 + +0...0 connect(4, ..., ...) = 0 9 + 10 + +0 > S 0:0(0) <mss 1460,sackOK,TS val 0 ecr 0,nop,wscale 8> 11 + +0 < S. 0:0(0) ack 1 win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> 12 + +0 > . 1:1(0) ack 1 13 + 14 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 15 + +0 > P. 1:4001(4000) ack 1 16 + +0 < . 1:1(0) ack 4001 win 257 17 + 18 + +0 recvmsg(4, {msg_name(...)=..., 19 + msg_iov(1)=[{...,0}], 20 + msg_flags=MSG_ERRQUEUE, 21 + msg_control=[ 22 + {cmsg_level=CMSG_LEVEL_IP, 23 + cmsg_type=CMSG_TYPE_RECVERR, 24 + cmsg_data={ee_errno=0, 25 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 26 + ee_type=0, 27 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 28 + ee_info=0, 29 + ee_data=0}} 30 + ]}, MSG_ERRQUEUE) = 0
+44
tools/testing/selftests/net/packetdrill/tcp_zerocopy_closed.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // send with MSG_ZEROCOPY on a non-established socket 3 + // 4 + // verify that a send in state TCP_CLOSE correctly aborts the zerocopy 5 + // operation, specifically it does not increment the zerocopy counter. 6 + // 7 + // First send on a closed socket and wait for (absent) notification. 8 + // Then connect and send and verify that notification nr. is zero. 9 + 10 + `./defaults.sh` 11 + 12 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 4 13 + +0 setsockopt(4, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 14 + 15 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = -1 EPIPE (Broken pipe) 16 + 17 + +0.1 recvmsg(4, {msg_name(...)=..., 18 + msg_iov(1)=[{...,0}], 19 + msg_flags=MSG_ERRQUEUE, 20 + msg_control=[]}, MSG_ERRQUEUE) = -1 EAGAIN (Resource temporarily unavailable) 21 + 22 + +0...0 connect(4, ..., ...) = 0 23 + 24 + +0 > S 0:0(0) <mss 1460,sackOK,TS val 0 ecr 0,nop,wscale 8> 25 + +0 < S. 0:0(0) ack 1 win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> 26 + +0 > . 1:1(0) ack 1 27 + 28 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 29 + +0 > P. 1:4001(4000) ack 1 30 + +0 < . 1:1(0) ack 4001 win 257 31 + 32 + +0 recvmsg(4, {msg_name(...)=..., 33 + msg_iov(1)=[{...,0}], 34 + msg_flags=MSG_ERRQUEUE, 35 + msg_control=[ 36 + {cmsg_level=CMSG_LEVEL_IP, 37 + cmsg_type=CMSG_TYPE_RECVERR, 38 + cmsg_data={ee_errno=0, 39 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 40 + ee_type=0, 41 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 42 + ee_info=0, 43 + ee_data=0}} 44 + ]}, MSG_ERRQUEUE) = 0
+61
tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_edge.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // epoll zerocopy test: 3 + // 4 + // EPOLLERR is known to be not edge-triggered unlike EPOLLIN and EPOLLOUT but 5 + // it is not level-triggered either. 6 + // 7 + // fire two sends with MSG_ZEROCOPY and receive the acks. confirm that EPOLLERR 8 + // is correctly fired only once, when EPOLLET is set. send another packet with 9 + // MSG_ZEROCOPY. confirm that EPOLLERR is correctly fired again only once. 10 + `./defaults.sh` 11 + 12 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 13 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 14 + +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 15 + +0 bind(3, ..., ...) = 0 16 + +0 listen(3, 1) = 0 17 + 18 + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> 19 + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> 20 + +0 < . 1:1(0) ack 1 win 257 21 + 22 + +0 accept(3, ..., ...) = 4 23 + 24 + +0 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 25 + +0 epoll_create(1) = 5 26 + +0 epoll_ctl(5, EPOLL_CTL_ADD, 4, {events=EPOLLOUT|EPOLLET, fd=4}) = 0 27 + +0 epoll_wait(5, {events=EPOLLOUT, fd=4}, 1, 0) = 1 28 + 29 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 30 + +0 > P. 1:4001(4000) ack 1 31 + +0 < . 1:1(0) ack 4001 win 257 32 + 33 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 34 + +0 > P. 4001:8001(4000) ack 1 35 + +0 < . 1:1(0) ack 8001 win 257 36 + 37 + // receive only one EPOLLERR for the two sends above. 38 + +0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1 39 + +0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0 40 + 41 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 42 + +0 > P. 8001:12001(4000) ack 1 43 + +0 < . 1:1(0) ack 12001 win 257 44 + 45 + // receive only one EPOLLERR for the third send above. 46 + +0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1 47 + +0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0 48 + 49 + +0 recvmsg(4, {msg_name(...)=..., 50 + msg_iov(1)=[{...,0}], 51 + msg_flags=MSG_ERRQUEUE, 52 + msg_control=[ 53 + {cmsg_level=CMSG_LEVEL_IP, 54 + cmsg_type=CMSG_TYPE_RECVERR, 55 + cmsg_data={ee_errno=0, 56 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 57 + ee_type=0, 58 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 59 + ee_info=0, 60 + ee_data=2}} 61 + ]}, MSG_ERRQUEUE) = 0
+63
tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_exclusive.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // epoll zerocopy test: 3 + // 4 + // EPOLLERR is known to be not edge-triggered unlike EPOLLIN and EPOLLOUT but 5 + // it is not level-triggered either. this tests verify that the same behavior is 6 + // maintained when we have EPOLLEXCLUSIVE. 7 + // 8 + // fire two sends with MSG_ZEROCOPY and receive the acks. confirm that EPOLLERR 9 + // is correctly fired only once, when EPOLLET is set. send another packet with 10 + // MSG_ZEROCOPY. confirm that EPOLLERR is correctly fired again only once. 11 + `./defaults.sh` 12 + 13 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 14 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 15 + +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 16 + +0 bind(3, ..., ...) = 0 17 + +0 listen(3, 1) = 0 18 + 19 + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> 20 + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> 21 + +0 < . 1:1(0) ack 1 win 257 22 + 23 + +0 accept(3, ..., ...) = 4 24 + 25 + +0 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 26 + +0 epoll_create(1) = 5 27 + +0 epoll_ctl(5, EPOLL_CTL_ADD, 4, 28 + {events=EPOLLOUT|EPOLLET|EPOLLEXCLUSIVE, fd=4}) = 0 29 + +0 epoll_wait(5, {events=EPOLLOUT, fd=4}, 1, 0) = 1 30 + 31 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 32 + +0 > P. 1:4001(4000) ack 1 33 + +0 < . 1:1(0) ack 4001 win 257 34 + 35 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 36 + +0 > P. 4001:8001(4000) ack 1 37 + +0 < . 1:1(0) ack 8001 win 257 38 + 39 + // receive only one EPOLLERR for the two sends above. 40 + +0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1 41 + +0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0 42 + 43 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 44 + +0 > P. 8001:12001(4000) ack 1 45 + +0 < . 1:1(0) ack 12001 win 257 46 + 47 + // receive only one EPOLLERR for the third send above. 48 + +0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1 49 + +0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0 50 + 51 + +0 recvmsg(4, {msg_name(...)=..., 52 + msg_iov(1)=[{...,0}], 53 + msg_flags=MSG_ERRQUEUE, 54 + msg_control=[ 55 + {cmsg_level=CMSG_LEVEL_IP, 56 + cmsg_type=CMSG_TYPE_RECVERR, 57 + cmsg_data={ee_errno=0, 58 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 59 + ee_type=0, 60 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 61 + ee_info=0, 62 + ee_data=2}} 63 + ]}, MSG_ERRQUEUE) = 0
+66
tools/testing/selftests/net/packetdrill/tcp_zerocopy_epoll_oneshot.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // epoll zerocopy test: 3 + // 4 + // This is a test to confirm that EPOLLERR is only fired once for an FD when 5 + // EPOLLONESHOT is set. 6 + // 7 + // fire two sends with MSG_ZEROCOPY and receive the acks. confirm that EPOLLERR 8 + // is correctly fired only once, when EPOLLONESHOT is set. send another packet 9 + // with MSG_ZEROCOPY. confirm that EPOLLERR is not fired. Rearm the FD and 10 + // confirm that EPOLLERR is correctly set. 11 + `./defaults.sh` 12 + 13 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 14 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 15 + +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 16 + +0 bind(3, ..., ...) = 0 17 + +0 listen(3, 1) = 0 18 + 19 + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> 20 + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> 21 + +0 < . 1:1(0) ack 1 win 257 22 + 23 + +0 accept(3, ..., ...) = 4 24 + 25 + +0 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 26 + +0 epoll_create(1) = 5 27 + +0 epoll_ctl(5, EPOLL_CTL_ADD, 4, 28 + {events=EPOLLOUT|EPOLLET|EPOLLONESHOT, fd=4}) = 0 29 + 30 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 31 + +0 > P. 1:4001(4000) ack 1 32 + +0 < . 1:1(0) ack 4001 win 257 33 + 34 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 35 + +0 > P. 4001:8001(4000) ack 1 36 + +0 < . 1:1(0) ack 8001 win 257 37 + 38 + // receive only one EPOLLERR for the two sends above. 39 + +0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1 40 + +0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0 41 + 42 + +0 send(4, ..., 4000, MSG_ZEROCOPY) = 4000 43 + +0 > P. 8001:12001(4000) ack 1 44 + +0 < . 1:1(0) ack 12001 win 257 45 + 46 + // receive no EPOLLERR for the third send above. 47 + +0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0 48 + 49 + // rearm the FD and verify the EPOLLERR is fired again. 50 + +0 epoll_ctl(5, EPOLL_CTL_MOD, 4, {events=EPOLLOUT|EPOLLONESHOT, fd=4}) = 0 51 + +0 epoll_wait(5, {events=EPOLLERR|EPOLLOUT, fd=4}, 1, 0) = 1 52 + +0 epoll_wait(5, {events=0, ptr=0}, 1, 0) = 0 53 + 54 + +0 recvmsg(4, {msg_name(...)=..., 55 + msg_iov(1)=[{...,0}], 56 + msg_flags=MSG_ERRQUEUE, 57 + msg_control=[ 58 + {cmsg_level=CMSG_LEVEL_IP, 59 + cmsg_type=CMSG_TYPE_RECVERR, 60 + cmsg_data={ee_errno=0, 61 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 62 + ee_type=0, 63 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 64 + ee_info=0, 65 + ee_data=2}} 66 + ]}, MSG_ERRQUEUE) = 0
+56
tools/testing/selftests/net/packetdrill/tcp_zerocopy_fastopen-client.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Fastopen client zerocopy test: 3 + // 4 + // send data with MSG_FASTOPEN | MSG_ZEROCOPY and verify that the 5 + // kernel returns the notification ID. 6 + // 7 + // Fastopen requires a stored cookie. Create two sockets. The first 8 + // one will have no data in the initial send. On return 0 the 9 + // zerocopy notification counter is not incremented. Verify this too. 10 + 11 + `./defaults.sh` 12 + 13 + // Send a FastOpen request, no cookie yet so no data in SYN 14 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 15 + +0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 16 + +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 17 + +0 sendto(3, ..., 500, MSG_FASTOPEN|MSG_ZEROCOPY, ..., ...) = -1 EINPROGRESS (Operation now in progress) 18 + +0 > S 0:0(0) <mss 1460,sackOK,TS val 1000 ecr 0,nop,wscale 8,FO,nop,nop> 19 + +.01 < S. 123:123(0) ack 1 win 14600 <mss 940,TS val 2000 ecr 1000,sackOK,nop,wscale 6, FO abcd1234,nop,nop> 20 + +0 > . 1:1(0) ack 1 <nop,nop,TS val 1001 ecr 2000> 21 + 22 + // Read from error queue: no zerocopy notification 23 + +1 recvmsg(3, {msg_name(...)=..., 24 + msg_iov(1)=[{...,0}], 25 + msg_flags=MSG_ERRQUEUE, 26 + msg_control=[]}, MSG_ERRQUEUE) = -1 EAGAIN (Resource temporarily unavailable) 27 + 28 + +.01 close(3) = 0 29 + +0 > F. 1:1(0) ack 1 <nop,nop,TS val 1002 ecr 2000> 30 + +.01 < F. 1:1(0) ack 2 win 92 <nop,nop,TS val 2001 ecr 1002> 31 + +0 > . 2:2(0) ack 2 <nop,nop,TS val 1003 ecr 2001> 32 + 33 + // Send another Fastopen request, now SYN will have data 34 + +.07 `sysctl -q net.ipv4.tcp_timestamps=0` 35 + +.1 socket(..., SOCK_STREAM, IPPROTO_TCP) = 5 36 + +0 fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0 37 + +0 setsockopt(5, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 38 + +0 sendto(5, ..., 500, MSG_FASTOPEN|MSG_ZEROCOPY, ..., ...) = 500 39 + +0 > S 0:500(500) <mss 1460,nop,nop,sackOK,nop,wscale 8,FO abcd1234,nop,nop> 40 + +.05 < S. 5678:5678(0) ack 501 win 14600 <mss 1460,nop,nop,sackOK,nop,wscale 6> 41 + +0 > . 501:501(0) ack 1 42 + 43 + // Read from error queue: now has first zerocopy notification 44 + +0.5 recvmsg(5, {msg_name(...)=..., 45 + msg_iov(1)=[{...,0}], 46 + msg_flags=MSG_ERRQUEUE, 47 + msg_control=[ 48 + {cmsg_level=CMSG_LEVEL_IP, 49 + cmsg_type=CMSG_TYPE_RECVERR, 50 + cmsg_data={ee_errno=0, 51 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 52 + ee_type=0, 53 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 54 + ee_info=0, 55 + ee_data=0}} 56 + ]}, MSG_ERRQUEUE) = 0
+44
tools/testing/selftests/net/packetdrill/tcp_zerocopy_fastopen-server.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Fastopen server zerocopy test: 3 + // 4 + // send data with MSG_FASTOPEN | MSG_ZEROCOPY and verify that the 5 + // kernel returns the notification ID. 6 + 7 + `./defaults.sh 8 + ./set_sysctls.py /proc/sys/net/ipv4/tcp_fastopen=0x207` 9 + 10 + // Set up a TFO server listening socket. 11 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 12 + +.1 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 13 + +0 bind(3, ..., ...) = 0 14 + +0 listen(3, 1) = 0 15 + +0 setsockopt(3, SOL_TCP, TCP_FASTOPEN, [2], 4) = 0 16 + +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 17 + 18 + // Client sends a SYN with data. 19 + +.1 < S 0:1000(1000) win 32792 <mss 1460,sackOK,nop,nop> 20 + +0 > S. 0:0(0) ack 1001 <mss 1460,nop,nop,sackOK> 21 + 22 + // Server accepts and replies with data. 23 + +.005 accept(3, ..., ...) = 4 24 + +0 read(4, ..., 1024) = 1000 25 + +0 sendto(4, ..., 1000, MSG_ZEROCOPY, ..., ...) = 1000 26 + +0 > P. 1:1001(1000) ack 1001 27 + +.05 < . 1001:1001(0) ack 1001 win 32792 28 + 29 + // Read from error queue: now has first zerocopy notification 30 + +0.1 recvmsg(4, {msg_name(...)=..., 31 + msg_iov(1)=[{...,0}], 32 + msg_flags=MSG_ERRQUEUE, 33 + msg_control=[ 34 + {cmsg_level=CMSG_LEVEL_IP, 35 + cmsg_type=CMSG_TYPE_RECVERR, 36 + cmsg_data={ee_errno=0, 37 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 38 + ee_type=0, 39 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 40 + ee_info=0, 41 + ee_data=0}} 42 + ]}, MSG_ERRQUEUE) = 0 43 + 44 + `/tmp/sysctl_restore_${PPID}.sh`
+118
tools/testing/selftests/net/packetdrill/tcp_zerocopy_maxfrags.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // tcp_MAX_SKB_FRAGS test 3 + // 4 + // Verify that sending an iovec of tcp_MAX_SKB_FRAGS + 1 elements will 5 + // 1) fit in a single packet without zerocopy 6 + // 2) spill over into a second packet with zerocopy, 7 + // because each iovec element becomes a frag 8 + // 3) the PSH bit is set on an skb when it runs out of fragments 9 + 10 + `./defaults.sh` 11 + 12 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 13 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 14 + +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 15 + 16 + // Each pinned zerocopy page is fully accounted to skb->truesize. 17 + // This test generates a worst case packet with each frag storing 18 + // one byte, but increasing truesize with a page (64KB on PPC). 19 + +0 setsockopt(3, SOL_SOCKET, SO_SNDBUF, [2000000], 4) = 0 20 + 21 + +0 bind(3, ..., ...) = 0 22 + +0 listen(3, 1) = 0 23 + 24 + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> 25 + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> 26 + +0 < . 1:1(0) ack 1 win 257 27 + 28 + +0 accept(3, ..., ...) = 4 29 + 30 + // send an iov of 18 elements: just becomes a linear skb 31 + +0 sendmsg(4, {msg_name(...)=..., 32 + msg_iov(18)=[{..., 1}, {..., 1}, {..., 1}, {..., 1}, 33 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 34 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 35 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 36 + {..., 1}, {..., 1}], 37 + msg_flags=0}, 0) = 18 38 + 39 + +0 > P. 1:19(18) ack 1 40 + +0 < . 1:1(0) ack 19 win 257 41 + 42 + // send a zerocopy iov of 18 elements: 43 + +1 sendmsg(4, {msg_name(...)=..., 44 + msg_iov(18)=[{..., 1}, {..., 1}, {..., 1}, {..., 1}, 45 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 46 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 47 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 48 + {..., 1}, {..., 1}], 49 + msg_flags=0}, MSG_ZEROCOPY) = 18 50 + 51 + // verify that it is split in one skb of 17 frags + 1 of 1 frag 52 + // verify that both have the PSH bit set 53 + +0 > P. 19:36(17) ack 1 54 + +0 < . 1:1(0) ack 36 win 257 55 + 56 + +0 > P. 36:37(1) ack 1 57 + +0 < . 1:1(0) ack 37 win 257 58 + 59 + +1 recvmsg(4, {msg_name(...)=..., 60 + msg_iov(1)=[{...,0}], 61 + msg_flags=MSG_ERRQUEUE, 62 + msg_control=[ 63 + {cmsg_level=CMSG_LEVEL_IP, 64 + cmsg_type=CMSG_TYPE_RECVERR, 65 + cmsg_data={ee_errno=0, 66 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 67 + ee_type=0, 68 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 69 + ee_info=0, 70 + ee_data=0}} 71 + ]}, MSG_ERRQUEUE) = 0 72 + 73 + // send a zerocopy iov of 64 elements: 74 + +0 sendmsg(4, {msg_name(...)=..., 75 + msg_iov(64)=[{..., 1}, {..., 1}, {..., 1}, {..., 1}, 76 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 77 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 78 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 79 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 80 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 81 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 82 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 83 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 84 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 85 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 86 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 87 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 88 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 89 + {..., 1}, {..., 1}, {..., 1}, {..., 1}, 90 + {..., 1}, {..., 1}, {..., 1}, {..., 1}], 91 + msg_flags=0}, MSG_ZEROCOPY) = 64 92 + 93 + // verify that it is split in skbs with 17 frags 94 + +0 > P. 37:54(17) ack 1 95 + +0 < . 1:1(0) ack 54 win 257 96 + 97 + +0 > P. 54:71(17) ack 1 98 + +0 < . 1:1(0) ack 71 win 257 99 + 100 + +0 > P. 71:88(17) ack 1 101 + +0 < . 1:1(0) ack 88 win 257 102 + 103 + +0 > P. 88:101(13) ack 1 104 + +0 < . 1:1(0) ack 101 win 257 105 + 106 + +1 recvmsg(4, {msg_name(...)=..., 107 + msg_iov(1)=[{...,0}], 108 + msg_flags=MSG_ERRQUEUE, 109 + msg_control=[ 110 + {cmsg_level=CMSG_LEVEL_IP, 111 + cmsg_type=CMSG_TYPE_RECVERR, 112 + cmsg_data={ee_errno=0, 113 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 114 + ee_type=0, 115 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 116 + ee_info=1, 117 + ee_data=1}} 118 + ]}, MSG_ERRQUEUE) = 0
+57
tools/testing/selftests/net/packetdrill/tcp_zerocopy_small.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // small packet zerocopy test: 3 + // 4 + // verify that SO_EE_CODE_ZEROCOPY_COPIED is set on zerocopy 5 + // packets of all sizes, including the smallest payload, 1B. 6 + 7 + `./defaults.sh` 8 + 9 + 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 10 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 11 + +0 setsockopt(3, SOL_SOCKET, SO_ZEROCOPY, [1], 4) = 0 12 + +0 bind(3, ..., ...) = 0 13 + +0 listen(3, 1) = 0 14 + 15 + +0 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> 16 + +0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8> 17 + +0 < . 1:1(0) ack 1 win 257 18 + 19 + +0 accept(3, ..., ...) = 4 20 + 21 + // send 1B 22 + +0 send(4, ..., 1, MSG_ZEROCOPY) = 1 23 + +0 > P. 1:2(1) ack 1 24 + +0 < . 1:1(0) ack 2 win 257 25 + 26 + +1 recvmsg(4, {msg_name(...)=..., 27 + msg_iov(1)=[{...,0}], 28 + msg_flags=MSG_ERRQUEUE, 29 + msg_control=[ 30 + {cmsg_level=CMSG_LEVEL_IP, 31 + cmsg_type=CMSG_TYPE_RECVERR, 32 + cmsg_data={ee_errno=0, 33 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 34 + ee_type=0, 35 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 36 + ee_info=0, 37 + ee_data=0}} 38 + ]}, MSG_ERRQUEUE) = 0 39 + 40 + // send 1B again 41 + +0 send(4, ..., 1, MSG_ZEROCOPY) = 1 42 + +0 > P. 2:3(1) ack 1 43 + +0 < . 1:1(0) ack 3 win 257 44 + 45 + +1 recvmsg(4, {msg_name(...)=..., 46 + msg_iov(1)=[{...,0}], 47 + msg_flags=MSG_ERRQUEUE, 48 + msg_control=[ 49 + {cmsg_level=CMSG_LEVEL_IP, 50 + cmsg_type=CMSG_TYPE_RECVERR, 51 + cmsg_data={ee_errno=0, 52 + ee_origin=SO_EE_ORIGIN_ZEROCOPY, 53 + ee_type=0, 54 + ee_code=SO_EE_CODE_ZEROCOPY_COPIED, 55 + ee_info=1, 56 + ee_data=1}} 57 + ]}, MSG_ERRQUEUE) = 0