From 67f261a87d42118d2f587c9a8d20d94972e47498 Mon Sep 17 00:00:00 2001 From: Mithun Iyer Date: Mon, 15 Jun 2020 16:18:25 -0700 Subject: TCP to honor updated window size during handshake. In passive open cases, we transition to Established state after initializing endpoint's sender and receiver. With this we lose out on any updates coming from the ACK that completes the handshake. This change ensures that we uniformly transition to Established in all cases and does minor cleanups. Fixes #2938 PiperOrigin-RevId: 316567014 --- test/packetimpact/tests/BUILD | 10 ++++ .../tests/tcp_handshake_window_size_test.go | 66 ++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 test/packetimpact/tests/tcp_handshake_window_size_test.go (limited to 'test') diff --git a/test/packetimpact/tests/BUILD b/test/packetimpact/tests/BUILD index 95dd6c440..09e91b832 100644 --- a/test/packetimpact/tests/BUILD +++ b/test/packetimpact/tests/BUILD @@ -232,6 +232,16 @@ packetimpact_go_test( ], ) +packetimpact_go_test( + name = "tcp_handshake_window_size", + srcs = ["tcp_handshake_window_size_test.go"], + deps = [ + "//pkg/tcpip/header", + "//test/packetimpact/testbench", + "@org_golang_x_sys//unix:go_default_library", + ], +) + packetimpact_go_test( name = "icmpv6_param_problem", srcs = ["icmpv6_param_problem_test.go"], diff --git a/test/packetimpact/tests/tcp_handshake_window_size_test.go b/test/packetimpact/tests/tcp_handshake_window_size_test.go new file mode 100644 index 000000000..652b530d0 --- /dev/null +++ b/test/packetimpact/tests/tcp_handshake_window_size_test.go @@ -0,0 +1,66 @@ +// Copyright 2020 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 tcp_handshake_window_size_test + +import ( + "flag" + "testing" + "time" + + "golang.org/x/sys/unix" + "gvisor.dev/gvisor/pkg/tcpip/header" + "gvisor.dev/gvisor/test/packetimpact/testbench" +) + +func init() { + testbench.RegisterFlags(flag.CommandLine) +} + +// TestTCPHandshakeWindowSize tests if the stack is honoring the window size +// communicated during handshake. +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) + conn := testbench.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort}) + defer conn.Close() + + // 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 { + t.Fatalf("expected SYN-ACK: %s", err) + } + // Update the advertised window size to a non-zero value with the ACK that + // completes the handshake. + // + // 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))}) + + acceptFd, _ := dut.Accept(listenFD) + defer dut.Close(acceptFd) + + sampleData := []byte("Sample Data") + samplePayload := &testbench.Payload{Bytes: sampleData} + + // 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 { + t.Fatalf("expected payload was not received: %s", err) + } +} -- cgit v1.2.3