Skip to content

Commit

Permalink
selftests/net: packetdrill: import tcp/fast_recovery, tcp/nagle, tcp/…
Browse files Browse the repository at this point in the history
…timestamping

Use the standard import and testing method, as described in the
import of tcp/ecn , tcp/close , tcp/sack , tcp/tcp_info.

Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Soham Chakradeo <sohamch@google.com>
Link: https://patch.msgid.link/20241217185203.297935-3-sohamch.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Soham Chakradeo authored and Jakub Kicinski committed Dec 18, 2024
1 parent 88395c0 commit eab3598
Show file tree
Hide file tree
Showing 10 changed files with 683 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// SPDX-License-Identifier: GPL-2.0
// Test PRR-slowstart implementation.
// In this variant we test a simple case where in-flight == ssthresh
// all the way through recovery, so during fast recovery we send one segment
// for each segment SACKed/ACKed.

// Set up config.
`./defaults.sh`

// Establish a connection.
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>
// RTT 100ms
+.1 < . 1:1(0) ack 1 win 320
+0 accept(3, ..., ...) = 4

// Send 10 data segments.
+0 write(4, ..., 10000) = 10000
+0 > P. 1:10001(10000) ack 1

// Lost packet 1:1001.
+.11 < . 1:1(0) ack 1 win 320 <sack 1001:2001,nop,nop>
+.01 < . 1:1(0) ack 1 win 320 <sack 1001:3001,nop,nop>
+.01 < . 1:1(0) ack 1 win 320 <sack 1001:4001,nop,nop>
// Enter fast recovery.
+0 > . 1:1001(1000) ack 1
+.01 %{
assert tcpi_ca_state == TCP_CA_Recovery, tcpi_ca_state
assert tcpi_snd_cwnd == 7, tcpi_snd_cwnd
assert tcpi_snd_ssthresh == 7, tcpi_snd_ssthresh
}%

// Write some more, which we will send 1 MSS at a time,
// as in-flight segments are SACKed or ACKed.
+.01 write(4, ..., 7000) = 7000

+.01 < . 1:1(0) ack 1 win 320 <sack 1001:5001,nop,nop>
+0 > . 10001:11001(1000) ack 1

+.01 < . 1:1(0) ack 1 win 320 <sack 1001:6001,nop,nop>
+0 > . 11001:12001(1000) ack 1

+.01 < . 1:1(0) ack 1 win 320 <sack 1001:7001,nop,nop>
+0 > . 12001:13001(1000) ack 1

+.01 < . 1:1(0) ack 1 win 320 <sack 1001:8001,nop,nop>
+0 > . 13001:14001(1000) ack 1

+.01 < . 1:1(0) ack 1 win 320 <sack 1001:9001,nop,nop>
+0 > . 14001:15001(1000) ack 1

+.01 < . 1:1(0) ack 1 win 320 <sack 1001:10001,nop,nop>
+0 > . 15001:16001(1000) ack 1

+.02 < . 1:1(0) ack 10001 win 320
+0 > P. 16001:17001(1000) ack 1
// Leave fast recovery.
+.01 %{
assert tcpi_ca_state == TCP_CA_Open, tcpi_ca_state
assert tcpi_snd_cwnd == 7, tcpi_snd_cwnd
assert tcpi_snd_ssthresh == 7, tcpi_snd_ssthresh
}%

+.03 < . 1:1(0) ack 12001 win 320
+.02 < . 1:1(0) ack 14001 win 320
+.02 < . 1:1(0) ack 16001 win 320
+.02 < . 1:1(0) ack 17001 win 320
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0
// Test PRR-slowstart implementation. The sender sends 20 packets. Packet
// 1 to 4, and 11 to 16 are dropped.
`./defaults.sh`

// Establish a connection.
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>

+.01 < . 1:1(0) ack 1 win 320
+0 accept(3, ..., ...) = 4

// Write 20 data segments.
+0 write(4, ..., 20000) = 20000
+0 > P. 1:10001(10000) ack 1

