Ask for *testing.T instead of storing it

Storing *testing.T on test helper structs is problematic when
subtests are used, because it is possible for nested tests to call
Fatal on parent test, which incorrect terminates the parent test.

For example

  func TestOuter(t *testing.T) {
    dut := NewDUT(t)

    t.Run("first test", func(t *testing.T) {
      dut.FallibleCall()
    })

    t.Run("second test", func(t *testing.T) {
      dut.FallibleCall()
    }
  }

In the example above, assuming `FallibleCall` calls `t.Fatal` on the
`t` it holds, if `dut.FallibleCall` fails in "first test", it will
call `Fatal` on the parent `t`, quitting `TestOuter`. This is not a
behavior we want.

PiperOrigin-RevId: 323350241
This commit is contained in:
Jay Zhuang
2020-07-27 06:39:06 -07:00
committed by gVisor bot
parent 2ecf66903e
commit cf7141fb43
30 changed files with 877 additions and 745 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+27 -17
View File
@@ -28,7 +28,6 @@ import (
// Sniffer can sniff raw packets on the wire.
type Sniffer struct {
t *testing.T
fd int
}
@@ -40,6 +39,8 @@ func htons(x uint16) uint16 {
// NewSniffer creates a Sniffer connected to *device.
func NewSniffer(t *testing.T) (Sniffer, error) {
t.Helper()
snifferFd, err := unix.Socket(unix.AF_PACKET, unix.SOCK_RAW, int(htons(unix.ETH_P_ALL)))
if err != nil {
return Sniffer{}, err
@@ -51,7 +52,6 @@ func NewSniffer(t *testing.T) (Sniffer, error) {
t.Fatalf("can't setsockopt SO_RCVBUF to 10M: %s", err)
}
return Sniffer{
t: t,
fd: snifferFd,
}, nil
}
@@ -61,7 +61,9 @@ func NewSniffer(t *testing.T) (Sniffer, error) {
const maxReadSize int = 65536
// Recv tries to read one frame until the timeout is up.
func (s *Sniffer) Recv(timeout time.Duration) []byte {
func (s *Sniffer) Recv(t *testing.T, timeout time.Duration) []byte {
t.Helper()
deadline := time.Now().Add(timeout)
for {
timeout = deadline.Sub(time.Now())
@@ -75,7 +77,7 @@ func (s *Sniffer) Recv(timeout time.Duration) []byte {
}
if err := unix.SetsockoptTimeval(s.fd, unix.SOL_SOCKET, unix.SO_RCVTIMEO, &tv); err != nil {
s.t.Fatalf("can't setsockopt SO_RCVTIMEO: %s", err)
t.Fatalf("can't setsockopt SO_RCVTIMEO: %s", err)
}
buf := make([]byte, maxReadSize)
@@ -85,10 +87,10 @@ func (s *Sniffer) Recv(timeout time.Duration) []byte {
continue
}
if err != nil {
s.t.Fatalf("can't read: %s", err)
t.Fatalf("can't read: %s", err)
}
if nread > maxReadSize {
s.t.Fatalf("received a truncated frame of %d bytes", nread)
t.Fatalf("received a truncated frame of %d bytes, want at most %d bytes", nread, maxReadSize)
}
return buf[:nread]
}
@@ -96,14 +98,16 @@ func (s *Sniffer) Recv(timeout time.Duration) []byte {
// Drain drains the Sniffer's socket receive buffer by receiving until there's
// nothing else to receive.
func (s *Sniffer) Drain() {
s.t.Helper()
func (s *Sniffer) Drain(t *testing.T) {
t.Helper()
flags, err := unix.FcntlInt(uintptr(s.fd), unix.F_GETFL, 0)
if err != nil {
s.t.Fatalf("failed to get sniffer socket fd flags: %s", err)
t.Fatalf("failed to get sniffer socket fd flags: %s", err)
}
if _, err := unix.FcntlInt(uintptr(s.fd), unix.F_SETFL, flags|unix.O_NONBLOCK); err != nil {
s.t.Fatalf("failed to make sniffer socket non-blocking: %s", err)
nonBlockingFlags := flags | unix.O_NONBLOCK
if _, err := unix.FcntlInt(uintptr(s.fd), unix.F_SETFL, nonBlockingFlags); err != nil {
t.Fatalf("failed to make sniffer socket non-blocking with flags %b: %s", nonBlockingFlags, err)
}
for {
buf := make([]byte, maxReadSize)
@@ -113,7 +117,7 @@ func (s *Sniffer) Drain() {
}
}
if _, err := unix.FcntlInt(uintptr(s.fd), unix.F_SETFL, flags); err != nil {
s.t.Fatalf("failed to restore sniffer socket fd flags: %s", err)
t.Fatalf("failed to restore sniffer socket fd flags to %b: %s", flags, err)
}
}
@@ -128,12 +132,13 @@ func (s *Sniffer) close() error {
// Injector can inject raw frames.
type Injector struct {
t *testing.T
fd int
}
// NewInjector creates a new injector on *device.
func NewInjector(t *testing.T) (Injector, error) {
t.Helper()
ifInfo, err := net.InterfaceByName(Device)
if err != nil {
return Injector{}, err
@@ -156,15 +161,20 @@ func NewInjector(t *testing.T) (Injector, error) {
return Injector{}, err
}
return Injector{
t: t,
fd: injectFd,
}, nil
}
// Send a raw frame.
func (i *Injector) Send(b []byte) {
if _, err := unix.Write(i.fd, b); err != nil {
i.t.Fatalf("can't write: %s of len %d", err, len(b))
func (i *Injector) Send(t *testing.T, b []byte) {
t.Helper()
n, err := unix.Write(i.fd, b)
if err != nil {
t.Fatalf("can't write bytes of len %d: %s", len(b), err)
}
if n != len(b) {
t.Fatalf("got %d bytes written, want %d", n, len(b))
}
}
@@ -39,34 +39,34 @@ func TestFinWait2Timeout(t *testing.T) {
t.Run(tt.description, func(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFd, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFd)
listenFd, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFd)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
conn.Connect()
defer conn.Close(t)
conn.Connect(t)
acceptFd, _ := dut.Accept(listenFd)
acceptFd, _ := dut.Accept(t, listenFd)
if tt.linger2 {
tv := unix.Timeval{Sec: 1, Usec: 0}
dut.SetSockOptTimeval(acceptFd, unix.SOL_TCP, unix.TCP_LINGER2, &tv)
dut.SetSockOptTimeval(t, acceptFd, unix.SOL_TCP, unix.TCP_LINGER2, &tv)
}
dut.Close(acceptFd)
dut.Close(t, acceptFd)
if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagFin | header.TCPFlagAck)}, time.Second); err != nil {
if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagFin | header.TCPFlagAck)}, time.Second); err != nil {
t.Fatalf("expected a FIN-ACK within 1 second but got none: %s", err)
}
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
time.Sleep(5 * time.Second)
conn.Drain()
conn.Drain(t)
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
if tt.linger2 {
if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst)}, time.Second); err != nil {
if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst)}, time.Second); err != nil {
t.Fatalf("expected a RST packet within a second but got none: %s", err)
}
} else {
if got, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst)}, 10*time.Second); got != nil || err == nil {
if got, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst)}, 10*time.Second); got != nil || err == nil {
t.Fatalf("expected no RST packets within ten seconds but got one: %s", got)
}
}
@@ -34,7 +34,7 @@ func TestICMPv6ParamProblemTest(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
conn := testbench.NewIPv6Conn(t, testbench.IPv6{}, testbench.IPv6{})
defer conn.Close()
defer conn.Close(t)
ipv6 := testbench.IPv6{
// 254 is reserved and used for experimentation and testing. This should
// cause an error.
@@ -45,8 +45,8 @@ func TestICMPv6ParamProblemTest(t *testing.T) {
Payload: []byte("hello world"),
}
toSend := (*testbench.Connection)(&conn).CreateFrame(testbench.Layers{&ipv6}, &icmpv6)
(*testbench.Connection)(&conn).SendFrame(toSend)
toSend := (*testbench.Connection)(&conn).CreateFrame(t, testbench.Layers{&ipv6}, &icmpv6)
(*testbench.Connection)(&conn).SendFrame(t, toSend)
// Build the expected ICMPv6 payload, which includes an index to the
// problematic byte and also the problematic packet as described in
@@ -72,7 +72,7 @@ func TestICMPv6ParamProblemTest(t *testing.T) {
&expectedICMPv6,
}
timeout := time.Second
if _, err := conn.ExpectFrame(paramProblem, timeout); err != nil {
if _, err := conn.ExpectFrame(t, paramProblem, timeout); err != nil {
t.Errorf("expected %s within %s but got none: %s", paramProblem, timeout, err)
}
}
@@ -31,8 +31,8 @@ func init() {
testbench.RegisterFlags(flag.CommandLine)
}
func recvTCPSegment(conn *testbench.TCPIPv4, expect *testbench.TCP, expectPayload *testbench.Payload) (uint16, error) {
layers, err := conn.ExpectData(expect, expectPayload, time.Second)
func recvTCPSegment(t *testing.T, conn *testbench.TCPIPv4, expect *testbench.TCP, expectPayload *testbench.Payload) (uint16, error) {
layers, err := conn.ExpectData(t, expect, expectPayload, time.Second)
if err != nil {
return 0, fmt.Errorf("failed to receive TCP segment: %s", err)
}
@@ -69,17 +69,17 @@ func TestIPv4RetransmitIdentificationUniqueness(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFD, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFD)
listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFD)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
defer conn.Close(t)
conn.Connect()
remoteFD, _ := dut.Accept(listenFD)
defer dut.Close(remoteFD)
conn.Connect(t)
remoteFD, _ := dut.Accept(t, listenFD)
defer dut.Close(t, remoteFD)
dut.SetSockOptInt(remoteFD, unix.IPPROTO_TCP, unix.TCP_NODELAY, 1)
dut.SetSockOptInt(t, remoteFD, unix.IPPROTO_TCP, unix.TCP_NODELAY, 1)
// TODO(b/129291778) The following socket option clears the DF bit on
// IP packets sent over the socket, and is currently not supported by
@@ -87,30 +87,30 @@ func TestIPv4RetransmitIdentificationUniqueness(t *testing.T) {
// socket option being not supported does not affect the operation of
// this test. Once the socket option is supported, the following call
// can be changed to simply assert success.
ret, errno := dut.SetSockOptIntWithErrno(context.Background(), remoteFD, unix.IPPROTO_IP, linux.IP_MTU_DISCOVER, linux.IP_PMTUDISC_DONT)
ret, errno := dut.SetSockOptIntWithErrno(context.Background(), t, remoteFD, unix.IPPROTO_IP, linux.IP_MTU_DISCOVER, linux.IP_PMTUDISC_DONT)
if ret == -1 && errno != unix.ENOTSUP {
t.Fatalf("failed to set IP_MTU_DISCOVER socket option to IP_PMTUDISC_DONT: %s", errno)
}
samplePayload := &testbench.Payload{Bytes: tc.payload}
dut.Send(remoteFD, tc.payload, 0)
if _, err := conn.ExpectData(&testbench.TCP{}, samplePayload, time.Second); err != nil {
dut.Send(t, remoteFD, tc.payload, 0)
if _, err := conn.ExpectData(t, &testbench.TCP{}, samplePayload, time.Second); err != nil {
t.Fatalf("failed to receive TCP segment sent for RTT calculation: %s", err)
}
// Let the DUT estimate RTO with RTT from the DATA-ACK.
// TODO(gvisor.dev/issue/2685) Estimate RTO during handshake, after which
// we can skip sending this ACK.
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
dut.Send(remoteFD, tc.payload, 0)
expectTCP := &testbench.TCP{SeqNum: testbench.Uint32(uint32(*conn.RemoteSeqNum()))}
originalID, err := recvTCPSegment(&conn, expectTCP, samplePayload)
dut.Send(t, remoteFD, tc.payload, 0)
expectTCP := &testbench.TCP{SeqNum: testbench.Uint32(uint32(*conn.RemoteSeqNum(t)))}
originalID, err := recvTCPSegment(t, &conn, expectTCP, samplePayload)
if err != nil {
t.Fatalf("failed to receive TCP segment: %s", err)
}
retransmitID, err := recvTCPSegment(&conn, expectTCP, samplePayload)
retransmitID, err := recvTCPSegment(t, &conn, expectTCP, samplePayload)
if err != nil {
t.Fatalf("failed to receive retransmitted TCP segment: %s", err)
}
@@ -48,7 +48,7 @@ func TestIPv6FragmentReassembly(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
conn := testbench.NewIPv6Conn(t, testbench.IPv6{}, testbench.IPv6{})
defer conn.Close()
defer conn.Close(t)
firstPayloadToSend := make([]byte, firstPayloadLength)
for i := range firstPayloadToSend {
@@ -81,7 +81,7 @@ func TestIPv6FragmentReassembly(t *testing.T) {
buffer.NewVectorisedView(len(secondPayloadToSend), []buffer.View{secondPayloadToSend}),
)
conn.Send(testbench.IPv6{},
conn.Send(t, testbench.IPv6{},
&testbench.IPv6FragmentExtHdr{
FragmentOffset: testbench.Uint16(0),
MoreFragments: testbench.Bool(true),
@@ -96,7 +96,7 @@ func TestIPv6FragmentReassembly(t *testing.T) {
icmpv6ProtoNum := header.IPv6ExtensionHeaderIdentifier(header.ICMPv6ProtocolNumber)
conn.Send(testbench.IPv6{},
conn.Send(t, testbench.IPv6{},
&testbench.IPv6FragmentExtHdr{
NextHeader: &icmpv6ProtoNum,
FragmentOffset: testbench.Uint16((firstPayloadLength + header.ICMPv6EchoMinimumSize) / 8),
@@ -107,7 +107,7 @@ func TestIPv6FragmentReassembly(t *testing.T) {
Bytes: secondPayloadToSend,
})
gotEchoReplyFirstPart, err := conn.ExpectFrame(testbench.Layers{
gotEchoReplyFirstPart, err := conn.ExpectFrame(t, testbench.Layers{
&testbench.Ether{},
&testbench.IPv6{},
&testbench.IPv6FragmentExtHdr{
@@ -142,7 +142,7 @@ func TestIPv6FragmentReassembly(t *testing.T) {
hex.Dump(wantFirstPayload))
}
gotEchoReplySecondPart, err := conn.ExpectFrame(testbench.Layers{
gotEchoReplySecondPart, err := conn.ExpectFrame(t, testbench.Layers{
&testbench.Ether{},
&testbench.IPv6{},
&testbench.IPv6FragmentExtHdr{
@@ -23,21 +23,21 @@ import (
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
tb "gvisor.dev/gvisor/test/packetimpact/testbench"
"gvisor.dev/gvisor/test/packetimpact/testbench"
)
func init() {
tb.RegisterFlags(flag.CommandLine)
testbench.RegisterFlags(flag.CommandLine)
}
func mkHopByHopOptionsExtHdr(optType byte) tb.Layer {
return &tb.IPv6HopByHopOptionsExtHdr{
func mkHopByHopOptionsExtHdr(optType byte) testbench.Layer {
return &testbench.IPv6HopByHopOptionsExtHdr{
Options: []byte{optType, 0x04, 0x00, 0x00, 0x00, 0x00},
}
}
func mkDestinationOptionsExtHdr(optType byte) tb.Layer {
return &tb.IPv6DestinationOptionsExtHdr{
func mkDestinationOptionsExtHdr(optType byte) testbench.Layer {
return &testbench.IPv6DestinationOptionsExtHdr{
Options: []byte{optType, 0x04, 0x00, 0x00, 0x00, 0x00},
}
}
@@ -49,7 +49,7 @@ func optionTypeFromAction(action header.IPv6OptionUnknownAction) byte {
func TestIPv6UnknownOptionAction(t *testing.T) {
for _, tt := range []struct {
description string
mkExtHdr func(optType byte) tb.Layer
mkExtHdr func(optType byte) testbench.Layer
action header.IPv6OptionUnknownAction
multicastDst bool
wantICMPv6 bool
@@ -140,21 +140,21 @@ func TestIPv6UnknownOptionAction(t *testing.T) {
},
} {
t.Run(tt.description, func(t *testing.T) {
dut := tb.NewDUT(t)
dut := testbench.NewDUT(t)
defer dut.TearDown()
ipv6Conn := tb.NewIPv6Conn(t, tb.IPv6{}, tb.IPv6{})
conn := (*tb.Connection)(&ipv6Conn)
defer ipv6Conn.Close()
ipv6Conn := testbench.NewIPv6Conn(t, testbench.IPv6{}, testbench.IPv6{})
conn := (*testbench.Connection)(&ipv6Conn)
defer ipv6Conn.Close(t)
outgoingOverride := tb.Layers{}
outgoingOverride := testbench.Layers{}
if tt.multicastDst {
outgoingOverride = tb.Layers{&tb.IPv6{
DstAddr: tb.Address(tcpip.Address(net.ParseIP("ff02::1"))),
outgoingOverride = testbench.Layers{&testbench.IPv6{
DstAddr: testbench.Address(tcpip.Address(net.ParseIP("ff02::1"))),
}}
}
outgoing := conn.CreateFrame(outgoingOverride, tt.mkExtHdr(optionTypeFromAction(tt.action)))
conn.SendFrame(outgoing)
outgoing := conn.CreateFrame(t, outgoingOverride, tt.mkExtHdr(optionTypeFromAction(tt.action)))
conn.SendFrame(t, outgoing)
ipv6Sent := outgoing[1:]
invokingPacket, err := ipv6Sent.ToBytes()
if err != nil {
@@ -167,12 +167,12 @@ func TestIPv6UnknownOptionAction(t *testing.T) {
// after the IPv6 header (after NextHeader and ExtHdrLen).
binary.BigEndian.PutUint32(icmpv6Payload, header.IPv6MinimumSize+2)
icmpv6Payload = append(icmpv6Payload, invokingPacket...)
gotICMPv6, err := ipv6Conn.ExpectFrame(tb.Layers{
&tb.Ether{},
&tb.IPv6{},
&tb.ICMPv6{
Type: tb.ICMPv6Type(header.ICMPv6ParamProblem),
Code: tb.Byte(2),
gotICMPv6, err := ipv6Conn.ExpectFrame(t, testbench.Layers{
&testbench.Ether{},
&testbench.IPv6{},
&testbench.ICMPv6{
Type: testbench.ICMPv6Type(header.ICMPv6ParamProblem),
Code: testbench.Byte(2),
Payload: icmpv6Payload,
},
}, time.Second)
@@ -33,39 +33,39 @@ func init() {
func TestCloseWaitAck(t *testing.T) {
for _, tt := range []struct {
description string
makeTestingTCP func(conn *testbench.TCPIPv4, seqNumOffset seqnum.Size, windowSize seqnum.Size) testbench.TCP
makeTestingTCP func(t *testing.T, conn *testbench.TCPIPv4, seqNumOffset, windowSize seqnum.Size) testbench.TCP
seqNumOffset seqnum.Size
expectAck bool
}{
{"OTW", GenerateOTWSeqSegment, 0, false},
{"OTW", GenerateOTWSeqSegment, 1, true},
{"OTW", GenerateOTWSeqSegment, 2, true},
{"ACK", GenerateUnaccACKSegment, 0, false},
{"ACK", GenerateUnaccACKSegment, 1, true},
{"ACK", GenerateUnaccACKSegment, 2, true},
{"OTW", generateOTWSeqSegment, 0, false},
{"OTW", generateOTWSeqSegment, 1, true},
{"OTW", generateOTWSeqSegment, 2, true},
{"ACK", generateUnaccACKSegment, 0, false},
{"ACK", generateUnaccACKSegment, 1, true},
{"ACK", generateUnaccACKSegment, 2, true},
} {
t.Run(fmt.Sprintf("%s%d", tt.description, tt.seqNumOffset), func(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFd, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFd)
listenFd, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFd)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
defer conn.Close(t)
conn.Connect()
acceptFd, _ := dut.Accept(listenFd)
conn.Connect(t)
acceptFd, _ := dut.Accept(t, listenFd)
// Send a FIN to DUT to intiate the active close
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagFin)})
gotTCP, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second)
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagFin)})
gotTCP, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second)
if err != nil {
t.Fatalf("expected an ACK for our fin and DUT should enter CLOSE_WAIT: %s", err)
}
windowSize := seqnum.Size(*gotTCP.WindowSize)
// Send a segment with OTW Seq / unacc ACK and expect an ACK back
conn.Send(tt.makeTestingTCP(&conn, tt.seqNumOffset, windowSize), &testbench.Payload{Bytes: []byte("Sample Data")})
gotAck, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second)
conn.Send(t, tt.makeTestingTCP(t, &conn, tt.seqNumOffset, windowSize), &testbench.Payload{Bytes: []byte("Sample Data")})
gotAck, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second)
if tt.expectAck && err != nil {
t.Fatalf("expected an ack but got none: %s", err)
}
@@ -74,35 +74,36 @@ func TestCloseWaitAck(t *testing.T) {
}
// Now let's verify DUT is indeed in CLOSE_WAIT
dut.Close(acceptFd)
if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagFin)}, time.Second); err != nil {
dut.Close(t, acceptFd)
if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagFin)}, time.Second); err != nil {
t.Fatalf("expected DUT to send a FIN: %s", err)
}
// Ack the FIN from DUT
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
// Send some extra data to DUT
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, &testbench.Payload{Bytes: []byte("Sample Data")})
if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst)}, time.Second); err != nil {
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, &testbench.Payload{Bytes: []byte("Sample Data")})
if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst)}, time.Second); err != nil {
t.Fatalf("expected DUT to send an RST: %s", err)
}
})
}
}
// This generates an segment with seqnum = RCV.NXT + RCV.WND + seqNumOffset, the
// generated segment is only acceptable when seqNumOffset is 0, otherwise an ACK
// is expected from the receiver.
func GenerateOTWSeqSegment(conn *testbench.TCPIPv4, seqNumOffset seqnum.Size, windowSize seqnum.Size) testbench.TCP {
lastAcceptable := conn.LocalSeqNum().Add(windowSize)
// generateOTWSeqSegment generates an segment with
// seqnum = RCV.NXT + RCV.WND + seqNumOffset, the generated segment is only
// acceptable when seqNumOffset is 0, otherwise an ACK is expected from the
// receiver.
func generateOTWSeqSegment(t *testing.T, conn *testbench.TCPIPv4, seqNumOffset seqnum.Size, windowSize seqnum.Size) testbench.TCP {
lastAcceptable := conn.LocalSeqNum(t).Add(windowSize)
otwSeq := uint32(lastAcceptable.Add(seqNumOffset))
return testbench.TCP{SeqNum: testbench.Uint32(otwSeq), Flags: testbench.Uint8(header.TCPFlagAck)}
}
// This generates an segment with acknum = SND.NXT + seqNumOffset, the generated
// segment is only acceptable when seqNumOffset is 0, otherwise an ACK is
// expected from the receiver.
func GenerateUnaccACKSegment(conn *testbench.TCPIPv4, seqNumOffset seqnum.Size, windowSize seqnum.Size) testbench.TCP {
lastAcceptable := conn.RemoteSeqNum()
// generateUnaccACKSegment generates an segment with
// acknum = SND.NXT + seqNumOffset, the generated segment is only acceptable
// when seqNumOffset is 0, otherwise an ACK is expected from the receiver.
func generateUnaccACKSegment(t *testing.T, conn *testbench.TCPIPv4, seqNumOffset seqnum.Size, windowSize seqnum.Size) testbench.TCP {
lastAcceptable := conn.RemoteSeqNum(t)
unaccAck := uint32(lastAcceptable.Add(seqNumOffset))
return testbench.TCP{AckNum: testbench.Uint32(unaccAck), Flags: testbench.Uint8(header.TCPFlagAck)}
}
+18 -18
View File
@@ -32,53 +32,53 @@ func init() {
func TestTCPCorkMSS(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFD, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFD)
listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFD)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
defer conn.Close(t)
const mss = uint32(header.TCPDefaultMSS)
options := make([]byte, header.TCPOptionMSSLength)
header.EncodeMSSOption(mss, options)
conn.ConnectWithOptions(options)
conn.ConnectWithOptions(t, options)
acceptFD, _ := dut.Accept(listenFD)
defer dut.Close(acceptFD)
acceptFD, _ := dut.Accept(t, listenFD)
defer dut.Close(t, acceptFD)
dut.SetSockOptInt(acceptFD, unix.IPPROTO_TCP, unix.TCP_CORK, 1)
dut.SetSockOptInt(t, acceptFD, unix.IPPROTO_TCP, unix.TCP_CORK, 1)
// Let the dut application send 2 small segments to be held up and coalesced
// until the application sends a larger segment to fill up to > MSS.
sampleData := []byte("Sample Data")
dut.Send(acceptFD, sampleData, 0)
dut.Send(acceptFD, sampleData, 0)
dut.Send(t, acceptFD, sampleData, 0)
dut.Send(t, acceptFD, sampleData, 0)
expectedData := sampleData
expectedData = append(expectedData, sampleData...)
largeData := make([]byte, mss+1)
expectedData = append(expectedData, largeData...)
dut.Send(acceptFD, largeData, 0)
dut.Send(t, acceptFD, largeData, 0)
// Expect the segments to be coalesced and sent and capped to MSS.
expectedPayload := testbench.Payload{Bytes: expectedData[:mss]}
if _, err := conn.ExpectData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, &expectedPayload, time.Second); err != nil {
if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, &expectedPayload, time.Second); err != nil {
t.Fatalf("expected payload was not received: %s", err)
}
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
// Expect the coalesced segment to be split and transmitted.
expectedPayload = testbench.Payload{Bytes: expectedData[mss:]}
if _, err := conn.ExpectData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagPsh)}, &expectedPayload, time.Second); err != nil {
if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagPsh)}, &expectedPayload, time.Second); err != nil {
t.Fatalf("expected payload was not received: %s", err)
}
// Check for segments to *not* be held up because of TCP_CORK when
// the current send window is less than MSS.
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), WindowSize: testbench.Uint16(uint16(2 * len(sampleData)))})
dut.Send(acceptFD, sampleData, 0)
dut.Send(acceptFD, sampleData, 0)
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), WindowSize: testbench.Uint16(uint16(2 * len(sampleData)))})
dut.Send(t, acceptFD, sampleData, 0)
dut.Send(t, acceptFD, sampleData, 0)
expectedPayload = testbench.Payload{Bytes: append(sampleData, sampleData...)}
if _, err := conn.ExpectData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagPsh)}, &expectedPayload, time.Second); err != nil {
if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagPsh)}, &expectedPayload, time.Second); err != nil {
t.Fatalf("expected payload was not received: %s", err)
}
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
}
@@ -33,14 +33,14 @@ func init() {
func TestTCPHandshakeWindowSize(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFD, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFD)
listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFD)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
defer conn.Close(t)
// Start handshake with zero window size.
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn), WindowSize: testbench.Uint16(uint16(0))})
if _, err := conn.ExpectData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn | header.TCPFlagAck)}, nil, time.Second); err != nil {
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn), WindowSize: testbench.Uint16(uint16(0))})
if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn | header.TCPFlagAck)}, nil, time.Second); err != nil {
t.Fatalf("expected SYN-ACK: %s", err)
}
// Update the advertised window size to a non-zero value with the ACK that
@@ -48,10 +48,10 @@ func TestTCPHandshakeWindowSize(t *testing.T) {
//
// Set the window size with MSB set and expect the dut to treat it as
// an unsigned value.
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), WindowSize: testbench.Uint16(uint16(1 << 15))})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), WindowSize: testbench.Uint16(uint16(1 << 15))})
acceptFd, _ := dut.Accept(listenFD)
defer dut.Close(acceptFd)
acceptFd, _ := dut.Accept(t, listenFD)
defer dut.Close(t, acceptFd)
sampleData := []byte("Sample Data")
samplePayload := &testbench.Payload{Bytes: sampleData}
@@ -59,8 +59,8 @@ func TestTCPHandshakeWindowSize(t *testing.T) {
// Since we advertised a zero window followed by a non-zero window,
// expect the dut to honor the recently advertised non-zero window
// and actually send out the data instead of probing for zero window.
dut.Send(acceptFd, sampleData, 0)
if _, err := conn.ExpectNextData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagPsh)}, samplePayload, time.Second); err != nil {
dut.Send(t, acceptFd, sampleData, 0)
if _, err := conn.ExpectNextData(t, &testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagPsh)}, samplePayload, time.Second); err != nil {
t.Fatalf("expected payload was not received: %s", err)
}
}
@@ -38,29 +38,29 @@ func TestTCPSynSentUnreachable(t *testing.T) {
// Create the DUT and connection.
dut := testbench.NewDUT(t)
defer dut.TearDown()
clientFD, clientPort := dut.CreateBoundSocket(unix.SOCK_STREAM|unix.SOCK_NONBLOCK, unix.IPPROTO_TCP, net.ParseIP(testbench.RemoteIPv4))
clientFD, clientPort := dut.CreateBoundSocket(t, unix.SOCK_STREAM|unix.SOCK_NONBLOCK, unix.IPPROTO_TCP, net.ParseIP(testbench.RemoteIPv4))
port := uint16(9001)
conn := testbench.NewTCPIPv4(t, testbench.TCP{SrcPort: &port, DstPort: &clientPort}, testbench.TCP{SrcPort: &clientPort, DstPort: &port})
defer conn.Close()
defer conn.Close(t)
// Bring the DUT to SYN-SENT state with a non-blocking connect.
ctx, cancel := context.WithTimeout(context.Background(), testbench.RPCTimeout)
defer cancel()
sa := unix.SockaddrInet4{Port: int(port)}
copy(sa.Addr[:], net.IP(net.ParseIP(testbench.LocalIPv4)).To4())
if _, err := dut.ConnectWithErrno(ctx, clientFD, &sa); err != syscall.Errno(unix.EINPROGRESS) {
if _, err := dut.ConnectWithErrno(ctx, t, clientFD, &sa); err != syscall.Errno(unix.EINPROGRESS) {
t.Errorf("expected connect to fail with EINPROGRESS, but got %v", err)
}
// Get the SYN.
tcpLayers, err := conn.ExpectData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn)}, nil, time.Second)
tcpLayers, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn)}, nil, time.Second)
if err != nil {
t.Fatalf("expected SYN: %s", err)
}
// Send a host unreachable message.
rawConn := (*testbench.Connection)(&conn)
layers := rawConn.CreateFrame(nil)
layers := rawConn.CreateFrame(t, nil)
layers = layers[:len(layers)-1]
const ipLayer = 1
const tcpLayer = ipLayer + 1
@@ -74,9 +74,9 @@ func TestTCPSynSentUnreachable(t *testing.T) {
}
var icmpv4 testbench.ICMPv4 = testbench.ICMPv4{Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), Code: testbench.Uint8(header.ICMPv4HostUnreachable)}
layers = append(layers, &icmpv4, ip, tcp)
rawConn.SendFrameStateless(layers)
rawConn.SendFrameStateless(t, layers)
if _, err = dut.ConnectWithErrno(ctx, clientFD, &sa); err != syscall.Errno(unix.EHOSTUNREACH) {
if _, err = dut.ConnectWithErrno(ctx, t, clientFD, &sa); err != syscall.Errno(unix.EHOSTUNREACH) {
t.Errorf("expected connect to fail with EHOSTUNREACH, but got %v", err)
}
}
@@ -88,9 +88,9 @@ func TestTCPSynSentUnreachable6(t *testing.T) {
// Create the DUT and connection.
dut := testbench.NewDUT(t)
defer dut.TearDown()
clientFD, clientPort := dut.CreateBoundSocket(unix.SOCK_STREAM|unix.SOCK_NONBLOCK, unix.IPPROTO_TCP, net.ParseIP(testbench.RemoteIPv6))
clientFD, clientPort := dut.CreateBoundSocket(t, unix.SOCK_STREAM|unix.SOCK_NONBLOCK, unix.IPPROTO_TCP, net.ParseIP(testbench.RemoteIPv6))
conn := testbench.NewTCPIPv6(t, testbench.TCP{DstPort: &clientPort}, testbench.TCP{SrcPort: &clientPort})
defer conn.Close()
defer conn.Close(t)
// Bring the DUT to SYN-SENT state with a non-blocking connect.
ctx, cancel := context.WithTimeout(context.Background(), testbench.RPCTimeout)
@@ -100,19 +100,19 @@ func TestTCPSynSentUnreachable6(t *testing.T) {
ZoneId: uint32(testbench.RemoteInterfaceID),
}
copy(sa.Addr[:], net.IP(net.ParseIP(testbench.LocalIPv6)).To16())
if _, err := dut.ConnectWithErrno(ctx, clientFD, &sa); err != syscall.Errno(unix.EINPROGRESS) {
if _, err := dut.ConnectWithErrno(ctx, t, clientFD, &sa); err != syscall.Errno(unix.EINPROGRESS) {
t.Errorf("expected connect to fail with EINPROGRESS, but got %v", err)
}
// Get the SYN.
tcpLayers, err := conn.ExpectData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn)}, nil, time.Second)
tcpLayers, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn)}, nil, time.Second)
if err != nil {
t.Fatalf("expected SYN: %s", err)
}
// Send a host unreachable message.
rawConn := (*testbench.Connection)(&conn)
layers := rawConn.CreateFrame(nil)
layers := rawConn.CreateFrame(t, nil)
layers = layers[:len(layers)-1]
const ipLayer = 1
const tcpLayer = ipLayer + 1
@@ -131,9 +131,9 @@ func TestTCPSynSentUnreachable6(t *testing.T) {
Payload: []byte{0, 0, 0, 0},
}
layers = append(layers, &icmpv6, ip, tcp)
rawConn.SendFrameStateless(layers)
rawConn.SendFrameStateless(t, layers)
if _, err = dut.ConnectWithErrno(ctx, clientFD, &sa); err != syscall.Errno(unix.ENETUNREACH) {
if _, err = dut.ConnectWithErrno(ctx, t, clientFD, &sa); err != syscall.Errno(unix.ENETUNREACH) {
t.Errorf("expected connect to fail with ENETUNREACH, but got %v", err)
}
}
@@ -31,12 +31,12 @@ func init() {
func TestTcpNoAcceptCloseReset(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFd, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
listenFd, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
conn.Connect()
defer conn.Close()
dut.Close(listenFd)
if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst | header.TCPFlagAck)}, 1*time.Second); err != nil {
conn.Connect(t)
defer conn.Close(t)
dut.Close(t, listenFd)
if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst | header.TCPFlagAck)}, 1*time.Second); err != nil {
t.Fatalf("expected a RST-ACK packet but got none: %s", err)
}
}
@@ -63,25 +63,25 @@ func TestTCPOutsideTheWindow(t *testing.T) {
t.Run(fmt.Sprintf("%s%d", tt.description, tt.seqNumOffset), func(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFD, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFD)
listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFD)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
conn.Connect()
acceptFD, _ := dut.Accept(listenFD)
defer dut.Close(acceptFD)
defer conn.Close(t)
conn.Connect(t)
acceptFD, _ := dut.Accept(t, listenFD)
defer dut.Close(t, acceptFD)
windowSize := seqnum.Size(*conn.SynAck().WindowSize) + tt.seqNumOffset
conn.Drain()
windowSize := seqnum.Size(*conn.SynAck(t).WindowSize) + tt.seqNumOffset
conn.Drain(t)
// Ignore whatever incrementing that this out-of-order packet might cause
// to the AckNum.
localSeqNum := testbench.Uint32(uint32(*conn.LocalSeqNum()))
conn.Send(testbench.TCP{
localSeqNum := testbench.Uint32(uint32(*conn.LocalSeqNum(t)))
conn.Send(t, testbench.TCP{
Flags: testbench.Uint8(tt.tcpFlags),
SeqNum: testbench.Uint32(uint32(conn.LocalSeqNum().Add(windowSize))),
SeqNum: testbench.Uint32(uint32(conn.LocalSeqNum(t).Add(windowSize))),
}, tt.payload...)
timeout := 3 * time.Second
gotACK, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), AckNum: localSeqNum}, timeout)
gotACK, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), AckNum: localSeqNum}, timeout)
if tt.expectACK && err != nil {
t.Fatalf("expected an ACK packet within %s but got none: %s", timeout, err)
}
@@ -32,15 +32,15 @@ func init() {
func TestPAWSMechanism(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFD, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFD)
listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFD)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
defer conn.Close(t)
options := make([]byte, header.TCPOptionTSLength)
header.EncodeTSOption(currentTS(), 0, options)
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn), Options: options})
synAck, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn | header.TCPFlagAck)}, time.Second)
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn), Options: options})
synAck, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn | header.TCPFlagAck)}, time.Second)
if err != nil {
t.Fatalf("didn't get synack during handshake: %s", err)
}
@@ -50,9 +50,9 @@ func TestPAWSMechanism(t *testing.T) {
}
tsecr := parsedSynOpts.TSVal
header.EncodeTSOption(currentTS(), tsecr, options)
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), Options: options})
acceptFD, _ := dut.Accept(listenFD)
defer dut.Close(acceptFD)
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), Options: options})
acceptFD, _ := dut.Accept(t, listenFD)
defer dut.Close(t, acceptFD)
sampleData := []byte("Sample Data")
sentTSVal := currentTS()
@@ -61,9 +61,9 @@ func TestPAWSMechanism(t *testing.T) {
// every time we send one, it should not cause any flakiness because timestamps
// only need to be non-decreasing.
time.Sleep(3 * time.Millisecond)
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), Options: options}, &testbench.Payload{Bytes: sampleData})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), Options: options}, &testbench.Payload{Bytes: sampleData})
gotTCP, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second)
gotTCP, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second)
if err != nil {
t.Fatalf("expected an ACK but got none: %s", err)
}
@@ -86,9 +86,9 @@ func TestPAWSMechanism(t *testing.T) {
// 3ms here is chosen arbitrarily and this time.Sleep() should not cause flakiness
// due to the exact same reasoning discussed above.
time.Sleep(3 * time.Millisecond)
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), Options: options}, &testbench.Payload{Bytes: sampleData})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck), Options: options}, &testbench.Payload{Bytes: sampleData})
gotTCP, err = conn.Expect(testbench.TCP{AckNum: lastAckNum, Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second)
gotTCP, err = conn.Expect(t, testbench.TCP{AckNum: lastAckNum, Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second)
if err != nil {
t.Fatalf("expected segment with AckNum %d but got none: %s", lastAckNum, err)
}
@@ -52,26 +52,26 @@ func TestQueueReceiveInSynSent(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
socket, remotePort := dut.CreateBoundSocket(unix.SOCK_STREAM, unix.IPPROTO_TCP, net.ParseIP(testbench.RemoteIPv4))
socket, remotePort := dut.CreateBoundSocket(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, net.ParseIP(testbench.RemoteIPv4))
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
defer conn.Close(t)
sampleData := []byte("Sample Data")
dut.SetNonBlocking(socket, true)
if _, err := dut.ConnectWithErrno(context.Background(), socket, conn.LocalAddr()); !errors.Is(err, syscall.EINPROGRESS) {
dut.SetNonBlocking(t, socket, true)
if _, err := dut.ConnectWithErrno(context.Background(), t, socket, conn.LocalAddr(t)); !errors.Is(err, syscall.EINPROGRESS) {
t.Fatalf("failed to bring DUT to SYN-SENT, got: %s, want EINPROGRESS", err)
}
if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn)}, time.Second); err != nil {
if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn)}, time.Second); err != nil {
t.Fatalf("expected a SYN from DUT, but got none: %s", err)
}
if _, _, err := dut.RecvWithErrno(context.Background(), socket, int32(len(sampleData)), 0); err != syscall.Errno(unix.EWOULDBLOCK) {
if _, _, err := dut.RecvWithErrno(context.Background(), t, socket, int32(len(sampleData)), 0); err != syscall.Errno(unix.EWOULDBLOCK) {
t.Fatalf("expected error %s, got %s", syscall.Errno(unix.EWOULDBLOCK), err)
}
// Test blocking read.
dut.SetNonBlocking(socket, false)
dut.SetNonBlocking(t, socket, false)
var wg sync.WaitGroup
defer wg.Wait()
@@ -86,7 +86,7 @@ func TestQueueReceiveInSynSent(t *testing.T) {
block.Done()
// Issue RECEIVE call in SYN-SENT, this should be queued for
// process until the connection is established.
n, buff, err := dut.RecvWithErrno(ctx, socket, int32(len(sampleData)), 0)
n, buff, err := dut.RecvWithErrno(ctx, t, socket, int32(len(sampleData)), 0)
if tt.reset {
if err != syscall.Errno(unix.ECONNREFUSED) {
t.Errorf("expected error %s, got %s", syscall.Errno(unix.ECONNREFUSED), err)
@@ -112,19 +112,19 @@ func TestQueueReceiveInSynSent(t *testing.T) {
time.Sleep(100 * time.Millisecond)
if tt.reset {
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst | header.TCPFlagAck)})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst | header.TCPFlagAck)})
return
}
// Bring the connection to Established.
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn | header.TCPFlagAck)})
if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second); err != nil {
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn | header.TCPFlagAck)})
if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second); err != nil {
t.Fatalf("expected an ACK from DUT, but got none: %s", err)
}
// Send sample payload and expect an ACK.
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, &testbench.Payload{Bytes: sampleData})
if _, err := conn.Expect(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second); err != nil {
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, &testbench.Payload{Bytes: sampleData})
if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)}, time.Second); err != nil {
t.Fatalf("expected an ACK from DUT, but got none: %s", err)
}
})
+24 -24
View File
@@ -32,10 +32,10 @@ func init() {
func TestReorderingWindow(t *testing.T) {
dut := tb.NewDUT(t)
defer dut.TearDown()
listenFd, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFd)
listenFd, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFd)
conn := tb.NewTCPIPv4(t, tb.TCP{DstPort: &remotePort}, tb.TCP{SrcPort: &remotePort})
defer conn.Close()
defer conn.Close(t)
// Enable SACK.
opts := make([]byte, 40)
@@ -49,17 +49,17 @@ func TestReorderingWindow(t *testing.T) {
const mss = minMTU - header.IPv4MinimumSize - header.TCPMinimumSize
optsOff += header.EncodeMSSOption(mss, opts[optsOff:])
conn.ConnectWithOptions(opts[:optsOff])
conn.ConnectWithOptions(t, opts[:optsOff])
acceptFd, _ := dut.Accept(listenFd)
defer dut.Close(acceptFd)
acceptFd, _ := dut.Accept(t, listenFd)
defer dut.Close(t, acceptFd)
if tb.DUTType == "linux" {
// Linux has changed its handling of reordering, force the old behavior.
dut.SetSockOpt(acceptFd, unix.IPPROTO_TCP, unix.TCP_CONGESTION, []byte("reno"))
dut.SetSockOpt(t, acceptFd, unix.IPPROTO_TCP, unix.TCP_CONGESTION, []byte("reno"))
}
pls := dut.GetSockOptInt(acceptFd, unix.IPPROTO_TCP, unix.TCP_MAXSEG)
pls := dut.GetSockOptInt(t, acceptFd, unix.IPPROTO_TCP, unix.TCP_MAXSEG)
if tb.DUTType == "netstack" {
// netstack does not impliment TCP_MAXSEG correctly. Fake it
// here. Netstack uses the max SACK size which is 32. The MSS
@@ -69,13 +69,13 @@ func TestReorderingWindow(t *testing.T) {
payload := make([]byte, pls)
seqNum1 := *conn.RemoteSeqNum()
seqNum1 := *conn.RemoteSeqNum(t)
const numPkts = 10
// Send some packets, checking that we receive each.
for i, sn := 0, seqNum1; i < numPkts; i++ {
dut.Send(acceptFd, payload, 0)
dut.Send(t, acceptFd, payload, 0)
gotOne, err := conn.Expect(tb.TCP{SeqNum: tb.Uint32(uint32(sn))}, time.Second)
gotOne, err := conn.Expect(t, tb.TCP{SeqNum: tb.Uint32(uint32(sn))}, time.Second)
sn.UpdateForward(seqnum.Size(len(payload)))
if err != nil {
t.Errorf("Expect #%d: %s", i+1, err)
@@ -86,7 +86,7 @@ func TestReorderingWindow(t *testing.T) {
}
}
seqNum2 := *conn.RemoteSeqNum()
seqNum2 := *conn.RemoteSeqNum(t)
// SACK packets #2-4.
sackBlock := make([]byte, 40)
@@ -97,13 +97,13 @@ func TestReorderingWindow(t *testing.T) {
seqNum1.Add(seqnum.Size(len(payload))),
seqNum1.Add(seqnum.Size(4 * len(payload))),
}}, sackBlock[sbOff:])
conn.Send(tb.TCP{Flags: tb.Uint8(header.TCPFlagAck), AckNum: tb.Uint32(uint32(seqNum1)), Options: sackBlock[:sbOff]})
conn.Send(t, tb.TCP{Flags: tb.Uint8(header.TCPFlagAck), AckNum: tb.Uint32(uint32(seqNum1)), Options: sackBlock[:sbOff]})
// ACK first packet.
conn.Send(tb.TCP{Flags: tb.Uint8(header.TCPFlagAck), AckNum: tb.Uint32(uint32(seqNum1) + uint32(len(payload)))})
conn.Send(t, tb.TCP{Flags: tb.Uint8(header.TCPFlagAck), AckNum: tb.Uint32(uint32(seqNum1) + uint32(len(payload)))})
// Check for retransmit.
gotOne, err := conn.Expect(tb.TCP{SeqNum: tb.Uint32(uint32(seqNum1))}, time.Second)
gotOne, err := conn.Expect(t, tb.TCP{SeqNum: tb.Uint32(uint32(seqNum1))}, time.Second)
if err != nil {
t.Error("Expect for retransmit:", err)
}
@@ -123,14 +123,14 @@ func TestReorderingWindow(t *testing.T) {
seqNum1.Add(seqnum.Size(4 * len(payload))),
}}, dsackBlock[dsbOff:])
conn.Send(tb.TCP{Flags: tb.Uint8(header.TCPFlagAck), AckNum: tb.Uint32(uint32(seqNum2)), Options: dsackBlock[:dsbOff]})
conn.Send(t, tb.TCP{Flags: tb.Uint8(header.TCPFlagAck), AckNum: tb.Uint32(uint32(seqNum2)), Options: dsackBlock[:dsbOff]})
// Send half of the original window of packets, checking that we
// received each.
for i, sn := 0, seqNum2; i < numPkts/2; i++ {
dut.Send(acceptFd, payload, 0)
dut.Send(t, acceptFd, payload, 0)
gotOne, err := conn.Expect(tb.TCP{SeqNum: tb.Uint32(uint32(sn))}, time.Second)
gotOne, err := conn.Expect(t, tb.TCP{SeqNum: tb.Uint32(uint32(sn))}, time.Second)
sn.UpdateForward(seqnum.Size(len(payload)))
if err != nil {
t.Errorf("Expect #%d: %s", i+1, err)
@@ -144,8 +144,8 @@ func TestReorderingWindow(t *testing.T) {
if tb.DUTType == "netstack" {
// The window should now be halved, so we should receive any
// more, even if we send them.
dut.Send(acceptFd, payload, 0)
if got, err := conn.Expect(tb.TCP{}, 100*time.Millisecond); got != nil || err == nil {
dut.Send(t, acceptFd, payload, 0)
if got, err := conn.Expect(t, tb.TCP{}, 100*time.Millisecond); got != nil || err == nil {
t.Fatalf("expected no packets within 100 millisecond, but got one: %s", got)
}
return
@@ -153,9 +153,9 @@ func TestReorderingWindow(t *testing.T) {
// Linux reduces the window by three. Check that we can receive the rest.
for i, sn := 0, seqNum2.Add(seqnum.Size(numPkts/2*len(payload))); i < 2; i++ {
dut.Send(acceptFd, payload, 0)
dut.Send(t, acceptFd, payload, 0)
gotOne, err := conn.Expect(tb.TCP{SeqNum: tb.Uint32(uint32(sn))}, time.Second)
gotOne, err := conn.Expect(t, tb.TCP{SeqNum: tb.Uint32(uint32(sn))}, time.Second)
sn.UpdateForward(seqnum.Size(len(payload)))
if err != nil {
t.Errorf("Expect #%d: %s", i+1, err)
@@ -167,8 +167,8 @@ func TestReorderingWindow(t *testing.T) {
}
// The window should now be full.
dut.Send(acceptFd, payload, 0)
if got, err := conn.Expect(tb.TCP{}, 100*time.Millisecond); got != nil || err == nil {
dut.Send(t, acceptFd, payload, 0)
if got, err := conn.Expect(t, tb.TCP{}, 100*time.Millisecond); got != nil || err == nil {
t.Fatalf("expected no packets within 100 millisecond, but got one: %s", got)
}
}
+14 -14
View File
@@ -33,41 +33,41 @@ func init() {
func TestRetransmits(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFd, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFd)
listenFd, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFd)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
defer conn.Close(t)
conn.Connect()
acceptFd, _ := dut.Accept(listenFd)
defer dut.Close(acceptFd)
conn.Connect(t)
acceptFd, _ := dut.Accept(t, listenFd)
defer dut.Close(t, acceptFd)
dut.SetSockOptInt(acceptFd, unix.IPPROTO_TCP, unix.TCP_NODELAY, 1)
dut.SetSockOptInt(t, acceptFd, unix.IPPROTO_TCP, unix.TCP_NODELAY, 1)
sampleData := []byte("Sample Data")
samplePayload := &testbench.Payload{Bytes: sampleData}
dut.Send(acceptFd, sampleData, 0)
if _, err := conn.ExpectData(&testbench.TCP{}, samplePayload, time.Second); err != nil {
dut.Send(t, acceptFd, sampleData, 0)
if _, err := conn.ExpectData(t, &testbench.TCP{}, samplePayload, time.Second); err != nil {
t.Fatalf("expected payload was not received: %s", err)
}
// Give a chance for the dut to estimate RTO with RTT from the DATA-ACK.
// TODO(gvisor.dev/issue/2685) Estimate RTO during handshake, after which
// we can skip sending this ACK.
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
startRTO := time.Second
current := startRTO
first := time.Now()
dut.Send(acceptFd, sampleData, 0)
seq := testbench.Uint32(uint32(*conn.RemoteSeqNum()))
if _, err := conn.ExpectData(&testbench.TCP{SeqNum: seq}, samplePayload, startRTO); err != nil {
dut.Send(t, acceptFd, sampleData, 0)
seq := testbench.Uint32(uint32(*conn.RemoteSeqNum(t)))
if _, err := conn.ExpectData(t, &testbench.TCP{SeqNum: seq}, samplePayload, startRTO); err != nil {
t.Fatalf("expected payload was not received: %s", err)
}
// Expect retransmits of the same segment.
for i := 0; i < 5; i++ {
start := time.Now()
if _, err := conn.ExpectData(&testbench.TCP{SeqNum: seq}, samplePayload, 2*current); err != nil {
if _, err := conn.ExpectData(t, &testbench.TCP{SeqNum: seq}, samplePayload, 2*current); err != nil {
t.Fatalf("expected payload was not received: %s loop %d", err, i)
}
if i == 0 {
@@ -61,23 +61,23 @@ func TestSendWindowSizesPiggyback(t *testing.T) {
t.Run(fmt.Sprintf("%s%d", tt.description, tt.windowSize), func(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFd, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFd)
listenFd, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFd)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort, WindowSize: testbench.Uint16(tt.windowSize)}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
defer conn.Close(t)
conn.Connect()
acceptFd, _ := dut.Accept(listenFd)
defer dut.Close(acceptFd)
conn.Connect(t)
acceptFd, _ := dut.Accept(t, listenFd)
defer dut.Close(t, acceptFd)
dut.SetSockOptInt(acceptFd, unix.IPPROTO_TCP, unix.TCP_NODELAY, 1)
dut.SetSockOptInt(t, acceptFd, unix.IPPROTO_TCP, unix.TCP_NODELAY, 1)
expectedTCP := testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagPsh)}
dut.Send(acceptFd, sampleData, 0)
dut.Send(t, acceptFd, sampleData, 0)
expectedPayload := testbench.Payload{Bytes: tt.expectedPayload1}
if _, err := conn.ExpectData(&expectedTCP, &expectedPayload, time.Second); err != nil {
if _, err := conn.ExpectData(t, &expectedTCP, &expectedPayload, time.Second); err != nil {
t.Fatalf("expected payload was not received: %s", err)
}
@@ -86,18 +86,18 @@ func TestSendWindowSizesPiggyback(t *testing.T) {
if tt.enqueue {
// Enqueue a segment for the dut to transmit.
dut.Send(acceptFd, sampleData, 0)
dut.Send(t, acceptFd, sampleData, 0)
}
// Send ACK for the previous segment along with data for the dut to
// receive and ACK back. Sending this ACK would make room for the dut
// to transmit any enqueued segment.
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagPsh), WindowSize: testbench.Uint16(tt.windowSize)}, &testbench.Payload{Bytes: sampleData})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck | header.TCPFlagPsh), WindowSize: testbench.Uint16(tt.windowSize)}, &testbench.Payload{Bytes: sampleData})
// Expect the dut to piggyback the ACK for received data along with
// the segment enqueued for transmit.
expectedPayload = testbench.Payload{Bytes: tt.expectedPayload2}
if _, err := conn.ExpectData(&expectedTCP, &expectedPayload, time.Second); err != nil {
if _, err := conn.ExpectData(t, &expectedTCP, &expectedPayload, time.Second); err != nil {
t.Fatalf("expected payload was not received: %s", err)
}
})
@@ -32,21 +32,21 @@ func init() {
func TestTCPSynRcvdReset(t *testing.T) {
dut := testbench.NewDUT(t)
defer dut.TearDown()
listenFD, remotePort := dut.CreateListener(unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(listenFD)
listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
defer dut.Close(t, listenFD)
conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
defer conn.Close()
defer conn.Close(t)
// Expect dut connection to have transitioned to SYN-RCVD state.
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn)})
if _, err := conn.ExpectData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn | header.TCPFlagAck)}, nil, time.Second); err != nil {
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn)})
if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.Uint8(header.TCPFlagSyn | header.TCPFlagAck)}, nil, time.Second); err != nil {
t.Fatalf("expected SYN-ACK %s", err)
}
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst)})
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst)})
// Expect the connection to have transitioned SYN-RCVD to CLOSED.
// TODO(gvisor.dev/issue/478): Check for TCP_INFO on the dut side.
conn.Send(testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
if _, err := conn.ExpectData(&testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst)}, nil, time.Second); err != nil {
conn.Send(t, testbench.TCP{Flags: testbench.Uint8(header.TCPFlagAck)})
if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.Uint8(header.TCPFlagRst)}, nil, time.Second); err != nil {
t.Fatalf("expected a TCP RST %s", err)
}
}

Some files were not shown because too many files have changed in this diff Show More