diff options
Diffstat (limited to 'test/packetimpact')
-rw-r--r-- | test/packetimpact/testbench/BUILD | 2 | ||||
-rw-r--r-- | test/packetimpact/testbench/dut.go | 33 | ||||
-rw-r--r-- | test/packetimpact/testbench/layers.go | 62 | ||||
-rw-r--r-- | test/packetimpact/testbench/layers_test.go | 2 | ||||
-rw-r--r-- | test/packetimpact/tests/BUILD | 7 | ||||
-rw-r--r-- | test/packetimpact/tests/icmpv6_param_problem_test.go | 7 | ||||
-rw-r--r-- | test/packetimpact/tests/ipv6_unknown_options_action_test.go | 20 | ||||
-rw-r--r-- | test/packetimpact/tests/tcp_connect_icmp_error_test.go | 19 | ||||
-rw-r--r-- | test/packetimpact/tests/tcp_info_test.go | 18 | ||||
-rw-r--r-- | test/packetimpact/tests/tcp_network_unreachable_test.go | 57 | ||||
-rw-r--r-- | test/packetimpact/tests/tcp_rack_test.go | 16 | ||||
-rw-r--r-- | test/packetimpact/tests/tcp_retransmits_test.go | 10 | ||||
-rw-r--r-- | test/packetimpact/tests/tcp_synsent_reset_test.go | 19 | ||||
-rw-r--r-- | test/packetimpact/tests/udp_icmp_error_propagation_test.go | 29 |
14 files changed, 143 insertions, 158 deletions
diff --git a/test/packetimpact/testbench/BUILD b/test/packetimpact/testbench/BUILD index 616215dc3..d8059ab98 100644 --- a/test/packetimpact/testbench/BUILD +++ b/test/packetimpact/testbench/BUILD @@ -16,6 +16,8 @@ go_library( ], visibility = ["//test/packetimpact:__subpackages__"], deps = [ + "//pkg/abi/linux", + "//pkg/binary", "//pkg/hostarch", "//pkg/tcpip", "//pkg/tcpip/buffer", diff --git a/test/packetimpact/testbench/dut.go b/test/packetimpact/testbench/dut.go index eabdc8cb3..269e163bb 100644 --- a/test/packetimpact/testbench/dut.go +++ b/test/packetimpact/testbench/dut.go @@ -22,11 +22,13 @@ import ( "testing" "time" - pb "gvisor.dev/gvisor/test/packetimpact/proto/posix_server_go_proto" - "golang.org/x/sys/unix" "google.golang.org/grpc" "google.golang.org/grpc/keepalive" + "gvisor.dev/gvisor/pkg/abi/linux" + bin "gvisor.dev/gvisor/pkg/binary" + "gvisor.dev/gvisor/pkg/hostarch" + pb "gvisor.dev/gvisor/test/packetimpact/proto/posix_server_go_proto" ) // DUT communicates with the DUT to force it to make POSIX calls. @@ -428,6 +430,33 @@ func (dut *DUT) GetSockOptTimevalWithErrno(ctx context.Context, t *testing.T, so return ret, timeval, errno } +// GetSockOptTCPInfo retreives TCPInfo for the given socket descriptor. +func (dut *DUT) GetSockOptTCPInfo(t *testing.T, sockfd int32) linux.TCPInfo { + t.Helper() + + ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout) + defer cancel() + ret, info, err := dut.GetSockOptTCPInfoWithErrno(ctx, t, sockfd) + if ret != 0 || err != unix.Errno(0) { + t.Fatalf("failed to GetSockOptTCPInfo: %s", err) + } + return info +} + +// GetSockOptTCPInfoWithErrno retreives TCPInfo with any errno. +func (dut *DUT) GetSockOptTCPInfoWithErrno(ctx context.Context, t *testing.T, sockfd int32) (int32, linux.TCPInfo, error) { + t.Helper() + + info := linux.TCPInfo{} + ret, infoBytes, errno := dut.GetSockOptWithErrno(ctx, t, sockfd, unix.SOL_TCP, unix.TCP_INFO, int32(linux.SizeOfTCPInfo)) + if got, want := len(infoBytes), linux.SizeOfTCPInfo; got != want { + t.Fatalf("expected %T, got %d bytes want %d bytes", info, got, want) + } + bin.Unmarshal(infoBytes, hostarch.ByteOrder, &info) + + return ret, info, errno +} + // Listen calls listen on the DUT and causes a fatal test failure if it doesn't // succeed. If more control over the timeout or error handling is needed, use // ListenWithErrno. diff --git a/test/packetimpact/testbench/layers.go b/test/packetimpact/testbench/layers.go index 2311f7686..ef8b63db4 100644 --- a/test/packetimpact/testbench/layers.go +++ b/test/packetimpact/testbench/layers.go @@ -824,6 +824,7 @@ type ICMPv6 struct { Type *header.ICMPv6Type Code *header.ICMPv6Code Checksum *uint16 + Pointer *uint32 // Only in Parameter Problem. Payload []byte } @@ -835,7 +836,7 @@ func (l *ICMPv6) String() string { // ToBytes implements Layer.ToBytes. func (l *ICMPv6) ToBytes() ([]byte, error) { - b := make([]byte, header.ICMPv6HeaderSize+len(l.Payload)) + b := make([]byte, header.ICMPv6MinimumSize+len(l.Payload)) h := header.ICMPv6(b) if l.Type != nil { h.SetType(*l.Type) @@ -843,27 +844,30 @@ func (l *ICMPv6) ToBytes() ([]byte, error) { if l.Code != nil { h.SetCode(*l.Code) } - if n := copy(h.MessageBody(), l.Payload); n != len(l.Payload) { + if n := copy(h.Payload(), l.Payload); n != len(l.Payload) { panic(fmt.Sprintf("copied %d bytes, expected to copy %d bytes", n, len(l.Payload))) } + typ := h.Type() + switch typ { + case header.ICMPv6ParamProblem: + if l.Pointer != nil { + h.SetTypeSpecific(*l.Pointer) + } + } if l.Checksum != nil { h.SetChecksum(*l.Checksum) } else { // It is possible that the ICMPv6 header does not follow the IPv6 header // immediately, there could be one or more extension headers in between. - // We need to search forward to find the IPv6 header. - for prev := l.Prev(); prev != nil; prev = prev.Prev() { - if ipv6, ok := prev.(*IPv6); ok { - payload, err := payload(l) - if err != nil { - return nil, err - } + // We need to search backwards to find the IPv6 header. + for layer := l.Prev(); layer != nil; layer = layer.Prev() { + if ipv6, ok := layer.(*IPv6); ok { h.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ - Header: h, + Header: h[:header.ICMPv6PayloadOffset], Src: *ipv6.SrcAddr, Dst: *ipv6.DstAddr, - PayloadCsum: header.ChecksumVV(payload, 0 /* initial */), - PayloadLen: payload.Size(), + PayloadCsum: header.Checksum(l.Payload, 0 /* initial */), + PayloadLen: len(l.Payload), })) break } @@ -884,20 +888,19 @@ func ICMPv6Code(v header.ICMPv6Code) *header.ICMPv6Code { return &v } -// Byte is a helper routine that allocates a new byte value to store -// v and returns a pointer to it. -func Byte(v byte) *byte { - return &v -} - // parseICMPv6 parses the bytes assuming that they start with an ICMPv6 header. func parseICMPv6(b []byte) (Layer, layerParser) { h := header.ICMPv6(b) + msgType := h.Type() icmpv6 := ICMPv6{ - Type: ICMPv6Type(h.Type()), + Type: ICMPv6Type(msgType), Code: ICMPv6Code(h.Code()), Checksum: Uint16(h.Checksum()), - Payload: h.MessageBody(), + Payload: h.Payload(), + } + switch msgType { + case header.ICMPv6ParamProblem: + icmpv6.Pointer = Uint32(h.TypeSpecific()) } return &icmpv6, nil } @@ -907,7 +910,7 @@ func (l *ICMPv6) match(other Layer) bool { } func (l *ICMPv6) length() int { - return header.ICMPv6HeaderSize + len(l.Payload) + return header.ICMPv6MinimumSize + len(l.Payload) } // merge overrides the values in l with the values from other but only in fields @@ -954,8 +957,8 @@ func (l *ICMPv4) ToBytes() ([]byte, error) { if l.Code != nil { h.SetCode(*l.Code) } - if copied := copy(h.Payload(), l.Payload); copied != len(l.Payload) { - panic(fmt.Sprintf("wrong number of bytes copied into h.Payload(): got = %d, want = %d", len(h.Payload()), len(l.Payload))) + if n := copy(h.Payload(), l.Payload); n != len(l.Payload) { + panic(fmt.Sprintf("wrong number of bytes copied into h.Payload(): got = %d, want = %d", n, len(l.Payload))) } typ := h.Type() switch typ { @@ -977,16 +980,7 @@ func (l *ICMPv4) ToBytes() ([]byte, error) { if l.Checksum != nil { h.SetChecksum(*l.Checksum) } else { - // Compute the checksum based on the ICMPv4.Payload and also the subsequent - // layers. - payload, err := payload(l) - if err != nil { - return nil, err - } - var vv buffer.VectorisedView - vv.AppendView(buffer.View(l.Payload)) - vv.Append(payload) - h.SetChecksum(header.ICMPv4Checksum(h, header.ChecksumVV(vv, 0 /* initial */))) + h.SetChecksum(^header.Checksum(h, 0)) } return h, nil @@ -1019,7 +1013,7 @@ func (l *ICMPv4) match(other Layer) bool { } func (l *ICMPv4) length() int { - return header.ICMPv4MinimumSize + return header.ICMPv4MinimumSize + len(l.Payload) } // merge overrides the values in l with the values from other but only in fields diff --git a/test/packetimpact/testbench/layers_test.go b/test/packetimpact/testbench/layers_test.go index 614a5de1e..bc96e0c88 100644 --- a/test/packetimpact/testbench/layers_test.go +++ b/test/packetimpact/testbench/layers_test.go @@ -596,7 +596,7 @@ func TestIPv6ExtHdrOptions(t *testing.T) { Type: ICMPv6Type(header.ICMPv6ParamProblem), Code: ICMPv6Code(header.ICMPv6ErroneousHeader), Checksum: Uint16(0x5f98), - Payload: []byte{0x00, 0x00, 0x00, 0x06}, + Pointer: Uint32(6), }, }, }, diff --git a/test/packetimpact/tests/BUILD b/test/packetimpact/tests/BUILD index c4fe293e0..b1d280f98 100644 --- a/test/packetimpact/tests/BUILD +++ b/test/packetimpact/tests/BUILD @@ -104,8 +104,6 @@ packetimpact_testbench( srcs = ["tcp_retransmits_test.go"], deps = [ "//pkg/abi/linux", - "//pkg/binary", - "//pkg/hostarch", "//pkg/tcpip/header", "//test/packetimpact/testbench", "@org_golang_x_sys//unix:go_default_library", @@ -189,6 +187,7 @@ packetimpact_testbench( name = "tcp_synsent_reset", srcs = ["tcp_synsent_reset_test.go"], deps = [ + "//pkg/abi/linux", "//pkg/tcpip/header", "//test/packetimpact/testbench", "@org_golang_x_sys//unix:go_default_library", @@ -353,8 +352,6 @@ packetimpact_testbench( srcs = ["tcp_rack_test.go"], deps = [ "//pkg/abi/linux", - "//pkg/binary", - "//pkg/hostarch", "//pkg/tcpip/header", "//pkg/tcpip/seqnum", "//test/packetimpact/testbench", @@ -367,8 +364,6 @@ packetimpact_testbench( srcs = ["tcp_info_test.go"], deps = [ "//pkg/abi/linux", - "//pkg/binary", - "//pkg/hostarch", "//pkg/tcpip/header", "//test/packetimpact/testbench", "@org_golang_x_sys//unix:go_default_library", diff --git a/test/packetimpact/tests/icmpv6_param_problem_test.go b/test/packetimpact/tests/icmpv6_param_problem_test.go index 1beccb6cf..fdabcf1ad 100644 --- a/test/packetimpact/tests/icmpv6_param_problem_test.go +++ b/test/packetimpact/tests/icmpv6_param_problem_test.go @@ -15,7 +15,6 @@ package icmpv6_param_problem_test import ( - "encoding/binary" "flag" "testing" "time" @@ -56,13 +55,11 @@ func TestICMPv6ParamProblemTest(t *testing.T) { t.Fatalf("can't convert %s to bytes: %s", ipv6Sent, err) } - // The problematic field is the NextHeader. - b := make([]byte, 4) - binary.BigEndian.PutUint32(b, header.IPv6NextHeaderOffset) - expectedPayload = append(b, expectedPayload...) expectedICMPv6 := testbench.ICMPv6{ Type: testbench.ICMPv6Type(header.ICMPv6ParamProblem), Payload: expectedPayload, + // The problematic field is the NextHeader. + Pointer: testbench.Uint32(header.IPv6NextHeaderOffset), } paramProblem := testbench.Layers{ diff --git a/test/packetimpact/tests/ipv6_unknown_options_action_test.go b/test/packetimpact/tests/ipv6_unknown_options_action_test.go index f999d13d2..d762c43a7 100644 --- a/test/packetimpact/tests/ipv6_unknown_options_action_test.go +++ b/test/packetimpact/tests/ipv6_unknown_options_action_test.go @@ -15,7 +15,6 @@ package ipv6_unknown_options_action_test import ( - "encoding/binary" "flag" "net" "testing" @@ -154,23 +153,22 @@ func TestIPv6UnknownOptionAction(t *testing.T) { outgoing := conn.CreateFrame(t, outgoingOverride, tt.mkExtHdr(optionTypeFromAction(tt.action))) conn.SendFrame(t, outgoing) ipv6Sent := outgoing[1:] - invokingPacket, err := ipv6Sent.ToBytes() + icmpv6Payload, err := ipv6Sent.ToBytes() if err != nil { t.Fatalf("failed to serialize the outgoing packet: %s", err) } - icmpv6Payload := make([]byte, 4) - // The pointer in the ICMPv6 parameter problem message should point to - // the option type of the unknown option. In our test case, it is the - // first option in the extension header whose option type is 2 bytes - // after the IPv6 header (after NextHeader and ExtHdrLen). - binary.BigEndian.PutUint32(icmpv6Payload, header.IPv6MinimumSize+2) - icmpv6Payload = append(icmpv6Payload, invokingPacket...) gotICMPv6, err := conn.ExpectFrame(t, testbench.Layers{ &testbench.Ether{}, &testbench.IPv6{}, &testbench.ICMPv6{ - Type: testbench.ICMPv6Type(header.ICMPv6ParamProblem), - Code: testbench.ICMPv6Code(header.ICMPv6UnknownOption), + Type: testbench.ICMPv6Type(header.ICMPv6ParamProblem), + Code: testbench.ICMPv6Code(header.ICMPv6UnknownOption), + // The pointer in the ICMPv6 parameter problem message + // should point to the option type of the unknown option. In + // our test case, it is the first option in the extension + // header whose option type is 2 bytes after the IPv6 header + // (after NextHeader and ExtHdrLen). + Pointer: testbench.Uint32(header.IPv6MinimumSize + 2), Payload: icmpv6Payload, }, }, time.Second) diff --git a/test/packetimpact/tests/tcp_connect_icmp_error_test.go b/test/packetimpact/tests/tcp_connect_icmp_error_test.go index 79bfe9eb7..3b4c4cd63 100644 --- a/test/packetimpact/tests/tcp_connect_icmp_error_test.go +++ b/test/packetimpact/tests/tcp_connect_icmp_error_test.go @@ -33,17 +33,18 @@ func init() { func sendICMPError(t *testing.T, conn *testbench.TCPIPv4, tcp *testbench.TCP) { t.Helper() - layers := conn.CreateFrame(t, nil) - layers = layers[:len(layers)-1] - ip, ok := tcp.Prev().(*testbench.IPv4) - if !ok { - t.Fatalf("expected %s to be IPv4", tcp.Prev()) + icmpPayload := testbench.Layers{tcp.Prev(), tcp} + bytes, err := icmpPayload.ToBytes() + if err != nil { + t.Fatalf("got icmpPayload.ToBytes() = (_, %s), want = (_, nil)", err) } - icmpErr := &testbench.ICMPv4{ - Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), - Code: testbench.ICMPv4Code(header.ICMPv4HostUnreachable)} - layers = append(layers, icmpErr, ip, tcp) + layers := conn.CreateFrame(t, nil) + layers[len(layers)-1] = &testbench.ICMPv4{ + Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), + Code: testbench.ICMPv4Code(header.ICMPv4HostUnreachable), + Payload: bytes, + } conn.SendFrameStateless(t, layers) } diff --git a/test/packetimpact/tests/tcp_info_test.go b/test/packetimpact/tests/tcp_info_test.go index 93f58ec49..b7514e846 100644 --- a/test/packetimpact/tests/tcp_info_test.go +++ b/test/packetimpact/tests/tcp_info_test.go @@ -21,8 +21,6 @@ import ( "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/binary" - "gvisor.dev/gvisor/pkg/hostarch" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/test/packetimpact/testbench" ) @@ -53,13 +51,10 @@ func TestTCPInfo(t *testing.T) { } conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}) - info := linux.TCPInfo{} - infoBytes := dut.GetSockOpt(t, acceptFD, unix.SOL_TCP, unix.TCP_INFO, int32(linux.SizeOfTCPInfo)) - if got, want := len(infoBytes), linux.SizeOfTCPInfo; got != want { - t.Fatalf("expected %T, got %d bytes want %d bytes", info, got, want) + info := dut.GetSockOptTCPInfo(t, acceptFD) + if got, want := uint32(info.State), linux.TCP_ESTABLISHED; got != want { + t.Fatalf("got %d want %d", got, want) } - binary.Unmarshal(infoBytes, hostarch.ByteOrder, &info) - rtt := time.Duration(info.RTT) * time.Microsecond rttvar := time.Duration(info.RTTVar) * time.Microsecond rto := time.Duration(info.RTO) * time.Microsecond @@ -94,12 +89,7 @@ func TestTCPInfo(t *testing.T) { t.Fatalf("expected a packet with payload %v: %s", samplePayload, err) } - info = linux.TCPInfo{} - infoBytes = dut.GetSockOpt(t, acceptFD, unix.SOL_TCP, unix.TCP_INFO, int32(linux.SizeOfTCPInfo)) - if got, want := len(infoBytes), linux.SizeOfTCPInfo; got != want { - t.Fatalf("expected %T, got %d bytes want %d bytes", info, got, want) - } - binary.Unmarshal(infoBytes, hostarch.ByteOrder, &info) + info = dut.GetSockOptTCPInfo(t, acceptFD) if info.CaState != linux.TCP_CA_Loss { t.Errorf("expected the connection to be in loss recovery, got: %v want: %v", info.CaState, linux.TCP_CA_Loss) } diff --git a/test/packetimpact/tests/tcp_network_unreachable_test.go b/test/packetimpact/tests/tcp_network_unreachable_test.go index 5168450ad..60a2dbf3d 100644 --- a/test/packetimpact/tests/tcp_network_unreachable_test.go +++ b/test/packetimpact/tests/tcp_network_unreachable_test.go @@ -50,30 +50,24 @@ func TestTCPSynSentUnreachable(t *testing.T) { } // Get the SYN. - tcpLayers, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}, nil, time.Second) + tcp, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}, time.Second) if err != nil { t.Fatalf("expected SYN: %s", err) } // Send a host unreachable message. - layers := conn.CreateFrame(t, nil) - layers = layers[:len(layers)-1] - const ipLayer = 1 - const tcpLayer = ipLayer + 1 - ip, ok := tcpLayers[ipLayer].(*testbench.IPv4) - if !ok { - t.Fatalf("expected %s to be IPv4", tcpLayers[ipLayer]) - } - tcp, ok := tcpLayers[tcpLayer].(*testbench.TCP) - if !ok { - t.Fatalf("expected %s to be TCP", tcpLayers[tcpLayer]) - } - var icmpv4 testbench.ICMPv4 = testbench.ICMPv4{ - Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), - Code: testbench.ICMPv4Code(header.ICMPv4HostUnreachable), + icmpPayload := testbench.Layers{tcp.Prev(), tcp} + bytes, err := icmpPayload.ToBytes() + if err != nil { + t.Fatalf("got icmpPayload.ToBytes() = (_, %s), want = (_, nil)", err) } - layers = append(layers, &icmpv4, ip, tcp) + layers := conn.CreateFrame(t, nil) + layers[len(layers)-1] = &testbench.ICMPv4{ + Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), + Code: testbench.ICMPv4Code(header.ICMPv4HostUnreachable), + Payload: bytes, + } conn.SendFrameStateless(t, layers) if err := getConnectError(t, &dut, clientFD); err != unix.EHOSTUNREACH { @@ -104,31 +98,24 @@ func TestTCPSynSentUnreachable6(t *testing.T) { } // Get the SYN. - tcpLayers, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}, nil, time.Second) + tcp, err := conn.Expect(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}, time.Second) if err != nil { t.Fatalf("expected SYN: %s", err) } // Send a host unreachable message. - layers := conn.CreateFrame(t, nil) - layers = layers[:len(layers)-1] - const ipLayer = 1 - const tcpLayer = ipLayer + 1 - ip, ok := tcpLayers[ipLayer].(*testbench.IPv6) - if !ok { - t.Fatalf("expected %s to be IPv6", tcpLayers[ipLayer]) - } - tcp, ok := tcpLayers[tcpLayer].(*testbench.TCP) - if !ok { - t.Fatalf("expected %s to be TCP", tcpLayers[tcpLayer]) + icmpPayload := testbench.Layers{tcp.Prev(), tcp} + bytes, err := icmpPayload.ToBytes() + if err != nil { + t.Fatalf("got icmpPayload.ToBytes() = (_, %s), want = (_, nil)", err) } - var icmpv6 testbench.ICMPv6 = testbench.ICMPv6{ - Type: testbench.ICMPv6Type(header.ICMPv6DstUnreachable), - Code: testbench.ICMPv6Code(header.ICMPv6NetworkUnreachable), - // Per RFC 4443 3.1, the payload contains 4 zeroed bytes. - Payload: []byte{0, 0, 0, 0}, + + layers := conn.CreateFrame(t, nil) + layers[len(layers)-1] = &testbench.ICMPv6{ + Type: testbench.ICMPv6Type(header.ICMPv6DstUnreachable), + Code: testbench.ICMPv6Code(header.ICMPv6NetworkUnreachable), + Payload: bytes, } - layers = append(layers, &icmpv6, ip, tcp) conn.SendFrameStateless(t, layers) if err := getConnectError(t, &dut, clientFD); err != unix.ENETUNREACH { diff --git a/test/packetimpact/tests/tcp_rack_test.go b/test/packetimpact/tests/tcp_rack_test.go index ff1431bbf..5a60bf712 100644 --- a/test/packetimpact/tests/tcp_rack_test.go +++ b/test/packetimpact/tests/tcp_rack_test.go @@ -21,8 +21,6 @@ import ( "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/binary" - "gvisor.dev/gvisor/pkg/hostarch" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/seqnum" "gvisor.dev/gvisor/test/packetimpact/testbench" @@ -69,12 +67,7 @@ func closeSACKConnection(t *testing.T, dut testbench.DUT, conn testbench.TCPIPv4 } func getRTTAndRTO(t *testing.T, dut testbench.DUT, acceptFd int32) (rtt, rto time.Duration) { - info := linux.TCPInfo{} - infoBytes := dut.GetSockOpt(t, acceptFd, unix.SOL_TCP, unix.TCP_INFO, int32(linux.SizeOfTCPInfo)) - if got, want := len(infoBytes), linux.SizeOfTCPInfo; got != want { - t.Fatalf("expected %T, got %d bytes want %d bytes", info, got, want) - } - binary.Unmarshal(infoBytes, hostarch.ByteOrder, &info) + info := dut.GetSockOptTCPInfo(t, acceptFd) return time.Duration(info.RTT) * time.Microsecond, time.Duration(info.RTO) * time.Microsecond } @@ -402,12 +395,7 @@ func TestRACKWithLostRetransmission(t *testing.T) { } // Check the congestion control state. - info := linux.TCPInfo{} - infoBytes := dut.GetSockOpt(t, acceptFd, unix.SOL_TCP, unix.TCP_INFO, int32(linux.SizeOfTCPInfo)) - if got, want := len(infoBytes), linux.SizeOfTCPInfo; got != want { - t.Fatalf("expected %T, got %d bytes want %d bytes", info, got, want) - } - binary.Unmarshal(infoBytes, hostarch.ByteOrder, &info) + info := dut.GetSockOptTCPInfo(t, acceptFd) if info.CaState != linux.TCP_CA_Recovery { t.Fatalf("expected connection to be in fast recovery, want: %v got: %v", linux.TCP_CA_Recovery, info.CaState) } diff --git a/test/packetimpact/tests/tcp_retransmits_test.go b/test/packetimpact/tests/tcp_retransmits_test.go index 1eafe20c3..d3fb789f4 100644 --- a/test/packetimpact/tests/tcp_retransmits_test.go +++ b/test/packetimpact/tests/tcp_retransmits_test.go @@ -21,9 +21,6 @@ import ( "time" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/binary" - "gvisor.dev/gvisor/pkg/hostarch" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/test/packetimpact/testbench" ) @@ -33,12 +30,7 @@ func init() { } func getRTO(t *testing.T, dut testbench.DUT, acceptFd int32) (rto time.Duration) { - info := linux.TCPInfo{} - infoBytes := dut.GetSockOpt(t, acceptFd, unix.SOL_TCP, unix.TCP_INFO, int32(linux.SizeOfTCPInfo)) - if got, want := len(infoBytes), linux.SizeOfTCPInfo; got != want { - t.Fatalf("unexpected size for TCP_INFO, got %d bytes want %d bytes", got, want) - } - binary.Unmarshal(infoBytes, hostarch.ByteOrder, &info) + info := dut.GetSockOptTCPInfo(t, acceptFd) return time.Duration(info.RTO) * time.Microsecond } diff --git a/test/packetimpact/tests/tcp_synsent_reset_test.go b/test/packetimpact/tests/tcp_synsent_reset_test.go index cccb0abc6..fe53e7061 100644 --- a/test/packetimpact/tests/tcp_synsent_reset_test.go +++ b/test/packetimpact/tests/tcp_synsent_reset_test.go @@ -20,6 +20,7 @@ import ( "time" "golang.org/x/sys/unix" + "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/test/packetimpact/testbench" ) @@ -29,7 +30,7 @@ func init() { } // dutSynSentState sets up the dut connection in SYN-SENT state. -func dutSynSentState(t *testing.T) (*testbench.DUT, *testbench.TCPIPv4, uint16, uint16) { +func dutSynSentState(t *testing.T) (*testbench.DUT, *testbench.TCPIPv4, int32, uint16, uint16) { t.Helper() dut := testbench.NewDUT(t) @@ -46,26 +47,29 @@ func dutSynSentState(t *testing.T) (*testbench.DUT, *testbench.TCPIPv4, uint16, t.Fatalf("expected SYN\n") } - return &dut, &conn, port, clientPort + return &dut, &conn, clientFD, port, clientPort } // TestTCPSynSentReset tests RFC793, p67: SYN-SENT to CLOSED transition. func TestTCPSynSentReset(t *testing.T) { - _, conn, _, _ := dutSynSentState(t) + dut, conn, fd, _, _ := dutSynSentState(t) defer conn.Close(t) conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagRst | header.TCPFlagAck)}) // Expect the connection to have closed. - // TODO(gvisor.dev/issue/478): Check for TCP_INFO on the dut side. conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}) if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagRst)}, nil, time.Second); err != nil { t.Fatalf("expected a TCP RST") } + info := dut.GetSockOptTCPInfo(t, fd) + if got, want := uint32(info.State), linux.TCP_CLOSE; got != want { + t.Fatalf("got %d want %d", got, want) + } } // TestTCPSynSentRcvdReset tests RFC793, p70, SYN-SENT to SYN-RCVD to CLOSED // transitions. func TestTCPSynSentRcvdReset(t *testing.T) { - dut, c, remotePort, clientPort := dutSynSentState(t) + dut, c, fd, remotePort, clientPort := dutSynSentState(t) defer c.Close(t) conn := dut.Net.NewTCPIPv4(t, testbench.TCP{SrcPort: &remotePort, DstPort: &clientPort}, testbench.TCP{SrcPort: &clientPort, DstPort: &remotePort}) @@ -79,9 +83,12 @@ func TestTCPSynSentRcvdReset(t *testing.T) { } conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(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(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}) if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagRst)}, nil, time.Second); err != nil { t.Fatalf("expected a TCP RST") } + info := dut.GetSockOptTCPInfo(t, fd) + if got, want := uint32(info.State), linux.TCP_CLOSE; got != want { + t.Fatalf("got %d want %d", got, want) + } } diff --git a/test/packetimpact/tests/udp_icmp_error_propagation_test.go b/test/packetimpact/tests/udp_icmp_error_propagation_test.go index 3159d5b89..087aeb66e 100644 --- a/test/packetimpact/tests/udp_icmp_error_propagation_test.go +++ b/test/packetimpact/tests/udp_icmp_error_propagation_test.go @@ -58,16 +58,20 @@ func (e icmpError) String() string { return "Unknown ICMP error" } -func (e icmpError) ToICMPv4() *testbench.ICMPv4 { +func (e icmpError) ToICMPv4(payload []byte) *testbench.ICMPv4 { switch e { case portUnreachable: return &testbench.ICMPv4{ - Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), - Code: testbench.ICMPv4Code(header.ICMPv4PortUnreachable)} + Type: testbench.ICMPv4Type(header.ICMPv4DstUnreachable), + Code: testbench.ICMPv4Code(header.ICMPv4PortUnreachable), + Payload: payload, + } case timeToLiveExceeded: return &testbench.ICMPv4{ - Type: testbench.ICMPv4Type(header.ICMPv4TimeExceeded), - Code: testbench.ICMPv4Code(header.ICMPv4TTLExceeded)} + Type: testbench.ICMPv4Type(header.ICMPv4TimeExceeded), + Code: testbench.ICMPv4Code(header.ICMPv4TTLExceeded), + Payload: payload, + } } return nil } @@ -101,8 +105,6 @@ func wantErrno(c connectionMode, icmpErr icmpError) unix.Errno { func sendICMPError(t *testing.T, conn *testbench.UDPIPv4, icmpErr icmpError, udp *testbench.UDP) { t.Helper() - layers := conn.CreateFrame(t, nil) - layers = layers[:len(layers)-1] ip, ok := udp.Prev().(*testbench.IPv4) if !ok { t.Fatalf("expected %s to be IPv4", udp.Prev()) @@ -113,12 +115,15 @@ func sendICMPError(t *testing.T, conn *testbench.UDPIPv4, icmpErr icmpError, udp // to 1. ip.Checksum = nil } - // Note that the ICMP payload is valid in this case because the UDP - // payload is empty. If the UDP payload were not empty, the packet - // length during serialization may not be calculated correctly, - // resulting in a mal-formed packet. - layers = append(layers, icmpErr.ToICMPv4(), ip, udp) + icmpPayload := testbench.Layers{ip, udp} + bytes, err := icmpPayload.ToBytes() + if err != nil { + t.Fatalf("got icmpPayload.ToBytes() = (_, %s), want = (_, nil)", err) + } + + layers := conn.CreateFrame(t, nil) + layers[len(layers)-1] = icmpErr.ToICMPv4(bytes) conn.SendFrameStateless(t, layers) } |