// Receive first DUPACK, entering PRR part
+.01 < . 1:1(0) ack 1 win 320 <sack 4001:5001,nop,nop>
+0 > . 10001:11001(1000) ack 1
+.002 < . 1:1(0) ack 1 win 320 <sack 4001:6001,nop,nop>
+0 > . 11001:12001(1000) ack 1
+.002 < . 1:1(0) ack 1 win 320 <sack 4001:7001,nop,nop>
+0 > . 1:1001(1000) ack 1
+.002 < . 1:1(0) ack 1 win 320 <sack 4001:8001,nop,nop>
+0 > . 1001:2001(1000) ack 1
+.002 < . 1:1(0) ack 1 win 320 <sack 4001:9001,nop,nop>
+0 > . 2001:3001(1000) ack 1
+.002 < . 1:1(0) ack 1 win 320 <sack 4001:10001,nop,nop>
+0 > . 3001:4001(1000) ack 1
// Enter PRR CRB
+.002 < . 1:1(0) ack 1 win 320 <sack 4001:11001,nop,nop>
+0 > . 12001:13001(1000) ack 1
+.002 < . 1:1(0) ack 1 win 320 <sack 4001:12001,nop,nop>
+0 > . 13001:14001(1000) ack 1
// Enter PRR slow start
+.01 < . 1:1(0) ack 1001 win 320 <sack 4001:12001,nop,nop>
+0 > P. 14001:16001(2000) ack 1
+.002 < . 1:1(0) ack 1001 win 320 <sack 2001:12001,nop,nop>
+0 > . 1001:2001(1000) ack 1
+0 > . 16001:17001(1000) ack 1
// inflight reaches ssthresh, goes into packet conservation mode
+.002 < . 1:1(0) ack 1001 win 320 <sack 2001:13001,nop,nop>
+0 > . 17001:18001(1000) ack 1
+.002 < . 1:1(0) ack 1001 win 320 <sack 2001:14001,nop,nop>
+0 > . 18001:19001(1000) ack 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-2.0
// Test PRR-slowstart implementation. The sender sends 20 packets. Packet
// 1 to 4 are lost. The sender writes another 10 packets.
`./defaults.sh`

// Establish a connection.
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>

+.01 < . 1:1(0) ack 1 win 320
+0 accept(3, ..., ...) = 4

// Send 20 data segments.
+0 write(4, ..., 10000) = 10000
+0 > P. 1:10001(10000) ack 1

// Lost packet 1,2,3,4
+.01 < . 1:1(0) ack 1 win 320 <sack 4001:5001,nop,nop>
+.002 < . 1:1(0) ack 1 win 320 <sack 4001:6001,nop,nop>
+0 < . 1:1(0) ack 1 win 320 <sack 4001:7001,nop,nop>
+0 > . 1:1001(1000) ack 1
+0 < . 1:1(0) ack 1 win 320 <sack 4001:8001,nop,nop>
+0 > . 1001:2001(1000) ack 1
+0 < . 1:1(0) ack 1 win 320 <sack 4001:9001,nop,nop>
+0 > . 2001:3001(1000) ack 1
+0 < . 1:1(0) ack 1 win 320 <sack 4001:10001,nop,nop>
+0 > . 3001:4001(1000) ack 1

// Receiver ACKs all data.
+.01 < . 1:1(0) ack 1001 win 320 <sack 4001:10001,nop,nop>
+0 < . 1:1(0) ack 2001 win 320 <sack 4001:10001,nop,nop>
+0 < . 1:1(0) ack 3001 win 320 <sack 4001:10001,nop,nop>
+0 < . 1:1(0) ack 10001 win 320

// Writes another 10 packets, which the ssthresh*mss amount
// should be sent right away
+.01 write(4, ..., 10000) = 10000
+0 > . 10001:17001(7000) ack 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0
// Test PRR-slowstart implementation.
// In this variant we verify that the sender uses SACK info on an ACK
// below snd_una.

// Set up config.
`./defaults.sh`

// Establish a connection.
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 8>
+0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 8>
// RTT 10ms
+.01 < . 1:1(0) ack 1 win 320
+0 accept(3, ..., ...) = 4

// Send 10 data segments.
+0 write(4, ..., 10000) = 10000
+0 > P. 1:10001(10000) ack 1

// Lost packet 1:1001,4001:5001,7001:8001.
+.01 < . 1:1(0) ack 1 win 320 <sack 1001:2001,nop,nop>
+0 < . 1:1(0) ack 1 win 320 <sack 1001:3001,nop,nop>
+0 < . 1:1(0) ack 1 win 320 <sack 1001:3001 8001:9001,nop,nop>
+0 > . 1:1001(1000) ack 1

+.012 < . 1:1(0) ack 4001 win 320 <sack 8001:9001,nop,nop>
+0 > . 4001:7001(3000) ack 1

+0 write(4, ..., 10000) = 10000

// The following ACK was reordered - delayed so that it arrives with
// an ACK field below snd_una. Here we check that the newly-SACKed
// 2MSS at 5001:7001 cause us to send out 2 more MSS.
+.002 < . 1:1(0) ack 3001 win 320 <sack 5001:7001,nop,nop>
+0 > . 7001:8001(1000) ack 1
+0 > . 10001:11001(1000) ack 1
40 changes: 40 additions & 0 deletions tools/testing/selftests/net/packetdrill/tcp_nagle_https_client.pkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0
// This is a test inspired by an Android client app using SSL. This
// test verifies using TCP_NODELAY would save application latency
// (Perhaps even better with TCP_NAGLE).
//
`./defaults.sh
ethtool -K tun0 tso off gso off
./set_sysctls.py /proc/sys/net/ipv4/tcp_timestamps=0`

0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 4
+0 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
+0 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0

