Refactor tcp_tests to separate individual tests.

This change should reduce the run time of the tcp_test target as well as allow
us to add leakchecking code to each test individually rather than create
standalone main_test.go file.

It also cleans up the BUILD file in the tcp directory so that the only tests in
the BUILD file are the whitebox tests and blackbox tests are now segregated to a
separate directory.

PiperOrigin-RevId: 424225303
This commit is contained in:
Bhasker Hariharan
2022-01-25 18:03:27 -08:00
committed by gVisor bot
parent e3c34d68d3
commit d3cce99370
12 changed files with 712 additions and 527 deletions
+1 -38
View File
@@ -1,4 +1,4 @@
load("//tools:defs.bzl", "go_library", "go_test", "more_shards")
load("//tools:defs.bzl", "go_library", "go_test")
load("//tools/go_generics:defs.bzl", "go_template_instance")
package(licenses = ["notice"])
@@ -78,43 +78,6 @@ go_library(
],
)
go_test(
name = "tcp_x_test",
size = "large",
srcs = [
"dual_stack_test.go",
"forwarder_test.go",
"rcv_test.go",
"sack_scoreboard_test.go",
"tcp_noracedetector_test.go",
"tcp_rack_test.go",
"tcp_sack_test.go",
"tcp_test.go",
"tcp_timestamp_test.go",
],
shard_count = more_shards,
deps = [
":tcp",
"//pkg/rand",
"//pkg/sync",
"//pkg/tcpip",
"//pkg/tcpip/checker",
"//pkg/tcpip/faketime",
"//pkg/tcpip/header",
"//pkg/tcpip/link/loopback",
"//pkg/tcpip/link/sniffer",
"//pkg/tcpip/network/ipv4",
"//pkg/tcpip/network/ipv6",
"//pkg/tcpip/seqnum",
"//pkg/tcpip/stack",
"//pkg/tcpip/testutil",
"//pkg/tcpip/transport/tcp/testing/context",
"//pkg/test/testutil",
"//pkg/waiter",
"@com_github_google_go_cmp//cmp:go_default_library",
],
)
go_test(
name = "tcp_test",
size = "small",
+161
View File
@@ -0,0 +1,161 @@
load("//tools:defs.bzl", "go_library", "go_test", "more_shards")
package(licenses = ["notice"])
go_test(
name = "tcp_test",
size = "large",
srcs = ["tcp_test.go"],
shard_count = more_shards,
deps = [
":e2e",
"//pkg/rand",
"//pkg/sync",
"//pkg/tcpip",
"//pkg/tcpip/checker",
"//pkg/tcpip/faketime",
"//pkg/tcpip/header",
"//pkg/tcpip/link/loopback",
"//pkg/tcpip/link/sniffer",
"//pkg/tcpip/network/ipv4",
"//pkg/tcpip/network/ipv6",
"//pkg/tcpip/seqnum",
"//pkg/tcpip/stack",
"//pkg/tcpip/testutil",
"//pkg/tcpip/transport/tcp",
"//pkg/tcpip/transport/tcp/testing/context",
"//pkg/test/testutil",
"//pkg/waiter",
"@com_github_google_go_cmp//cmp:go_default_library",
],
)
go_test(
name = "dual_stack_test",
size = "small",
srcs = ["dual_stack_test.go"],
deps = [
":e2e",
"//pkg/tcpip",
"//pkg/tcpip/checker",
"//pkg/tcpip/header",
"//pkg/tcpip/network/ipv4",
"//pkg/tcpip/seqnum",
"//pkg/tcpip/transport/tcp",
"//pkg/tcpip/transport/tcp/testing/context",
"//pkg/waiter",
"@com_github_google_go_cmp//cmp:go_default_library",
],
)
go_library(
name = "e2e",
testonly = 1,
srcs = ["e2e.go"],
deps = [
"//pkg/tcpip",
"//pkg/tcpip/checker",
"//pkg/tcpip/header",
"//pkg/tcpip/seqnum",
"//pkg/tcpip/transport/tcp",
"//pkg/tcpip/transport/tcp/testing/context",
"//pkg/waiter",
"@com_github_google_go_cmp//cmp:go_default_library",
],
)
go_test(
name = "forwarder_test",
size = "small",
srcs = ["forwarder_test.go"],
deps = [
":e2e",
"//pkg/tcpip",
"//pkg/tcpip/header",
"//pkg/tcpip/transport/tcp",
"//pkg/tcpip/transport/tcp/testing/context",
],
)
go_test(
name = "rcv_test",
size = "small",
srcs = ["rcv_test.go"],
deps = [
"//pkg/tcpip/header",
"//pkg/tcpip/seqnum",
],
)
go_test(
name = "sack_scoreboard_test",
size = "small",
srcs = ["sack_scoreboard_test.go"],
deps = [
"//pkg/tcpip/header",
"//pkg/tcpip/seqnum",
"//pkg/tcpip/transport/tcp",
],
)
go_test(
name = "tcp_timestamp_test",
size = "small",
srcs = ["tcp_timestamp_test.go"],
deps = [
":e2e",
"//pkg/tcpip",
"//pkg/tcpip/checker",
"//pkg/tcpip/header",
"//pkg/tcpip/transport/tcp",
"//pkg/tcpip/transport/tcp/testing/context",
"//pkg/waiter",
"@com_github_google_go_cmp//cmp:go_default_library",
],
)
go_test(
name = "tcp_rack_test",
size = "small",
srcs = ["tcp_rack_test.go"],
deps = [
":e2e",
"//pkg/tcpip",
"//pkg/tcpip/header",
"//pkg/tcpip/seqnum",
"//pkg/tcpip/stack",
"//pkg/tcpip/transport/tcp/testing/context",
"//pkg/test/testutil",
],
)
go_test(
name = "tcp_sack_test",
size = "small",
srcs = ["tcp_sack_test.go"],
deps = [
":e2e",
"//pkg/tcpip",
"//pkg/tcpip/checker",
"//pkg/tcpip/header",
"//pkg/tcpip/seqnum",
"//pkg/tcpip/stack",
"//pkg/tcpip/transport/tcp",
"//pkg/tcpip/transport/tcp/testing/context",
"//pkg/test/testutil",
],
)
go_test(
name = "tcp_noracedetector_test",
size = "small",
srcs = ["tcp_noracedetector_test.go"],
deps = [
":e2e",
"//pkg/tcpip",
"//pkg/tcpip/header",
"//pkg/tcpip/transport/tcp",
"//pkg/tcpip/transport/tcp/testing/context",
"//pkg/test/testutil",
],
)
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package tcp_test
package dual_stack_test
import (
"strings"
@@ -26,12 +26,13 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/test/e2e"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/testing/context"
"gvisor.dev/gvisor/pkg/waiter"
)
func TestV4MappedConnectOnV6Only(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(true)
@@ -43,70 +44,18 @@ func TestV4MappedConnectOnV6Only(t *testing.T) {
}
}
func testV4Connect(t *testing.T, c *context.Context, checkers ...checker.NetworkChecker) {
// Start connection attempt.
we, ch := waiter.NewChannelEntry(waiter.WritableEvents)
c.WQ.EventRegister(&we)
defer c.WQ.EventUnregister(&we)
err := c.EP.Connect(tcpip.FullAddress{Addr: context.TestV4MappedAddr, Port: context.TestPort})
if d := cmp.Diff(&tcpip.ErrConnectStarted{}, err); d != "" {
t.Fatalf("c.EP.Connect(...) mismatch (-want +got):\n%s", d)
}
// Receive SYN packet.
b := c.GetPacket()
synCheckers := append(checkers, checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagSyn),
))
checker.IPv4(t, b, synCheckers...)
tcp := header.TCP(header.IPv4(b).Payload())
c.IRS = seqnum.Value(tcp.SequenceNumber())
iss := seqnum.Value(789)
c.SendPacket(nil, &context.Headers{
SrcPort: tcp.DestinationPort(),
DstPort: tcp.SourcePort(),
Flags: header.TCPFlagSyn | header.TCPFlagAck,
SeqNum: iss,
AckNum: c.IRS.Add(1),
RcvWnd: 30000,
})
// Receive ACK packet.
ackCheckers := append(checkers, checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagAck),
checker.TCPSeqNum(uint32(c.IRS)+1),
checker.TCPAckNum(uint32(iss)+1),
))
checker.IPv4(t, c.GetPacket(), ackCheckers...)
// Wait for connection to be established.
select {
case <-ch:
if err := c.EP.LastError(); err != nil {
t.Fatalf("Unexpected error when connecting: %v", err)
}
case <-time.After(1 * time.Second):
t.Fatalf("Timed out waiting for connection")
}
}
func TestV4MappedConnect(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
// Test the connection request.
testV4Connect(t, c)
e2e.TestV4Connect(t, c)
}
func TestV4ConnectWhenBoundToWildcard(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
@@ -117,11 +66,11 @@ func TestV4ConnectWhenBoundToWildcard(t *testing.T) {
}
// Test the connection request.
testV4Connect(t, c)
e2e.TestV4Connect(t, c)
}
func TestV4ConnectWhenBoundToV4MappedWildcard(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
@@ -132,11 +81,11 @@ func TestV4ConnectWhenBoundToV4MappedWildcard(t *testing.T) {
}
// Test the connection request.
testV4Connect(t, c)
e2e.TestV4Connect(t, c)
}
func TestV4ConnectWhenBoundToV4Mapped(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
@@ -147,83 +96,31 @@ func TestV4ConnectWhenBoundToV4Mapped(t *testing.T) {
}
// Test the connection request.
testV4Connect(t, c)
}
func testV6Connect(t *testing.T, c *context.Context, checkers ...checker.NetworkChecker) {
// Start connection attempt to IPv6 address.
we, ch := waiter.NewChannelEntry(waiter.WritableEvents)
c.WQ.EventRegister(&we)
defer c.WQ.EventUnregister(&we)
err := c.EP.Connect(tcpip.FullAddress{Addr: context.TestV6Addr, Port: context.TestPort})
if d := cmp.Diff(&tcpip.ErrConnectStarted{}, err); d != "" {
t.Fatalf("Connect(...) mismatch (-want +got):\n%s", d)
}
// Receive SYN packet.
b := c.GetV6Packet()
synCheckers := append(checkers, checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagSyn),
))
checker.IPv6(t, b, synCheckers...)
tcp := header.TCP(header.IPv6(b).Payload())
c.IRS = seqnum.Value(tcp.SequenceNumber())
iss := seqnum.Value(789)
c.SendV6Packet(nil, &context.Headers{
SrcPort: tcp.DestinationPort(),
DstPort: tcp.SourcePort(),
Flags: header.TCPFlagSyn | header.TCPFlagAck,
SeqNum: iss,
AckNum: c.IRS.Add(1),
RcvWnd: 30000,
})
// Receive ACK packet.
ackCheckers := append(checkers, checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagAck),
checker.TCPSeqNum(uint32(c.IRS)+1),
checker.TCPAckNum(uint32(iss)+1),
))
checker.IPv6(t, c.GetV6Packet(), ackCheckers...)
// Wait for connection to be established.
select {
case <-ch:
if err := c.EP.LastError(); err != nil {
t.Fatalf("Unexpected error when connecting: %v", err)
}
case <-time.After(1 * time.Second):
t.Fatalf("Timed out waiting for connection")
}
e2e.TestV4Connect(t, c)
}
func TestV6Connect(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
// Test the connection request.
testV6Connect(t, c)
e2e.TestV6Connect(t, c)
}
func TestV6ConnectV6Only(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(true)
// Test the connection request.
testV6Connect(t, c)
e2e.TestV6Connect(t, c)
}
func TestV6ConnectWhenBoundToWildcard(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
@@ -234,13 +131,13 @@ func TestV6ConnectWhenBoundToWildcard(t *testing.T) {
}
// Test the connection request.
testV6Connect(t, c)
e2e.TestV6Connect(t, c)
}
func TestStackV6OnlyConnectWhenBoundToWildcard(t *testing.T) {
c := context.NewWithOpts(t, context.Options{
EnableV6: true,
MTU: defaultMTU,
MTU: e2e.DefaultMTU,
})
defer c.Cleanup()
@@ -253,11 +150,11 @@ func TestStackV6OnlyConnectWhenBoundToWildcard(t *testing.T) {
}
// Test the connection request.
testV6Connect(t, c)
e2e.TestV6Connect(t, c)
}
func TestV6ConnectWhenBoundToLocalAddress(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
@@ -268,11 +165,11 @@ func TestV6ConnectWhenBoundToLocalAddress(t *testing.T) {
}
// Test the connection request.
testV6Connect(t, c)
e2e.TestV6Connect(t, c)
}
func TestV4RefuseOnV6Only(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(true)
@@ -309,7 +206,7 @@ func TestV4RefuseOnV6Only(t *testing.T) {
}
func TestV6RefuseOnBoundToV4Mapped(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
@@ -428,7 +325,7 @@ func testV4Accept(t *testing.T, c *context.Context) {
}
func TestV4AcceptOnV6(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
@@ -443,7 +340,7 @@ func TestV4AcceptOnV6(t *testing.T) {
}
func TestV4AcceptOnBoundToV4MappedWildcard(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
@@ -458,7 +355,7 @@ func TestV4AcceptOnBoundToV4MappedWildcard(t *testing.T) {
}
func TestV4AcceptOnBoundToV4Mapped(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
@@ -473,7 +370,7 @@ func TestV4AcceptOnBoundToV4Mapped(t *testing.T) {
}
func TestV6AcceptOnV6(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(false)
@@ -546,7 +443,7 @@ func TestV6AcceptOnV6(t *testing.T) {
}
func TestV4AcceptOnV4(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
// Create TCP endpoint.
@@ -630,7 +527,7 @@ func testV4ListenClose(t *testing.T, c *context.Context) {
}
func TestV4ListenCloseOnV4(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
// Create TCP endpoint.
+296
View File
@@ -0,0 +1,296 @@
// Copyright 2022 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package e2e contains definitions common to all e2e tcp tests.
package e2e
import (
"bytes"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/checker"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/testing/context"
"gvisor.dev/gvisor/pkg/waiter"
)
const (
// DefaultMTU is the MTU, in bytes, used throughout the tests, except
// where another value is explicitly used. It is chosen to match the MTU
// of loopback interfaces on linux systems.
DefaultMTU = 65535
// DefaultIPv4MSS is the MSS sent by the network stack in SYN/SYN-ACK for an
// IPv4 endpoint when the MTU is set to defaultMTU in the test.
DefaultIPv4MSS = DefaultMTU - header.IPv4MinimumSize - header.TCPMinimumSize
// TSOptionSize is the size in bytes of the TCP timestamp option.
TSOptionSize = 12
// MaxTCPOptionSize is the maximum size TCP Options in a TCP header.
MaxTCPOptionSize = 40
)
// CheckBrokenUpWrite does a large write > than the specified maxPayload and
// verifies that the received packets carry the expected payload and
// that the large write was broken up into > 1 packet.
func CheckBrokenUpWrite(t *testing.T, c *context.Context, maxPayload int) {
payloadMultiplier := 10
dataLen := payloadMultiplier * maxPayload
data := make([]byte, dataLen)
for i := range data {
data[i] = byte(i)
}
var r bytes.Reader
r.Reset(data)
if _, err := c.EP.Write(&r, tcpip.WriteOptions{}); err != nil {
t.Fatalf("Write failed: %s", err)
}
// Check that data is received in chunks.
bytesReceived := 0
numPackets := 0
iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
for bytesReceived != dataLen {
b := c.GetPacket()
numPackets++
tcpHdr := header.TCP(header.IPv4(b).Payload())
payloadLen := len(tcpHdr.Payload())
checker.IPv4(t, b,
checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPSeqNum(uint32(c.IRS)+1+uint32(bytesReceived)),
checker.TCPAckNum(uint32(iss)),
checker.TCPFlagsMatch(header.TCPFlagAck, ^header.TCPFlagPsh),
),
)
pdata := data[bytesReceived : bytesReceived+payloadLen]
if p := tcpHdr.Payload(); !bytes.Equal(pdata, p) {
t.Fatalf("got data = %v, want = %v", p, pdata)
}
bytesReceived += payloadLen
var options []byte
if c.TimeStampEnabled {
// If timestamp option is enabled, echo back the timestamp and increment
// the TSEcr value included in the packet and send that back as the TSVal.
parsedOpts := tcpHdr.ParsedOptions()
tsOpt := [12]byte{header.TCPOptionNOP, header.TCPOptionNOP}
header.EncodeTSOption(parsedOpts.TSEcr+1, parsedOpts.TSVal, tsOpt[2:])
options = tsOpt[:]
}
// Acknowledge the data.
c.SendPacket(nil, &context.Headers{
SrcPort: context.TestPort,
DstPort: c.Port,
Flags: header.TCPFlagAck,
SeqNum: iss,
AckNum: c.IRS.Add(1 + seqnum.Size(bytesReceived)),
RcvWnd: 30000,
TCPOpts: options,
})
}
if numPackets == 1 {
t.Fatalf("expected write to be broken up into multiple packets, but got 1 packet")
}
}
// CreateConnectedWithSACKPermittedOption creates and connects c.ep with the
// SACKPermitted option enabled if the stack in the context has the SACK support
// enabled.
func CreateConnectedWithSACKPermittedOption(c *context.Context) *context.RawEndpoint {
return c.CreateConnectedWithOptionsNoDelay(header.TCPSynOptions{SACKPermitted: c.SACKEnabled()})
}
// CreateConnectedWithSACKAndTS creates and connects c.ep with the SACK & TS
// option enabled if the stack in the context has SACK and TS enabled.
func CreateConnectedWithSACKAndTS(c *context.Context) *context.RawEndpoint {
return c.CreateConnectedWithOptionsNoDelay(header.TCPSynOptions{SACKPermitted: c.SACKEnabled(), TS: true})
}
// SetStackSACKPermitted sets the tcpip.TCPSACKEnabled option of the context stack to
// enabled value.
func SetStackSACKPermitted(t *testing.T, c *context.Context, enable bool) {
t.Helper()
opt := tcpip.TCPSACKEnabled(enable)
if err := c.Stack().SetTransportProtocolOption(tcp.ProtocolNumber, &opt); err != nil {
t.Fatalf("c.s.SetTransportProtocolOption(%d, &%T(%t)): %s", tcp.ProtocolNumber, opt, opt, err)
}
}
// SetStackTCPRecovery sets the tcpip.TCPRecovery option of the context stack to
// the specified recovery value.
func SetStackTCPRecovery(t *testing.T, c *context.Context, recovery int) {
t.Helper()
opt := tcpip.TCPRecovery(recovery)
if err := c.Stack().SetTransportProtocolOption(header.TCPProtocolNumber, &opt); err != nil {
t.Fatalf("c.s.SetTransportProtocolOption(%d, &%v(%v)): %s", header.TCPProtocolNumber, opt, opt, err)
}
}
// SendAndReceiveWithSACK creates a SACK enabled connection w/ RACK enabled if
// enableRACK is true. It then proceeds to write a large payload and verifies
// that numPackets were received.
func SendAndReceiveWithSACK(t *testing.T, c *context.Context, maxPayload int, numPackets int, enableRACK bool) []byte {
SetStackSACKPermitted(t, c, true)
if !enableRACK {
SetStackTCPRecovery(t, c, 0)
}
// The delay should be below initial RTO (1s) otherwise retransimission
// will start. Choose a relatively large value so that estimated RTT
// keeps high even after a few rounds of undelayed RTT samples.
c.CreateConnectedWithOptions(header.TCPSynOptions{SACKPermitted: c.SACKEnabled(), TS: true}, 800*time.Millisecond /* delay */)
data := make([]byte, numPackets*maxPayload)
for i := range data {
data[i] = byte(i)
}
// Write the data.
var r bytes.Reader
r.Reset(data)
if _, err := c.EP.Write(&r, tcpip.WriteOptions{}); err != nil {
t.Fatalf("Write failed: %s", err)
}
bytesRead := 0
for i := 0; i < numPackets; i++ {
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, TSOptionSize)
bytesRead += maxPayload
}
return data
}
// EnableCUBIC sets the CUBIC congestion control as the default congestion
// control algorithm for all newly created endpoints in the context stack.
func EnableCUBIC(t *testing.T, c *context.Context) {
t.Helper()
opt := tcpip.CongestionControlOption("cubic")
if err := c.Stack().SetTransportProtocolOption(tcp.ProtocolNumber, &opt); err != nil {
t.Fatalf("SetTransportProtocolOption(%d, &%T(%s)) %s", tcp.ProtocolNumber, opt, opt, err)
}
}
// TestV4Connect establishes an IPv4 Connection with the context stack.
func TestV4Connect(t *testing.T, c *context.Context, checkers ...checker.NetworkChecker) {
// Start connection attempt.
we, ch := waiter.NewChannelEntry(waiter.WritableEvents)
c.WQ.EventRegister(&we)
defer c.WQ.EventUnregister(&we)
err := c.EP.Connect(tcpip.FullAddress{Addr: context.TestV4MappedAddr, Port: context.TestPort})
if d := cmp.Diff(&tcpip.ErrConnectStarted{}, err); d != "" {
t.Fatalf("c.EP.Connect(...) mismatch (-want +got):\n%s", d)
}
// Receive SYN packet.
b := c.GetPacket()
synCheckers := append(checkers, checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagSyn),
))
checker.IPv4(t, b, synCheckers...)
tcp := header.TCP(header.IPv4(b).Payload())
c.IRS = seqnum.Value(tcp.SequenceNumber())
iss := seqnum.Value(789)
c.SendPacket(nil, &context.Headers{
SrcPort: tcp.DestinationPort(),
DstPort: tcp.SourcePort(),
Flags: header.TCPFlagSyn | header.TCPFlagAck,
SeqNum: iss,
AckNum: c.IRS.Add(1),
RcvWnd: 30000,
})
// Receive ACK packet.
ackCheckers := append(checkers, checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagAck),
checker.TCPSeqNum(uint32(c.IRS)+1),
checker.TCPAckNum(uint32(iss)+1),
))
checker.IPv4(t, c.GetPacket(), ackCheckers...)
// Wait for connection to be established.
select {
case <-ch:
if err := c.EP.LastError(); err != nil {
t.Fatalf("Unexpected error when connecting: %v", err)
}
case <-time.After(1 * time.Second):
t.Fatalf("Timed out waiting for connection")
}
}
// TestV6Connect establishes an IPv6 Connection with the context stack.
func TestV6Connect(t *testing.T, c *context.Context, checkers ...checker.NetworkChecker) {
// Start connection attempt to IPv6 address.
we, ch := waiter.NewChannelEntry(waiter.WritableEvents)
c.WQ.EventRegister(&we)
defer c.WQ.EventUnregister(&we)
err := c.EP.Connect(tcpip.FullAddress{Addr: context.TestV6Addr, Port: context.TestPort})
if d := cmp.Diff(&tcpip.ErrConnectStarted{}, err); d != "" {
t.Fatalf("Connect(...) mismatch (-want +got):\n%s", d)
}
// Receive SYN packet.
b := c.GetV6Packet()
synCheckers := append(checkers, checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagSyn),
))
checker.IPv6(t, b, synCheckers...)
tcp := header.TCP(header.IPv6(b).Payload())
c.IRS = seqnum.Value(tcp.SequenceNumber())
iss := seqnum.Value(789)
c.SendV6Packet(nil, &context.Headers{
SrcPort: tcp.DestinationPort(),
DstPort: tcp.SourcePort(),
Flags: header.TCPFlagSyn | header.TCPFlagAck,
SeqNum: iss,
AckNum: c.IRS.Add(1),
RcvWnd: 30000,
})
// Receive ACK packet.
ackCheckers := append(checkers, checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagAck),
checker.TCPSeqNum(uint32(c.IRS)+1),
checker.TCPAckNum(uint32(iss)+1),
))
checker.IPv6(t, c.GetV6Packet(), ackCheckers...)
// Wait for connection to be established.
select {
case <-ch:
if err := c.EP.LastError(); err != nil {
t.Fatalf("Unexpected error when connecting: %v", err)
}
case <-time.After(1 * time.Second):
t.Fatalf("Timed out waiting for connection")
}
}
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package tcp_test
package forwarder_test
import (
"testing"
@@ -21,6 +21,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/test/e2e"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/testing/context"
)
@@ -54,7 +55,7 @@ func TestForwarderSendMSSLessThanMTU(t *testing.T) {
}
// Check that data gets properly segmented.
testBrokenUpWrite(t, c, maxPayload)
e2e.CheckBrokenUpWrite(t, c, maxPayload)
}
func TestForwarderDoesNotRejectECNFlags(t *testing.T) {
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package tcp_test
package rcv_test
import (
"testing"
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package tcp_test
package sack_scoreboard_test
import (
"testing"
@@ -19,7 +19,7 @@
//go:build !race
// +build !race
package tcp_test
package tcp_noracedetector_test
import (
"bytes"
@@ -31,6 +31,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/test/e2e"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/testing/context"
"gvisor.dev/gvisor/pkg/test/testutil"
)
@@ -355,7 +356,7 @@ func TestCubicCongestionAvoidance(t *testing.T) {
c := context.New(t, uint32(header.TCPMinimumSize+header.IPv4MinimumSize+maxPayload))
defer c.Cleanup()
enableCUBIC(t, c)
e2e.EnableCUBIC(t, c)
c.CreateConnected(789, 30000, -1 /* epRcvBuf */)
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package tcp_test
package tcp_rack_test
import (
"bytes"
@@ -24,25 +24,17 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/test/e2e"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/testing/context"
"gvisor.dev/gvisor/pkg/test/testutil"
)
const (
maxPayload = 10
tsOptionSize = 12
maxTCPOptionSize = 40
mtu = header.TCPMinimumSize + header.IPv4MinimumSize + maxTCPOptionSize + maxPayload
)
func setStackTCPRecovery(t *testing.T, c *context.Context, recovery int) {
t.Helper()
opt := tcpip.TCPRecovery(recovery)
if err := c.Stack().SetTransportProtocolOption(header.TCPProtocolNumber, &opt); err != nil {
t.Fatalf("c.s.SetTransportProtocolOption(%d, &%v(%v)): %s", header.TCPProtocolNumber, opt, opt, err)
}
}
// TestRACKUpdate tests the RACK related fields are updated when an ACK is
// received on a SACK enabled connection.
func TestRACKUpdate(t *testing.T) {
@@ -68,8 +60,8 @@ func TestRACKUpdate(t *testing.T) {
}
close(probeDone)
})
setStackSACKPermitted(t, c, true)
createConnectedWithSACKAndTS(c)
e2e.SetStackSACKPermitted(t, c, true)
e2e.CreateConnectedWithSACKAndTS(c)
data := make([]byte, maxPayload)
for i := range data {
@@ -85,7 +77,7 @@ func TestRACKUpdate(t *testing.T) {
}
bytesRead := 0
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
bytesRead += maxPayload
c.SendAck(seqnum.Value(context.TestInitialSequenceNumber).Add(1), bytesRead)
@@ -126,8 +118,8 @@ func TestRACKDetectReorder(t *testing.T) {
}
close(probeDone)
})
setStackSACKPermitted(t, c, true)
createConnectedWithSACKAndTS(c)
e2e.SetStackSACKPermitted(t, c, true)
e2e.CreateConnectedWithSACKAndTS(c)
data := make([]byte, ackNumToVerify*maxPayload)
for i := range data {
data[i] = byte(i)
@@ -142,7 +134,7 @@ func TestRACKDetectReorder(t *testing.T) {
bytesRead := 0
for i := 0; i < ackNumToVerify; i++ {
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
bytesRead += maxPayload
}
@@ -157,37 +149,6 @@ func TestRACKDetectReorder(t *testing.T) {
<-probeDone
}
func sendAndReceiveWithSACK(t *testing.T, c *context.Context, numPackets int, enableRACK bool) []byte {
setStackSACKPermitted(t, c, true)
if !enableRACK {
setStackTCPRecovery(t, c, 0)
}
// The delay should be below initial RTO (1s) otherwise retransimission
// will start. Choose a relatively large value so that estimated RTT
// keeps high even after a few rounds of undelayed RTT samples.
c.CreateConnectedWithOptions(header.TCPSynOptions{SACKPermitted: c.SACKEnabled(), TS: true}, 800*time.Millisecond /* delay */)
data := make([]byte, numPackets*maxPayload)
for i := range data {
data[i] = byte(i)
}
// Write the data.
var r bytes.Reader
r.Reset(data)
if _, err := c.EP.Write(&r, tcpip.WriteOptions{}); err != nil {
t.Fatalf("Write failed: %s", err)
}
bytesRead := 0
for i := 0; i < numPackets; i++ {
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
bytesRead += maxPayload
}
return data
}
const (
validDSACKDetected = 1
failedToDetectDSACK = 2
@@ -223,7 +184,7 @@ func TestRACKTLPRecovery(t *testing.T) {
// Send 8 packets.
numPackets := 8
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Packets [6-8] are lost. Send cumulative ACK for [1-5].
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
@@ -231,7 +192,7 @@ func TestRACKTLPRecovery(t *testing.T) {
c.SendAck(seq, bytesRead)
// PTO should fire and send #8 packet as a TLP.
c.ReceiveAndCheckPacketWithOptions(data, 7*maxPayload, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, 7*maxPayload, maxPayload, e2e.TSOptionSize)
var info tcpip.TCPInfoOption
if err := c.EP.GetSockOpt(&info); err != nil {
t.Fatalf("GetSockOpt failed: %v", err)
@@ -249,9 +210,9 @@ func TestRACKTLPRecovery(t *testing.T) {
// The sender should be entering RACK based loss-recovery and sending #6 and
// #7 one after another.
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
bytesRead += maxPayload
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
bytesRead += 2 * maxPayload
c.SendAck(seq, bytesRead)
@@ -294,7 +255,7 @@ func TestRACKTLPFallbackRTO(t *testing.T) {
// Send 8 packets.
numPackets := 8
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Packets [6-8] are lost. Send cumulative ACK for [1-5].
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
@@ -302,12 +263,12 @@ func TestRACKTLPFallbackRTO(t *testing.T) {
c.SendAck(seq, bytesRead)
// PTO should fire and send #8 packet as a TLP.
c.ReceiveAndCheckPacketWithOptions(data, 7*maxPayload, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, 7*maxPayload, maxPayload, e2e.TSOptionSize)
// Either the TLP or the ACK the receiver sent with SACK blocks was lost.
// Confirm that RTO fires and retransmits packet #6.
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
metricPollFn := func() error {
tcpStats := c.Stack().Stats().TCP
@@ -346,7 +307,7 @@ func TestNoTLPRecoveryOnDSACK(t *testing.T) {
// Send 8 packets.
numPackets := 8
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Packets [1-5] are received first. [6-8] took a detour and will take a
// while to arrive. Ack [1-5].
@@ -355,7 +316,7 @@ func TestNoTLPRecoveryOnDSACK(t *testing.T) {
c.SendAck(seq, bytesRead)
// The tail loss probe (#8 packet) is received.
c.ReceiveAndCheckPacketWithOptions(data, 7*maxPayload, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, 7*maxPayload, maxPayload, e2e.TSOptionSize)
// Now that all 8 packets are received + duplicate 8th packet, send ack.
bytesRead += 3 * maxPayload
@@ -409,7 +370,7 @@ func TestNoTLPOnSACK(t *testing.T) {
// Send 8 packets.
numPackets := 8
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Packets [1-5] and #7 were received. #6 and #8 were dropped.
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
@@ -420,7 +381,7 @@ func TestNoTLPOnSACK(t *testing.T) {
// The sender should retransmit #6. If the sender sends a TLP, then #8 will
// received and fail this test.
c.ReceiveAndCheckPacketWithOptions(data, 5*maxPayload, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, 5*maxPayload, maxPayload, e2e.TSOptionSize)
metricPollFn := func() error {
tcpStats := c.Stack().Stats().TCP
@@ -459,7 +420,7 @@ func TestRACKOnePacketTailLoss(t *testing.T) {
// Send 3 packets.
numPackets := 3
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Packets [1-2] are received. #3 is lost.
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
@@ -467,7 +428,7 @@ func TestRACKOnePacketTailLoss(t *testing.T) {
c.SendAck(seq, bytesRead)
// PTO should fire and send #3 packet as a TLP.
c.ReceiveAndCheckPacketWithOptions(data, 2*maxPayload, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, 2*maxPayload, maxPayload, e2e.TSOptionSize)
bytesRead += maxPayload
c.SendAck(seq, bytesRead)
@@ -510,7 +471,7 @@ func TestRACKDetectDSACK(t *testing.T) {
addDSACKSeenCheckerProbe(t, c, ackNumToVerify, probeDone)
numPackets := 8
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Cumulative ACK for [1-5] packets and SACK #8 packet (to prevent TLP).
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
@@ -520,7 +481,7 @@ func TestRACKDetectDSACK(t *testing.T) {
c.SendAckWithSACK(seq, bytesRead, []header.SACKBlock{{eighthPStart, eighthPEnd}})
// Expect retransmission of #6 packet after RTO expires.
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
// Send DSACK block for #6 packet indicating both
// initial and retransmitted packet are received and
@@ -575,7 +536,7 @@ func TestRACKDetectDSACKWithOutOfOrder(t *testing.T) {
addDSACKSeenCheckerProbe(t, c, ackNumToVerify, probeDone)
numPackets := 10
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Cumulative ACK for [1-5] packets and SACK for #7 packet (to prevent TLP).
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
@@ -585,7 +546,7 @@ func TestRACKDetectDSACKWithOutOfOrder(t *testing.T) {
c.SendAckWithSACK(seq, bytesRead, []header.SACKBlock{{seventhPStart, seventhPEnd}})
// Expect retransmission of #6 packet.
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
// Send DSACK block for #6 packet indicating both
// initial and retransmitted packet are received and
@@ -622,7 +583,7 @@ func TestRACKDetectDSACKWithOutOfOrderDup(t *testing.T) {
addDSACKSeenCheckerProbe(t, c, ackNumToVerify, probeDone)
numPackets := 10
sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// ACK [1-5] packets.
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
@@ -666,7 +627,7 @@ func TestRACKDetectDSACKSingleDup(t *testing.T) {
addDSACKSeenCheckerProbe(t, c, ackNumToVerify, probeDone)
numPackets := 4
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Send ACK for #1 packet.
bytesRead := maxPayload
@@ -680,7 +641,7 @@ func TestRACKDetectDSACKSingleDup(t *testing.T) {
c.SendAckWithSACK(seq, bytesRead, []header.SACKBlock{{start, end}})
// Expect retransmission of #2 packet.
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
// ACK for retransmitted #2 packet.
bytesRead += maxPayload
@@ -737,7 +698,7 @@ func TestRACKDetectDSACKDupWithCumulativeACK(t *testing.T) {
addDSACKSeenCheckerProbe(t, c, ackNumToVerify, probeDone)
numPackets := 6
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Send ACK for #1 packet.
bytesRead := maxPayload
@@ -751,7 +712,7 @@ func TestRACKDetectDSACKDupWithCumulativeACK(t *testing.T) {
c.SendAckWithSACK(seq, bytesRead, []header.SACKBlock{{start, end}})
// Expect retransmission of #2 packet.
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
// Received delayed #2 packet.
bytesRead += maxPayload
@@ -791,7 +752,7 @@ func TestRACKDetectDSACKDup(t *testing.T) {
addDSACKSeenCheckerProbe(t, c, ackNumToVerify, probeDone)
numPackets := 7
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Send ACK for #1 packet.
bytesRead := maxPayload
@@ -810,7 +771,7 @@ func TestRACKDetectDSACKDup(t *testing.T) {
c.SendAckWithSACK(seq, bytesRead, []header.SACKBlock{{start1, end1}, {start, end}})
// Expect retransmission of #2 packet.
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
// Consider #2 packet has been dropped and SACK #4 packet.
start2 := c.IRS.Add(1 + seqnum.Size(3*maxPayload))
@@ -859,7 +820,7 @@ func TestRACKWithInvalidDSACKBlock(t *testing.T) {
})
numPackets := 10
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Cumulative ACK for [1-5] packets and SACK for #7 packet (to prevent TLP).
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
@@ -869,7 +830,7 @@ func TestRACKWithInvalidDSACKBlock(t *testing.T) {
c.SendAckWithSACK(seq, bytesRead, []header.SACKBlock{{seventhPStart, seventhPEnd}})
// Expect retransmission of #6 packet.
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
// Send DSACK block for #6 packet indicating both
// initial and retransmitted packet are received and
@@ -924,7 +885,7 @@ func TestRACKCheckReorderWindow(t *testing.T) {
addReorderWindowCheckerProbe(c, ackNumToVerify, probeDone)
const numPackets = 7
sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Send ACK for #1 packet.
bytesRead := maxPayload
@@ -953,7 +914,7 @@ func TestRACKWithDuplicateACK(t *testing.T) {
defer c.Cleanup()
const numPackets = 4
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Send three duplicate ACKs to trigger fast recovery. The first
// segment is considered as lost and will be retransmitted after
@@ -967,7 +928,7 @@ func TestRACKWithDuplicateACK(t *testing.T) {
}
// Receive the retransmitted packet.
c.ReceiveAndCheckPacketWithOptions(data, 0, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, 0, maxPayload, e2e.TSOptionSize)
metricPollFn := func() error {
tcpStats := c.Stack().Stats().TCP
@@ -1016,7 +977,7 @@ func TestRACKUpdateSackedOut(t *testing.T) {
ackNum++
})
sendAndReceiveWithSACK(t, c, 8, true /* enableRACK */)
e2e.SendAndReceiveWithSACK(t, c, maxPayload, 8 /* numPackets */, true /* enableRACK */)
// ACK for [3-5] packets.
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
@@ -1038,8 +999,8 @@ func TestRACKWithWindowFull(t *testing.T) {
c := context.New(t, uint32(mtu))
defer c.Cleanup()
setStackSACKPermitted(t, c, true)
createConnectedWithSACKAndTS(c)
e2e.SetStackSACKPermitted(t, c, true)
e2e.CreateConnectedWithSACKAndTS(c)
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
const numPkts = 10
@@ -1057,12 +1018,12 @@ func TestRACKWithWindowFull(t *testing.T) {
bytesRead := 0
for i := 0; i < numPkts; i++ {
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, bytesRead, maxPayload, e2e.TSOptionSize)
bytesRead += maxPayload
}
// Expect retransmission of last packet due to TLP.
c.ReceiveAndCheckPacketWithOptions(data, (numPkts-1)*maxPayload, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, (numPkts-1)*maxPayload, maxPayload, e2e.TSOptionSize)
// SACK for first and last packet.
start := c.IRS.Add(seqnum.Size(maxPayload))
@@ -1079,13 +1040,13 @@ func TestRACKWithWindowFull(t *testing.T) {
time.Sleep(info.RTT)
// Expect retransmission of #2 packet.
c.ReceiveAndCheckPacketWithOptions(data, 2*maxPayload, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, 2*maxPayload, maxPayload, e2e.TSOptionSize)
// Send ACK for #2 packet.
c.SendAck(seq, 3*maxPayload)
// Expect retransmission of #3 packet.
c.ReceiveAndCheckPacketWithOptions(data, 3*maxPayload, maxPayload, tsOptionSize)
c.ReceiveAndCheckPacketWithOptions(data, 3*maxPayload, maxPayload, e2e.TSOptionSize)
// Send ACK with zero window size.
c.SendPacket(nil, &context.Headers{
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package tcp_test
package tcp_sack_test
import (
"bytes"
@@ -28,42 +28,28 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/test/e2e"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/testing/context"
"gvisor.dev/gvisor/pkg/test/testutil"
)
// createConnectedWithSACKPermittedOption creates and connects c.ep with the
// SACKPermitted option enabled if the stack in the context has the SACK support
// enabled.
func createConnectedWithSACKPermittedOption(c *context.Context) *context.RawEndpoint {
return c.CreateConnectedWithOptionsNoDelay(header.TCPSynOptions{SACKPermitted: c.SACKEnabled()})
}
// createConnectedWithSACKAndTS creates and connects c.ep with the SACK & TS
// option enabled if the stack in the context has SACK and TS enabled.
func createConnectedWithSACKAndTS(c *context.Context) *context.RawEndpoint {
return c.CreateConnectedWithOptionsNoDelay(header.TCPSynOptions{SACKPermitted: c.SACKEnabled(), TS: true})
}
func setStackSACKPermitted(t *testing.T, c *context.Context, enable bool) {
t.Helper()
opt := tcpip.TCPSACKEnabled(enable)
if err := c.Stack().SetTransportProtocolOption(tcp.ProtocolNumber, &opt); err != nil {
t.Fatalf("c.s.SetTransportProtocolOption(%d, &%T(%t)): %s", tcp.ProtocolNumber, opt, opt, err)
}
}
const (
maxPayload = 10
tsOptionSize = 12
mtu = header.TCPMinimumSize + header.IPv4MinimumSize + e2e.MaxTCPOptionSize + maxPayload
)
// TestSackPermittedConnect establishes a connection with the SACK option
// enabled.
func TestSackPermittedConnect(t *testing.T) {
for _, sackEnabled := range []bool{false, true} {
t.Run(fmt.Sprintf("stack.sackEnabled: %v", sackEnabled), func(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
setStackSACKPermitted(t, c, sackEnabled)
setStackTCPRecovery(t, c, 0)
rep := createConnectedWithSACKPermittedOption(c)
e2e.SetStackSACKPermitted(t, c, sackEnabled)
e2e.SetStackTCPRecovery(t, c, 0)
rep := e2e.CreateConnectedWithSACKPermittedOption(c)
data := []byte{1, 2, 3}
rep.SendPacket(data, nil)
@@ -103,11 +89,11 @@ func TestSackPermittedConnect(t *testing.T) {
func TestSackDisabledConnect(t *testing.T) {
for _, sackEnabled := range []bool{false, true} {
t.Run(fmt.Sprintf("sackEnabled: %v", sackEnabled), func(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
setStackSACKPermitted(t, c, sackEnabled)
setStackTCPRecovery(t, c, 0)
e2e.SetStackSACKPermitted(t, c, sackEnabled)
e2e.SetStackTCPRecovery(t, c, 0)
rep := c.CreateConnectedWithOptionsNoDelay(header.TCPSynOptions{})
@@ -159,7 +145,7 @@ func TestSackPermittedAccept(t *testing.T) {
t.Run(fmt.Sprintf("test: %#v", tc), func(t *testing.T) {
for _, sackEnabled := range []bool{false, true} {
t.Run(fmt.Sprintf("test stack.sackEnabled: %v", sackEnabled), func(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
if tc.cookieEnabled {
@@ -168,10 +154,10 @@ func TestSackPermittedAccept(t *testing.T) {
t.Fatalf("SetTransportProtocolOption(%d, &%T(%t)): %s", tcp.ProtocolNumber, opt, opt, err)
}
}
setStackSACKPermitted(t, c, sackEnabled)
setStackTCPRecovery(t, c, 0)
e2e.SetStackSACKPermitted(t, c, sackEnabled)
e2e.SetStackTCPRecovery(t, c, 0)
rep := c.AcceptWithOptionsNoDelay(tc.wndScale, header.TCPSynOptions{MSS: defaultIPv4MSS, SACKPermitted: tc.sackPermitted})
rep := c.AcceptWithOptionsNoDelay(tc.wndScale, header.TCPSynOptions{MSS: e2e.DefaultIPv4MSS, SACKPermitted: tc.sackPermitted})
// Now verify no SACK blocks are
// received when sack is disabled.
data := []byte{1, 2, 3}
@@ -232,7 +218,7 @@ func TestSackDisabledAccept(t *testing.T) {
t.Run(fmt.Sprintf("test: %#v", tc), func(t *testing.T) {
for _, sackEnabled := range []bool{false, true} {
t.Run(fmt.Sprintf("test: sackEnabled: %v", sackEnabled), func(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
if tc.cookieEnabled {
@@ -242,10 +228,10 @@ func TestSackDisabledAccept(t *testing.T) {
}
}
setStackSACKPermitted(t, c, sackEnabled)
setStackTCPRecovery(t, c, 0)
e2e.SetStackSACKPermitted(t, c, sackEnabled)
e2e.SetStackTCPRecovery(t, c, 0)
rep := c.AcceptWithOptionsNoDelay(tc.wndScale, header.TCPSynOptions{MSS: defaultIPv4MSS})
rep := c.AcceptWithOptionsNoDelay(tc.wndScale, header.TCPSynOptions{MSS: e2e.DefaultIPv4MSS})
// Now verify no SACK blocks are
// received when sack is disabled.
@@ -373,11 +359,9 @@ func TestSACKRecovery(t *testing.T) {
// Enabling SACK means the payload size is reduced to account
// for the extra space required for the TCP options.
//
// We increase the MTU by 40 bytes to account for SACK and Timestamp
// options.
const maxTCPOptionSize = 40
c := context.New(t, uint32(header.TCPMinimumSize+header.IPv4MinimumSize+maxTCPOptionSize+maxPayload))
// We increase the MTU by e2e.MaxTCPOptionSize bytes to account for SACK
// and Timestamp options.
c := context.New(t, uint32(header.TCPMinimumSize+header.IPv4MinimumSize+e2e.MaxTCPOptionSize+maxPayload))
defer c.Cleanup()
c.Stack().AddTCPProbe(func(s stack.TCPEndpointState) {
@@ -390,9 +374,9 @@ func TestSACKRecovery(t *testing.T) {
// causes the test to panic due to logging after test finished.
log.Printf("state: %+v\n", s)
})
setStackSACKPermitted(t, c, true)
setStackTCPRecovery(t, c, 0)
createConnectedWithSACKAndTS(c)
e2e.SetStackSACKPermitted(t, c, true)
e2e.SetStackTCPRecovery(t, c, 0)
e2e.CreateConnectedWithSACKAndTS(c)
const iterations = 3
data := make([]byte, 2*maxPayload*(tcp.InitialCwnd<<(iterations+1)))
@@ -604,7 +588,7 @@ func TestRecoveryEntry(t *testing.T) {
defer c.Cleanup()
numPackets := 5
data := sendAndReceiveWithSACK(t, c, numPackets, false /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, false /* enableRACK */)
// Ack #1 packet.
seq := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
@@ -768,8 +752,8 @@ func TestDetectSpuriousRecoveryWithRTO(t *testing.T) {
close(probeDone)
})
setStackSACKPermitted(t, c, true)
createConnectedWithSACKAndTS(c)
e2e.SetStackSACKPermitted(t, c, true)
e2e.CreateConnectedWithSACKAndTS(c)
numPackets := 5
data := make([]byte, numPackets*maxPayload)
for i := range data {
@@ -854,8 +838,8 @@ func TestSACKDetectSpuriousRecoveryWithDupACK(t *testing.T) {
close(probeDone)
})
setStackSACKPermitted(t, c, true)
createConnectedWithSACKAndTS(c)
e2e.SetStackSACKPermitted(t, c, true)
e2e.CreateConnectedWithSACKAndTS(c)
numPackets := 5
data := make([]byte, numPackets*maxPayload)
for i := range data {
@@ -930,10 +914,10 @@ func TestSACKDetectSpuriousRecoveryWithDupACK(t *testing.T) {
func TestNoSpuriousRecoveryWithDSACK(t *testing.T) {
c := context.New(t, uint32(mtu))
defer c.Cleanup()
setStackSACKPermitted(t, c, true)
createConnectedWithSACKAndTS(c)
e2e.SetStackSACKPermitted(t, c, true)
e2e.CreateConnectedWithSACKAndTS(c)
numPackets := 5
data := sendAndReceiveWithSACK(t, c, numPackets, true /* enableRACK */)
data := e2e.SendAndReceiveWithSACK(t, c, maxPayload, numPackets, true /* enableRACK */)
// Receive the retransmitted packet after TLP.
c.ReceiveAndCheckPacketWithOptions(data, 4*maxPayload, maxPayload, tsOptionSize)
File diff suppressed because it is too large Load Diff
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package tcp_test
package tcp_timestamp_test
import (
"bytes"
@@ -25,6 +25,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/checker"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/test/e2e"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp/testing/context"
"gvisor.dev/gvisor/pkg/waiter"
)
@@ -39,7 +40,7 @@ func createConnectedWithTimestampOption(c *context.Context) *context.RawEndpoint
// an active connect and sets the TS Echo Reply fields correctly when the
// SYN-ACK also indicates support for the TS option and provides a TSVal.
func TestTimeStampEnabledConnect(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
rep := createConnectedWithTimestampOption(c)
@@ -128,14 +129,14 @@ func TestTimeStampEnabledConnect(t *testing.T) {
// timestamp option is not enabled and future packets do not contain a
// timestamp.
func TestTimeStampDisabledConnect(t *testing.T) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
c.CreateConnectedWithOptionsNoDelay(header.TCPSynOptions{})
}
func timeStampEnabledAccept(t *testing.T, cookieEnabled bool, wndScale int, wndSize uint16) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
if cookieEnabled {
@@ -147,7 +148,7 @@ func timeStampEnabledAccept(t *testing.T, cookieEnabled bool, wndScale int, wndS
t.Logf("Test w/ CookieEnabled = %v", cookieEnabled)
tsVal := rand.Uint32()
c.AcceptWithOptionsNoDelay(wndScale, header.TCPSynOptions{MSS: defaultIPv4MSS, TS: true, TSVal: tsVal})
c.AcceptWithOptionsNoDelay(wndScale, header.TCPSynOptions{MSS: e2e.DefaultIPv4MSS, TS: true, TSVal: tsVal})
// Now send some data and validate that timestamp is echoed correctly in the ACK.
data := []byte{1, 2, 3}
@@ -198,7 +199,7 @@ func TestTimeStampEnabledAccept(t *testing.T) {
}
func timeStampDisabledAccept(t *testing.T, cookieEnabled bool, wndScale int, wndSize uint16) {
c := context.New(t, defaultMTU)
c := context.New(t, e2e.DefaultMTU)
defer c.Cleanup()
if cookieEnabled {
@@ -209,7 +210,7 @@ func timeStampDisabledAccept(t *testing.T, cookieEnabled bool, wndScale int, wnd
}
t.Logf("Test w/ CookieEnabled = %v", cookieEnabled)
c.AcceptWithOptionsNoDelay(wndScale, header.TCPSynOptions{MSS: defaultIPv4MSS})
c.AcceptWithOptionsNoDelay(wndScale, header.TCPSynOptions{MSS: e2e.DefaultIPv4MSS})
// Now send some data with the accepted connection endpoint and validate
// that no timestamp option is sent in the TCP segment.
@@ -261,7 +262,7 @@ func TestSendGreaterThanMTUWithOptions(t *testing.T) {
defer c.Cleanup()
createConnectedWithTimestampOption(c)
testBrokenUpWrite(t, c, maxPayload)
e2e.CheckBrokenUpWrite(t, c, maxPayload)
}
func TestSegmentNotDroppedWhenTimestampMissing(t *testing.T) {