diff options
Diffstat (limited to 'test/packetdrill/tests/linux')
50 files changed, 1510 insertions, 0 deletions
diff --git a/test/packetdrill/tests/linux/README b/test/packetdrill/tests/linux/README new file mode 100644 index 0000000..0e6db19 --- /dev/null +++ b/test/packetdrill/tests/linux/README @@ -0,0 +1,7 @@ +Packetdrill tests for Linux. + +This directory contains Packetdrill tests for Linux. The tests all pass under +kernel 3.11.0-rc4 (installed on an Ubuntu 13.04 machine). However, due to TCP +metrics caching in recent kernels, a second run of all tests can result in +failures. The script run_tests.sh in this directory uses the iproute tool to +flush the TCP metrics cache before each test. diff --git a/test/packetdrill/tests/linux/blocking/blocking-accept.pkt b/test/packetdrill/tests/linux/blocking/blocking-accept.pkt new file mode 100644 index 0000000..02c7cd8 --- /dev/null +++ b/test/packetdrill/tests/linux/blocking/blocking-accept.pkt @@ -0,0 +1,15 @@ +// Test for blocking accept. + +// Establish a connection. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 +0.000...0.200 accept(3, ..., ...) = 4 + +0.100 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 + +0.300 write(4, ..., 2000) = 2000 +0.300 > P. 1:2001(2000) ack 1 diff --git a/test/packetdrill/tests/linux/blocking/blocking-read.pkt b/test/packetdrill/tests/linux/blocking/blocking-read.pkt new file mode 100644 index 0000000..1c734c1 --- /dev/null +++ b/test/packetdrill/tests/linux/blocking/blocking-read.pkt @@ -0,0 +1,25 @@ +// Test for blocking read. + +// Establish a connection. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +0.200...0.300 read(4, ..., 2000) = 2000 +0.300 < P. 1:2001(2000) ack 1 win 257 +0.300 > . 1:1(0) ack 2001 + +0.400...0.500 read(4, ..., 2000) = 2000 +0.500 < P. 2001:4001(2000) ack 1 win 257 +0.500 > . 1:1(0) ack 4001 + +0.600 < P. 4001:6001(2000) ack 1 win 257 +0.600 > . 1:1(0) ack 6001 +0.600...0.600 read(4, ..., 1000) = 1000 +0.600...0.600 read(4, ..., 1000) = 1000 diff --git a/test/packetdrill/tests/linux/close/close-read-data-fin.pkt b/test/packetdrill/tests/linux/close/close-read-data-fin.pkt new file mode 100644 index 0000000..bad95c2 --- /dev/null +++ b/test/packetdrill/tests/linux/close/close-read-data-fin.pkt @@ -0,0 +1,38 @@ +// If we close the connection after read()'ing what +// the other side sent, a FIN will be generated. This +// behavior conforms to RFC 793. + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +// Receive first segment +0.210 < P. 1:1001(1000) ack 1 win 46 + +// Send one ACK +0.210 > . 1:1(0) ack 1001 + +// Application writes 1000 bytes +0.250 write(4, ..., 1000) = 1000 +0.250 > P. 1:1001(1000) ack 1001 + +// ACK +0.300 < . 1001:1001(0) ack 1001 win 257 + +0.400 read(4, ..., 1000) = 1000 + +// Client closes the connection +0.610 < F. 1001:1001(0) ack 1001 win 260 + +// Respond with (delayed) ACK +0.650 > . 1001:1001(0) ack 1002 + +// We close the connection +0.700 close(4) = 0 +0.701 > F. 1001:1001(0) ack 1002 diff --git a/test/packetdrill/tests/linux/close/close-so-linger-onoff-1-linger-0-rst.pkt b/test/packetdrill/tests/linux/close/close-so-linger-onoff-1-linger-0-rst.pkt new file mode 100644 index 0000000..dcec1cf --- /dev/null +++ b/test/packetdrill/tests/linux/close/close-so-linger-onoff-1-linger-0-rst.pkt @@ -0,0 +1,28 @@ +// Verify that when a process uses SO_LINGER with {onoff=1, linger=0}, +// and then closes the socket, the kernel sends a RST. +// (TODO(ncardwell): it also frees the socket immediately without any +// time in TIME_WAIT; we should test this too once we have some +// infrastructure for testing this kind of thing reliably...) + +// Initialize a server socket. +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 6> ++0 < . 1:1(0) ack 1 win 257 + ++0 accept(3, ..., ...) = 4 + ++0 setsockopt(4, SOL_SOCKET, SO_LINGER, {onoff=1, linger=0}, 8) = 0 + +// Write some data, receive an ACK. ++0 write(4, ..., 1000) = 1000 ++0 > P. 1:1001(1000) ack 1 ++0 < . 1:1(0) ack 1001 win 257 + +// Clean up. ++0 close(4) = 0 ++0 > R. 1001:1001(0) ack 1 diff --git a/test/packetdrill/tests/linux/close/close-unread-data-rst.pkt b/test/packetdrill/tests/linux/close/close-unread-data-rst.pkt new file mode 100644 index 0000000..d30808b --- /dev/null +++ b/test/packetdrill/tests/linux/close/close-unread-data-rst.pkt @@ -0,0 +1,38 @@ +// If we close the connection before read()'ing what +// the other side sent, a RST will be generated instead +// of a FIN. + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +// Receive first segment. +0.210 < P. 1:1001(1000) ack 1 win 46 + +// Send one ACK. +0.210 > . 1:1(0) ack 1001 + +// Application writes 1000 bytes. +0.250 write(4, ..., 1000) = 1000 +0.250 > P. 1:1001(1000) ack 1001 + +// ACK +0.300 < . 1001:1001(0) ack 1001 win 257 + +// Client closes the connection. +0.610 < F. 1001:1001(0) ack 1001 win 260 + +// Respond with (delayed) ACK. +0.650 > . 1001:1001(0) ack 1002 + +// We close the connection. +0.700 close(4) = 0 +// Since we have not read, we generate a RST instead of a FIN +// conforming to RFC 1122 section 4.2.2.13. +0.701 > R. 1001:1001(0) ack 1002 diff --git a/test/packetdrill/tests/linux/connect/http-get-nonblocking-ts.pkt b/test/packetdrill/tests/linux/connect/http-get-nonblocking-ts.pkt new file mode 100644 index 0000000..f998df4 --- /dev/null +++ b/test/packetdrill/tests/linux/connect/http-get-nonblocking-ts.pkt @@ -0,0 +1,34 @@ +// A simple client-side HTTP-style test that does a connect, sends a +// short request, and receives a short response. + +// Create a socket and set it to non-blocking. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) +0.000 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 + +// Establish connection and verify that there was no error. +0.100 connect(3, ..., ...) = -1 EINPROGRESS (Operation now in progress) +0.100 > S 0:0(0) <mss 1460,sackOK,TS val 100 ecr 0,nop,wscale 6> +0.200 < S. 0:0(0) ack 1 win 5792 <mss 1460,sackOK,TS val 700 ecr 100,nop,wscale 7> +0.200 > . 1:1(0) ack 1 <nop,nop,TS val 200 ecr 700> +0.200 getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 +0.200 fcntl(3, F_SETFL, O_RDWR) = 0 // set back to blocking + +// Send the HTTP request. +0.200 write(3, ..., 57) = 57 +0.200 > P. 1:58(57) ack 1 <nop,nop,TS val 200 ecr 700> +0.300 < . 1:1(0) ack 58 win 92 <nop,nop,TS val 800 ecr 200> + +// Receive the HTTP response and the server's FIN. +0.300 < P. 1:786(785) ack 58 win 92 <nop,nop,TS val 800 ecr 200> +0.300 > . 58:58(0) ack 786 <nop,nop,TS val 300 ecr 800> +0.300 < F. 786:786(0) ack 58 win 92 <nop,nop,TS val 800 ecr 200> +0.300 read(3, ..., 1024) = 785 +0.300 read(3, ..., 1024) = 0 +// Delayed ACK. +0.340 > . 58:58(0) ack 787 <nop,nop,TS val 300 ecr 800> + +// Close the connection. +0.350 close(3) = 0 +0.350 > F. 58:58(0) ack 787 <nop,nop,TS val 300 ecr 800> +0.450 < . 787:787(0) ack 59 win 92 <nop,nop,TS val 900 ecr 300> diff --git a/test/packetdrill/tests/linux/early_retransmit/er-delayed-2pkt-sack.pkt b/test/packetdrill/tests/linux/early_retransmit/er-delayed-2pkt-sack.pkt new file mode 100644 index 0000000..72afec0 --- /dev/null +++ b/test/packetdrill/tests/linux/early_retransmit/er-delayed-2pkt-sack.pkt @@ -0,0 +1,27 @@ +// Test delayed ER with 2 packets outstanding, receiver sending SACKs. + +// Enable delayed early retransmit. +`sysctl -q net.ipv4.tcp_early_retrans=2` + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +0.200 write(4, ..., 2920) = 2920 +0.200 > P. 1:2921(2920) ack 1 +0.300 < . 1:1(0) ack 1 win 257 <sack 1461:2921,nop,nop> +0.325 > . 1:1461(1460) ack 1 // delayed Early Retransmit at RTT/4 = 25ms +0.425 < . 1:1(0) ack 2921 win 257 + +0.500 close(4) = 0 +0.500 > F. 2921:2921(0) ack 1 +0.600 < F. 1:1(0) ack 2922 win 257 +0.601 > . 2922:2922(0) ack 2 + +0.700 `sysctl -q net.ipv4.tcp_early_retrans=3` diff --git a/test/packetdrill/tests/linux/early_retransmit/er-delayed-3pkt-sack.pkt b/test/packetdrill/tests/linux/early_retransmit/er-delayed-3pkt-sack.pkt new file mode 100644 index 0000000..5d05264 --- /dev/null +++ b/test/packetdrill/tests/linux/early_retransmit/er-delayed-3pkt-sack.pkt @@ -0,0 +1,28 @@ +// Test delayed ER with 3 packets outstanding, receiver sending SACKs. + +// Enable delayed early retransmit. +`sysctl -q net.ipv4.tcp_early_retrans=2` + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +0.200 write(4, ..., 4380) = 4380 +0.200 > P. 1:4381(4380) ack 1 +0.300 < . 1:1(0) ack 1 win 257 <sack 1461:2921,nop,nop> +0.300 < . 1:1(0) ack 1 win 257 <sack 1461:4381,nop,nop> +0.325 > . 1:1461(1460) ack 1 // delayed Early Retransmit at RTT/4 = 25ms +0.425 < . 1:1(0) ack 4381 win 257 + +0.500 close(4) = 0 +0.500 > F. 4381:4381(0) ack 1 +0.600 < F. 1:1(0) ack 4382 win 257 +0.601 > . 4382:4382(0) ack 2 + +0.700 `sysctl -q net.ipv4.tcp_early_retrans=3` diff --git a/test/packetdrill/tests/linux/early_retransmit/er-delayed-filled-3pkt-sack.pkt b/test/packetdrill/tests/linux/early_retransmit/er-delayed-filled-3pkt-sack.pkt new file mode 100644 index 0000000..e06db1b --- /dev/null +++ b/test/packetdrill/tests/linux/early_retransmit/er-delayed-filled-3pkt-sack.pkt @@ -0,0 +1,31 @@ +// Test delayed ER with 3 packets outstanding, receiver sending SACKs. +// Added wrinkles: (1) ACK for missing first packet finally arrives, +// filling the hole and making the ER superfluous. +// This test verifies that the ER timer gets correctly cancelled. + +// Enable delayed early retransmit. +`sysctl -q net.ipv4.tcp_early_retrans=2` + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +0.200 write(4, ..., 4380) = 4380 +0.200 > P. 1:4381(4380) ack 1 +0.300 < . 1:1(0) ack 1 win 257 <sack 1461:2921,nop,nop> +0.300 < . 1:1(0) ack 1 win 257 <sack 1461:4381,nop,nop> +0.310 < . 1:1(0) ack 4381 win 257 +// No ER or RTO timer should fire here, since all data is ACKed + +1.800 close(4) = 0 +1.800 > F. 4381:4381(0) ack 1 +1.900 < F. 1:1(0) ack 4382 win 257 +1.900 > . 4382:4382(0) ack 2 + +2.000 `sysctl -q net.ipv4.tcp_early_retrans=3` diff --git a/test/packetdrill/tests/linux/early_retransmit/er-delayed-get-ack-3pkt-sack.pkt b/test/packetdrill/tests/linux/early_retransmit/er-delayed-get-ack-3pkt-sack.pkt new file mode 100644 index 0000000..794bcb0 --- /dev/null +++ b/test/packetdrill/tests/linux/early_retransmit/er-delayed-get-ack-3pkt-sack.pkt @@ -0,0 +1,35 @@ +// Test delayed ER with 3 packets outstanding, receiver sending SACKs. +// Added wrinkles: (1) sender gets an ACK before delayed ER timer fires, +// so we don't do the originally scheduled ER but instead reschedule +// the ER timer for later. + +// Enable delayed early retransmit. +`sysctl -q net.ipv4.tcp_early_retrans=2` + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +0.200 write(4, ..., 4380) = 4380 +0.200 > P. 1:4381(4380) ack 1 +0.300 < . 1:1(0) ack 1 win 257 <sack 1461:2921,nop,nop> +0.300 < . 1:1(0) ack 1 win 257 <sack 1461:4381,nop,nop> +// Next we get an ACK before ER fires. Any ACK should cause us +// to cancel ER timer, whether it ACKs new data or (as in this case) does not. +// Then we reschedule the ER timer again. +0.310 < . 1:1(0) ack 1 win 257 <sack 1461:4381,nop,nop> +0.335 > . 1:1461(1460) ack 1 // delayed ER at 0.310 + RTT/4=25ms +0.435 < . 1:1(0) ack 4381 win 257 + +0.700 close(4) = 0 +0.700 > F. 4381:4381(0) ack 1 +0.800 < F. 1:1(0) ack 4382 win 257 +0.800 > . 4382:4382(0) ack 2 + +0.900 `sysctl -q net.ipv4.tcp_early_retrans=3` diff --git a/test/packetdrill/tests/linux/early_retransmit/er-quick-2pkt-sack.pkt b/test/packetdrill/tests/linux/early_retransmit/er-quick-2pkt-sack.pkt new file mode 100644 index 0000000..6d0652c --- /dev/null +++ b/test/packetdrill/tests/linux/early_retransmit/er-quick-2pkt-sack.pkt @@ -0,0 +1,27 @@ +// Test quick ER (no delay) with 2 packets outstanding, receiver sending SACKs. + +// Enable quick early retransmit. +`sysctl -q net.ipv4.tcp_early_retrans=1` + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +0.200 write(4, ..., 2920) = 2920 +0.200 > P. 1:2921(2920) ack 1 +0.300 < . 1:1(0) ack 1 win 257 <sack 1461:2921,nop,nop> +0.300 > . 1:1461(1460) ack 1 // quick Early Retransmit +0.400 < . 1:1(0) ack 2921 win 257 + +0.500 close(4) = 0 +0.500 > F. 2921:2921(0) ack 1 +0.600 < F. 1:1(0) ack 2922 win 257 +0.601 > . 2922:2922(0) ack 2 + +0.700 `sysctl -q net.ipv4.tcp_early_retrans=3` diff --git a/test/packetdrill/tests/linux/early_retransmit/er-quick-3pkt-sack.pkt b/test/packetdrill/tests/linux/early_retransmit/er-quick-3pkt-sack.pkt new file mode 100644 index 0000000..49719bb --- /dev/null +++ b/test/packetdrill/tests/linux/early_retransmit/er-quick-3pkt-sack.pkt @@ -0,0 +1,28 @@ +// Test quick ER (no delay) with 3 packets outstanding, receiver sending SACKs. + +// Enable quick early retransmit. +`sysctl -q net.ipv4.tcp_early_retrans=1` + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +0.200 write(4, ..., 4380) = 4380 +0.200 > P. 1:4381(4380) ack 1 +0.300 < . 1:1(0) ack 1 win 257 <sack 1461:2921,nop,nop> +0.300 < . 1:1(0) ack 1 win 257 <sack 1461:4381,nop,nop> +0.300 > . 1:1461(1460) ack 1 // quick ER (no delay) +0.400 < . 1:1(0) ack 4381 win 257 + +0.500 close(4) = 0 +0.500 > F. 4381:4381(0) ack 1 +0.600 < F. 1:1(0) ack 4382 win 257 +0.601 > . 4382:4382(0) ack 2 + +0.700 `sysctl -q net.ipv4.tcp_early_retrans=3` diff --git a/test/packetdrill/tests/linux/fast_recovery/prr-ss-ack-below-snd_una-reno.pkt b/test/packetdrill/tests/linux/fast_recovery/prr-ss-ack-below-snd_una-reno.pkt new file mode 100644 index 0000000..4cc7b3b --- /dev/null +++ b/test/packetdrill/tests/linux/fast_recovery/prr-ss-ack-below-snd_una-reno.pkt @@ -0,0 +1,51 @@ +// Test PRR-slowstart implementation. +// In this variant we verify that the sender uses SACK info on an ACK +// below snd_una. +// This variant tests behavior with Reno congestion control. + +`sysctl -q net.ipv4.tcp_congestion_control=reno` + +// Establish a connection. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +// RTT 100ms +0.200 < . 1:1(0) ack 1 win 320 +0.200 accept(3, ..., ...) = 4 + +// Send 10 data segments. +0.200 write(4, ..., 10000) = 10000 +0.200 > P. 1:10001(10000) ack 1 + +// Lost packet 1:1001,4001:5001,7001:8001. +// Lots of reordering in both directions. +0.310 < . 1:1(0) ack 1 win 320 <sack 1001:2001,nop,nop> +0.320 < . 1:1(0) ack 1 win 320 <sack 1001:3001,nop,nop> +0.330 < . 1:1(0) ack 1 win 320 <sack 1001:3001 8001:9001,nop,nop> +// Enter fast recovery. +0.330 > . 1:1001(1000) ack 1 +0.330 > . 3001:4001(1000) ack 1 + +// An ACK advances snd_una. +0.440 < . 1:1(0) ack 4001 win 320 <sack 8001:9001,nop,nop> +0.440 > . 4001:5001(1000) ack 1 +0.440 > . 5001:6001(1000) ack 1 + +// 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 1 more MSS. +0.450 < . 1:1(0) ack 3001 win 320 <sack 5001:7001,nop,nop> +0.450 > . 7001:8001(1000) ack 1 + +// Receiver ACKs all data. +0.560 < . 1:1(0) ack 10001 win 320 + +// Write another 10 MSS, of which 5MSS (cwnd=ssthresh) should go out: +0.600 write(4, ..., 10000) = 10000 +0.600 > . 10001:15001(5000) ack 1 + +0.700 `sysctl -q net.ipv4.tcp_congestion_control=cubic` diff --git a/test/packetdrill/tests/linux/fast_retransmit/fr-4pkt-sack-linux.pkt b/test/packetdrill/tests/linux/fast_retransmit/fr-4pkt-sack-linux.pkt new file mode 100644 index 0000000..a1416d9 --- /dev/null +++ b/test/packetdrill/tests/linux/fast_retransmit/fr-4pkt-sack-linux.pkt @@ -0,0 +1,35 @@ +// Test fast retransmit with 4 packets outstanding, receiver sending SACKs. +// In this variant the receiver supports SACK. + +// 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 <...> + ++.1 < . 1:1(0) ack 1 win 257 ++0 accept(3, ..., ...) = 4 + +// Send 1 data segment and get an ACK, so cwnd is now 4. ++0 write(4, ..., 1000) = 1000 ++0 > P. 1:1001(1000) ack 1 + ++.1 < . 1:1(0) ack 1001 win 257 + +// Write 4 data segments. ++0 write(4, ..., 4000) = 4000 ++0 > P. 1001:5001(4000) ack 1 + +// Get 3 SACKs. ++.1 < . 1:1(0) ack 1001 win 257 <sack 2001:3001,nop,nop> ++0 < . 1:1(0) ack 1001 win 257 <sack 2001:4001,nop,nop> ++0 < . 1:1(0) ack 1001 win 257 <sack 2001:5001,nop,nop> +// We've received 3 duplicate ACKs, so we do a fast retransmit. ++0 > . 1001:2001(1000) ack 1 + +// Receiver ACKs all data. ++.1 < . 1:1(0) ack 6001 win 257 diff --git a/test/packetdrill/tests/linux/icmp/icmp-all-types.pkt b/test/packetdrill/tests/linux/icmp/icmp-all-types.pkt new file mode 100644 index 0000000..169cdb4 --- /dev/null +++ b/test/packetdrill/tests/linux/icmp/icmp-all-types.pkt @@ -0,0 +1,71 @@ +// Test handling of incoming ICMP packets. +// This test tests all known ICMP packet types, and a few unknown +// types. + +// Establish a connection. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +// Send 1 data segment. +0.200 write(4, ..., 1460) = 1460 +0.200 > P. 1:1461(1460) ack 1 + +// We get lots of incoming ICMP messages. + +// First the unreachable type and all its codes +0.300 < icmp unreachable net_unreachable +0.301 < icmp unreachable host_unreachable +0.302 < icmp unreachable protocol_unreachable +0.303 < icmp unreachable port_unreachable +0.304 < icmp unreachable frag_needed mtu 1234 +0.305 < icmp unreachable source_route_failed +0.306 < icmp unreachable net_unknown +0.307 < icmp unreachable host_unknown +0.308 < icmp unreachable source_host_isolated +0.309 < icmp unreachable net_prohibited +0.310 < icmp unreachable host_prohibited +0.311 < icmp unreachable net_unreachable_for_tos +0.312 < icmp unreachable host_unreachable_for_tos +0.313 < icmp unreachable packet_filtered +0.314 < icmp unreachable precedence_violation +0.315 < icmp unreachable precedence_cutoff + +// Then all the other types. These are legal because the code is optional. +0.400 < icmp echo_reply +0.401 < icmp source_quench +0.402 < icmp redirect +0.403 < icmp echo_request +0.404 < icmp time_exceeded +0.405 < icmp parameter_problem +0.406 < icmp timestamp_request +0.407 < icmp timestamp_reply +0.408 < icmp information_request +0.409 < icmp information_reply +0.410 < icmp address_mask_request +0.411 < icmp address_mask_reply + +// Now try symbolic types with numeric codes. +0.450 < icmp unreachable code_0 +0.451 < icmp unreachable code_1 +0.452 < icmp unreachable code_255 + +// Now try numeric types with numeric codes +0.460 < icmp type_0 code_0 +0.461 < icmp type_1 code_0 +0.462 < icmp type_255 code_0 + +// Receiver ACKs all data. +0.470 < . 1:1(0) ack 1461 win 257 + +// Clean up. +0.600 close(4) = 0 +0.600 > F. 1461:1461(0) ack 1 +0.700 < F. 1:1(0) ack 1462 win 257 +0.700 > . 1462:1462(0) ack 2 diff --git a/test/packetdrill/tests/linux/inet_diag/inet-diag-ipv4-mapped-ipv6.pkt b/test/packetdrill/tests/linux/inet_diag/inet-diag-ipv4-mapped-ipv6.pkt new file mode 100644 index 0000000..2b7d8ea --- /dev/null +++ b/test/packetdrill/tests/linux/inet_diag/inet-diag-ipv4-mapped-ipv6.pkt @@ -0,0 +1,29 @@ +// Test inet_diag for AF_INET6 sockets with IPv4 traffic. +// We use the "ss" socket statistics tool, which uses inet_diag sockets. +// We use the default tcptest local IP address for IPv4-mapped-IPv6. + +// Options (command line arguments in script file) to force ipv4-mapped-ipv6. +--ip_version="ipv4-mapped-ipv6" + +// 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 2> ++0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> + ++0 `ss -6 -n state SYN-RECV | grep ::ffff:192.168.0.1:8080 > /dev/null` + ++0 < . 1:1(0) ack 1 win 32890 + ++0 accept(3, ..., ...) = 4 + +// first, use inet_diag with no filter: ++0 `ss -6 -n | grep ::ffff:192.168.0.1:8080 > /dev/null` + +// then try filters, which use a different code path: ++0 `ss -6 -n --options --extended --info '( sport = :8080 )' | grep ::ffff:192.168.0.1:8080 > /dev/null` ++0 `ss -6 -n --options --extended --info '( sport = :8080 )' src ::ffff:192.168.0.1/128 | grep ::ffff:192.168.0.1:8080 > /dev/null` diff --git a/test/packetdrill/tests/linux/inet_diag/inet-diag-ipv4.pkt b/test/packetdrill/tests/linux/inet_diag/inet-diag-ipv4.pkt new file mode 100644 index 0000000..c4e632a --- /dev/null +++ b/test/packetdrill/tests/linux/inet_diag/inet-diag-ipv4.pkt @@ -0,0 +1,28 @@ +// Test inet_diag for AF_INET sockets with IPv4 traffic. +// We use the "ss" socket statistics tool, which uses inet_diag sockets. +// We use the default tcptest local IP address for IPv4. + +// Options (command line arguments in script file) to force IPv4. +--ip_version=ipv4 + +// 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 2> ++0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> + ++0 `ss -4 -n state SYN-RECV | grep 192.168.0.1:8080 > /dev/null` + ++0 < . 1:1(0) ack 1 win 32890 + ++0 accept(3, ..., ...) = 4 + +// first, use inet_diag with no filter: ++0 `ss -4 -n | grep :8080 | grep 192.168.0.1:8080 > /dev/null` + +// then try filters, which use a different code path: ++0 `ss -4 -n --options --extended --info '( sport = :8080 )' | grep 192.168.0.1:8080 > /dev/null` ++0 `ss -4 -n --options --extended --info '( sport = :8080 )' src 192.168.0.1/32 | grep 192.168.0.1:8080 > /dev/null` diff --git a/test/packetdrill/tests/linux/inet_diag/inet-diag-ipv6.pkt b/test/packetdrill/tests/linux/inet_diag/inet-diag-ipv6.pkt new file mode 100644 index 0000000..183d3ce --- /dev/null +++ b/test/packetdrill/tests/linux/inet_diag/inet-diag-ipv6.pkt @@ -0,0 +1,29 @@ +// Test inet_diag for AF_INET6 sockets with IPv6 traffic. +// We use the "ss" socket statistics tool, which uses inet_diag sockets. +// We use the default tcptest local IP address for IPv6. + +// Options (command line arguments in script file) to force IPv6. +--ip_version=ipv6 +--mtu=1520 + +// 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 2> ++0 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> + ++0 `ss -6 -n state SYN-RECV | grep fd3d:fa7b:d17d::1:8080 > /dev/null` + ++0 < . 1:1(0) ack 1 win 32890 + ++0 accept(3, ..., ...) = 4 + +// first, use inet_diag with no filter: ++0 `ss -6 -n | grep :8080 | grep fd3d:fa7b:d17d::1:8080 > /dev/null` + +// then try filters, which use a different code path: ++0 `ss -6 -n --options --extended --info '( sport = :8080 )' | grep fd3d:fa7b:d17d::1:8080 > /dev/null` ++0 `ss -6 -n --options --extended --info '( sport = :8080 )' src fd3d:fa7b:d17d::1/128 | grep fd3d:fa7b:d17d::1:8080 > /dev/null` diff --git a/test/packetdrill/tests/linux/init_rto/init_rto_passive_open.pkt b/test/packetdrill/tests/linux/init_rto/init_rto_passive_open.pkt new file mode 100644 index 0000000..8775c3c --- /dev/null +++ b/test/packetdrill/tests/linux/init_rto/init_rto_passive_open.pkt @@ -0,0 +1,17 @@ +// A simple test of initRTO (sysctl_tcp_synack_rto, default to 1sec) for +// the passive open side. + +// We want the SYN-ACK to be retransmitted 1 sec after the SYN, but +// usually it happens at 1.2 or 1.4 sec due to the fact that the +// kernel only schedules SYN-ACK retransmissions periodically. +// Specifically, the TCP_SYNQ_INTERVAL (period of the SYN-ACK timer) is 200ms. +--tolerance_usecs=405000 + +// Create a listener socket. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +1.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> diff --git a/test/packetdrill/tests/linux/initial_window/iw10-base-case.pkt b/test/packetdrill/tests/linux/initial_window/iw10-base-case.pkt new file mode 100755 index 0000000..f790f56 --- /dev/null +++ b/test/packetdrill/tests/linux/initial_window/iw10-base-case.pkt @@ -0,0 +1,21 @@ +// A simple server-side test that sends exactly an initial window (IW10) +// worth of packets. + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +0.200 write(4, ..., 14600) = 14600 +0.200 > P. 1:14601(14600) ack 1 +0.300 < . 1:1(0) ack 14601 win 257 + +0.400 close(4) = 0 +0.401 > F. 14601:14601(0) ack 1 +0.501 < F. 1:1(0) ack 14602 win 257 +0.502 > . 14602:14602(0) ack 2 diff --git a/test/packetdrill/tests/linux/initial_window/iw10-short-response.pkt b/test/packetdrill/tests/linux/initial_window/iw10-short-response.pkt new file mode 100755 index 0000000..6db3c4b --- /dev/null +++ b/test/packetdrill/tests/linux/initial_window/iw10-short-response.pkt @@ -0,0 +1,21 @@ +// A simple server-side test that sends a response smaller +// than the initial window of 10 MSS. + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +0.200 write(4, ..., 7300) = 7300 +0.200 > P. 1:7301(7300) ack 1 +0.300 < . 1:1(0) ack 7301 win 257 + +0.400 close(4) = 0 +0.401 > F. 7301:7301(0) ack 1 +0.501 < F. 1:1(0) ack 7302 win 257 +0.502 > . 7302:7302(0) ack 2 diff --git a/test/packetdrill/tests/linux/ioctl/ioctl-siocinq-fin.pkt b/test/packetdrill/tests/linux/ioctl/ioctl-siocinq-fin.pkt new file mode 100644 index 0000000..8499e02 --- /dev/null +++ b/test/packetdrill/tests/linux/ioctl/ioctl-siocinq-fin.pkt @@ -0,0 +1,30 @@ +// A simple test for the TCP SIOCINQ ioctl. + +// Create a socket. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +// Establish a connection. +0.100 < S 0:0(0) win 20000 <mss 1000,sackOK,nop,nop> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK> +0.200 < . 1:1(0) ack 1 win 20000 +0.200 accept(3, ..., ...) = 4 + +// Receive a segment. +0.200 < P. 1:1001(1000) ack 1 win 257 +0.200 > . 1:1(0) ack 1001 + +0.210 ioctl(4, SIOCINQ, [1000]) = 0 +0.220 read(4, ..., 1000) = 1000 +0.230 ioctl(4, SIOCINQ, [0]) = 0 + +// Receive a segment with a FIN. +0.300 < FP. 1001:2001(1000) ack 1 win 257 +0.300 > . 1:1(0) ack 2002 + +0.310 ioctl(4, SIOCINQ, [1000]) = 0 +0.320 read(4, ..., 1000) = 1000 +0.330 ioctl(4, SIOCINQ, [0]) = 0 diff --git a/test/packetdrill/tests/linux/listen/listen-incoming-ack.pkt b/test/packetdrill/tests/linux/listen/listen-incoming-ack.pkt new file mode 100644 index 0000000..65f3733 --- /dev/null +++ b/test/packetdrill/tests/linux/listen/listen-incoming-ack.pkt @@ -0,0 +1,20 @@ +// Test behavior when a listener gets an incoming packet that has +// the ACK bit set but not the SYN bit set. + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < . 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.100 > R 0:0(0) win 0 + +// Now make sure that when a valid SYN arrives shortly thereafter +// (with the same address 4-tuple) we can still successfully establish +// a connection. + +0.200 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.200 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> + +0.300 < . 1:1(0) ack 1 win 320 +0.300 accept(3, ..., ...) = 4 diff --git a/test/packetdrill/tests/linux/listen/listen-incoming-no-tcp-flags.pkt b/test/packetdrill/tests/linux/listen/listen-incoming-no-tcp-flags.pkt new file mode 100644 index 0000000..3ae1ff3 --- /dev/null +++ b/test/packetdrill/tests/linux/listen/listen-incoming-no-tcp-flags.pkt @@ -0,0 +1,21 @@ +// Test behavior when a listener gets an incoming packet that has +// no TCP flags set. + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +// An incoming TCP segment with no TCP flags set. +0.100 < - 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +// Linux ignores the packet and sends nothing. + +// Now make sure that when a valid SYN arrives shortly thereafter +// (with the same address 4-tuple) we can still successfully establish +// a connection. + +0.200 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.200 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> + +0.300 < . 1:1(0) ack 1 win 320 +0.300 accept(3, ..., ...) = 4 diff --git a/test/packetdrill/tests/linux/listen/listen-incoming-rst.pkt b/test/packetdrill/tests/linux/listen/listen-incoming-rst.pkt new file mode 100644 index 0000000..83d25f2 --- /dev/null +++ b/test/packetdrill/tests/linux/listen/listen-incoming-rst.pkt @@ -0,0 +1,22 @@ +// Test behavior when a listener gets an incoming packet that has +// the RST bit set but not the SYN bit set. + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < R 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> + +// The TCP stack should not respond to incoming RSTs, or else +// we could get infinite RST ping-pong storms. + +// Now make sure that when a valid SYN arrives shortly thereafter +// (with the same address 4-tuple) we can still successfully establish +// a connection. + +0.200 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.200 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> + +0.300 < . 1:1(0) ack 1 win 320 +0.300 accept(3, ..., ...) = 4 diff --git a/test/packetdrill/tests/linux/listen/listen-incoming-syn-ack.pkt b/test/packetdrill/tests/linux/listen/listen-incoming-syn-ack.pkt new file mode 100644 index 0000000..bc2569c --- /dev/null +++ b/test/packetdrill/tests/linux/listen/listen-incoming-syn-ack.pkt @@ -0,0 +1,20 @@ +// Test behavior when a listener gets an incoming packet that has +// the SYN and ACK bits set. + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S. 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.100 > R 0:0(0) win 0 + +// Now make sure that when a valid SYN arrives shortly thereafter +// (with the same address 4-tuple) we can still successfully establish +// a connection. + +0.200 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.200 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> + +0.300 < . 1:1(0) ack 1 win 320 +0.300 accept(3, ..., ...) = 4 diff --git a/test/packetdrill/tests/linux/listen/listen-incoming-syn-rst.pkt b/test/packetdrill/tests/linux/listen/listen-incoming-syn-rst.pkt new file mode 100644 index 0000000..f3c0607 --- /dev/null +++ b/test/packetdrill/tests/linux/listen/listen-incoming-syn-rst.pkt @@ -0,0 +1,22 @@ +// Test behavior when a listener gets an incoming packet that has +// the SYN and RST bits set. + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < SR 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> + +// The TCP stack should not respond to incoming RSTs, or else +// we could get infinite RST ping-pong storms. + +// Now make sure that when a valid SYN arrives shortly thereafter +// (with the same address 4-tuple) we can still successfully establish +// a connection. + +0.200 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.200 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> + +0.300 < . 1:1(0) ack 1 win 320 +0.300 accept(3, ..., ...) = 4 diff --git a/test/packetdrill/tests/linux/listen/listen-unbound.pkt b/test/packetdrill/tests/linux/listen/listen-unbound.pkt new file mode 100644 index 0000000..fcf74fc --- /dev/null +++ b/test/packetdrill/tests/linux/listen/listen-unbound.pkt @@ -0,0 +1,5 @@ +// Test behavior when a listener gets an incoming packet that has +// the RST bit set but not the SYN bit set. + +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 listen(3, 1) = 0
\ No newline at end of file diff --git a/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-client-ts.pkt b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-client-ts.pkt new file mode 100644 index 0000000..a8544f5 --- /dev/null +++ b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-client-ts.pkt @@ -0,0 +1,17 @@ +// Test that getsockopt of TCP_MAXSEG works on active/client TCP connections. +// In this variant we test that a simple query of segment size works, +// in the case where TCP timestamps reduce the usable payload space. + +// Create a socket. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0.100...0.200 connect(3, ..., ...) = 0 + +// Establish a connection. +0.100 > S 0:0(0) <mss 1460,sackOK,TS val 100 ecr 0,nop,wscale 6> +0.200 < S. 0:0(0) ack 1 win 32792 <mss 1100,sackOK,TS val 200 ecr 100,nop,wscale 7> +0.200 > . 1:1(0) ack 1 <nop,nop,TS val 200 ecr 200> + +// Verify that the kernel reduced the returned segment size +// to account for TCP timestamps. +0.300 getsockopt(3, SOL_TCP, TCP_MAXSEG, [1088], [4]) = 0 diff --git a/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-client.pkt b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-client.pkt new file mode 100644 index 0000000..a75b8b3 --- /dev/null +++ b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-client.pkt @@ -0,0 +1,14 @@ +// Test that getsockopt of TCP_MAXSEG works on active/client TCP connections. +// In this variant we test that a simple query of segment size works. + +// Create a socket. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +0.100...0.200 connect(3, ..., ...) = 0 + +// Establish a connection. +0.100 > S 0:0(0) <mss 1460,sackOK,TS val 100 ecr 0,nop,wscale 6> +0.200 < S. 0:0(0) ack 1 win 32792 <mss 1100,nop,wscale 7> +0.200 > . 1:1(0) ack 1 + +0.300 getsockopt(3, SOL_TCP, TCP_MAXSEG, [1100], [4]) = 0 diff --git a/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server-advmss-ipv4.pkt b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server-advmss-ipv4.pkt new file mode 100644 index 0000000..c07c5c0 --- /dev/null +++ b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server-advmss-ipv4.pkt @@ -0,0 +1,29 @@ +// Test that getsockopt of TCP_MAXSEG works on passive/server TCP connections. +// In this variant we test that we get the expected result when +// the routing config specifies an "advmss 1430 mtu lock 1470" for the +// route to the remote IP under test. + +// To ensure that we do not cache something that interferes with other tests: +--remote_ip="192.0.2.2" + +`ip route change 192.0.2.2 via 192.168.0.2 dev tun0 advmss 1430 mtu lock 1470` + +// Set up a listening socket. +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 + +// Establish a connection without timestamps. ++0 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7> ++0 > S. 0:0(0) ack 1 <mss 1430,nop,nop,sackOK,nop,wscale 6> ++0 < . 1:1(0) ack 1 win 257 + ++0 accept(3, ..., ...) = 4 + +// Verify that the kernel returns the expected TCP max payload size. ++0 getsockopt(4, SOL_TCP, TCP_MAXSEG, [1430], [4]) = 0 + ++0 write(4, ..., 1500) = 1500 ++0 > . 1:1431(1430) ack 1 ++0 > P. 1431:1501(70) ack 1 diff --git a/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server-advmss-ts-ipv4.pkt b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server-advmss-ts-ipv4.pkt new file mode 100644 index 0000000..2222d51 --- /dev/null +++ b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server-advmss-ts-ipv4.pkt @@ -0,0 +1,30 @@ +// Test that getsockopt of TCP_MAXSEG works on passive/server TCP connections. +// In this variant we test that we get the expected result when +// the routing config specifies an "advmss 1430 mtu lock 1470" for the +// route to the remote IP under test. + +// To ensure that we do not cache something that interferes with other tests: +--remote_ip="192.0.2.2" + +`ip route change 192.0.2.2 via 192.168.0.2 dev tun0 advmss 1430 mtu lock 1470` + +// Set up a listening socket. +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 + +// Establish a connection ++0 < S 0:0(0) win 32792 <mss 1460,sackOK,TS val 0 ecr 0,nop,wscale 7> ++0 > S. 0:0(0) ack 1 <mss 1430,sackOK,TS val 0 ecr 0,nop,wscale 6> ++0 < . 1:1(0) ack 1 win 257 <nop,nop,TS val 0 ecr 0> + ++0 accept(3, ..., ...) = 4 + +// Verify that the kernel reduced the returned segment size +// to account for TCP timestamps. ++0 getsockopt(4, SOL_TCP, TCP_MAXSEG, [1418], [4]) = 0 + ++0 write(4, ..., 1500) = 1500 ++0 > . 1:1419(1418) ack 1 <nop,nop,TS val 0 ecr 0> ++0 > P. 1419:1501(82) ack 1 <nop,nop,TS val 0 ecr 0> diff --git a/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server-ts.pkt b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server-ts.pkt new file mode 100644 index 0000000..5d28c93 --- /dev/null +++ b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server-ts.pkt @@ -0,0 +1,20 @@ +// Test that getsockopt of TCP_MAXSEG works on passive/server TCP connections. +// In this variant we test that a simple query of segment size works, +// in the case where TCP timestamps reduce the usable payload space. + +// Set up a listening socket. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +// Establish a connection +0.100 < S 0:0(0) win 32792 <mss 1100,sackOK,TS val 100 ecr 0,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,sackOK,TS val 100 ecr 100,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 <nop,nop,TS val 200 ecr 100> + +0.300 accept(3, ..., ...) = 4 + +// Verify that the kernel reduced the returned segment size +// to account for TCP timestamps. +0.400 getsockopt(4, SOL_TCP, TCP_MAXSEG, [1088], [4]) = 0 diff --git a/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server.pkt b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server.pkt new file mode 100644 index 0000000..03516c1 --- /dev/null +++ b/test/packetdrill/tests/linux/mss/mss-getsockopt-tcp_maxseg-server.pkt @@ -0,0 +1,17 @@ +// Test that getsockopt of TCP_MAXSEG works on passive/server TCP connections. +// In this variant we test that a simple query of segment size works. + +// Set up a listening socket. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +// Establish a connection +0.100 < S 0:0(0) win 32792 <mss 1100,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 + +0.300 accept(3, ..., ...) = 4 + +0.400 getsockopt(4, SOL_TCP, TCP_MAXSEG, [1100], [4]) = 0 diff --git a/test/packetdrill/tests/linux/mss/mss-setsockopt-tcp_maxseg-client.pkt b/test/packetdrill/tests/linux/mss/mss-setsockopt-tcp_maxseg-client.pkt new file mode 100644 index 0000000..906ad6e --- /dev/null +++ b/test/packetdrill/tests/linux/mss/mss-setsockopt-tcp_maxseg-client.pkt @@ -0,0 +1,24 @@ +// Test TCP_MAXSEG works on active/client TCP connections. + +// Create a socket. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 + +// Set MSS to 1100. +0.010 setsockopt(3, SOL_TCP, TCP_MAXSEG, [1100], 4) = 0 +// TODO(ncardwell): the following is silly; should we fix it? +0.020 getsockopt(3, SOL_TCP, TCP_MAXSEG, [536], [4]) = 0 + +0.100...0.200 connect(3, ..., ...) = 0 + +// Establish a connection with an outgoing advertised MSS of 1100. +0.100 > S 0:0(0) <mss 1100,sackOK,TS val 100 ecr 0,nop,wscale 6> +0.200 < S. 0:0(0) ack 1 win 32792 <mss 1460,nop,wscale 7> +0.200 > . 1:1(0) ack 1 + +0.300 getsockopt(3, SOL_TCP, TCP_MAXSEG, [1100], [4]) = 0 + +0.400 %{ assert tcpi_advmss == 1100; assert tcpi_snd_mss == 1100 }% + +// IW10 MSS should yield outgoing TSO packet with 10*1100 == 11000 bytes: +0.500 write(3, ..., 12000) = 12000 +0.500 > . 1:11001(11000) ack 1 diff --git a/test/packetdrill/tests/linux/mss/mss-setsockopt-tcp_maxseg-server.pkt b/test/packetdrill/tests/linux/mss/mss-setsockopt-tcp_maxseg-server.pkt new file mode 100644 index 0000000..f2ed31d --- /dev/null +++ b/test/packetdrill/tests/linux/mss/mss-setsockopt-tcp_maxseg-server.pkt @@ -0,0 +1,27 @@ +// Test TCP_MAXSEG works on passive/server TCP connections. + +// Set up a listening socket. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +// Set MSS to 1100. +0.010 setsockopt(3, SOL_TCP, TCP_MAXSEG, [1100], 4) = 0 +// TODO(ncardwell): the following is silly; should we fix it? +0.020 getsockopt(3, SOL_TCP, TCP_MAXSEG, [536], [4]) = 0 + +// Establish a connection with an outgoing advertised MSS of 1100. +0.100 < S 0:0(0) win 32792 <mss 1300,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1100,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 + +0.300 accept(3, ..., ...) = 4 + +0.400 getsockopt(4, SOL_TCP, TCP_MAXSEG, [1100], [4]) = 0 + +0.500 %{ assert tcpi_advmss == 1100; assert tcpi_snd_mss == 1100 }% + +// IW10 MSS should yield outgoing TSO packet with 10*1100 == 11000 bytes: +0.600 write(4, ..., 12000) = 12000 +0.600 > . 1:11001(11000) ack 1 diff --git a/test/packetdrill/tests/linux/pmtu_discovery/pmtud-10pkt-1460-to-1160.pkt b/test/packetdrill/tests/linux/pmtu_discovery/pmtud-10pkt-1460-to-1160.pkt new file mode 100644 index 0000000..df30dee --- /dev/null +++ b/test/packetdrill/tests/linux/pmtu_discovery/pmtud-10pkt-1460-to-1160.pkt @@ -0,0 +1,54 @@ +// Test Path MTU discovery, RFC 1191. +// This is a more substantive case, with 10*original_mss to send. +// In this variant, we get an ICMP "unreachable frag_needed mtu 1200" +// message and because the TCP sequence number is valid, TCP +// immediately retransmits 'cwnd' packets using a smaller MSS +// based on the MTU from the ICMP message. + +// Establish a connection. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +// Send 10 data segments. +0.200 write(4, ..., 14600) = 14600 +0.200 > P. 1:14601(14600) ack 1 + +// ICMP says that the first segment was too big. +0.250 < [1:1461(1460)] icmp unreachable frag_needed mtu 1200 +// TCP picks a packet size using the MTU from the message, and +// retransmits 'cwnd' packets: +0.250 > . 1:1161(1160) ack 1 +0.250 > . 1161:2321(1160) ack 1 +0.250 > . 2321:3481(1160) ack 1 +0.250 > . 3481:4641(1160) ack 1 +0.250 > . 4641:5801(1160) ack 1 +0.250 > . 5801:6961(1160) ack 1 +0.250 > . 6961:8121(1160) ack 1 +0.250 > . 8121:9281(1160) ack 1 +0.250 > . 9281:10441(1160) ack 1 +0.250 > . 10441:11601(1160) ack 1 + +// ACKs for packets retransmitted at a smaller MSS release yet more packets... + +0.350 < . 1:1(0) ack 1161 win 257 +0.350 > . 11601:12761(1160) ack 1 +0.350 > . 12761:13921(1160) ack 1 + +0.355 < . 1:1(0) ack 2321 win 257 +0.355 > P. 13921:14601(680) ack 1 + +// Receiver ACKs all data. +0.455 < . 1:1(0) ack 14601 win 257 + +// Clean up. +0.500 close(4) = 0 +0.500 > F. 14601:14601(0) ack 1 +0.600 < F. 1:1(0) ack 14602 win 257 +0.600 > . 14602:14602(0) ack 2 diff --git a/test/packetdrill/tests/linux/pmtu_discovery/pmtud-1pkt-1460-to-1160.pkt b/test/packetdrill/tests/linux/pmtu_discovery/pmtud-1pkt-1460-to-1160.pkt new file mode 100644 index 0000000..9776f10 --- /dev/null +++ b/test/packetdrill/tests/linux/pmtu_discovery/pmtud-1pkt-1460-to-1160.pkt @@ -0,0 +1,36 @@ +// Test Path MTU discovery, RFC 1191. +// This is a simple case, with one packet to send. +// In this variant, we get an ICMP "unreachable frag_needed mtu 1200" +// message and because the TCP sequence number is valid, TCP +// immediately retransmits our first outstanding packet +// with a smaller MSS based on the MTU from the ICMP message. + +// Establish a connection. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1460,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +// Send 1 data segment. +0.200 write(4, ..., 1460) = 1460 +0.200 > P. 1:1461(1460) ack 1 + +// ICMP says that segment was too big. +0.250 < [1:1461(1460)] icmp unreachable frag_needed mtu 1200 +// TCP picks a packet size using the MTU from the message, and retransmits. +0.250 > . 1:1161(1160) ack 1 +0.250 > P. 1161:1461(300) ack 1 + +// Receiver ACKs all data. +0.350 < . 1:1(0) ack 1461 win 257 + +// Clean up. +1.300 close(4) = 0 +1.300 > F. 1461:1461(0) ack 1 +1.400 < F. 1:1(0) ack 1462 win 257 +1.400 > . 1462:1462(0) ack 2 diff --git a/test/packetdrill/tests/linux/receiver_rtt/rcv-rtt-with-timestamps-new.pkt b/test/packetdrill/tests/linux/receiver_rtt/rcv-rtt-with-timestamps-new.pkt new file mode 100644 index 0000000..2155f21 --- /dev/null +++ b/test/packetdrill/tests/linux/receiver_rtt/rcv-rtt-with-timestamps-new.pkt @@ -0,0 +1,57 @@ +// Test that receiver-side RTT estimation is sane when +// using TCP timestamps. We assert that the receive-side +// RTT estimate is between 95 and 105ms. + +// Use a small receive buffer so that we advertise small windows, to keep the +// test short. +`sysctl -q net.ipv4.tcp_rmem="4096 10000 2097152"` + +// Create a socket. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +// Verify that the receive buffer is the tcp_rmem default. +0.000 getsockopt(3, SOL_SOCKET, SO_RCVBUF, [10000], [4]) = 0 + +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +// Establish a connection. +0.100 < S 0:0(0) win 20000 <mss 1000,sackOK,TS val 100 ecr 0> +0.100 > S. 0:0(0) ack 1 <mss 1460,sackOK,TS val 100 ecr 100> +0.200 < . 1:1(0) ack 1 win 20000 <nop,nop,TS val 200 ecr 100> +0.200 accept(3, ..., ...) = 4 +0.200 %{ assert tcpi_rcv_rtt == 0 }% + +// First flight. +0.200 < . 1:1001(1000) ack 1 win 20000 <nop,nop,TS val 200 ecr 100> +0.200 > . 1:1(0) ack 1001 <nop,nop,TS val 200 ecr 200> +0.200 < . 1001:2001(1000) ack 1 win 20000 <nop,nop,TS val 200 ecr 100> +0.200 > . 1:1(0) ack 2001 <nop,nop,TS val 200 ecr 200> +0.200 read(4, ..., 2000) = 2000 +0.200 %{ assert tcpi_rcv_rtt >= 95*1000 and tcpi_rcv_rtt <= 105*1000 }% + +// Second flight. +0.300 < . 2001:3001(1000) ack 1 win 20000 <nop,nop,TS val 300 ecr 200> +0.300 > . 1:1(0) ack 3001 <nop,nop,TS val 300 ecr 300> +0.300 < . 3001:4001(1000) ack 1 win 20000 <nop,nop,TS val 300 ecr 200> +0.300 > . 1:1(0) ack 4001 <nop,nop,TS val 300 ecr 300> +0.300 < . 4001:5001(1000) ack 1 win 20000 <nop,nop,TS val 300 ecr 200> +0.300 > . 1:1(0) ack 5001 <nop,nop,TS val 300 ecr 300> +0.300 < . 5001:6001(1000) ack 1 win 20000 <nop,nop,TS val 300 ecr 200> +0.300 read(4, ..., 4000) = 4000 +0.300 > . 1:1(0) ack 6001 <nop,nop,TS val 300 ecr 300> +0.300 %{ assert tcpi_rcv_rtt >= 95*1000 and tcpi_rcv_rtt <= 105*1000 }% + +// Third flight. +// We omit outgoing ACKs because we don't care about this behavior, +// and don't want to introduce dependencies on the receive window behavior. +0.400 < . 6001:7001(1000) ack 1 win 20000 <nop,nop,TS val 400 ecr 300> +0.400 < . 7001:8001(1000) ack 1 win 20000 <nop,nop,TS val 400 ecr 300> +0.400 < . 8001:9001(1000) ack 1 win 20000 <nop,nop,TS val 400 ecr 300> +0.400 < . 9001:10001(1000) ack 1 win 20000 <nop,nop,TS val 400 ecr 300> +0.400 < . 10001:11001(1000) ack 1 win 20000 <nop,nop,TS val 400 ecr 300> +0.400 read(4, ..., 5000) = 5000 +0.400 %{ assert tcpi_rcv_rtt >= 95*1000 and tcpi_rcv_rtt <= 105*1000 }% + +0.500 `sysctl -q net.ipv4.tcp_rmem="4096 87380 3732736"` diff --git a/test/packetdrill/tests/linux/receiver_rtt/rcv-rtt-without-timestamps-new.pkt b/test/packetdrill/tests/linux/receiver_rtt/rcv-rtt-without-timestamps-new.pkt new file mode 100644 index 0000000..e963993 --- /dev/null +++ b/test/packetdrill/tests/linux/receiver_rtt/rcv-rtt-without-timestamps-new.pkt @@ -0,0 +1,62 @@ +// Test that receiver-side RTT estimation is sane when +// *not* using TCP timestamps. When we are not using timestamps +// then the receive-side RTT estimation logic uses as an RTT +// sample the time elapsed between (a) when the receiver advertises +// that a sender may send sequence number N, and (b) when the +// sequence number N arrives. In this (not unusual) case below, +// this takes 1 RTT; so we assert that the receive-side +// RTT estimate is between 95 and 105ms. + +// Use a small receive buffer so that we advertise small windows, to keep the +// test short. +`sysctl -q net.ipv4.tcp_rmem="4096 10000 2097152"` + +// Create a socket. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 + +// Verify that the receive buffer is the tcp_rmem default. +0.000 getsockopt(3, SOL_SOCKET, SO_RCVBUF, [10000], [4]) = 0 + +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +// Establish a connection. +0.100 < S 0:0(0) win 20000 <mss 1000,nop,nop,sackOK> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK> +0.200 < . 1:1(0) ack 1 win 20000 +0.200 accept(3, ..., ...) = 4 +0.200 %{ assert tcpi_rcv_rtt == 0 }% + +// First flight. +0.200 < . 1:1001(1000) ack 1 win 20000 +0.200 > . 1:1(0) ack 1001 +0.200 < . 1001:2001(1000) ack 1 win 20000 +0.200 > . 1:1(0) ack 2001 +0.200 read(4, ..., 2000) = 2000 +0.200 %{ assert tcpi_rcv_rtt == 0 }% + +// Second flight. +0.300 < . 2001:3001(1000) ack 1 win 20000 +0.300 > . 1:1(0) ack 3001 +0.300 < . 3001:4001(1000) ack 1 win 20000 +0.300 > . 1:1(0) ack 4001 +0.300 < . 4001:5001(1000) ack 1 win 20000 +0.300 > . 1:1(0) ack 5001 +0.300 < . 5001:6001(1000) ack 1 win 20000 +0.300 read(4, ..., 4000) = 4000 +0.300 > . 1:1(0) ack 6001 +0.300 %{ assert tcpi_rcv_rtt >= 95*1000 and tcpi_rcv_rtt <= 105*1000 }% + +// Third flight. +// We omit outgoing ACKs because we don't care about this behavior, +// and don't want to introduce dependencies on the receive window behavior. +0.400 < . 6001:7001(1000) ack 1 win 20000 +0.400 < . 7001:8001(1000) ack 1 win 20000 +0.400 < . 8001:9001(1000) ack 1 win 20000 +0.400 < . 9001:10001(1000) ack 1 win 20000 +0.400 < . 10001:11001(1000) ack 1 win 20000 +0.400 read(4, ..., 5000) = 5000 +0.400 %{ assert tcpi_rcv_rtt >= 95*1000 and tcpi_rcv_rtt <= 105*1000 }% + +0.500 `sysctl -q net.ipv4.tcp_rmem="4096 87380 3732736"` diff --git a/test/packetdrill/tests/linux/run_tests.sh b/test/packetdrill/tests/linux/run_tests.sh new file mode 100755 index 0000000..309cd20 --- /dev/null +++ b/test/packetdrill/tests/linux/run_tests.sh @@ -0,0 +1,6 @@ +#!/bin/bash +for f in `find . -name "*.pkt" | sort`; do + echo "Running $f ..." + ip tcp_metrics flush all > /dev/null 2>&1 + ../../packetdrill $f +done diff --git a/test/packetdrill/tests/linux/sack/sack-shift-sacked-1-2-3-fack.pkt b/test/packetdrill/tests/linux/sack/sack-shift-sacked-1-2-3-fack.pkt new file mode 100644 index 0000000..52b8cda --- /dev/null +++ b/test/packetdrill/tests/linux/sack/sack-shift-sacked-1-2-3-fack.pkt @@ -0,0 +1,47 @@ +// Test shifting of newly-SACKed ranges onto the previous already-SACKed skb. +// This variant SACKs segments 1, 2, and 3. + +// Establish a connection and send 10 MSS. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 1024 +0.200 accept(3, ..., ...) = 4 + +0.200 write(4, ..., 10000) = 10000 +0.200 > P. 1:10001(10000) ack 1 +0.200 %{ +assert tcpi_reordering == 3 +assert tcpi_unacked == 10 +assert tcpi_sacked == 0 +}% + +0.300 < . 1:1(0) ack 1 win 257 <sack 1001:2001,nop,nop> +0.300 %{ +assert tcpi_reordering == 3 +assert tcpi_unacked == 10 +assert tcpi_sacked == 1 +}% + +// This SACK for an adjacent range causes the sender to +// shift the newly-SACKed range onto the previous skb. +0.310 < . 1:1(0) ack 1 win 257 <sack 1001:3001,nop,nop> +0.310 %{ +assert tcpi_reordering == 3 +assert tcpi_unacked == 10 +assert tcpi_sacked == 2 +}% + +// This SACK for an adjacent range causes the sender to +// shift the newly-SACKed range onto the previous skb. +0.320 < . 1:1(0) ack 1 win 257 <sack 1001:4001,nop,nop> +0.320 %{ +assert tcpi_reordering == 3 +assert tcpi_unacked == 10 +assert tcpi_sacked == 3 +assert tcpi_ca_state == TCP_CA_Recovery +}% diff --git a/test/packetdrill/tests/linux/sack/sack-shift-sacked-1-2:6-fack.pkt b/test/packetdrill/tests/linux/sack/sack-shift-sacked-1-2:6-fack.pkt new file mode 100644 index 0000000..464ba69 --- /dev/null +++ b/test/packetdrill/tests/linux/sack/sack-shift-sacked-1-2:6-fack.pkt @@ -0,0 +1,39 @@ +// Test shifting of newly-SACKed ranges onto the previous already-SACKed skb. +// This variant receives a SACK for segment 1 and then a SACK for +// segments 1-6, to check handling of large newly-SACKed ranges. + +// Establish a connection and send 10 MSS. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 1024 +0.200 accept(3, ..., ...) = 4 + +0.200 write(4, ..., 10000) = 10000 +0.200 > P. 1:10001(10000) ack 1 +0.200 %{ +assert tcpi_reordering == 3 +assert tcpi_unacked == 10 +assert tcpi_sacked == 0 +}% + +0.300 < . 1:1(0) ack 1 win 257 <sack 1001:2001,nop,nop> +0.300 %{ +assert tcpi_reordering == 3 +assert tcpi_unacked == 10 +assert tcpi_sacked == 1 +}% + +// This SACK for an adjacent range causes the sender to +// shift the newly-SACKed range onto the previous skb. +0.310 < . 1:1(0) ack 1 win 257 <sack 1001:7001,nop,nop> +0.310 %{ +assert tcpi_reordering == 3 +assert tcpi_unacked == 10 +assert tcpi_sacked == 6 +assert tcpi_ca_state == TCP_CA_Recovery +}% diff --git a/test/packetdrill/tests/linux/shutdown/shutdown-rd-close.pkt b/test/packetdrill/tests/linux/shutdown/shutdown-rd-close.pkt new file mode 100644 index 0000000..f5fff60 --- /dev/null +++ b/test/packetdrill/tests/linux/shutdown/shutdown-rd-close.pkt @@ -0,0 +1,29 @@ +// Verify behavior for the sequence: +// shutdown(SHUT_RD), close(). + +// Initialize a server socket. +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 6> ++0 < . 1:1(0) ack 1 win 257 + ++0 accept(3, ..., ...) = 4 + ++.010 shutdown(4, SHUT_RD) = 0 ++0 read(4, ..., 1000) = 0 + +// Verify that writing and sending still works. ++.010 write(4, ..., 1000) = 1000 ++0 > P. 1:1001(1000) ack 1 ++0 < . 1:1(0) ack 1001 win 257 + ++.010 close(4) = 0 ++0 > F. 1001:1001(0) ack 1 ++0 < . 1:1(0) ack 1002 win 257 + ++.010 < F. 1:1(0) ack 1002 win 257 ++0 > . 1002:1002(0) ack 2 diff --git a/test/packetdrill/tests/linux/shutdown/shutdown-rd-wr-close.pkt b/test/packetdrill/tests/linux/shutdown/shutdown-rd-wr-close.pkt new file mode 100644 index 0000000..5b97fad --- /dev/null +++ b/test/packetdrill/tests/linux/shutdown/shutdown-rd-wr-close.pkt @@ -0,0 +1,45 @@ +// Verify behavior for the sequence: +// shutdown(SHUT_RD), receive, send, shutdown(SHUT_WR), close(). + +// Initialize a server socket. +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 6> ++0 < . 1:1(0) ack 1 win 257 + ++0 accept(3, ..., ...) = 4 + ++.010 shutdown(4, SHUT_RD) = 0 + ++0 read(4, ..., 1000) = 0 + +// You would think that after SHUT_RD we would respond to incoming +// data with a RST and not queue the data for reading, but we actually +// ACK the data, enqueue it for reading, and can read() the data. +// AFAICT in 2003 Andi Kleen seems to have decided that this case is too +// obscure to slow down the fast path for receiving and reading data: +// http://marc.info/?l=linux-netdev&m=105774722214242&w=2 +// So.... +// Verify that receiving and reading still works. ++0 < . 1:1001(1000) ack 1 win 257 ++0 > . 1:1(0) ack 1001 ++0 read(4, ..., 1000) = 1000 + +// Verify that writing and sending still works. ++.010 write(4, ..., 1000) = 1000 ++0 > P. 1:1001(1000) ack 1001 ++0 < . 1001:1001(0) ack 1001 win 257 + ++.010 shutdown(4, SHUT_WR) = 0 ++0 > F. 1001:1001(0) ack 1001 ++0 < . 1001:1001(0) ack 1002 win 257 ++0 write(4, ..., 1000) = -1 EPIPE (Broken pipe) + ++.010 close(4) = 0 + ++.010 < F. 1001:1001(0) ack 1002 win 257 ++0 > . 1002:1002(0) ack 1002 diff --git a/test/packetdrill/tests/linux/shutdown/shutdown-rdwr-close.pkt b/test/packetdrill/tests/linux/shutdown/shutdown-rdwr-close.pkt new file mode 100644 index 0000000..cb55c3b --- /dev/null +++ b/test/packetdrill/tests/linux/shutdown/shutdown-rdwr-close.pkt @@ -0,0 +1,26 @@ +// Verify behavior for the sequence: +// shutdown(SHUT_RDWR), close(). + +// Initialize a server socket. +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 6> ++0 < . 1:1(0) ack 1 win 257 + ++0 accept(3, ..., ...) = 4 + ++.010 shutdown(4, SHUT_RDWR) = 0 ++0 > F. 1:1(0) ack 1 ++0 < . 1:1(0) ack 2 win 257 + ++0 read(4, ..., 1000) = 0 ++0 write(4, ..., 1000) = -1 EPIPE (Broken pipe) + ++.010 close(4) = 0 + ++.010 < F. 1:1(0) ack 2 win 257 ++0 > . 2:2(0) ack 2 diff --git a/test/packetdrill/tests/linux/shutdown/shutdown-wr-close.pkt b/test/packetdrill/tests/linux/shutdown/shutdown-wr-close.pkt new file mode 100644 index 0000000..c840f84 --- /dev/null +++ b/test/packetdrill/tests/linux/shutdown/shutdown-wr-close.pkt @@ -0,0 +1,29 @@ +// Verify behavior for the sequence: +// shutdown(SHUT_WR), close(). + +// Initialize a server socket. +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 6> ++0 < . 1:1(0) ack 1 win 257 + ++0 accept(3, ..., ...) = 4 + ++.010 shutdown(4, SHUT_WR) = 0 ++0 > F. 1:1(0) ack 1 ++0 < . 1:1(0) ack 2 win 257 ++0 write(4, ..., 1000) = -1 EPIPE (Broken pipe) + +// Verify that receiving and reading still works. ++.010 < . 1:1001(1000) ack 2 win 257 ++0 > . 2:2(0) ack 1001 ++0 read(4, ..., 1000) = 1000 + ++.010 close(4) = 0 + ++.010 < F. 1001:1001(0) ack 2 win 257 ++0 > . 2:2(0) ack 1002 diff --git a/test/packetdrill/tests/linux/undo/undo-fr-ack-then-dsack-on-ack-below-snd_una.pkt b/test/packetdrill/tests/linux/undo/undo-fr-ack-then-dsack-on-ack-below-snd_una.pkt new file mode 100644 index 0000000..b3347f9 --- /dev/null +++ b/test/packetdrill/tests/linux/undo/undo-fr-ack-then-dsack-on-ack-below-snd_una.pkt @@ -0,0 +1,55 @@ +// Test fast recovery and undo: send 10 MSS, get 3 dupacks, do a +// fast retransmit, get a DSACK for the retransmitted segment, and +// undo the cwnd reduction. +// Assumes initial cwnd is 10. Receiver supports SACK. +// +// In this variant there is reordering in the return path, +// so that we end up getting an ACK below snd_una that +// has the critical DSACK that tells us we need to undo. + +// Establish a connection. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +// Send 10 MSS. +0.200 write(4, ..., 10000) = 10000 +0.200 > P. 1:10001(10000) ack 1 + +// Get 3 dupacks. +0.300 < . 1:1(0) ack 1 win 257 <sack 1001:2001,nop,nop> +0.300 < . 1:1(0) ack 1 win 257 <sack 1001:3001,nop,nop> +0.300 < . 1:1(0) ack 1 win 257 <sack 1001:4001,nop,nop> +// We've received 3 duplicate ACKs, so we do a fast retransmit. +0.300 > . 1:1001(1000) ack 1 +// Apparently just reordering; receiver ACKs all data. Retransmit was spurious. +0.300 < . 1:1(0) ack 4001 win 257 +0.300 < . 1:1(0) ack 6001 win 257 +0.300 < . 1:1(0) ack 8001 win 257 +0.300 < . 1:1(0) ack 10001 win 257 + +// We send some more new data so we can have an ACK that races our DSACK. +0.303 write(4, ..., 1000) = 1000 +0.303 > P. 10001:11001(1000) ack 1 + +// Receiver ACKs all outstanding data. +0.400 < . 1:1(0) ack 11001 win 257 + +// Oops; there was reordering in the ACK path! +// Now we get the DSACK for the retransmitted packet. +// It's a DSACK on an ack below snd_una. +0.401 < . 1:1(0) ack 10001 win 257 <sack 1:1001,nop,nop> + +// Verify that the DSACK caused an undo, restoring cwnd to 10. +0.450 write(4, ..., 11000) = 11000 +0.450 > . 11001:21001(10000) ack 1 +0.450 %{ +assert tcpi_snd_cwnd == 10 +assert tcpi_unacked == 10 +}% diff --git a/test/packetdrill/tests/linux/undo/undo-fr-acks-dropped-then-dsack.pkt b/test/packetdrill/tests/linux/undo/undo-fr-acks-dropped-then-dsack.pkt new file mode 100644 index 0000000..f39ddc8 --- /dev/null +++ b/test/packetdrill/tests/linux/undo/undo-fr-acks-dropped-then-dsack.pkt @@ -0,0 +1,44 @@ +// Test fast recovery and undo: send 10 MSS, get 3 dupacks, do a +// fast retransmit, get a DSACK for the retransmitted segment, and +// undo the cwnd reduction. +// Assumes initial cwnd is 10. Receiver supports SACK. +// +// In this variant the original ACKs are lost, and all the sender gets is +// a DSACK. + +// Establish a connection. +0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 + +0.100 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7> +0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6> +0.200 < . 1:1(0) ack 1 win 257 +0.200 accept(3, ..., ...) = 4 + +// Send 10 MSS. +0.200 write(4, ..., 10000) = 10000 +0.200 > P. 1:10001(10000) ack 1 + +// Get 3 dupacks. +0.300 < . 1:1(0) ack 1 win 257 <sack 1001:2001,nop,nop> +0.300 < . 1:1(0) ack 1 win 257 <sack 1001:3001,nop,nop> +0.300 < . 1:1(0) ack 1 win 257 <sack 1001:4001,nop,nop> +// We've received 3 duplicate ACKs, so we do a fast retransmit. +0.300 > . 1:1001(1000) ack 1 +0.300 %{ assert tcpi_snd_cwnd == 7 }% + +// Apparently just reordering. Retransmit was spurious. +// Original ACKs for sequence ranges up to 10001 are all lost. + +// Receiver sends DSACK for retransmitted packet. +0.400 < . 1:1(0) ack 10001 win 257 <sack 1:1001,nop,nop> + +// Verify that the DSACK caused an undo, restoring cwnd to 10. +0.400 write(4, ..., 11000) = 11000 +0.400 > . 10001:20001(10000) ack 1 +0.400 %{ +assert tcpi_snd_cwnd == 10 +assert tcpi_unacked == 10 +}% |