+0 connect(4, ..., ...) = -1 EINPROGRESS (Operation now in progress)
+0 > S 0:0(0) <mss 1460,nop,nop,sackOK,nop,wscale 8>
+.1 < S. 0:0(0) ack 1 win 5792 <mss 974,nop,nop,sackOK,nop,wscale 7>
+0 > . 1:1(0) ack 1

// SSL handshake (resumed session)
+0 write(4, ..., 517) = 517
+0 > P. 1:518(517) ack 1
+.1 < . 1:1(0) ack 518 win 229

+0 < P. 1:144(143) ack 1 win 229
+0 > . 518:518(0) ack 144
+0 read(4, ..., 1000) = 143

// Application POST header (51B) and body (2002B)
+0 write(4, ..., 51) = 51
+0 > P. 518:569(51) ack 144
+.03 write(4, ..., 2002) = 2002
+0 > . 569:1543(974) ack 144
+0 > P. 1543:2517(974) ack 144
// Without disabling Nagle, this packet will not happen until the remote ACK.
+0 > P. 2517:2571(54) ack 144

+.1 < . 1:1(0) ack 2571 win 229

// Reset sysctls
`/tmp/sysctl_restore_${PPID}.sh`
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0
// Test the MSG_MORE flag will correctly corks the tiny writes
`./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,nop,wscale 7>
+0 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 8>
+.01 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
// Disable Nagle by default on this socket.
+0 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0

// Test the basic case: MSG_MORE overwrites TCP_NODELAY and enables Nagle.
+0 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 40}], msg_flags=0}, MSG_MORE) = 40
+.21~+.215 > P. 1:41(40) ack 1
+.01 < . 1:1(0) ack 41 win 257

// Test unsetting MSG_MORE releases the packet
+0 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 100}], msg_flags=0}, MSG_MORE) = 100
+.005 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 160}], msg_flags=0}, MSG_MORE) = 160
+.01 sendmsg(4, {msg_name(...)=...,
msg_iov(3)=[{..., 100}, {..., 200}, {..., 195}],
msg_flags=0}, MSG_MORE) = 495
+.008 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 5}], msg_flags=0}, 0) = 5
+0 > P. 41:801(760) ack 1
+.02 < . 1:1(0) ack 801 win 257


// Test >MSS write will unleash MSS packets but hold on the remaining data.
+.1 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 3100}], msg_flags=0}, MSG_MORE) = 3100
+0 > . 801:3801(3000) ack 1
+.003 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 50}], msg_flags=0}, MSG_MORE) = 50

+.01 < . 1:1(0) ack 2801 win 257
// Err... we relase the remaining right after the ACK? note that PUSH is reset
+0 > . 3801:3951(150) ack 1

// Test we'll hold on the subsequent writes when inflight (3801:3951) > 0
+.001 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 1}], msg_flags=0}, MSG_MORE) = 1
+.002 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 2}], msg_flags=0}, MSG_MORE) = 2
+.003 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 3}], msg_flags=0}, MSG_MORE) = 3
+.004 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 4}], msg_flags=0}, MSG_MORE) = 4
+.02 < . 1:1(0) ack 3951 win 257
+0 > . 3951:3961(10) ack 1
+.02 < . 1:1(0) ack 3961 win 257


// Test the case a MSG_MORE send followed by a write flushes the data
+0 sendmsg(4, {msg_name(...)=...,
msg_iov(1)=[{..., 20}], msg_flags=0}, MSG_MORE) = 20
+.05 write(4, ..., 20) = 20
+0 > P. 3961:4001(40) ack 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: GPL-2.0
// Test TCP_CORK and TCP_NODELAY sockopt behavior
`./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,nop,wscale 7>
+0 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 8>
+.01 < . 1:1(0) ack 1 win 257
+0 accept(3, ..., ...) = 4
// Set TCP_CORK sockopt to hold small packets
+0 setsockopt(4, SOL_TCP, TCP_CORK, [1], 4) = 0

+0 write(4, ..., 40) = 40
+.05 write(4, ..., 40) = 40

// Unset TCP_CORK should push pending bytes out
+.01 setsockopt(4, SOL_TCP, TCP_CORK, [0], 4) = 0
+0 > P. 1:81(80) ack 1
+.01 < . 1:1(0) ack 81 win 257

// Set TCP_CORK sockopt to hold small packets
+0 setsockopt(4, SOL_TCP, TCP_CORK, [1], 4) = 0

+0 write(4, ..., 40) = 40
+.05 write(4, ..., 40) = 40

// Set TCP_NODELAY sockopt should push pending bytes out
+0 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0
+0 > P. 81:161(80) ack 1
+.01 < . 1:1(0) ack 161 win 257

// Set MSG_MORE to hold small packets
+0 send(4, ..., 40, MSG_MORE) = 40
+.05 send(4, ..., 40, MSG_MORE) = 40

// Set TCP_NODELAY sockopt should push pending bytes out
+.01 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0
+0 > . 161:241(80) ack 1
+.01 < . 1:1(0) ack 241 win 257
Loading

0 comments on commit eab3598

Please sign in to comment.