github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/packetimpact/tests/tcp_info_test.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tcp_info_test 16 17 import ( 18 "flag" 19 "testing" 20 "time" 21 22 "golang.org/x/sys/unix" 23 "github.com/SagerNet/gvisor/pkg/abi/linux" 24 "github.com/SagerNet/gvisor/pkg/tcpip/header" 25 "github.com/SagerNet/gvisor/test/packetimpact/testbench" 26 ) 27 28 func init() { 29 testbench.Initialize(flag.CommandLine) 30 } 31 32 func TestTCPInfo(t *testing.T) { 33 // Create a socket, listen, TCP connect, and accept. 34 dut := testbench.NewDUT(t) 35 listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1) 36 defer dut.Close(t, listenFD) 37 38 conn := dut.Net.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort}) 39 defer conn.Close(t) 40 conn.Connect(t) 41 42 acceptFD, _ := dut.Accept(t, listenFD) 43 defer dut.Close(t, acceptFD) 44 45 // Send and receive sample data. 46 sampleData := []byte("Sample Data") 47 samplePayload := &testbench.Payload{Bytes: sampleData} 48 dut.Send(t, acceptFD, sampleData, 0) 49 if _, err := conn.ExpectData(t, &testbench.TCP{}, samplePayload, time.Second); err != nil { 50 t.Fatalf("expected a packet with payload %s: %s", samplePayload, err) 51 } 52 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}) 53 54 info := dut.GetSockOptTCPInfo(t, acceptFD) 55 if got, want := uint32(info.State), linux.TCP_ESTABLISHED; got != want { 56 t.Fatalf("got %d want %d", got, want) 57 } 58 if info.RTT == 0 { 59 t.Errorf("got RTT=0, want nonzero") 60 } 61 if info.RTTVar == 0 { 62 t.Errorf("got RTTVar=0, want nonzero") 63 } 64 if info.RTO == 0 { 65 t.Errorf("got RTO=0, want nonzero") 66 } 67 if info.ReordSeen != 0 { 68 t.Errorf("expected the connection to not have any reordering, got: %d want: 0", info.ReordSeen) 69 } 70 if info.SndCwnd == 0 { 71 t.Errorf("expected send congestion window to be greater than zero") 72 } 73 if info.CaState != linux.TCP_CA_Open { 74 t.Errorf("expected the connection to be in open state, got: %d want: %d", info.CaState, linux.TCP_CA_Open) 75 } 76 77 if t.Failed() { 78 t.FailNow() 79 } 80 81 // Check the congestion control state and send congestion window after 82 // retransmission timeout. 83 seq := testbench.Uint32(uint32(*conn.RemoteSeqNum(t))) 84 dut.Send(t, acceptFD, sampleData, 0) 85 if _, err := conn.ExpectData(t, &testbench.TCP{}, samplePayload, time.Second); err != nil { 86 t.Fatalf("expected a packet with payload %s: %s", samplePayload, err) 87 } 88 89 // Given a generous retransmission timeout. 90 timeout := time.Duration(info.RTO) * 2 * time.Microsecond 91 if _, err := conn.ExpectData(t, &testbench.TCP{SeqNum: seq}, samplePayload, timeout); err != nil { 92 t.Fatalf("expected a packet with payload %s: %s", samplePayload, err) 93 } 94 95 info = dut.GetSockOptTCPInfo(t, acceptFD) 96 if info.CaState != linux.TCP_CA_Loss { 97 t.Errorf("expected the connection to be in loss recovery, got: %d want: %d", info.CaState, linux.TCP_CA_Loss) 98 } 99 if info.SndCwnd != 1 { 100 t.Errorf("expected send congestion window to be 1, got: %d", info.SndCwnd) 101 } 102 }