diff --git a/.buildkite/pipeline.yaml b/.buildkite/pipeline.yaml index 1a8eac749..d11a31675 100644 --- a/.buildkite/pipeline.yaml +++ b/.buildkite/pipeline.yaml @@ -36,7 +36,7 @@ _templates: ./pkg/tcpip/transport/icmp ./pkg/tcpip/transport/tcp ./pkg/tcpip/transport/udp - ./pkg/buffer + ./pkg/bufferv2 ./pkg/waiter env: # Force a clean checkout every time to avoid reuse of files between runs. diff --git a/pkg/bufferv2/buffer.go b/pkg/bufferv2/buffer.go index a4105dbd4..39aa72c38 100644 --- a/pkg/bufferv2/buffer.go +++ b/pkg/bufferv2/buffer.go @@ -206,6 +206,10 @@ func (b *Buffer) Prepend(src *View) error { if src == nil { return nil } + if src.Size() == 0 { + src.Release() + return nil + } // If the first buffer does not have room just prepend the view. v := b.data.Front() if v == nil || v.read == 0 { @@ -251,6 +255,10 @@ func (b *Buffer) Append(src *View) error { if src == nil { return nil } + if src.Size() == 0 { + src.Release() + return nil + } // If the last buffer is full, just append the view. v := b.data.Back() if v.Full() { @@ -377,8 +385,6 @@ func (b *Buffer) PullUp(offset, length int) (View, bool) { func (b *Buffer) Flatten() []byte { if v := b.data.Front(); v == nil { return nil // No data at all. - } else if v.Next() == nil { - return v.AsSlice() // Only one buffer. } data := make([]byte, 0, b.size) // Need to flatten. for v := b.data.Front(); v != nil; v = v.Next() { diff --git a/pkg/bufferv2/buffer_state.go b/pkg/bufferv2/buffer_state.go index d558a1d1b..378611c82 100644 --- a/pkg/bufferv2/buffer_state.go +++ b/pkg/bufferv2/buffer_state.go @@ -14,13 +14,12 @@ package bufferv2 -// saveBuf is invoked by stateify. +// saveData is invoked by stateify. func (b *Buffer) saveData() []byte { return b.Flatten() } -// loadBuf is invoked by stateify. +// loadData is invoked by stateify. func (b *Buffer) loadData(data []byte) { - v := NewViewWithData(data) - b.Append(v) + *b = MakeWithData(data) } diff --git a/pkg/bufferv2/chunk.go b/pkg/bufferv2/chunk.go index b88eceb2b..4c62216ea 100644 --- a/pkg/bufferv2/chunk.go +++ b/pkg/bufferv2/chunk.go @@ -77,6 +77,8 @@ func getChunkPool(size int) *sync.Pool { } // Chunk represents a slice of pooled memory. +// +// +stateify savable type chunk struct { chunkRefs data []byte diff --git a/pkg/bufferv2/view.go b/pkg/bufferv2/view.go index 7fcd5dbff..fa7c5739a 100644 --- a/pkg/bufferv2/view.go +++ b/pkg/bufferv2/view.go @@ -45,11 +45,13 @@ var viewPool = sync.Pool{ // Users must not write directly to slices returned by AsSlice. Instead, they // must use Write/WriteAt/CopyIn to modify the underlying View. This preserves // the safety guarantees of copy-on-write. +// +// +stateify savable type View struct { - viewEntry - read int - write int - chunk *chunk + viewEntry `state:"nosave"` + read int + write int + chunk *chunk } // NewView creates a new view with capacity at least as big as cap. It is @@ -107,6 +109,15 @@ func (v *View) Release() { viewPool.Put(v) } +// Reset sets the view's read and write indices back to zero. +func (v *View) Reset() { + if v == nil { + panic("cannot reset a nil view") + } + v.read = 0 + v.write = 0 +} + func (v *View) sharesChunk() bool { return v.chunk.refCount.Load() > 1 } @@ -144,7 +155,7 @@ func (v *View) TrimFront(n int) { // AsSlice returns a slice of the data written to this view. func (v *View) AsSlice() []byte { - if v == nil { + if v.Size() == 0 { return nil } return v.chunk.data[v.read:v.write] @@ -173,6 +184,16 @@ func (v *View) Read(p []byte) (int, error) { return n, nil } +// ReadByte implements the io.ByteReader interface. +func (v *View) ReadByte() (byte, error) { + if v.Size() == 0 { + return 0, io.EOF + } + b := v.AsSlice()[0] + v.read++ + return b, nil +} + // WriteTo writes data to w until the view is empty or an error occurs. The // return value n is the number of bytes written. // diff --git a/pkg/sentry/devices/tundev/BUILD b/pkg/sentry/devices/tundev/BUILD index a2fc2917e..dde02478e 100644 --- a/pkg/sentry/devices/tundev/BUILD +++ b/pkg/sentry/devices/tundev/BUILD @@ -8,6 +8,7 @@ go_library( visibility = ["//pkg/sentry:internal"], deps = [ "//pkg/abi/linux", + "//pkg/bufferv2", "//pkg/context", "//pkg/errors/linuxerr", "//pkg/hostarch", diff --git a/pkg/sentry/devices/tundev/tundev.go b/pkg/sentry/devices/tundev/tundev.go index 1849fdaf8..738b7ebc1 100644 --- a/pkg/sentry/devices/tundev/tundev.go +++ b/pkg/sentry/devices/tundev/tundev.go @@ -16,8 +16,11 @@ package tundev import ( + "io" + "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/hostarch" @@ -125,8 +128,11 @@ func (fd *tunFD) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.Read if err != nil { return 0, err } - n, err := dst.CopyOut(ctx, data) - if n > 0 && n < len(data) { + defer data.Release() + + size := data.Size() + n, err := io.CopyN(dst.Writer(ctx), data, dst.NumBytes()) + if n > 0 && n < int64(size) { // Not an error for partial copying. Packet truncated. err = nil } @@ -150,8 +156,8 @@ func (fd *tunFD) Write(ctx context.Context, src usermem.IOSequence, opts vfs.Wri if int64(mtu) < src.NumBytes() { return 0, unix.EMSGSIZE } - data := make([]byte, src.NumBytes()) - if _, err := src.CopyIn(ctx, data); err != nil { + data := bufferv2.NewView(int(src.NumBytes())) + if _, err := io.CopyN(data, src.Reader(ctx), src.NumBytes()); err != nil { return 0, err } return fd.device.Write(data) diff --git a/pkg/sentry/fs/dev/BUILD b/pkg/sentry/fs/dev/BUILD index 5fb5acaae..92a8535d4 100644 --- a/pkg/sentry/fs/dev/BUILD +++ b/pkg/sentry/fs/dev/BUILD @@ -17,6 +17,7 @@ go_library( visibility = ["//pkg/sentry:internal"], deps = [ "//pkg/abi/linux", + "//pkg/bufferv2", "//pkg/context", "//pkg/errors/linuxerr", "//pkg/hostarch", diff --git a/pkg/sentry/fs/dev/net_tun.go b/pkg/sentry/fs/dev/net_tun.go index c5b7871cc..d2f2281c2 100644 --- a/pkg/sentry/fs/dev/net_tun.go +++ b/pkg/sentry/fs/dev/net_tun.go @@ -15,8 +15,11 @@ package dev import ( + "io" + "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/hostarch" @@ -135,8 +138,8 @@ func (n *netTunFileOperations) Write(ctx context.Context, file *fs.File, src use if src.NumBytes() == 0 { return 0, unix.EINVAL } - data := make([]byte, src.NumBytes()) - if _, err := src.CopyIn(ctx, data); err != nil { + data := bufferv2.NewView(int(src.NumBytes())) + if _, err := io.CopyN(data, src.Reader(ctx), src.NumBytes()); err != nil { return 0, err } return n.device.Write(data) @@ -148,8 +151,10 @@ func (n *netTunFileOperations) Read(ctx context.Context, file *fs.File, dst user if err != nil { return 0, err } - bytesCopied, err := dst.CopyOut(ctx, data) - if bytesCopied > 0 && bytesCopied < len(data) { + defer data.Release() + dataSize := data.Size() + bytesCopied, err := io.CopyN(dst.Writer(ctx), data, dst.NumBytes()) + if bytesCopied > 0 && bytesCopied < int64(dataSize) { // Not an error for partial copying. Packet truncated. err = nil } diff --git a/pkg/sentry/socket/netfilter/tcp_matcher.go b/pkg/sentry/socket/netfilter/tcp_matcher.go index a621a6a16..df4ff97c3 100644 --- a/pkg/sentry/socket/netfilter/tcp_matcher.go +++ b/pkg/sentry/socket/netfilter/tcp_matcher.go @@ -98,7 +98,7 @@ func (*TCPMatcher) name() string { func (tm *TCPMatcher) Match(hook stack.Hook, pkt *stack.PacketBuffer, _, _ string) (bool, bool) { switch pkt.NetworkProtocolNumber { case header.IPv4ProtocolNumber: - netHeader := header.IPv4(pkt.NetworkHeader().View()) + netHeader := header.IPv4(pkt.NetworkHeader().Slice()) if netHeader.TransportProtocol() != header.TCPProtocolNumber { return false, false } @@ -115,7 +115,7 @@ func (tm *TCPMatcher) Match(hook stack.Hook, pkt *stack.PacketBuffer, _, _ strin // As in Linux, we do not perform an IPv6 fragment check. See // xt_action_param.fragoff in // include/linux/netfilter/x_tables.h. - if header.IPv6(pkt.NetworkHeader().View()).TransportProtocol() != header.TCPProtocolNumber { + if header.IPv6(pkt.NetworkHeader().Slice()).TransportProtocol() != header.TCPProtocolNumber { return false, false } @@ -124,7 +124,7 @@ func (tm *TCPMatcher) Match(hook stack.Hook, pkt *stack.PacketBuffer, _, _ strin return false, false } - tcpHeader := header.TCP(pkt.TransportHeader().View()) + tcpHeader := header.TCP(pkt.TransportHeader().Slice()) if len(tcpHeader) < header.TCPMinimumSize { // There's no valid TCP header here, so we drop the packet immediately. return false, true diff --git a/pkg/sentry/socket/netfilter/udp_matcher.go b/pkg/sentry/socket/netfilter/udp_matcher.go index 2ca854764..ae5a34b3a 100644 --- a/pkg/sentry/socket/netfilter/udp_matcher.go +++ b/pkg/sentry/socket/netfilter/udp_matcher.go @@ -95,7 +95,7 @@ func (*UDPMatcher) name() string { func (um *UDPMatcher) Match(hook stack.Hook, pkt *stack.PacketBuffer, _, _ string) (bool, bool) { switch pkt.NetworkProtocolNumber { case header.IPv4ProtocolNumber: - netHeader := header.IPv4(pkt.NetworkHeader().View()) + netHeader := header.IPv4(pkt.NetworkHeader().Slice()) if netHeader.TransportProtocol() != header.UDPProtocolNumber { return false, false } @@ -112,7 +112,7 @@ func (um *UDPMatcher) Match(hook stack.Hook, pkt *stack.PacketBuffer, _, _ strin // As in Linux, we do not perform an IPv6 fragment check. See // xt_action_param.fragoff in // include/linux/netfilter/x_tables.h. - if header.IPv6(pkt.NetworkHeader().View()).TransportProtocol() != header.UDPProtocolNumber { + if header.IPv6(pkt.NetworkHeader().Slice()).TransportProtocol() != header.UDPProtocolNumber { return false, false } @@ -121,7 +121,7 @@ func (um *UDPMatcher) Match(hook stack.Hook, pkt *stack.PacketBuffer, _, _ strin return false, false } - udpHeader := header.UDP(pkt.TransportHeader().View()) + udpHeader := header.UDP(pkt.TransportHeader().Slice()) if len(udpHeader) < header.UDPMinimumSize { // There's no valid UDP header here, so we drop the packet immediately. return false, true diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go index 06587cc27..59756c7d2 100644 --- a/pkg/sentry/socket/netstack/netstack.go +++ b/pkg/sentry/socket/netstack/netstack.go @@ -3001,14 +3001,17 @@ func (s *socketOpsCommon) recvErr(t *kernel.Task, dst usermem.IOSequence) (int, if sockErr == nil { return 0, 0, nil, 0, socket.ControlMessages{}, syserr.ErrTryAgain } + if sockErr.Payload != nil { + defer sockErr.Payload.Release() + } // The payload of the original packet that caused the error is passed as // normal data via msg_iovec. -- recvmsg(2) msgFlags := linux.MSG_ERRQUEUE - if int(dst.NumBytes()) < len(sockErr.Payload) { + if int(dst.NumBytes()) < sockErr.Payload.Size() { msgFlags |= linux.MSG_TRUNC } - n, err := dst.CopyOut(t, sockErr.Payload) + n, err := dst.CopyOut(t, sockErr.Payload.AsSlice()) // The original destination address of the datagram that caused the error is // supplied via msg_name. -- recvmsg(2) diff --git a/pkg/sentry/socket/unix/transport/BUILD b/pkg/sentry/socket/unix/transport/BUILD index f3bcc48cb..c1319d0e3 100644 --- a/pkg/sentry/socket/unix/transport/BUILD +++ b/pkg/sentry/socket/unix/transport/BUILD @@ -94,7 +94,7 @@ go_library( deps = [ "//pkg/abi/linux", "//pkg/atomicbitops", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/context", "//pkg/errors/linuxerr", "//pkg/fdnotifier", diff --git a/pkg/tcpip/BUILD b/pkg/tcpip/BUILD index 9e69c4c88..d3a9e8af2 100644 --- a/pkg/tcpip/BUILD +++ b/pkg/tcpip/BUILD @@ -31,6 +31,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//pkg/atomicbitops", + "//pkg/bufferv2", "//pkg/sync", "//pkg/waiter", ], @@ -47,14 +48,16 @@ deps_test( allowed = [ # gVisor deps. "//pkg/atomicbitops", + "//pkg/bits", "//pkg/context", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/cpuid", "//pkg/gohacks", "//pkg/goid", "//pkg/ilist", "//pkg/linewriter", "//pkg/log", + "//pkg/pool", "//pkg/rand", "//pkg/refs", "//pkg/refsvfs2", diff --git a/pkg/tcpip/checker/BUILD b/pkg/tcpip/checker/BUILD index a36bc2c52..6e78454fe 100644 --- a/pkg/tcpip/checker/BUILD +++ b/pkg/tcpip/checker/BUILD @@ -8,7 +8,7 @@ go_library( srcs = ["checker.go"], visibility = ["//visibility:public"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/header", "//pkg/tcpip/seqnum", diff --git a/pkg/tcpip/checker/checker.go b/pkg/tcpip/checker/checker.go index e2e72f499..cb4c79a56 100644 --- a/pkg/tcpip/checker/checker.go +++ b/pkg/tcpip/checker/checker.go @@ -23,7 +23,7 @@ import ( "time" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/seqnum" @@ -43,13 +43,13 @@ type ControlMessagesChecker func(*testing.T, tcpip.ReceivableControlMessages) // properties. For example, to check the source and destination address, one // would call: // -// checker.IPv4(t, b, checker.SrcAddr(x), checker.DstAddr(y)) -func IPv4(t *testing.T, b []byte, checkers ...NetworkChecker) { +// checker.IPv4(t, v, checker.SrcAddr(x), checker.DstAddr(y)) +func IPv4(t *testing.T, v *bufferv2.View, checkers ...NetworkChecker) { t.Helper() - ipv4 := header.IPv4(b) + ipv4 := header.IPv4(v.AsSlice()) - if !ipv4.IsValid(len(b)) { + if !ipv4.IsValid(len(v.AsSlice())) { t.Fatalf("Not a valid IPv4 packet: %x", ipv4) } @@ -67,11 +67,11 @@ func IPv4(t *testing.T, b []byte, checkers ...NetworkChecker) { // IPv6 checks the validity and properties of the given IPv6 packet. The usage // is similar to IPv4. -func IPv6(t *testing.T, b []byte, checkers ...NetworkChecker) { +func IPv6(t *testing.T, v *bufferv2.View, checkers ...NetworkChecker) { t.Helper() - ipv6 := header.IPv6(b) - if !ipv6.IsValid(len(b)) { + ipv6 := header.IPv6(v.AsSlice()) + if !ipv6.IsValid(len(v.AsSlice())) { t.Fatalf("Not a valid IPv6 packet: %x", ipv6) } @@ -1535,19 +1535,20 @@ func IGMPGroupAddress(want tcpip.Address) TransportChecker { type IPv6ExtHdrChecker func(*testing.T, header.IPv6PayloadHeader) // IPv6WithExtHdr is like IPv6 but allows IPv6 packets with extension headers. -func IPv6WithExtHdr(t *testing.T, b []byte, checkers ...NetworkChecker) { +func IPv6WithExtHdr(t *testing.T, v *bufferv2.View, checkers ...NetworkChecker) { t.Helper() - ipv6 := header.IPv6(b) - if !ipv6.IsValid(len(b)) { + ipv6 := header.IPv6(v.AsSlice()) + if !ipv6.IsValid(len(v.AsSlice())) { t.Error("not a valid IPv6 packet") return } payloadIterator := header.MakeIPv6PayloadIterator( header.IPv6ExtensionHeaderIdentifier(ipv6.NextHeader()), - buffer.NewWithData(ipv6.Payload()), + bufferv2.MakeWithData(ipv6.Payload()), ) + defer payloadIterator.Release() var rawPayloadHeader header.IPv6RawPayloadHeader for { @@ -1560,6 +1561,7 @@ func IPv6WithExtHdr(t *testing.T, b []byte, checkers ...NetworkChecker) { t.Errorf("got payloadIterator.Next() = (%T, %t, _), want = (_, true, _)", h, done) return } + defer h.Release() r, ok := h.(header.IPv6RawPayloadHeader) if ok { rawPayloadHeader = r @@ -1594,8 +1596,9 @@ func IPv6ExtHdr(headers ...IPv6ExtHdrChecker) NetworkChecker { payloadIterator := header.MakeIPv6PayloadIterator( header.IPv6ExtensionHeaderIdentifier(extHdrs.IPv6.NextHeader()), - buffer.NewWithData(extHdrs.IPv6.Payload()), + bufferv2.MakeWithData(extHdrs.IPv6.Payload()), ) + defer payloadIterator.Release() for _, check := range headers { h, done, err := payloadIterator.Next() @@ -1608,6 +1611,7 @@ func IPv6ExtHdr(headers ...IPv6ExtHdrChecker) NetworkChecker { return } check(t, h) + h.Release() } // Validate we consumed all headers. // @@ -1630,6 +1634,8 @@ func IPv6ExtHdr(headers ...IPv6ExtHdrChecker) NetworkChecker { if _, ok := h.(header.IPv6RawPayloadHeader); !ok { t.Errorf("got payloadIterator.Next() = (%T, _, _), want = (header.IPv6RawPayloadHeader, _, _)", h) continue + } else { + h.Release() } wantDone = true } @@ -1684,6 +1690,9 @@ func IPv6HopByHopExtensionHeader(checkers ...IPv6ExtHdrOptionChecker) IPv6ExtHdr t.Errorf("got optionsIterator.Next() = (%T, %t, _), want = (_, false, _)", opt, done) } f(t, opt) + if uo, ok := opt.(*header.IPv6UnknownExtHdrOption); ok { + uo.Data.Release() + } } // Validate all options were consumed. for { @@ -1698,6 +1707,9 @@ func IPv6HopByHopExtensionHeader(checkers ...IPv6ExtHdrOptionChecker) IPv6ExtHdr if done { break } + if uo, ok := opt.(*header.IPv6UnknownExtHdrOption); ok { + uo.Data.Release() + } } } } diff --git a/pkg/tcpip/header/BUILD b/pkg/tcpip/header/BUILD index 8cddf9d74..80629c9e7 100644 --- a/pkg/tcpip/header/BUILD +++ b/pkg/tcpip/header/BUILD @@ -30,7 +30,7 @@ go_library( ], visibility = ["//visibility:public"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/seqnum", "@com_github_google_btree//:go_default_library", @@ -50,7 +50,7 @@ go_test( ], deps = [ ":header", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/rand", "//pkg/tcpip", "//pkg/tcpip/prependable", @@ -70,7 +70,7 @@ go_test( ], library = ":header", deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/testutil", "@com_github_google_go_cmp//cmp:go_default_library", diff --git a/pkg/tcpip/header/checksum.go b/pkg/tcpip/header/checksum.go index eb9efdac1..419dbf217 100644 --- a/pkg/tcpip/header/checksum.go +++ b/pkg/tcpip/header/checksum.go @@ -20,7 +20,7 @@ import ( "encoding/binary" "fmt" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" ) @@ -196,10 +196,10 @@ func Checksum(buf []byte, initial uint16) uint16 { // bytes in the given Buffer. // // The initial checksum must have been computed on an even number of bytes. -func ChecksumBuffer(buf buffer.Buffer, initial uint16) uint16 { +func ChecksumBuffer(buf bufferv2.Buffer, initial uint16) uint16 { var c Checksumer - buf.Apply(func(b []byte) { - c.Add(b) + buf.Apply(func(v *bufferv2.View) { + c.Add(v.AsSlice()) }) return ChecksumCombine(initial, c.Checksum()) } diff --git a/pkg/tcpip/header/checksum_test.go b/pkg/tcpip/header/checksum_test.go index 8fff52084..0128d6de8 100644 --- a/pkg/tcpip/header/checksum_test.go +++ b/pkg/tcpip/header/checksum_test.go @@ -23,7 +23,7 @@ import ( "sync" "testing" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" ) @@ -193,6 +193,8 @@ func testICMPChecksum(t *testing.T, headerChecksum func() uint16, icmpChecksum f close(start) } +// TODO(b/239732156): Replace magic constants with names corresponding to what +// they represent ICMP. func TestICMPv4Checksum(t *testing.T) { rnd := rand.New(rand.NewSource(42)) @@ -206,8 +208,8 @@ func TestICMPv4Checksum(t *testing.T) { if _, err := rnd.Read(buf); err != nil { t.Fatalf("rnd.Read failed: %v", err) } - b := buffer.NewWithData(buf[:5]) - b.AppendOwned(buf[5:]) + b := bufferv2.MakeWithData(buf[:5]) + b.Append(bufferv2.NewViewWithData(buf[5:])) want := header.Checksum(b.Flatten(), 0) want = ^header.Checksum(h, want) @@ -231,9 +233,9 @@ func TestICMPv6Checksum(t *testing.T) { if _, err := rnd.Read(buf); err != nil { t.Fatalf("rnd.Read failed: %v", err) } - b := buffer.NewWithData(buf[:7]) - b.AppendOwned(buf[7:10]) - b.AppendOwned(buf[10:]) + b := bufferv2.MakeWithData(buf[:7]) + b.Append(bufferv2.NewViewWithData(buf[7:10])) + b.Append(bufferv2.NewViewWithData(buf[10:])) dst := header.IPv6Loopback src := header.IPv6Loopback diff --git a/pkg/tcpip/header/ipv6_extension_headers.go b/pkg/tcpip/header/ipv6_extension_headers.go index d9af133e7..ecdb01514 100644 --- a/pkg/tcpip/header/ipv6_extension_headers.go +++ b/pkg/tcpip/header/ipv6_extension_headers.go @@ -15,15 +15,13 @@ package header import ( - "bufio" - "bytes" "encoding/binary" "errors" "fmt" "io" "math" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" ) @@ -154,26 +152,44 @@ func ipv6OptionsAlignmentPadding(headerOffset int, align int, alignOffset int) i // These headers include IPv6 extension headers or upper layer data. type IPv6PayloadHeader interface { isIPv6PayloadHeader() + + // Release frees all resources held by the header. + Release() } // IPv6RawPayloadHeader the remainder of an IPv6 payload after an iterator // encounters a Next Header field it does not recognize as an IPv6 extension -// header. +// header. The caller is responsible for releasing the underlying buffer after +// it's no longer needed. type IPv6RawPayloadHeader struct { Identifier IPv6ExtensionHeaderIdentifier - Buf buffer.Buffer + Buf bufferv2.Buffer } // isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader. func (IPv6RawPayloadHeader) isIPv6PayloadHeader() {} +// Release implements IPv6PayloadHeader.Release. +func (i IPv6RawPayloadHeader) Release() { + i.Buf.Release() +} + // ipv6OptionsExtHdr is an IPv6 extension header that holds options. -type ipv6OptionsExtHdr []byte +type ipv6OptionsExtHdr struct { + buf *bufferv2.View +} + +// Release implements IPv6PayloadHeader.Release. +func (i ipv6OptionsExtHdr) Release() { + if i.buf != nil { + i.buf.Release() + } +} // Iter returns an iterator over the IPv6 extension header options held in b. -func (b ipv6OptionsExtHdr) Iter() IPv6OptionsExtHdrOptionsIterator { +func (i ipv6OptionsExtHdr) Iter() IPv6OptionsExtHdrOptionsIterator { it := IPv6OptionsExtHdrOptionsIterator{} - it.reader.Reset(b) + it.reader = i.buf return it } @@ -187,7 +203,7 @@ func (b ipv6OptionsExtHdr) Iter() IPv6OptionsExtHdrOptionsIterator { // modify the backing payload so long as the IPv6OptionsExtHdrOptionsIterator // obtained before modification is no longer used. type IPv6OptionsExtHdrOptionsIterator struct { - reader bytes.Reader + reader *bufferv2.View // optionOffset is the number of bytes from the first byte of the // options field to the beginning of the current option. @@ -283,7 +299,7 @@ var ErrMalformedIPv6ExtHdrOption = errors.New("malformed IPv6 extension header o // header option that is unknown by the parsing utilities. type IPv6UnknownExtHdrOption struct { Identifier IPv6ExtHdrOptionIdentifier - Data []byte + Data *bufferv2.View } // UnknownAction implements IPv6OptionUnknownAction.UnknownAction. @@ -335,9 +351,9 @@ func (i *IPv6OptionsExtHdrOptionsIterator) Next() (IPv6ExtHdrOption, bool, error } // Do we have enough bytes in the reader for the next option? - if n := i.reader.Len(); n < int(length) { - // Reset the reader to effectively consume the remaining buffer. - i.reader.Reset(nil) + if n := i.reader.Size(); n < int(length) { + // Consume the remaining buffer. + i.reader.TrimFront(i.reader.Size()) // We return the same error as if we failed to read a non-padding option // so consumers of this iterator don't need to differentiate between @@ -350,13 +366,11 @@ func (i *IPv6OptionsExtHdrOptionsIterator) Next() (IPv6ExtHdrOption, bool, error switch id { case ipv6PadNExtHdrOptionIdentifier: // Special-case the variable length padding option to avoid a copy. - if _, err := i.reader.Seek(int64(length), io.SeekCurrent); err != nil { - panic(fmt.Sprintf("error when skipping PadN (N = %d) option's data bytes: %s", length, err)) - } + i.reader.TrimFront(int(length)) continue case ipv6RouterAlertHopByHopOptionIdentifier: var routerAlertValue [ipv6RouterAlertPayloadLength]byte - if n, err := io.ReadFull(&i.reader, routerAlertValue[:]); err != nil { + if n, err := io.ReadFull(i.reader, routerAlertValue[:]); err != nil { switch err { case io.EOF, io.ErrUnexpectedEOF: return nil, true, fmt.Errorf("got invalid length (%d) for router alert option (want = %d): %w", length, ipv6RouterAlertPayloadLength, ErrMalformedIPv6ExtHdrOption) @@ -368,11 +382,8 @@ func (i *IPv6OptionsExtHdrOptionsIterator) Next() (IPv6ExtHdrOption, bool, error } return &IPv6RouterAlertOption{Value: IPv6RouterAlertValue(binary.BigEndian.Uint16(routerAlertValue[:]))}, false, nil default: - bytes := make([]byte, length) - if n, err := io.ReadFull(&i.reader, bytes); err != nil { - // io.ReadFull may return io.EOF if i.reader has been exhausted. We use - // io.ErrUnexpectedEOF instead as the io.EOF is unexpected given the - // Length field found in the option. + bytes := bufferv2.NewView(int(length)) + if n, err := io.CopyN(bytes, i.reader, int64(length)); err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } @@ -404,14 +415,21 @@ func (IPv6DestinationOptionsExtHdr) isIPv6PayloadHeader() {} // IPv6RoutingExtHdr is a buffer holding the Routing extension header specific // data as outlined in RFC 8200 section 4.4. -type IPv6RoutingExtHdr []byte +type IPv6RoutingExtHdr struct { + Buf *bufferv2.View +} // isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader. func (IPv6RoutingExtHdr) isIPv6PayloadHeader() {} +// Release implements IPv6PayloadHeader.Release. +func (b IPv6RoutingExtHdr) Release() { + b.Buf.Release() +} + // SegmentsLeft returns the Segments Left field. func (b IPv6RoutingExtHdr) SegmentsLeft() uint8 { - return b[ipv6RoutingExtHdrSegmentsLeftIdx] + return b.Buf.AsSlice()[ipv6RoutingExtHdrSegmentsLeftIdx] } // IPv6FragmentExtHdr is a buffer holding the Fragment extension header specific @@ -423,6 +441,9 @@ type IPv6FragmentExtHdr [6]byte // isIPv6PayloadHeader implements IPv6PayloadHeader.isIPv6PayloadHeader. func (IPv6FragmentExtHdr) isIPv6PayloadHeader() {} +// Release implements IPv6PayloadHeader.Release. +func (IPv6FragmentExtHdr) Release() {} + // FragmentOffset returns the Fragment Offset field. // // This value indicates where the buffer following the Fragment extension header @@ -467,9 +488,7 @@ type IPv6PayloadIterator struct { // The identifier of the next header to parse. nextHdrIdentifier IPv6ExtensionHeaderIdentifier - // reader is an io.Reader over payload. - reader bufio.Reader - payload buffer.Buffer + payload bufferv2.Buffer // Indicates to the iterator that it should return the remaining payload as a // raw payload on the next call to Next. @@ -500,32 +519,31 @@ func (i IPv6PayloadIterator) ParseOffset() uint32 { } // MakeIPv6PayloadIterator returns an iterator over the IPv6 payload containing -// extension headers, or a raw payload if the payload cannot be parsed. -func MakeIPv6PayloadIterator(nextHdrIdentifier IPv6ExtensionHeaderIdentifier, payload buffer.Buffer) IPv6PayloadIterator { - readers := payload.Readers() - readerPs := make([]io.Reader, 0, len(readers)) - for i := range readers { - readerPs = append(readerPs, &readers[i]) - } - +// extension headers, or a raw payload if the payload cannot be parsed. The +// iterator takes ownership of the payload. +func MakeIPv6PayloadIterator(nextHdrIdentifier IPv6ExtensionHeaderIdentifier, payload bufferv2.Buffer) IPv6PayloadIterator { return IPv6PayloadIterator{ nextHdrIdentifier: nextHdrIdentifier, - payload: payload.Clone(), - // We need a buffer of size 1 for calls to bufio.Reader.ReadByte. - reader: *bufio.NewReaderSize(io.MultiReader(readerPs...), 1), - nextOffset: IPv6FixedHeaderSize, + payload: payload, + nextOffset: IPv6FixedHeaderSize, } } +// Release frees the resources owned by the iterator. +func (i *IPv6PayloadIterator) Release() { + i.payload.Release() +} + // AsRawHeader returns the remaining payload of i as a raw header and // optionally consumes the iterator. // // If consume is true, calls to Next after calling AsRawHeader on i will -// indicate that the iterator is done. +// indicate that the iterator is done. The returned header takes ownership of +// its payload. func (i *IPv6PayloadIterator) AsRawHeader(consume bool) IPv6RawPayloadHeader { identifier := i.nextHdrIdentifier - var buf buffer.Buffer + var buf bufferv2.Buffer if consume { // Since we consume the iterator, we return the payload as is. buf = i.payload @@ -564,21 +582,21 @@ func (i *IPv6PayloadIterator) Next() (IPv6PayloadHeader, bool, error) { // Is the header we are parsing a known extension header? switch i.nextHdrIdentifier { case IPv6HopByHopOptionsExtHdrIdentifier: - nextHdrIdentifier, bytes, err := i.nextHeaderData(false /* fragmentHdr */, nil) + nextHdrIdentifier, view, err := i.nextHeaderData(false /* fragmentHdr */, nil) if err != nil { return nil, true, err } i.nextHdrIdentifier = nextHdrIdentifier - return IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: bytes}, false, nil + return IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr{view}}, false, nil case IPv6RoutingExtHdrIdentifier: - nextHdrIdentifier, bytes, err := i.nextHeaderData(false /* fragmentHdr */, nil) + nextHdrIdentifier, view, err := i.nextHeaderData(false /* fragmentHdr */, nil) if err != nil { return nil, true, err } i.nextHdrIdentifier = nextHdrIdentifier - return IPv6RoutingExtHdr(bytes), false, nil + return IPv6RoutingExtHdr{view}, false, nil case IPv6FragmentExtHdrIdentifier: var data [6]byte // We ignore the returned bytes because we know the fragment extension @@ -602,13 +620,13 @@ func (i *IPv6PayloadIterator) Next() (IPv6PayloadHeader, bool, error) { i.nextHdrIdentifier = nextHdrIdentifier return fragmentExtHdr, false, nil case IPv6DestinationOptionsExtHdrIdentifier: - nextHdrIdentifier, bytes, err := i.nextHeaderData(false /* fragmentHdr */, nil) + nextHdrIdentifier, view, err := i.nextHeaderData(false /* fragmentHdr */, nil) if err != nil { return nil, true, err } i.nextHdrIdentifier = nextHdrIdentifier - return IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr: bytes}, false, nil + return IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr{view}}, false, nil case IPv6NoNextHeaderIdentifier: // This indicates the end of the IPv6 payload. return nil, true, nil @@ -629,21 +647,20 @@ func (i *IPv6PayloadIterator) Next() (IPv6PayloadHeader, bool, error) { // If bytes is not nil, extension header specific data will be read into bytes // if it has enough capacity. If bytes is provided but does not have enough // capacity for the data, nextHeaderData will panic. -func (i *IPv6PayloadIterator) nextHeaderData(fragmentHdr bool, bytes []byte) (IPv6ExtensionHeaderIdentifier, []byte, error) { +func (i *IPv6PayloadIterator) nextHeaderData(fragmentHdr bool, bytes []byte) (IPv6ExtensionHeaderIdentifier, *bufferv2.View, error) { // We ignore the number of bytes read because we know we will only ever read // at max 1 bytes since rune has a length of 1. If we read 0 bytes, the Read // would return io.EOF to indicate that io.Reader has reached the end of the // payload. - nextHdrIdentifier, err := i.reader.ReadByte() - i.payload.TrimFront(1) + rdr := i.payload.AsBufferReader() + nextHdrIdentifier, err := rdr.ReadByte() if err != nil { return 0, nil, fmt.Errorf("error when reading the Next Header field for extension header with id = %d: %w", i.nextHdrIdentifier, err) } i.parseOffset++ var length uint8 - length, err = i.reader.ReadByte() - i.payload.TrimFront(1) + length, err = rdr.ReadByte() if err != nil { if fragmentHdr { @@ -668,19 +685,24 @@ func (i *IPv6PayloadIterator) nextHeaderData(fragmentHdr bool, bytes []byte) (IP i.nextOffset += uint32((length + 1) * ipv6ExtHdrLenBytesPerUnit) bytesLen := int(length)*ipv6ExtHdrLenBytesPerUnit + ipv6ExtHdrLenBytesExcluded - if bytes == nil { - bytes = make([]byte, bytesLen) - } else if n := len(bytes); n < bytesLen { - panic(fmt.Sprintf("bytes only has space for %d bytes but need space for %d bytes (length = %d) for extension header with id = %d", n, bytesLen, length, i.nextHdrIdentifier)) + if fragmentHdr { + if n := len(bytes); n < bytesLen { + panic(fmt.Sprintf("bytes only has space for %d bytes but need space for %d bytes (length = %d) for extension header with id = %d", n, bytesLen, length, i.nextHdrIdentifier)) + } + if n, err := io.ReadFull(&rdr, bytes); err != nil { + return 0, nil, fmt.Errorf("read %d out of %d extension header data bytes (length = %d) for header with id = %d: %w", n, bytesLen, length, i.nextHdrIdentifier, err) + } + return IPv6ExtensionHeaderIdentifier(nextHdrIdentifier), nil, nil } - - n, err := io.ReadFull(&i.reader, bytes) - i.payload.TrimFront(int64(n)) - if err != nil { + v := bufferv2.NewView(bytesLen) + if n, err := io.CopyN(v, &rdr, int64(bytesLen)); err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + v.Release() return 0, nil, fmt.Errorf("read %d out of %d extension header data bytes (length = %d) for header with id = %d: %w", n, bytesLen, length, i.nextHdrIdentifier, err) } - - return IPv6ExtensionHeaderIdentifier(nextHdrIdentifier), bytes, nil + return IPv6ExtensionHeaderIdentifier(nextHdrIdentifier), v, nil } // IPv6SerializableExtHdr provides serialization for IPv6 extension diff --git a/pkg/tcpip/header/ipv6_extension_headers_test.go b/pkg/tcpip/header/ipv6_extension_headers_test.go index dc80e76b0..4571ca701 100644 --- a/pkg/tcpip/header/ipv6_extension_headers_test.go +++ b/pkg/tcpip/header/ipv6_extension_headers_test.go @@ -21,10 +21,19 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" ) +var ( + bufferTransformer = cmp.Transformer("buffer", func(b bufferv2.Buffer) []byte { + return b.Flatten() + }) + viewTransformer = cmp.Transformer("view", func(v bufferv2.View) []byte { + return v.AsSlice() + }) +) + // Equal returns true of a and b are equivalent. // // Note, Equal will return true if a and b hold the same Identifier value and @@ -33,8 +42,8 @@ import ( // // Needed to use cmp.Equal on IPv6RawPayloadHeader as it contains unexported // fields. -func (a IPv6RawPayloadHeader) Equal(b IPv6RawPayloadHeader) bool { - return a.Identifier == b.Identifier && bytes.Equal(a.Buf.Flatten(), b.Buf.Flatten()) +func (i IPv6RawPayloadHeader) Equal(b IPv6RawPayloadHeader) bool { + return i.Identifier == b.Identifier && bytes.Equal(i.Buf.Flatten(), b.Buf.Flatten()) } // Equal returns true of a and b are equivalent. @@ -44,7 +53,7 @@ func (a IPv6RawPayloadHeader) Equal(b IPv6RawPayloadHeader) bool { // Needed to use cmp.Equal on IPv6RawPayloadHeader as it contains unexported // fields. func (a IPv6HopByHopOptionsExtHdr) Equal(b IPv6HopByHopOptionsExtHdr) bool { - return bytes.Equal(a.ipv6OptionsExtHdr, b.ipv6OptionsExtHdr) + return bytes.Equal(a.ipv6OptionsExtHdr.buf.AsSlice(), b.ipv6OptionsExtHdr.buf.AsSlice()) } // Equal returns true of a and b are equivalent. @@ -54,7 +63,7 @@ func (a IPv6HopByHopOptionsExtHdr) Equal(b IPv6HopByHopOptionsExtHdr) bool { // Needed to use cmp.Equal on IPv6RawPayloadHeader as it contains unexported // fields. func (a IPv6DestinationOptionsExtHdr) Equal(b IPv6DestinationOptionsExtHdr) bool { - return bytes.Equal(a.ipv6OptionsExtHdr, b.ipv6OptionsExtHdr) + return bytes.Equal(a.ipv6OptionsExtHdr.buf.AsSlice(), b.ipv6OptionsExtHdr.buf.AsSlice()) } func TestIPv6UnknownExtHdrOption(t *testing.T) { @@ -107,7 +116,7 @@ func TestIPv6UnknownExtHdrOption(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - opt := &IPv6UnknownExtHdrOption{Identifier: test.identifier, Data: []byte{1, 2, 3, 4}} + opt := &IPv6UnknownExtHdrOption{Identifier: test.identifier, Data: bufferv2.NewViewWithData([]byte{1, 2, 3, 4})} if a := opt.UnknownAction(); a != test.expectedUnknownAction { t.Fatalf("got UnknownAction() = %d, want = %d", a, test.expectedUnknownAction) } @@ -266,12 +275,12 @@ func TestIPv6OptionsExtHdrIterErr(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Run("Hop By Hop", func(t *testing.T) { - extHdr := IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: test.bytes} + extHdr := IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr{bufferv2.NewViewWithData(test.bytes)}} check(t, extHdr.Iter(), test.err) }) t.Run("Destination", func(t *testing.T) { - extHdr := IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr: test.bytes} + extHdr := IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr{bufferv2.NewViewWithData(test.bytes)}} check(t, extHdr.Iter(), test.err) }) }) @@ -288,14 +297,14 @@ func TestIPv6OptionsExtHdrIter(t *testing.T) { name: "Single unknown with zero length", bytes: []byte{255, 0}, expected: []IPv6ExtHdrOption{ - &IPv6UnknownExtHdrOption{Identifier: 255, Data: []byte{}}, + &IPv6UnknownExtHdrOption{Identifier: 255, Data: bufferv2.NewViewWithData([]byte{})}, }, }, { name: "Single unknown with non-zero length", bytes: []byte{255, 3, 1, 2, 3}, expected: []IPv6ExtHdrOption{ - &IPv6UnknownExtHdrOption{Identifier: 255, Data: []byte{1, 2, 3}}, + &IPv6UnknownExtHdrOption{Identifier: 255, Data: bufferv2.NewViewWithData([]byte{1, 2, 3})}, }, }, { @@ -358,9 +367,9 @@ func TestIPv6OptionsExtHdrIter(t *testing.T) { 1, 2, 1, 2, }, expected: []IPv6ExtHdrOption{ - &IPv6UnknownExtHdrOption{Identifier: 255, Data: []byte{}}, - &IPv6UnknownExtHdrOption{Identifier: 254, Data: []byte{1}}, - &IPv6UnknownExtHdrOption{Identifier: 253, Data: []byte{2, 3, 4, 5}}, + &IPv6UnknownExtHdrOption{Identifier: 255, Data: bufferv2.NewViewWithData([]byte{})}, + &IPv6UnknownExtHdrOption{Identifier: 254, Data: bufferv2.NewViewWithData([]byte{1})}, + &IPv6UnknownExtHdrOption{Identifier: 253, Data: bufferv2.NewViewWithData([]byte{2, 3, 4, 5})}, }, }, } @@ -374,7 +383,7 @@ func TestIPv6OptionsExtHdrIter(t *testing.T) { if done { t.Errorf("(i=%d) unexpectedly done iterating", i) } - if diff := cmp.Diff(e, opt); diff != "" { + if diff := cmp.Diff(e, opt, viewTransformer, bufferTransformer); diff != "" { t.Errorf("(i=%d) got option mismatch (-want +got):\n%s", i, diff) } @@ -398,12 +407,12 @@ func TestIPv6OptionsExtHdrIter(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Run("Hop By Hop", func(t *testing.T) { - extHdr := IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: test.bytes} + extHdr := IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr{bufferv2.NewViewWithData(test.bytes)}} checkIter(t, extHdr.Iter(), test.expected) }) t.Run("Destination", func(t *testing.T) { - extHdr := IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr: test.bytes} + extHdr := IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr{bufferv2.NewViewWithData(test.bytes)}} checkIter(t, extHdr.Iter(), test.expected) }) }) @@ -435,7 +444,7 @@ func TestIPv6RoutingExtHdr(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - extHdr := IPv6RoutingExtHdr(test.bytes) + extHdr := IPv6RoutingExtHdr{bufferv2.NewViewWithData(test.bytes)} if got := extHdr.SegmentsLeft(); got != test.segmentsLeft { t.Errorf("got SegmentsLeft() = %d, want = %d", got, test.segmentsLeft) } @@ -490,10 +499,10 @@ func TestIPv6FragmentExtHdr(t *testing.T) { } } -func makeBufferFromByteBuffers(bs ...[]byte) buffer.Buffer { - buf := buffer.Buffer{} +func makeBufferFromByteBuffers(bs ...[]byte) bufferv2.Buffer { + buf := bufferv2.Buffer{} for _, b := range bs { - buf.AppendOwned(b) + buf.Append(bufferv2.NewViewWithData(b)) } return buf } @@ -502,7 +511,7 @@ func TestIPv6ExtHdrIterErr(t *testing.T) { tests := []struct { name string firstNextHdr IPv6ExtensionHeaderIdentifier - payload buffer.Buffer + payload bufferv2.Buffer err error }{ { @@ -512,7 +521,7 @@ func TestIPv6ExtHdrIterErr(t *testing.T) { { name: "Upper layer only with data", firstNextHdr: 255, - payload: buffer.NewWithData([]byte{1, 2, 3, 4}), + payload: bufferv2.MakeWithData([]byte{1, 2, 3, 4}), }, { name: "No next header", @@ -521,45 +530,45 @@ func TestIPv6ExtHdrIterErr(t *testing.T) { { name: "No next header with data", firstNextHdr: IPv6NoNextHeaderIdentifier, - payload: buffer.NewWithData([]byte{1, 2, 3, 4}), + payload: bufferv2.MakeWithData([]byte{1, 2, 3, 4}), }, { name: "Valid single hop by hop", firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier, - payload: buffer.NewWithData([]byte{255, 0, 1, 4, 1, 2, 3, 4}), + payload: bufferv2.MakeWithData([]byte{255, 0, 1, 4, 1, 2, 3, 4}), }, { name: "Hop by hop too small", firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier, - payload: buffer.NewWithData([]byte{255, 0, 1, 4, 1, 2, 3}), + payload: bufferv2.MakeWithData([]byte{255, 0, 1, 4, 1, 2, 3}), err: io.ErrUnexpectedEOF, }, { name: "Valid single fragment", firstNextHdr: IPv6FragmentExtHdrIdentifier, - payload: buffer.NewWithData([]byte{255, 0, 68, 9, 128, 4, 2, 1}), + payload: bufferv2.MakeWithData([]byte{255, 0, 68, 9, 128, 4, 2, 1}), }, { name: "Fragment too small", firstNextHdr: IPv6FragmentExtHdrIdentifier, - payload: buffer.NewWithData([]byte{255, 0, 68, 9, 128, 4, 2}), + payload: bufferv2.MakeWithData([]byte{255, 0, 68, 9, 128, 4, 2}), err: io.ErrUnexpectedEOF, }, { name: "Valid single destination", firstNextHdr: IPv6DestinationOptionsExtHdrIdentifier, - payload: buffer.NewWithData([]byte{255, 0, 1, 4, 1, 2, 3, 4}), + payload: bufferv2.MakeWithData([]byte{255, 0, 1, 4, 1, 2, 3, 4}), }, { name: "Destination too small", firstNextHdr: IPv6DestinationOptionsExtHdrIdentifier, - payload: buffer.NewWithData([]byte{255, 0, 1, 4, 1, 2, 3}), + payload: bufferv2.MakeWithData([]byte{255, 0, 1, 4, 1, 2, 3}), err: io.ErrUnexpectedEOF, }, { name: "Valid single routing", firstNextHdr: IPv6RoutingExtHdrIdentifier, - payload: buffer.NewWithData([]byte{255, 0, 1, 2, 3, 4, 5, 6}), + payload: bufferv2.MakeWithData([]byte{255, 0, 1, 2, 3, 4, 5, 6}), }, { name: "Valid single routing across views", @@ -569,13 +578,13 @@ func TestIPv6ExtHdrIterErr(t *testing.T) { { name: "Routing too small with zero length field", firstNextHdr: IPv6RoutingExtHdrIdentifier, - payload: buffer.NewWithData([]byte{255, 0, 1, 2, 3, 4, 5}), + payload: bufferv2.MakeWithData([]byte{255, 0, 1, 2, 3, 4, 5}), err: io.ErrUnexpectedEOF, }, { name: "Valid routing with non-zero length field", firstNextHdr: IPv6RoutingExtHdrIdentifier, - payload: buffer.NewWithData([]byte{255, 1, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8}), + payload: bufferv2.MakeWithData([]byte{255, 1, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8}), }, { name: "Valid routing with non-zero length field across views", @@ -585,7 +594,7 @@ func TestIPv6ExtHdrIterErr(t *testing.T) { { name: "Routing too small with non-zero length field", firstNextHdr: IPv6RoutingExtHdrIdentifier, - payload: buffer.NewWithData([]byte{255, 1, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7}), + payload: bufferv2.MakeWithData([]byte{255, 1, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7}), err: io.ErrUnexpectedEOF, }, { @@ -597,7 +606,7 @@ func TestIPv6ExtHdrIterErr(t *testing.T) { { name: "Mixed", firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier, - payload: buffer.NewWithData([]byte{ + payload: bufferv2.MakeWithData([]byte{ // Hop By Hop Options extension header. uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4, @@ -619,7 +628,7 @@ func TestIPv6ExtHdrIterErr(t *testing.T) { { name: "Mixed without upper layer data", firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier, - payload: buffer.NewWithData([]byte{ + payload: bufferv2.MakeWithData([]byte{ // Hop By Hop Options extension header. uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4, @@ -638,7 +647,7 @@ func TestIPv6ExtHdrIterErr(t *testing.T) { { name: "Mixed without upper layer data but last ext hdr too small", firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier, - payload: buffer.NewWithData([]byte{ + payload: bufferv2.MakeWithData([]byte{ // Hop By Hop Options extension header. uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4, @@ -692,7 +701,7 @@ func TestIPv6ExtHdrIter(t *testing.T) { tests := []struct { name string firstNextHdr IPv6ExtensionHeaderIdentifier - payload buffer.Buffer + payload bufferv2.Buffer expected []IPv6PayloadHeader }{ // With a non-atomic fragment that is not the first fragment, the payload @@ -701,7 +710,7 @@ func TestIPv6ExtHdrIter(t *testing.T) { { name: "hopbyhop - fragment (not first) - routing - upper", firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier, - payload: buffer.NewWithData([]byte{ + payload: bufferv2.MakeWithData([]byte{ // Hop By Hop extension header. uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4, @@ -721,18 +730,18 @@ func TestIPv6ExtHdrIter(t *testing.T) { 1, 2, 3, 4, }), expected: []IPv6PayloadHeader{ - IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: []byte{1, 4, 1, 2, 3, 4}}, + IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr{bufferv2.NewViewWithData([]byte{1, 4, 1, 2, 3, 4})}}, IPv6FragmentExtHdr([6]byte{68, 9, 128, 4, 2, 1}), IPv6RawPayloadHeader{ Identifier: IPv6RoutingExtHdrIdentifier, - Buf: buffer.NewWithData(routingExtHdrWithUpperLayerData), + Buf: bufferv2.MakeWithData(routingExtHdrWithUpperLayerData), }, }, }, { name: "hopbyhop - fragment (first) - routing - upper", firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier, - payload: buffer.NewWithData([]byte{ + payload: bufferv2.MakeWithData([]byte{ // Hop By Hop extension header. uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4, @@ -748,12 +757,12 @@ func TestIPv6ExtHdrIter(t *testing.T) { 1, 2, 3, 4, }), expected: []IPv6PayloadHeader{ - IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: []byte{1, 4, 1, 2, 3, 4}}, + IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr{bufferv2.NewViewWithData([]byte{1, 4, 1, 2, 3, 4})}}, IPv6FragmentExtHdr([6]byte{0, 1, 128, 4, 2, 1}), - IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}), + IPv6RoutingExtHdr{bufferv2.NewViewWithData([]byte{1, 2, 3, 4, 5, 6})}, IPv6RawPayloadHeader{ Identifier: 255, - Buf: buffer.NewWithData(upperLayerData), + Buf: bufferv2.MakeWithData(upperLayerData), }, }, }, @@ -774,7 +783,7 @@ func TestIPv6ExtHdrIter(t *testing.T) { IPv6FragmentExtHdr([6]byte{68, 9, 128, 4, 2, 1}), IPv6RawPayloadHeader{ Identifier: IPv6RoutingExtHdrIdentifier, - Buf: buffer.NewWithData(routingExtHdrWithUpperLayerData), + Buf: bufferv2.MakeWithData(routingExtHdrWithUpperLayerData), }, }, }, @@ -784,7 +793,7 @@ func TestIPv6ExtHdrIter(t *testing.T) { { name: "atomic fragment - routing - destination - upper", firstNextHdr: IPv6FragmentExtHdrIdentifier, - payload: buffer.NewWithData([]byte{ + payload: bufferv2.MakeWithData([]byte{ // Fragment extension header. // // Reserved bits are 1 which should not affect anything. @@ -801,11 +810,11 @@ func TestIPv6ExtHdrIter(t *testing.T) { }), expected: []IPv6PayloadHeader{ IPv6FragmentExtHdr([6]byte{0, 6, 128, 4, 2, 1}), - IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}), - IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr: []byte{1, 4, 1, 2, 3, 4}}, + IPv6RoutingExtHdr{bufferv2.NewViewWithData([]byte{1, 2, 3, 4, 5, 6})}, + IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr{bufferv2.NewViewWithData([]byte{1, 4, 1, 2, 3, 4})}}, IPv6RawPayloadHeader{ Identifier: 255, - Buf: buffer.NewWithData(upperLayerData), + Buf: bufferv2.MakeWithData(upperLayerData), }, }, }, @@ -825,7 +834,7 @@ func TestIPv6ExtHdrIter(t *testing.T) { 1, 2}, []byte{3, 4}), expected: []IPv6PayloadHeader{ IPv6FragmentExtHdr([6]byte{0, 6, 128, 4, 2, 1}), - IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}), + IPv6RoutingExtHdr{bufferv2.NewViewWithData([]byte{1, 2, 3, 4, 5, 6})}, IPv6RawPayloadHeader{ Identifier: 255, Buf: makeBufferFromByteBuffers(upperLayerData[:2], upperLayerData[2:]), @@ -835,7 +844,7 @@ func TestIPv6ExtHdrIter(t *testing.T) { { name: "atomic fragment - destination - no next header", firstNextHdr: IPv6FragmentExtHdrIdentifier, - payload: buffer.NewWithData([]byte{ + payload: bufferv2.MakeWithData([]byte{ // Fragment extension header. // // Res (Reserved) bits are 1 which should not affect anything. @@ -849,13 +858,13 @@ func TestIPv6ExtHdrIter(t *testing.T) { }), expected: []IPv6PayloadHeader{ IPv6FragmentExtHdr([6]byte{0, 6, 128, 4, 2, 1}), - IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr: []byte{1, 4, 1, 2, 3, 4}}, + IPv6DestinationOptionsExtHdr{ipv6OptionsExtHdr{bufferv2.NewViewWithData([]byte{1, 4, 1, 2, 3, 4})}}, }, }, { name: "routing - atomic fragment - no next header", firstNextHdr: IPv6RoutingExtHdrIdentifier, - payload: buffer.NewWithData([]byte{ + payload: bufferv2.MakeWithData([]byte{ // Routing extension header. uint8(IPv6FragmentExtHdrIdentifier), 0, 1, 2, 3, 4, 5, 6, @@ -868,7 +877,7 @@ func TestIPv6ExtHdrIter(t *testing.T) { 1, 2, 3, 4, }), expected: []IPv6PayloadHeader{ - IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}), + IPv6RoutingExtHdr{bufferv2.NewViewWithData([]byte{1, 2, 3, 4, 5, 6})}, IPv6FragmentExtHdr([6]byte{0, 6, 128, 4, 2, 1}), }, }, @@ -888,14 +897,14 @@ func TestIPv6ExtHdrIter(t *testing.T) { 1, 2, 3, 4, }), expected: []IPv6PayloadHeader{ - IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}), + IPv6RoutingExtHdr{bufferv2.NewViewWithData([]byte{1, 2, 3, 4, 5, 6})}, IPv6FragmentExtHdr([6]byte{0, 6, 128, 4, 2, 1}), }, }, { name: "hopbyhop - routing - fragment - no next header", firstNextHdr: IPv6HopByHopOptionsExtHdrIdentifier, - payload: buffer.NewWithData([]byte{ + payload: bufferv2.MakeWithData([]byte{ // Hop By Hop Options extension header. uint8(IPv6RoutingExtHdrIdentifier), 0, 1, 4, 1, 2, 3, 4, @@ -911,12 +920,12 @@ func TestIPv6ExtHdrIter(t *testing.T) { 1, 2, 3, 4, }), expected: []IPv6PayloadHeader{ - IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr: []byte{1, 4, 1, 2, 3, 4}}, - IPv6RoutingExtHdr([]byte{1, 2, 3, 4, 5, 6}), + IPv6HopByHopOptionsExtHdr{ipv6OptionsExtHdr{bufferv2.NewViewWithData([]byte{1, 4, 1, 2, 3, 4})}}, + IPv6RoutingExtHdr{bufferv2.NewViewWithData([]byte{1, 2, 3, 4, 5, 6})}, IPv6FragmentExtHdr([6]byte{1, 6, 128, 4, 2, 1}), IPv6RawPayloadHeader{ Identifier: IPv6NoNextHeaderIdentifier, - Buf: buffer.NewWithData(upperLayerData), + Buf: bufferv2.MakeWithData(upperLayerData), }, }, }, @@ -925,46 +934,46 @@ func TestIPv6ExtHdrIter(t *testing.T) { { name: "TCP raw payload", firstNextHdr: IPv6ExtensionHeaderIdentifier(TCPProtocolNumber), - payload: buffer.NewWithData(upperLayerData), + payload: bufferv2.MakeWithData(upperLayerData), expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{ Identifier: IPv6ExtensionHeaderIdentifier(TCPProtocolNumber), - Buf: buffer.NewWithData(upperLayerData), + Buf: bufferv2.MakeWithData(upperLayerData), }}, }, { name: "UDP raw payload", firstNextHdr: IPv6ExtensionHeaderIdentifier(UDPProtocolNumber), - payload: buffer.NewWithData(upperLayerData), + payload: bufferv2.MakeWithData(upperLayerData), expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{ Identifier: IPv6ExtensionHeaderIdentifier(UDPProtocolNumber), - Buf: buffer.NewWithData(upperLayerData), + Buf: bufferv2.MakeWithData(upperLayerData), }}, }, { name: "ICMPv4 raw payload", firstNextHdr: IPv6ExtensionHeaderIdentifier(ICMPv4ProtocolNumber), - payload: buffer.NewWithData(upperLayerData), + payload: bufferv2.MakeWithData(upperLayerData), expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{ Identifier: IPv6ExtensionHeaderIdentifier(ICMPv4ProtocolNumber), - Buf: buffer.NewWithData(upperLayerData), + Buf: bufferv2.MakeWithData(upperLayerData), }}, }, { name: "ICMPv6 raw payload", firstNextHdr: IPv6ExtensionHeaderIdentifier(ICMPv6ProtocolNumber), - payload: buffer.NewWithData(upperLayerData), + payload: bufferv2.MakeWithData(upperLayerData), expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{ Identifier: IPv6ExtensionHeaderIdentifier(ICMPv6ProtocolNumber), - Buf: buffer.NewWithData(upperLayerData), + Buf: bufferv2.MakeWithData(upperLayerData), }}, }, { name: "Unknwon next header raw payload", firstNextHdr: 255, - payload: buffer.NewWithData(upperLayerData), + payload: bufferv2.MakeWithData(upperLayerData), expected: []IPv6PayloadHeader{IPv6RawPayloadHeader{ Identifier: 255, - Buf: buffer.NewWithData(upperLayerData), + Buf: bufferv2.MakeWithData(upperLayerData), }}, }, { @@ -990,7 +999,7 @@ func TestIPv6ExtHdrIter(t *testing.T) { if done { t.Errorf("(i=%d) unexpectedly done iterating", i) } - if diff := cmp.Diff(e, extHdr); diff != "" { + if diff := cmp.Diff(e, extHdr, viewTransformer, bufferTransformer); diff != "" { t.Errorf("(i=%d) got ext hdr mismatch (-want +got):\n%s", i, diff) } @@ -1019,7 +1028,7 @@ var _ IPv6SerializableHopByHopOption = (*dummyHbHOptionSerializer)(nil) // IPv6SerializableHopByHopOption for use in tests. type dummyHbHOptionSerializer struct { id IPv6ExtHdrOptionIdentifier - payload []byte + payload *bufferv2.View align int alignOffset int } @@ -1031,7 +1040,7 @@ func (s *dummyHbHOptionSerializer) identifier() IPv6ExtHdrOptionIdentifier { // length implements IPv6SerializableHopByHopOption. func (s *dummyHbHOptionSerializer) length() uint8 { - return uint8(len(s.payload)) + return uint8(s.payload.Size()) } // alignment implements IPv6SerializableHopByHopOption. @@ -1045,7 +1054,7 @@ func (s *dummyHbHOptionSerializer) alignment() (int, int) { // serializeInto implements IPv6SerializableHopByHopOption. func (s *dummyHbHOptionSerializer) serializeInto(b []byte) uint8 { - return uint8(copy(b, s.payload)) + return uint8(copy(b, s.payload.AsSlice())) } func TestIPv6HopByHopSerializer(t *testing.T) { @@ -1062,7 +1071,7 @@ func TestIPv6HopByHopSerializer(t *testing.T) { if dummy.id != unknown.Identifier { t.Errorf("got deserialized identifier = %d, want = %d", unknown.Identifier, dummy.id) } - if diff := cmp.Diff(dummy.payload, unknown.Data); diff != "" { + if diff := cmp.Diff(dummy.payload, unknown.Data, viewTransformer, bufferTransformer); diff != "" { t.Errorf("option payload deserialization mismatch (-want +got):\n%s", diff) } } @@ -1079,7 +1088,7 @@ func TestIPv6HopByHopSerializer(t *testing.T) { options: []IPv6SerializableHopByHopOption{ &dummyHbHOptionSerializer{ id: 15, - payload: []byte{9, 8, 7, 6}, + payload: bufferv2.NewViewWithData([]byte{9, 8, 7, 6}), }, }, expect: []byte{13, 0, 15, 4, 9, 8, 7, 6}, @@ -1091,7 +1100,7 @@ func TestIPv6HopByHopSerializer(t *testing.T) { options: []IPv6SerializableHopByHopOption{ &dummyHbHOptionSerializer{ id: 22, - payload: []byte{4, 5}, + payload: bufferv2.NewViewWithData([]byte{4, 5}), }, }, expect: []byte{88, 0, 22, 2, 4, 5, 1, 0}, @@ -1103,7 +1112,7 @@ func TestIPv6HopByHopSerializer(t *testing.T) { options: []IPv6SerializableHopByHopOption{ &dummyHbHOptionSerializer{ id: 33, - payload: []byte{1, 2, 3}, + payload: bufferv2.NewViewWithData([]byte{1, 2, 3}), }, }, expect: []byte{11, 0, 33, 3, 1, 2, 3, 0}, @@ -1115,7 +1124,7 @@ func TestIPv6HopByHopSerializer(t *testing.T) { options: []IPv6SerializableHopByHopOption{ &dummyHbHOptionSerializer{ id: 77, - payload: []byte{1, 2, 3, 4, 5, 6, 7, 8}, + payload: bufferv2.NewViewWithData([]byte{1, 2, 3, 4, 5, 6, 7, 8}), }, }, expect: []byte{55, 1, 77, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 0, 0}, @@ -1127,11 +1136,11 @@ func TestIPv6HopByHopSerializer(t *testing.T) { options: []IPv6SerializableHopByHopOption{ &dummyHbHOptionSerializer{ id: 11, - payload: []byte{1, 2, 3}, + payload: bufferv2.NewViewWithData([]byte{1, 2, 3}), }, &dummyHbHOptionSerializer{ id: 22, - payload: []byte{4, 5, 6}, + payload: bufferv2.NewViewWithData([]byte{4, 5, 6}), }, }, expect: []byte{33, 1, 11, 3, 1, 2, 3, 22, 3, 4, 5, 6, 1, 2, 0, 0}, @@ -1143,11 +1152,11 @@ func TestIPv6HopByHopSerializer(t *testing.T) { options: []IPv6SerializableHopByHopOption{ &dummyHbHOptionSerializer{ id: 11, - payload: []byte{1, 2, 3}, + payload: bufferv2.NewViewWithData([]byte{1, 2, 3}), }, &dummyHbHOptionSerializer{ id: 22, - payload: []byte{4, 5, 6}, + payload: bufferv2.NewViewWithData([]byte{4, 5, 6}), align: 2, }, }, @@ -1160,11 +1169,11 @@ func TestIPv6HopByHopSerializer(t *testing.T) { options: []IPv6SerializableHopByHopOption{ &dummyHbHOptionSerializer{ id: 11, - payload: []byte{1, 2}, + payload: bufferv2.NewViewWithData([]byte{1, 2}), }, &dummyHbHOptionSerializer{ id: 22, - payload: []byte{4, 5, 6}, + payload: bufferv2.NewViewWithData([]byte{4, 5, 6}), align: 8, alignOffset: 1, }, @@ -1216,7 +1225,7 @@ func TestIPv6HopByHopSerializer(t *testing.T) { // Deserialize the options and verify them. optLen := (b[ipv6HopByHopExtHdrLengthOffset] + ipv6HopByHopExtHdrUnaccountedLenWords) * ipv6ExtHdrLenBytesPerUnit - iter := ipv6OptionsExtHdr(b[ipv6HopByHopExtHdrOptionsOffset:optLen]).Iter() + iter := ipv6OptionsExtHdr{bufferv2.NewViewWithData(b[ipv6HopByHopExtHdrOptionsOffset:optLen])}.Iter() for _, testOpt := range test.options { opt, done, err := iter.Next() if err != nil { diff --git a/pkg/tcpip/header/parse/parse.go b/pkg/tcpip/header/parse/parse.go index 6dada8c36..dc1300528 100644 --- a/pkg/tcpip/header/parse/parse.go +++ b/pkg/tcpip/header/parse/parse.go @@ -83,9 +83,10 @@ func IPv6(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, fragID // - Any IPv6 header bytes after the first 40 (i.e. extensions). // - The transport header, if present. // - Any other payload data. - dataBuf := pkt.Data().AsBuffer() + dataBuf := pkt.Data().ToBuffer() dataBuf.TrimFront(header.IPv6MinimumSize) it := header.MakeIPv6PayloadIterator(header.IPv6ExtensionHeaderIdentifier(ipHdr.NextHeader()), dataBuf) + defer it.Release() // Iterate over the IPv6 extensions to find their length. var nextHdr tcpip.TransportProtocolNumber @@ -124,15 +125,18 @@ traverseExtensions: } rawPayload := it.AsRawHeader(true /* consume */) extensionsSize = dataBuf.Size() - rawPayload.Buf.Size() + rawPayload.Release() + extHdr.Release() break traverseExtensions case header.IPv6RawPayloadHeader: // We've found the payload after any extensions. extensionsSize = dataBuf.Size() - extHdr.Buf.Size() nextHdr = tcpip.TransportProtocolNumber(extHdr.Identifier) + extHdr.Release() break traverseExtensions - default: + extHdr.Release() // Any other extension is a no-op, keep looping until we find the payload. } } diff --git a/pkg/tcpip/link/ethernet/BUILD b/pkg/tcpip/link/ethernet/BUILD index 85d66db85..0c5831bfd 100644 --- a/pkg/tcpip/link/ethernet/BUILD +++ b/pkg/tcpip/link/ethernet/BUILD @@ -20,7 +20,7 @@ go_test( srcs = ["ethernet_test.go"], deps = [ ":ethernet", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", diff --git a/pkg/tcpip/link/ethernet/ethernet_test.go b/pkg/tcpip/link/ethernet/ethernet_test.go index 33d1f69cc..842c823eb 100644 --- a/pkg/tcpip/link/ethernet/ethernet_test.go +++ b/pkg/tcpip/link/ethernet/ethernet_test.go @@ -19,7 +19,7 @@ import ( "os" "testing" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -67,7 +67,7 @@ func TestDeliverNetworkPacket(t *testing.T) { DstAddr: otherLinkAddr2, Type: header.IPv4ProtocolNumber, }) - p := stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buffer.NewWithData(eth)}) + p := stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: bufferv2.MakeWithData(eth)}) defer p.DecRef() e.DeliverNetworkPacket(0, p) if networkDispatcher.networkPackets != 1 { @@ -140,9 +140,7 @@ func TestWritePacketToRemoteAddHeader(t *testing.T) { t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err) } - // TODO(b/230896518): Remove tcpipbuffer once WritePacketToRemote API is - // changed. - if err := s.WritePacketToRemote(nicID, remoteLinkAddr, netProto, buffer.Buffer{}); err != nil { + if err := s.WritePacketToRemote(nicID, remoteLinkAddr, netProto, bufferv2.Buffer{}); err != nil { t.Fatalf("s.WritePacketToRemote(%d, %s, _): %s", nicID, remoteLinkAddr, err) } @@ -152,7 +150,7 @@ func TestWritePacketToRemoteAddHeader(t *testing.T) { t.Fatal("expected to read a packet") } - eth := header.Ethernet(pkt.LinkHeader().View()) + eth := header.Ethernet(pkt.LinkHeader().Slice()) pkt.DecRef() if got := eth.SourceAddress(); got != localLinkAddr { t.Errorf("got eth.SourceAddress() = %s, want = %s", got, localLinkAddr) diff --git a/pkg/tcpip/link/fdbased/BUILD b/pkg/tcpip/link/fdbased/BUILD index e2da9cb8e..b61011a76 100644 --- a/pkg/tcpip/link/fdbased/BUILD +++ b/pkg/tcpip/link/fdbased/BUILD @@ -15,7 +15,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//pkg/atomicbitops", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/sync", "//pkg/tcpip", "//pkg/tcpip/header", @@ -31,7 +31,7 @@ go_test( srcs = ["endpoint_test.go"], library = ":fdbased", deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", diff --git a/pkg/tcpip/link/fdbased/endpoint.go b/pkg/tcpip/link/fdbased/endpoint.go index 57baca91f..bc691cad3 100644 --- a/pkg/tcpip/link/fdbased/endpoint.go +++ b/pkg/tcpip/link/fdbased/endpoint.go @@ -45,7 +45,7 @@ import ( "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -58,6 +58,7 @@ import ( type linkDispatcher interface { stop() dispatch() (bool, tcpip.Error) + release() } // PacketDispatchMode are the various supported methods of receiving and @@ -530,7 +531,7 @@ func (e *endpoint) writePacket(pkt *stack.PacketBuffer) tcpip.Error { vnetHdrBuf = vnetHdr.marshal() } - views := pkt.Slices() + views := pkt.AsSlices() numIovecs := len(views) if len(vnetHdrBuf) != 0 { numIovecs++ @@ -600,7 +601,7 @@ func (e *endpoint) sendBatch(batchFDInfo fdInfo, pkts []*stack.PacketBuffer) (in vnetHdrBuf = vnetHdr.marshal() } - views := pkt.Slices() + views := pkt.AsSlices() numIovecs := len(views) if len(vnetHdrBuf) != 0 { numIovecs++ @@ -706,13 +707,13 @@ func (e *endpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) } // viewsEqual tests whether v1 and v2 refer to the same backing bytes. -func viewsEqual(vs1, vs2 []buffer.View) bool { +func viewsEqual(vs1, vs2 []bufferv2.View) bool { return len(vs1) == len(vs2) && (len(vs1) == 0 || &vs1[0] == &vs2[0]) } // InjectOutobund implements stack.InjectableEndpoint.InjectOutbound. -func (e *endpoint) InjectOutbound(dest tcpip.Address, packet []byte) tcpip.Error { - return rawfile.NonBlockingWrite(e.fds[0].fd, packet) +func (e *endpoint) InjectOutbound(dest tcpip.Address, packet *bufferv2.View) tcpip.Error { + return rawfile.NonBlockingWrite(e.fds[0].fd, packet.AsSlice()) } // dispatchLoop reads packets from the file descriptor in a loop and dispatches @@ -724,6 +725,7 @@ func (e *endpoint) dispatchLoop(inboundDispatcher linkDispatcher) tcpip.Error { if e.closed != nil { e.closed(err) } + inboundDispatcher.release() return err } } diff --git a/pkg/tcpip/link/fdbased/endpoint_test.go b/pkg/tcpip/link/fdbased/endpoint_test.go index 6a0100efa..751fee319 100644 --- a/pkg/tcpip/link/fdbased/endpoint_test.go +++ b/pkg/tcpip/link/fdbased/endpoint_test.go @@ -29,7 +29,7 @@ import ( "github.com/google/go-cmp/cmp" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -67,10 +67,10 @@ func checkPacketInfoEqual(t *testing.T, got, want packetInfo) { return nil } return &packetContents{ - LinkHeader: pk.LinkHeader().View(), - NetworkHeader: pk.NetworkHeader().View(), - TransportHeader: pk.TransportHeader().View(), - Data: pk.Data().AsRange().ToOwnedView(), + LinkHeader: pk.LinkHeader().Slice(), + NetworkHeader: pk.NetworkHeader().Slice(), + TransportHeader: pk.TransportHeader().Slice(), + Data: pk.Data().AsRange().ToSlice(), } }), ); diff != "" { @@ -134,6 +134,7 @@ func (c *context) cleanup() { } func (c *context) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { + pkt.IncRef() c.ch <- packetInfo{protocol, pkt} } @@ -195,15 +196,15 @@ func testWritePacket(t *testing.T, plen int, eth bool, gsoMaxSize uint32, hash u const netHdrLen = 100 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()) + netHdrLen, - Payload: buffer.NewWithData(payload), + Payload: bufferv2.MakeWithData(payload), }) + defer pkt.DecRef() pkt.Hash = hash // Every PacketBuffer must have these set: // See nic.writePacket. pkt.EgressRoute.LocalLinkAddress = laddr pkt.EgressRoute.RemoteLinkAddress = raddr pkt.NetworkProtocolNumber = proto - defer pkt.DecRef() // Build header. b := pkt.NetworkHeader().Push(netHdrLen) @@ -386,7 +387,7 @@ func TestDeliverPacket(t *testing.T) { wantPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: header.EthernetMinimumSize, - Payload: buffer.NewWithData(all), + Payload: bufferv2.MakeWithData(all), }) defer wantPkt.DecRef() if eth { @@ -407,6 +408,7 @@ func TestDeliverPacket(t *testing.T) { // Receive packet through the endpoint. select { case pi := <-c.ch: + defer pi.Contents.DecRef() want := packetInfo{ Proto: proto, Contents: wantPkt, @@ -454,31 +456,31 @@ var capLengthTestCases = []struct { }{ { comment: "Single slice", - config: []int{2}, - n: 1, + config: []int{256}, + n: 128, wantUsed: 1, - wantLengths: []int{1}, + wantLengths: []int{128}, }, { comment: "Multiple slices", - config: []int{1, 2}, - n: 2, + config: []int{128, 256}, + n: 256, wantUsed: 2, - wantLengths: []int{1, 1}, + wantLengths: []int{128, 128}, }, { comment: "Entire buffer", - config: []int{1, 2}, - n: 3, + config: []int{128, 256}, + n: 384, wantUsed: 2, - wantLengths: []int{1, 2}, + wantLengths: []int{128, 256}, }, { comment: "Entire buffer but not on the last slice", - config: []int{1, 2, 3}, - n: 3, + config: []int{128, 256, 512}, + n: 384, wantUsed: 2, - wantLengths: []int{1, 2}, + wantLengths: []int{128, 256}, }, } @@ -486,6 +488,7 @@ func TestIovecBuffer(t *testing.T) { for _, c := range capLengthTestCases { t.Run(c.comment, func(t *testing.T) { b := newIovecBuffer(c.config, false /* skipsVnetHdr */) + defer b.release() // Test initial allocation. iovecs := b.nextIovecs() @@ -499,9 +502,10 @@ func TestIovecBuffer(t *testing.T) { // Test the buffer that get pulled. buf := b.pullBuffer(c.n) + defer buf.Release() var lengths []int - buf.Apply(func(v []byte) { - lengths = append(lengths, len(v)) + buf.Apply(func(v *bufferv2.View) { + lengths = append(lengths, v.Size()) }) if !reflect.DeepEqual(lengths, c.wantLengths) { t.Errorf("Pulled view lengths = %v, want %v", lengths, c.wantLengths) @@ -541,15 +545,17 @@ func TestIovecBufferSkipVnetHdr(t *testing.T) { }, { desc: "header skipped", - readN: virtioNetHdrSize + 100, - wantLen: 100, + readN: virtioNetHdrSize + 512, + wantLen: 512, }, } { t.Run(test.desc, func(t *testing.T) { - b := newIovecBuffer([]int{10, 20, 50, 50}, true) + b := newIovecBuffer([]int{128, 256, 512, 1024}, true) + defer b.release() // Pretend a read happend. b.nextIovecs() buf := b.pullBuffer(test.readN) + defer buf.Release() if got, want := int(buf.Size()), test.wantLen; got != want { t.Errorf("b.pullView(%d).Size() = %d; want %d", test.readN, got, want) } @@ -566,6 +572,7 @@ type fakeNetworkDispatcher struct { } func (d *fakeNetworkDispatcher) DeliverNetworkPacket(_ tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { + pkt.IncRef() d.pkts = append(d.pkts, pkt) } @@ -593,8 +600,6 @@ func TestDispatchPacketFormat(t *testing.T) { if err != nil { t.Fatal(err) } - defer unix.Close(fds[0]) - defer unix.Close(fds[1]) data := []byte{ // Ethernet header. @@ -618,6 +623,7 @@ func TestDispatchPacketFormat(t *testing.T) { if err != nil { t.Fatal(err) } + defer d.release() if ok, err := d.dispatch(); !ok || err != nil { t.Fatalf("d.dispatch() = %v, %v", ok, err) } @@ -627,7 +633,8 @@ func TestDispatchPacketFormat(t *testing.T) { t.Fatalf("len(sink.pkts) = %d, want %d", got, want) } pkt := sink.pkts[0] - if got, want := len(pkt.LinkHeader().View()), header.EthernetMinimumSize; got != want { + defer pkt.DecRef() + if got, want := len(pkt.LinkHeader().Slice()), header.EthernetMinimumSize; got != want { t.Errorf("pkt.LinkHeader().View().Size() = %d, want %d", got, want) } if got, want := pkt.Data().Size(), 4; got != want { diff --git a/pkg/tcpip/link/fdbased/mmap.go b/pkg/tcpip/link/fdbased/mmap.go index 07391dae7..ebb9ad778 100644 --- a/pkg/tcpip/link/fdbased/mmap.go +++ b/pkg/tcpip/link/fdbased/mmap.go @@ -22,7 +22,7 @@ import ( "fmt" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/rawfile" @@ -131,7 +131,9 @@ type packetMMapDispatcher struct { ringOffset int } -func (d *packetMMapDispatcher) readMMappedPacket() ([]byte, bool, tcpip.Error) { +func (*packetMMapDispatcher) release() {} + +func (d *packetMMapDispatcher) readMMappedPacket() (*bufferv2.View, bool, tcpip.Error) { hdr := tPacketHdr(d.ringBuffer[d.ringOffset*tpFrameSize:]) for hdr.tpStatus()&tpStatusUser == 0 { stopped, errno := rawfile.BlockingPollUntilStopped(d.efd, d.fd, unix.POLLIN|unix.POLLERR) @@ -155,8 +157,8 @@ func (d *packetMMapDispatcher) readMMappedPacket() ([]byte, bool, tcpip.Error) { } // Copy out the packet from the mmapped frame to a locally owned buffer. - pkt := make([]byte, hdr.tpSnapLen()) - copy(pkt, hdr.Payload()) + pkt := bufferv2.NewView(int(hdr.tpSnapLen())) + pkt.Write(hdr.Payload()) // Release packet to kernel. hdr.setTPStatus(tpStatusKernel) d.ringOffset = (d.ringOffset + 1) % tpFrameNR @@ -172,11 +174,11 @@ func (d *packetMMapDispatcher) dispatch() (bool, tcpip.Error) { } var p tcpip.NetworkProtocolNumber if d.e.hdrSize > 0 { - p = header.Ethernet(pkt).Type() + p = header.Ethernet(pkt.AsSlice()).Type() } else { // We don't get any indication of what the packet is, so try to guess // if it's an IPv4 or IPv6 packet. - switch header.IPVersion(pkt) { + switch header.IPVersion(pkt.AsSlice()) { case header.IPv4Version: p = header.IPv4ProtocolNumber case header.IPv6Version: @@ -187,7 +189,7 @@ func (d *packetMMapDispatcher) dispatch() (bool, tcpip.Error) { } pbuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(pkt), + Payload: bufferv2.MakeWithView(pkt), }) defer pbuf.DecRef() if d.e.hdrSize > 0 { diff --git a/pkg/tcpip/link/fdbased/packet_dispatchers.go b/pkg/tcpip/link/fdbased/packet_dispatchers.go index 16399d2fb..0ab67212e 100644 --- a/pkg/tcpip/link/fdbased/packet_dispatchers.go +++ b/pkg/tcpip/link/fdbased/packet_dispatchers.go @@ -21,7 +21,7 @@ import ( "fmt" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/rawfile" @@ -35,7 +35,7 @@ type iovecBuffer struct { // buffer is the actual buffer that holds the packet contents. Some contents // are reused across calls to pullBuffer if number of requested bytes is // smaller than the number of bytes allocated in the buffer. - buffer buffer.Buffer + views []*bufferv2.View // iovecs are initialized with base pointers/len of the corresponding // entries in the views defined above, except when GSO is enabled @@ -59,13 +59,11 @@ type iovecBuffer struct { func newIovecBuffer(sizes []int, skipsVnetHdr bool) *iovecBuffer { b := &iovecBuffer{ + views: make([]*bufferv2.View, len(sizes)), sizes: sizes, skipsVnetHdr: skipsVnetHdr, - // Setting pulledIndex to the length of sizes will allocate all - // the buffers. - pulledIndex: len(sizes), } - niov := len(sizes) + niov := len(b.views) if b.skipsVnetHdr { niov++ } @@ -78,26 +76,22 @@ func (b *iovecBuffer) nextIovecs() []unix.Iovec { if b.skipsVnetHdr { var vnetHdr [virtioNetHdrSize]byte // The kernel adds virtioNetHdr before each packet, but - // we don't use it, so so we allocate a buffer for it, + // we don't use it, so we allocate a buffer for it, // add it in iovecs but don't add it in a view. b.iovecs[0] = unix.Iovec{Base: &vnetHdr[0]} b.iovecs[0].SetLen(virtioNetHdrSize) vnetHdrOff++ } - var buf buffer.Buffer - for i, size := range b.sizes { - if i > b.pulledIndex { + for i := range b.views { + if b.views[i] != nil { break } - v := make([]byte, size) - buf.AppendOwned(v) - b.iovecs[i+vnetHdrOff] = unix.Iovec{Base: &v[0]} - b.iovecs[i+vnetHdrOff].SetLen(len(v)) + v := bufferv2.NewViewSize(b.sizes[i]) + b.views[i] = v + b.iovecs[i+vnetHdrOff] = unix.Iovec{Base: v.BasePtr()} + b.iovecs[i+vnetHdrOff].SetLen(v.Size()) } - buf.Merge(&b.buffer) - b.buffer = buf - b.pulledIndex = -1 return b.iovecs } @@ -106,34 +100,49 @@ func (b *iovecBuffer) nextIovecs() []unix.Iovec { // that holds the storage, and updates pulledIndex to indicate which part // of b.buffer's storage must be reallocated during the next call to // nextIovecs. -func (b *iovecBuffer) pullBuffer(n int) buffer.Buffer { - var pulled buffer.Buffer +func (b *iovecBuffer) pullBuffer(n int) bufferv2.Buffer { + var views []*bufferv2.View c := 0 if b.skipsVnetHdr { - c = virtioNetHdrSize + c += virtioNetHdrSize if c >= n { // Nothing in the packet. - return pulled + return bufferv2.Buffer{} } } // Remove the used views from the buffer. - pulled = b.buffer.Clone() - for _, size := range b.sizes { - b.pulledIndex++ - c += size - b.buffer.TrimFront(int64(size)) + for i, v := range b.views { + c += v.Size() if c >= n { + b.views[i].CapLength(v.Size() - (c - n)) + views = append(views, b.views[:i+1]...) break } } + for i := range views { + b.views[i] = nil + } if b.skipsVnetHdr { // Exclude the size of the vnet header. n -= virtioNetHdrSize } + pulled := bufferv2.Buffer{} + for _, v := range views { + pulled.Append(v) + } pulled.Truncate(int64(n)) return pulled } +func (b *iovecBuffer) release() { + for _, v := range b.views { + if v != nil { + v.Release() + v = nil + } + } +} + // stopFd is an eventfd used to signal the stop of a dispatcher. type stopFd struct { efd int @@ -189,6 +198,10 @@ func newReadVDispatcher(fd int, e *endpoint) (linkDispatcher, error) { return d, nil } +func (d *readVDispatcher) release() { + d.buf.release() +} + // dispatch reads one packet from the file descriptor and dispatches it. func (d *readVDispatcher) dispatch() (bool, tcpip.Error) { n, err := rawfile.BlockingReadvUntilStopped(d.efd, d.fd, d.buf.nextIovecs()) @@ -276,6 +289,12 @@ func newRecvMMsgDispatcher(fd int, e *endpoint) (linkDispatcher, error) { return d, nil } +func (d *recvMMsgDispatcher) release() { + for _, iov := range d.bufs { + iov.release() + } +} + // recvMMsgDispatch reads more than one packet at a time from the file // descriptor and dispatches it. func (d *recvMMsgDispatcher) dispatch() (bool, tcpip.Error) { diff --git a/pkg/tcpip/link/loopback/loopback.go b/pkg/tcpip/link/loopback/loopback.go index c23bf1a38..03a929e10 100644 --- a/pkg/tcpip/link/loopback/loopback.go +++ b/pkg/tcpip/link/loopback/loopback.go @@ -80,7 +80,7 @@ func (e *endpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) // fresh packet that only contains the underlying payload with no headers // or struct fields set. newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: pkt.Buffer(), + Payload: pkt.ToBuffer(), }) e.dispatcher.DeliverNetworkPacket(pkt.NetworkProtocolNumber, newPkt) newPkt.DecRef() diff --git a/pkg/tcpip/link/muxed/BUILD b/pkg/tcpip/link/muxed/BUILD index 29e8d4b8d..7bdd3baf2 100644 --- a/pkg/tcpip/link/muxed/BUILD +++ b/pkg/tcpip/link/muxed/BUILD @@ -7,6 +7,7 @@ go_library( srcs = ["injectable.go"], visibility = ["//visibility:public"], deps = [ + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/header", "//pkg/tcpip/stack", @@ -19,7 +20,7 @@ go_test( srcs = ["injectable_test.go"], library = ":muxed", deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", diff --git a/pkg/tcpip/link/muxed/injectable.go b/pkg/tcpip/link/muxed/injectable.go index e3d487307..60f8b1b2d 100644 --- a/pkg/tcpip/link/muxed/injectable.go +++ b/pkg/tcpip/link/muxed/injectable.go @@ -16,6 +16,7 @@ package muxed import ( + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -111,7 +112,7 @@ func (m *InjectableEndpoint) WritePackets(pkts stack.PacketBufferList) (int, tcp // InjectOutbound writes outbound packets to the appropriate // LinkInjectableEndpoint based on the dest address. -func (m *InjectableEndpoint) InjectOutbound(dest tcpip.Address, packet []byte) tcpip.Error { +func (m *InjectableEndpoint) InjectOutbound(dest tcpip.Address, packet *bufferv2.View) tcpip.Error { endpoint, ok := m.routes[dest] if !ok { return &tcpip.ErrNoRoute{} diff --git a/pkg/tcpip/link/muxed/injectable_test.go b/pkg/tcpip/link/muxed/injectable_test.go index 14a42f61b..5e2b85153 100644 --- a/pkg/tcpip/link/muxed/injectable_test.go +++ b/pkg/tcpip/link/muxed/injectable_test.go @@ -21,7 +21,7 @@ import ( "testing" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -33,7 +33,9 @@ import ( func TestInjectableEndpointRawDispatch(t *testing.T) { endpoint, sock, dstIP := makeTestInjectableEndpoint(t) - endpoint.InjectOutbound(dstIP, []byte{0xFA}) + v := bufferv2.NewViewWithData([]byte{0xFA}) + defer v.Release() + endpoint.InjectOutbound(dstIP, v) buf := make([]byte, ipv4.MaxTotalSize) bytesRead, err := sock.Read(buf) @@ -50,7 +52,7 @@ func TestInjectableEndpointDispatch(t *testing.T) { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: 1, - Payload: buffer.NewWithData([]byte{0xFB}), + Payload: bufferv2.MakeWithData([]byte{0xFB}), }) defer pkt.DecRef() pkt.TransportHeader().Push(1)[0] = 0xFA diff --git a/pkg/tcpip/link/pipe/pipe.go b/pkg/tcpip/link/pipe/pipe.go index 038f2e752..4504735f2 100644 --- a/pkg/tcpip/link/pipe/pipe.go +++ b/pkg/tcpip/link/pipe/pipe.go @@ -57,7 +57,7 @@ func (e *Endpoint) deliverPackets(pkts stack.PacketBufferList) { // or headers set so the next link protocol can properly set the link // header. newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: pkt.Buffer(), + Payload: pkt.ToBuffer(), }) e.linked.dispatcher.DeliverNetworkPacket(pkt.NetworkProtocolNumber, newPkt) newPkt.DecRef() diff --git a/pkg/tcpip/link/qdisc/fifo/BUILD b/pkg/tcpip/link/qdisc/fifo/BUILD index ecb54e97a..d77b6ddd1 100644 --- a/pkg/tcpip/link/qdisc/fifo/BUILD +++ b/pkg/tcpip/link/qdisc/fifo/BUILD @@ -24,7 +24,7 @@ go_test( srcs = ["qdisc_test.go"], deps = [ ":fifo", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/sync", diff --git a/pkg/tcpip/link/qdisc/fifo/qdisc_test.go b/pkg/tcpip/link/qdisc/fifo/qdisc_test.go index ae16557a3..a533cb0dd 100644 --- a/pkg/tcpip/link/qdisc/fifo/qdisc_test.go +++ b/pkg/tcpip/link/qdisc/fifo/qdisc_test.go @@ -20,7 +20,7 @@ import ( "testing" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/sync" @@ -68,7 +68,7 @@ func TestFastSimultaneousWrites(t *testing.T) { defer wg.Done() for j := 0; j < nWrites; j++ { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(v), + Payload: bufferv2.MakeWithData(v), }) pkt.Hash = rand.Uint32() linkEP.WritePacket(pkt) @@ -101,7 +101,7 @@ func TestWriteMorePacketsThanBatchSize(t *testing.T) { linkEp := fifo.New(lower, 1, 1000) for i := 0; i < want; i++ { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(v), + Payload: bufferv2.MakeWithData(v), }) linkEp.WritePacket(pkt) pkt.DecRef() diff --git a/pkg/tcpip/link/sharedmem/BUILD b/pkg/tcpip/link/sharedmem/BUILD index b3e312139..838d6f29f 100644 --- a/pkg/tcpip/link/sharedmem/BUILD +++ b/pkg/tcpip/link/sharedmem/BUILD @@ -19,7 +19,7 @@ go_library( ], deps = [ "//pkg/atomicbitops", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/cleanup", "//pkg/eventfd", "//pkg/log", @@ -40,7 +40,7 @@ go_test( srcs = ["sharedmem_test.go"], library = ":sharedmem", deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/sync", diff --git a/pkg/tcpip/link/sharedmem/server_rx.go b/pkg/tcpip/link/sharedmem/server_rx.go index 75e901be6..a62f64f31 100644 --- a/pkg/tcpip/link/sharedmem/server_rx.go +++ b/pkg/tcpip/link/sharedmem/server_rx.go @@ -20,6 +20,7 @@ package sharedmem import ( "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/atomicbitops" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/cleanup" "gvisor.dev/gvisor/pkg/eventfd" "gvisor.dev/gvisor/pkg/tcpip/link/sharedmem/pipe" @@ -125,23 +126,23 @@ func (s *serverRx) DisableNotification() { const completionNotificationSize = 8 // receive receives a single packet from the packetPipe. -func (s *serverRx) receive() []byte { +func (s *serverRx) receive() *bufferv2.View { desc := s.packetPipe.Pull() if desc == nil { return nil } pktInfo := queue.DecodeTxPacketHeader(desc) - contents := make([]byte, 0, pktInfo.Size) + contents := bufferv2.NewView(int(pktInfo.Size)) toCopy := pktInfo.Size for i := 0; i < pktInfo.BufferCount; i++ { txBuf := queue.DecodeTxBufferHeader(desc, i) if txBuf.Size <= toCopy { - contents = append(contents, s.data[txBuf.Offset:][:txBuf.Size]...) + contents.Write(s.data[txBuf.Offset:][:txBuf.Size]) toCopy -= txBuf.Size continue } - contents = append(contents, s.data[txBuf.Offset:][:toCopy]...) + contents.Write(s.data[txBuf.Offset:][:toCopy]) break } diff --git a/pkg/tcpip/link/sharedmem/sharedmem.go b/pkg/tcpip/link/sharedmem/sharedmem.go index d613659f9..628e20150 100644 --- a/pkg/tcpip/link/sharedmem/sharedmem.go +++ b/pkg/tcpip/link/sharedmem/sharedmem.go @@ -27,7 +27,7 @@ import ( "fmt" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/eventfd" "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sync" @@ -343,9 +343,9 @@ func (e *endpoint) writePacketLocked(r stack.RouteInfo, protocol tcpip.NetworkPr e.AddVirtioNetHeader(pkt) } - views := pkt.Slices() + views := pkt.AsSlices() // Transmit the packet. - // TODO(b/231582970): Change transmit() to take a buffer.Buffer instead of a + // TODO(b/231582970): Change transmit() to take a bufferv2.Buffer instead of a // collection of slices. ok := e.tx.transmit(views...) if !ok { @@ -403,17 +403,18 @@ func (e *endpoint) dispatchLoop(d stack.NetworkDispatcher) { // Copy data from the shared area to its own buffer, then // prepare to repost the buffer. - b := make([]byte, n) + v := bufferv2.NewView(int(n)) + v.Grow(int(n)) offset := uint32(0) for i := range rxb { - copy(b[offset:], e.rx.data[rxb[i].Offset:][:rxb[i].Size]) + v.WriteAt(e.rx.data[rxb[i].Offset:][:rxb[i].Size], int(offset)) offset += rxb[i].Size rxb[i].Size = e.bufferSize } pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(b), + Payload: bufferv2.MakeWithView(v), }) if e.virtioNetHeaderRequired { diff --git a/pkg/tcpip/link/sharedmem/sharedmem_server.go b/pkg/tcpip/link/sharedmem/sharedmem_server.go index 2666d1179..2b0860172 100644 --- a/pkg/tcpip/link/sharedmem/sharedmem_server.go +++ b/pkg/tcpip/link/sharedmem/sharedmem_server.go @@ -19,7 +19,7 @@ package sharedmem import ( "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -228,7 +228,7 @@ func (e *serverEndpoint) writePacketLocked(r stack.RouteInfo, protocol tcpip.Net e.AddVirtioNetHeader(pkt) } - views := pkt.Slices() + views := pkt.AsSlices() ok := e.tx.transmit(views) if !ok { return &tcpip.ErrWouldBlock{} @@ -295,7 +295,7 @@ func (e *serverEndpoint) dispatchLoop(d stack.NetworkDispatcher) { } } pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(b), + Payload: bufferv2.MakeWithView(b), }) if e.virtioNetHeaderRequired { _, ok := pkt.VirtioNetHeader().Consume(header.VirtioNetHeaderSize) diff --git a/pkg/tcpip/link/sharedmem/sharedmem_test.go b/pkg/tcpip/link/sharedmem/sharedmem_test.go index 268db5484..055990377 100644 --- a/pkg/tcpip/link/sharedmem/sharedmem_test.go +++ b/pkg/tcpip/link/sharedmem/sharedmem_test.go @@ -26,7 +26,7 @@ import ( "time" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/sync" @@ -148,7 +148,7 @@ func (c *testContext) DeliverNetworkPacket(proto tcpip.NetworkProtocolNumber, pk c.mu.Lock() c.packets = append(c.packets, packetInfo{ proto: proto, - data: pkt.Data().AsRange().ToOwnedView(), + data: pkt.Data().AsRange().ToSlice(), }) c.mu.Unlock() @@ -221,7 +221,7 @@ func TestSimpleSend(t *testing.T) { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: hdrLen + int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(data), + Payload: bufferv2.MakeWithData(data), }) copy(pkt.NetworkHeader().Push(hdrLen), hdrBuf) proto := tcpip.NetworkProtocolNumber(rand.Intn(0x10000)) @@ -360,7 +360,7 @@ func TestFillTxQueue(t *testing.T) { for i := queuePipeSize / 40; i > 0; i-- { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber @@ -386,7 +386,7 @@ func TestFillTxQueue(t *testing.T) { // Next attempt to write must fail. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber @@ -419,7 +419,7 @@ func TestFillTxQueueAfterBadCompletion(t *testing.T) { for i := 2; i > 0; i-- { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) pkts.PushBack(pkt) pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr @@ -448,7 +448,7 @@ func TestFillTxQueueAfterBadCompletion(t *testing.T) { for i := queuePipeSize / 40; i > 0; i-- { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber @@ -473,7 +473,7 @@ func TestFillTxQueueAfterBadCompletion(t *testing.T) { // Next attempt to write must fail. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber @@ -502,7 +502,7 @@ func TestFillTxMemory(t *testing.T) { for i := queueDataSize / bufferSize; i > 0; i-- { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber @@ -528,7 +528,7 @@ func TestFillTxMemory(t *testing.T) { // Next attempt to write must fail. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr @@ -556,7 +556,7 @@ func TestFillTxMemoryWithMultiBuffer(t *testing.T) { for i := queueDataSize/bufferSize - 1; i > 0; i-- { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) var pkts stack.PacketBufferList pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr @@ -577,7 +577,7 @@ func TestFillTxMemoryWithMultiBuffer(t *testing.T) { var pkts stack.PacketBufferList pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(make([]byte, bufferSize)), + Payload: bufferv2.MakeWithData(make([]byte, bufferSize)), }) pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber @@ -596,7 +596,7 @@ func TestFillTxMemoryWithMultiBuffer(t *testing.T) { var pkts stack.PacketBufferList pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber diff --git a/pkg/tcpip/link/sniffer/pcap.go b/pkg/tcpip/link/sniffer/pcap.go index efcb4f684..8cab65691 100644 --- a/pkg/tcpip/link/sniffer/pcap.go +++ b/pkg/tcpip/link/sniffer/pcap.go @@ -66,7 +66,7 @@ func (p *pcapPacket) MarshalBinary() ([]byte, error) { binary.BigEndian.PutUint32(b[8:12], uint32(captureLen)) binary.BigEndian.PutUint32(b[12:16], uint32(packetSize)) w := tcpip.SliceWriter(b[16:]) - for _, v := range p.packet.Slices() { + for _, v := range p.packet.AsSlices() { if captureLen == 0 { break } diff --git a/pkg/tcpip/link/sniffer/sniffer.go b/pkg/tcpip/link/sniffer/sniffer.go index fb85ae4c9..643a279a5 100644 --- a/pkg/tcpip/link/sniffer/sniffer.go +++ b/pkg/tcpip/link/sniffer/sniffer.go @@ -193,9 +193,9 @@ func logPacket(prefix string, dir direction, protocol tcpip.NetworkProtocolNumbe // // We trim the link headers from the cloned buffer as the sniffer doesn't // handle link headers. - buf := pkt.Buffer() - buf.TrimFront(int64(len(pkt.VirtioNetHeader().View()))) - buf.TrimFront(int64(len(pkt.LinkHeader().View()))) + buf := pkt.ToBuffer() + buf.TrimFront(int64(len(pkt.VirtioNetHeader().Slice()))) + buf.TrimFront(int64(len(pkt.LinkHeader().Slice()))) pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf}) defer pkt.DecRef() switch protocol { @@ -204,7 +204,7 @@ func logPacket(prefix string, dir direction, protocol tcpip.NetworkProtocolNumbe return } - ipv4 := header.IPv4(pkt.NetworkHeader().View()) + ipv4 := header.IPv4(pkt.NetworkHeader().Slice()) fragmentOffset = ipv4.FragmentOffset() moreFragments = ipv4.Flags()&header.IPv4FlagMoreFragments == header.IPv4FlagMoreFragments src = ipv4.SourceAddress() @@ -219,7 +219,7 @@ func logPacket(prefix string, dir direction, protocol tcpip.NetworkProtocolNumbe return } - ipv6 := header.IPv6(pkt.NetworkHeader().View()) + ipv6 := header.IPv6(pkt.NetworkHeader().Slice()) src = ipv6.SourceAddress() dst = ipv6.DestinationAddress() transProto = uint8(proto) @@ -233,7 +233,7 @@ func logPacket(prefix string, dir direction, protocol tcpip.NetworkProtocolNumbe return } - arp := header.ARP(pkt.NetworkHeader().View()) + arp := header.ARP(pkt.NetworkHeader().Slice()) log.Infof( "%s%s arp %s (%s) -> %s (%s) valid:%t", prefix, @@ -332,7 +332,7 @@ func logPacket(prefix string, dir direction, protocol tcpip.NetworkProtocolNumbe break } - udp := header.UDP(pkt.TransportHeader().View()) + udp := header.UDP(pkt.TransportHeader().Slice()) if fragmentOffset == 0 { srcPort = udp.SourcePort() dstPort = udp.DestinationPort() @@ -346,7 +346,7 @@ func logPacket(prefix string, dir direction, protocol tcpip.NetworkProtocolNumbe break } - tcp := header.TCP(pkt.TransportHeader().View()) + tcp := header.TCP(pkt.TransportHeader().Slice()) if fragmentOffset == 0 { offset := int(tcp.DataOffset()) if offset < header.TCPMinimumSize { diff --git a/pkg/tcpip/link/tun/BUILD b/pkg/tcpip/link/tun/BUILD index 7ab9a8dc2..4c81fed9b 100644 --- a/pkg/tcpip/link/tun/BUILD +++ b/pkg/tcpip/link/tun/BUILD @@ -26,7 +26,7 @@ go_library( deps = [ "//pkg/abi/linux", "//pkg/atomicbitops", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/context", "//pkg/errors/linuxerr", "//pkg/log", diff --git a/pkg/tcpip/link/tun/device.go b/pkg/tcpip/link/tun/device.go index 6585a064d..b4720a7fd 100644 --- a/pkg/tcpip/link/tun/device.go +++ b/pkg/tcpip/link/tun/device.go @@ -17,7 +17,7 @@ package tun import ( "fmt" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/sync" @@ -181,7 +181,7 @@ func (d *Device) MTU() (uint32, error) { } // Write inject one inbound packet to the network interface. -func (d *Device) Write(data []byte) (int64, error) { +func (d *Device) Write(data *bufferv2.View) (int64, error) { d.mu.RLock() endpoint := d.endpoint d.mu.RUnlock() @@ -192,28 +192,28 @@ func (d *Device) Write(data []byte) (int64, error) { return 0, linuxerr.EIO } - dataLen := int64(len(data)) + dataLen := int64(data.Size()) // Packet information. var pktInfoHdr PacketInfoHeader if !d.flags.NoPacketInfo { - if len(data) < PacketInfoHeaderSize { + if dataLen < PacketInfoHeaderSize { // Ignore bad packet. return dataLen, nil } - pktInfoHdr = PacketInfoHeader(data[:PacketInfoHeaderSize]) - data = data[PacketInfoHeaderSize:] + pktInfoHdr = PacketInfoHeader(data.AsSlice()[:PacketInfoHeaderSize]) + data.TrimFront(PacketInfoHeaderSize) } // Ethernet header (TAP only). var ethHdr header.Ethernet if d.flags.TAP { - if len(data) < header.EthernetMinimumSize { + if data.Size() < header.EthernetMinimumSize { // Ignore bad packet. return dataLen, nil } - ethHdr = header.Ethernet(data[:header.EthernetMinimumSize]) - data = data[header.EthernetMinimumSize:] + ethHdr = header.Ethernet(data.AsSlice()[:header.EthernetMinimumSize]) + data.TrimFront(header.EthernetMinimumSize) } // Try to determine network protocol number, default zero. @@ -226,7 +226,7 @@ func (d *Device) Write(data []byte) (int64, error) { case d.flags.TUN: // TUN interface with IFF_NO_PI enabled, thus // we need to determine protocol from version field - version := data[0] >> 4 + version := data.AsSlice()[0] >> 4 if version == 4 { protocol = header.IPv4ProtocolNumber } else if version == 6 { @@ -236,7 +236,7 @@ func (d *Device) Write(data []byte) (int64, error) { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: len(ethHdr), - Payload: buffer.NewWithData(data), + Payload: bufferv2.MakeWithView(data), }) defer pkt.DecRef() copy(pkt.LinkHeader().Push(len(ethHdr)), ethHdr) @@ -245,7 +245,7 @@ func (d *Device) Write(data []byte) (int64, error) { } // Read reads one outgoing packet from the network interface. -func (d *Device) Read() ([]byte, error) { +func (d *Device) Read() (*bufferv2.View, error) { d.mu.RLock() endpoint := d.endpoint d.mu.RUnlock() @@ -253,39 +253,35 @@ func (d *Device) Read() ([]byte, error) { return nil, linuxerr.EBADFD } - for { - pkt := endpoint.Read() - if pkt == nil { - return nil, linuxerr.ErrWouldBlock - } - - v, ok := d.encodePkt(pkt) - pkt.DecRef() - if !ok { - // Ignore unsupported packet. - continue - } - return v, nil + pkt := endpoint.Read() + if pkt == nil { + return nil, linuxerr.ErrWouldBlock } + v := d.encodePkt(pkt) + pkt.DecRef() + return v, nil } // encodePkt encodes packet for fd side. -func (d *Device) encodePkt(pkt *stack.PacketBuffer) ([]byte, bool) { - var buf buffer.Buffer +func (d *Device) encodePkt(pkt *stack.PacketBuffer) *bufferv2.View { + var view *bufferv2.View // Packet information. if !d.flags.NoPacketInfo { - hdr := make(PacketInfoHeader, PacketInfoHeaderSize) + view = bufferv2.NewView(PacketInfoHeaderSize + pkt.Size()) + view.Grow(PacketInfoHeaderSize) + hdr := PacketInfoHeader(view.AsSlice()) hdr.Encode(&PacketInfoFields{ Protocol: pkt.NetworkProtocolNumber, }) - buf.AppendOwned(hdr) + pktView := pkt.ToView() + view.Write(pktView.AsSlice()) + pktView.Release() + } else { + view = pkt.ToView() } - pktBuf := pkt.Buffer() - buf.Merge(&pktBuf) - - return buf.Flatten(), true + return view } // Name returns the name of the attached network interface. Empty string if diff --git a/pkg/tcpip/network/BUILD b/pkg/tcpip/network/BUILD index 9f8ff52bf..aebd991fc 100644 --- a/pkg/tcpip/network/BUILD +++ b/pkg/tcpip/network/BUILD @@ -11,7 +11,7 @@ go_test( "multicast_group_test.go", ], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/sync", diff --git a/pkg/tcpip/network/arp/BUILD b/pkg/tcpip/network/arp/BUILD index 095f0c81f..0d1139b69 100644 --- a/pkg/tcpip/network/arp/BUILD +++ b/pkg/tcpip/network/arp/BUILD @@ -26,7 +26,7 @@ go_test( srcs = ["arp_test.go"], deps = [ ":arp", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", diff --git a/pkg/tcpip/network/arp/arp.go b/pkg/tcpip/network/arp/arp.go index 217755b72..674ef5184 100644 --- a/pkg/tcpip/network/arp/arp.go +++ b/pkg/tcpip/network/arp/arp.go @@ -160,7 +160,7 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { return } - h := header.ARP(pkt.NetworkHeader().View()) + h := header.ARP(pkt.NetworkHeader().Slice()) if !h.IsValid() { stats.malformedPacketsReceived.Increment() return diff --git a/pkg/tcpip/network/arp/arp_test.go b/pkg/tcpip/network/arp/arp_test.go index 24ba5e782..6aa7f75ef 100644 --- a/pkg/tcpip/network/arp/arp_test.go +++ b/pkg/tcpip/network/arp/arp_test.go @@ -21,7 +21,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -183,7 +183,7 @@ func TestMalformedPacket(t *testing.T) { defer c.cleanup() pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(make([]byte, header.ARPSize)), + Payload: bufferv2.MakeWithData(make([]byte, header.ARPSize)), }) c.linkEP.InjectInbound(arp.ProtocolNumber, pkt) @@ -208,7 +208,7 @@ func TestDisabledEndpoint(t *testing.T) { ep.Disable() pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(make([]byte, header.ARPSize)), + Payload: bufferv2.MakeWithData(make([]byte, header.ARPSize)), }) c.linkEP.InjectInbound(arp.ProtocolNumber, pkt) @@ -240,7 +240,7 @@ func TestDirectReply(t *testing.T) { copy(h.ProtocolAddressTarget(), stackAddr) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(v), + Payload: bufferv2.MakeWithData(v), }) c.linkEP.InjectInbound(arp.ProtocolNumber, pkt) @@ -304,7 +304,7 @@ func TestDirectRequest(t *testing.T) { copy(h.ProtocolAddressSender(), test.senderAddr) copy(h.ProtocolAddressTarget(), test.targetAddr) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(v), + Payload: bufferv2.MakeWithData(v), }) c.linkEP.InjectInbound(arp.ProtocolNumber, pkt) pkt.DecRef() @@ -346,7 +346,7 @@ func TestDirectRequest(t *testing.T) { if got, want := pi.NetworkProtocolNumber, arp.ProtocolNumber; got != want { t.Fatalf("expected %d, got network protocol number %d", want, got) } - rep := header.ARP(pi.NetworkHeader().View()) + rep := header.ARP(pi.NetworkHeader().Slice()) pi.DecRef() if !rep.IsValid() { t.Fatalf("invalid ARP response: len = %d; response = %x", len(rep), rep) @@ -629,7 +629,9 @@ func TestLinkAddressRequest(t *testing.T) { t.Errorf("got pkt.EgressRoute.RemoteLinkAddress = %s, want = %s", pkt.EgressRoute.RemoteLinkAddress, test.expectedRemoteLinkAddr) } - rep := header.ARP(stack.PayloadSince(pkt.NetworkHeader())) + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() + rep := header.ARP(payload.AsSlice()) pkt.DecRef() if got := rep.Op(); got != header.ARPRequest { t.Errorf("got Op = %d, want = %d", got, header.ARPRequest) @@ -685,8 +687,9 @@ func TestDADARPRequestPacket(t *testing.T) { if pkt.EgressRoute.RemoteLinkAddress != header.EthernetBroadcastAddress { t.Errorf("got pkt.EgressRoute.RemoteLinkAddress = %s, want = %s", pkt.EgressRoute.RemoteLinkAddress, header.EthernetBroadcastAddress) } - - req := header.ARP(stack.PayloadSince(pkt.NetworkHeader())) + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() + req := header.ARP(payload.AsSlice()) pkt.DecRef() if !req.IsValid() { t.Errorf("got req.IsValid() = false, want = true") diff --git a/pkg/tcpip/network/internal/fragmentation/BUILD b/pkg/tcpip/network/internal/fragmentation/BUILD index ddd64e586..42f5ecb5b 100644 --- a/pkg/tcpip/network/internal/fragmentation/BUILD +++ b/pkg/tcpip/network/internal/fragmentation/BUILD @@ -27,7 +27,7 @@ go_library( "//pkg/tcpip/network/ipv6:__pkg__", ], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/log", "//pkg/sync", "//pkg/tcpip", @@ -46,7 +46,7 @@ go_test( ], library = ":fragmentation", deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip/faketime", diff --git a/pkg/tcpip/network/internal/fragmentation/fragmentation.go b/pkg/tcpip/network/internal/fragmentation/fragmentation.go index 5b7a90eea..ebd4a2f80 100644 --- a/pkg/tcpip/network/internal/fragmentation/fragmentation.go +++ b/pkg/tcpip/network/internal/fragmentation/fragmentation.go @@ -21,7 +21,7 @@ import ( "fmt" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" @@ -287,7 +287,7 @@ func (f *Fragmentation) releaseReassemblersLocked() { // PacketFragmenter is the book-keeping struct for packet fragmentation. type PacketFragmenter struct { transportHeader []byte - data buffer.Buffer + data bufferv2.Buffer reserve int fragmentPayloadLen int fragmentCount int @@ -312,8 +312,9 @@ func MakePacketFragmenter(pkt *stack.PacketBuffer, fragmentPayloadLen uint32, re // TODO(gvisor.dev/issue/3912): Once Authentication or ESP Headers are // supported for outbound packets, the fragmentable data should not include // these headers. - fragmentableData := buffer.NewWithData(pkt.TransportHeader().View()) - pktBuf := pkt.Data().AsBuffer() + var fragmentableData bufferv2.Buffer + fragmentableData.Append(pkt.TransportHeader().View()) + pktBuf := pkt.Data().ToBuffer() fragmentableData.Merge(&pktBuf) fragmentCount := (uint32(fragmentableData.Size()) + fragmentPayloadLen - 1) / fragmentPayloadLen @@ -344,7 +345,7 @@ func (pf *PacketFragmenter) BuildNextFragment() (*stack.PacketBuffer, int, int, }) // Copy data for the fragment. - copied := fragPkt.Data().ReadFromBuffer(&pf.data, pf.fragmentPayloadLen) + copied := fragPkt.Data().ReadFrom(&pf.data, pf.fragmentPayloadLen) offset := pf.fragmentOffset pf.fragmentOffset += copied @@ -358,3 +359,8 @@ func (pf *PacketFragmenter) BuildNextFragment() (*stack.PacketBuffer, int, int, func (pf *PacketFragmenter) RemainingFragmentCount() int { return pf.fragmentCount - pf.currentFragment } + +// Release frees resources owned by the packet fragmenter. +func (pf *PacketFragmenter) Release() { + pf.data.Release() +} diff --git a/pkg/tcpip/network/internal/fragmentation/fragmentation_test.go b/pkg/tcpip/network/internal/fragmentation/fragmentation_test.go index c80728a84..74f89fd7a 100644 --- a/pkg/tcpip/network/internal/fragmentation/fragmentation_test.go +++ b/pkg/tcpip/network/internal/fragmentation/fragmentation_test.go @@ -20,7 +20,7 @@ import ( "time" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip/faketime" "gvisor.dev/gvisor/pkg/tcpip/network/internal/testutil" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -31,10 +31,13 @@ import ( const reassembleTimeout = 1 // buf is a helper to build a Buffer from different strings. -func buf(size int, pieces ...string) buffer.Buffer { - buf := buffer.Buffer{} +func buf(size int, pieces ...string) bufferv2.Buffer { + buf := bufferv2.Buffer{} + c := buf.Clone() + defer c.Release() for _, p := range pieces { - buf.Append([]byte(p)) + v := bufferv2.NewViewWithData([]byte(p)) + buf.Append(v) } return buf @@ -56,7 +59,7 @@ type processInput struct { } type processOutput struct { - buf buffer.Buffer + buf bufferv2.Buffer proto uint8 done bool } @@ -74,7 +77,7 @@ func TestFragmentationProcess(t *testing.T) { {id: FragmentID{ID: 0}, first: 2, last: 3, more: false, pkt: pkt(2, "23")}, }, out: []processOutput{ - {buf: buffer.Buffer{}, done: false}, + {buf: bufferv2.Buffer{}, done: false}, {buf: buf(4, "01", "23"), done: true}, }, }, @@ -85,7 +88,7 @@ func TestFragmentationProcess(t *testing.T) { {id: FragmentID{ID: 0}, first: 2, last: 3, more: false, proto: 17, pkt: pkt(2, "23")}, }, out: []processOutput{ - {buf: buffer.Buffer{}, done: false}, + {buf: bufferv2.Buffer{}, done: false}, {buf: buf(4, "01", "23"), proto: 6, done: true}, }, }, @@ -98,8 +101,8 @@ func TestFragmentationProcess(t *testing.T) { {id: FragmentID{ID: 0}, first: 2, last: 3, more: false, pkt: pkt(2, "23")}, }, out: []processOutput{ - {buf: buffer.Buffer{}, done: false}, - {buf: buffer.Buffer{}, done: false}, + {buf: bufferv2.Buffer{}, done: false}, + {buf: bufferv2.Buffer{}, done: false}, {buf: buf(4, "ab", "cd"), done: true}, {buf: buf(4, "01", "23"), done: true}, }, @@ -111,6 +114,7 @@ func TestFragmentationProcess(t *testing.T) { firstFragmentProto := c.in[0].proto for i, in := range c.in { defer in.pkt.DecRef() + defer c.out[i].buf.Release() resPkt, proto, done, err := f.Process(in.id, in.first, in.last, in.more, in.proto, in.pkt) if resPkt != nil { defer resPkt.DecRef() @@ -124,7 +128,7 @@ func TestFragmentationProcess(t *testing.T) { in.id, in.first, in.last, in.more, in.proto, done, c.out[i].done) } if c.out[i].done { - if diff := cmp.Diff(c.out[i].buf.Flatten(), resPkt.Data().AsRange().ToOwnedView()); diff != "" { + if diff := cmp.Diff(c.out[i].buf.Flatten(), resPkt.Data().AsRange().ToSlice()); diff != "" { t.Errorf("got Process(%+v, %d, %d, %t, %d, %#v) result mismatch (-want, +got):\n%s", in.id, in.first, in.last, in.more, in.proto, in.pkt, diff) } @@ -525,8 +529,11 @@ func TestPacketFragmenter(t *testing.T) { t.Run(test.name, func(t *testing.T) { pkt := testutil.MakeRandPkt(test.transportHeaderLen, reserve, []int{test.payloadSize}, proto) defer pkt.DecRef() - originalPayload := []byte(stack.PayloadSince(pkt.TransportHeader())) - var reassembledPayload buffer.Buffer + payloadView := stack.PayloadSince(pkt.TransportHeader()) + defer payloadView.Release() + originalPayload := payloadView.AsSlice() + var reassembledPayload bufferv2.Buffer + defer reassembledPayload.Release() pf := MakePacketFragmenter(pkt, test.fragmentPayloadLen, reserve) for i := 0; ; i++ { fragPkt, offset, copied, more := pf.BuildNextFragment() @@ -550,10 +557,10 @@ func TestPacketFragmenter(t *testing.T) { if got := fragPkt.AvailableHeaderBytes(); got != reserve { t.Errorf("(fragment #%d) got fragPkt.AvailableHeaderBytes() = %d, want = %d", i, got, reserve) } - if got := len(fragPkt.TransportHeader().View()); got != 0 { + if got := len(fragPkt.TransportHeader().Slice()); got != 0 { t.Errorf("(fragment #%d) got fragPkt.TransportHeader().View().Size() = %d, want = 0", i, got) } - fragBuf := fragPkt.Data().AsBuffer() + fragBuf := fragPkt.Data().ToBuffer() reassembledPayload.Merge(&fragBuf) if !more { if i != len(test.wantFragments)-1 { @@ -682,11 +689,11 @@ func TestTimeoutHandler(t *testing.T) { } switch { case handler.pkt != nil && test.wantPkt == nil: - t.Errorf("got handler.pkt = not nil (pkt.Data = %x), want = nil", handler.pkt.Data().AsRange().ToOwnedView()) + t.Errorf("got handler.pkt = not nil (pkt.Data = %x), want = nil", handler.pkt.Data().AsRange().ToSlice()) case handler.pkt == nil && test.wantPkt != nil: - t.Errorf("got handler.pkt = nil, want = not nil (pkt.Data = %x)", test.wantPkt.Data().AsRange().ToOwnedView()) + t.Errorf("got handler.pkt = nil, want = not nil (pkt.Data = %x)", test.wantPkt.Data().AsRange().ToSlice()) case handler.pkt != nil && test.wantPkt != nil: - if diff := cmp.Diff(test.wantPkt.Data().AsRange().ToOwnedView(), handler.pkt.Data().AsRange().ToOwnedView()); diff != "" { + if diff := cmp.Diff(test.wantPkt.Data().AsRange().ToSlice(), handler.pkt.Data().AsRange().ToSlice()); diff != "" { t.Errorf("pkt.Data mismatch (-want, +got):\n%s", diff) } } diff --git a/pkg/tcpip/network/internal/fragmentation/reassembler_test.go b/pkg/tcpip/network/internal/fragmentation/reassembler_test.go index ccd7ac6a5..d1e758768 100644 --- a/pkg/tcpip/network/internal/fragmentation/reassembler_test.go +++ b/pkg/tcpip/network/internal/fragmentation/reassembler_test.go @@ -20,7 +20,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip/faketime" "gvisor.dev/gvisor/pkg/tcpip/stack" ) @@ -37,16 +37,16 @@ type processParams struct { func TestReassemblerProcess(t *testing.T) { const proto = 99 - v := func(size int) []byte { - payload := make([]byte, size) + v := func(size int) *bufferv2.View { + payload := bufferv2.NewViewSize(size) for i := 1; i < size; i++ { - payload[i] = uint8(i) * 3 + payload.WriteAt([]byte{uint8(i) * 3}, i) } return payload } pkt := func(sizes ...int) *stack.PacketBuffer { - var buf buffer.Buffer + var buf bufferv2.Buffer for _, size := range sizes { buf.Append(v(size)) } @@ -220,7 +220,7 @@ func TestReassemblerProcess(t *testing.T) { if a == nil || b == nil { return a == b } - return bytes.Equal(a.Data().AsRange().ToOwnedView(), b.Data().AsRange().ToOwnedView()) + return bytes.Equal(a.Data().AsRange().ToSlice(), b.Data().AsRange().ToSlice()) } if isDone { diff --git a/pkg/tcpip/network/internal/multicast/BUILD b/pkg/tcpip/network/internal/multicast/BUILD index d0d43d6d6..1c8c326ff 100644 --- a/pkg/tcpip/network/internal/multicast/BUILD +++ b/pkg/tcpip/network/internal/multicast/BUILD @@ -20,7 +20,7 @@ go_test( srcs = ["route_table_test.go"], library = ":multicast", deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", @@ -38,7 +38,7 @@ go_test( srcs = ["example_test.go"], deps = [ ":multicast", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", diff --git a/pkg/tcpip/network/internal/multicast/example_test.go b/pkg/tcpip/network/internal/multicast/example_test.go index 2b0174287..2dbb891f4 100644 --- a/pkg/tcpip/network/internal/multicast/example_test.go +++ b/pkg/tcpip/network/internal/multicast/example_test.go @@ -20,7 +20,7 @@ import ( "testing" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -129,7 +129,7 @@ func deliverPktLocally(*stack.PacketBuffer) { func newPacketBuffer(body string) *stack.PacketBuffer { return stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData([]byte(body)), + Payload: bufferv2.MakeWithData([]byte(body)), }) } diff --git a/pkg/tcpip/network/internal/multicast/route_table_test.go b/pkg/tcpip/network/internal/multicast/route_table_test.go index 6adedad19..31b69e30a 100644 --- a/pkg/tcpip/network/internal/multicast/route_table_test.go +++ b/pkg/tcpip/network/internal/multicast/route_table_test.go @@ -21,7 +21,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -47,7 +47,7 @@ var ( func newPacketBuffer(body string) *stack.PacketBuffer { return stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData([]byte(body)), + Payload: bufferv2.MakeWithData([]byte(body)), }) } @@ -259,7 +259,7 @@ func TestAddInstalledRouteWithPending(t *testing.T) { cmpOpts := []cmp.Option{ cmp.Transformer("AsSlices", func(pkt *stack.PacketBuffer) [][]byte { - return pkt.Slices() + return pkt.AsSlices() }), cmp.Comparer(func(a [][]byte, b [][]byte) bool { return cmp.Equal(a, b) diff --git a/pkg/tcpip/network/internal/testutil/BUILD b/pkg/tcpip/network/internal/testutil/BUILD index 22474e085..553159ced 100644 --- a/pkg/tcpip/network/internal/testutil/BUILD +++ b/pkg/tcpip/network/internal/testutil/BUILD @@ -13,7 +13,7 @@ go_library( "//pkg/tcpip/tests/integration:__pkg__", ], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/header", "//pkg/tcpip/stack", diff --git a/pkg/tcpip/network/internal/testutil/testutil.go b/pkg/tcpip/network/internal/testutil/testutil.go index aa4febc21..0ea0d0ded 100644 --- a/pkg/tcpip/network/internal/testutil/testutil.go +++ b/pkg/tcpip/network/internal/testutil/testutil.go @@ -20,7 +20,7 @@ import ( "fmt" "math/rand" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -104,19 +104,19 @@ func (ep *MockLinkEndpoint) Close() { // the other headers. The payload is made from Views of the sizes listed in // viewSizes. func MakeRandPkt(transportHeaderLength int, extraHeaderReserveLength int, viewSizes []int, proto tcpip.NetworkProtocolNumber) *stack.PacketBuffer { - var buffer buffer.Buffer + var buf bufferv2.Buffer for _, s := range viewSizes { - newView := make([]byte, s) - if _, err := rand.Read(newView); err != nil { + newView := bufferv2.NewViewSize(s) + if _, err := rand.Read(newView.AsSlice()); err != nil { panic(fmt.Sprintf("rand.Read: %s", err)) } - buffer.Append(newView) + buf.Append(newView) } pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: transportHeaderLength + extraHeaderReserveLength, - Payload: buffer, + Payload: buf, }) pkt.NetworkProtocolNumber = proto if _, err := rand.Read(pkt.TransportHeader().Push(transportHeaderLength)); err != nil { diff --git a/pkg/tcpip/network/ip_test.go b/pkg/tcpip/network/ip_test.go index bc137adf9..0215c61af 100644 --- a/pkg/tcpip/network/ip_test.go +++ b/pkg/tcpip/network/ip_test.go @@ -21,7 +21,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" @@ -128,7 +128,9 @@ func (t *testObject) checkValues(protocol tcpip.TransportProtocolNumber, v []byt // parsing are expected. func (t *testObject) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt *stack.PacketBuffer) stack.TransportPacketDisposition { netHdr := pkt.Network() - t.checkValues(protocol, pkt.Data().AsRange().ToOwnedView(), netHdr.SourceAddress(), netHdr.DestinationAddress()) + v := pkt.Data().AsRange().ToView() + defer v.Release() + t.checkValues(protocol, v.AsSlice(), netHdr.SourceAddress(), netHdr.DestinationAddress()) t.dataCalls++ return stack.TransportPacketHandled } @@ -137,7 +139,9 @@ func (t *testObject) DeliverTransportPacket(protocol tcpip.TransportProtocolNumb // incoming control (ICMP) packets. This is used by the test object to verify // that the results of the parsing are expected. func (t *testObject) DeliverTransportError(local, remote tcpip.Address, net tcpip.NetworkProtocolNumber, trans tcpip.TransportProtocolNumber, transErr stack.TransportError, pkt *stack.PacketBuffer) { - t.checkValues(trans, pkt.Data().AsRange().ToOwnedView(), remote, local) + v := pkt.Data().AsRange().ToView() + defer v.Release() + t.checkValues(trans, v.AsSlice(), remote, local) if diff := cmp.Diff( t.transErr, transportError{ @@ -199,18 +203,18 @@ func (t *testObject) WritePacket(_ *stack.Route, pkt *stack.PacketBuffer) tcpip. var dstAddr tcpip.Address if t.v4 { - h := header.IPv4(pkt.NetworkHeader().View()) + h := header.IPv4(pkt.NetworkHeader().Slice()) prot = tcpip.TransportProtocolNumber(h.Protocol()) srcAddr = h.SourceAddress() dstAddr = h.DestinationAddress() } else { - h := header.IPv6(pkt.NetworkHeader().View()) + h := header.IPv6(pkt.NetworkHeader().Slice()) prot = tcpip.TransportProtocolNumber(h.NextHeader()) srcAddr = h.SourceAddress() dstAddr = h.DestinationAddress() } - t.checkValues(prot, pkt.Data().AsRange().ToOwnedView(), srcAddr, dstAddr) + t.checkValues(prot, pkt.Data().AsRange().ToSlice(), srcAddr, dstAddr) return nil } @@ -389,7 +393,7 @@ func TestSourceAddressValidation(t *testing.T) { ip.SetChecksum(^ip.CalculateChecksum()) pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(header.IPv4ProtocolNumber, pktBuf) pktBuf.DecRef() @@ -416,7 +420,7 @@ func TestSourceAddressValidation(t *testing.T) { DstAddr: localIPv6Addr, }) pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(header.IPv6ProtocolNumber, pktBuf) pktBuf.DecRef() @@ -618,7 +622,7 @@ func TestIPv4Send(t *testing.T) { // Setup the packet buffer. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(ep.MaxHeaderLength()), - Payload: buffer.NewWithData(payload), + Payload: bufferv2.MakeWithData(payload), }) defer pkt.DecRef() @@ -682,7 +686,7 @@ func TestReceive(t *testing.T) { nic.testObject.contents = view[header.IPv4MinimumSize:totalLen] pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(view), + Payload: bufferv2.MakeWithData(view), }) ep.HandlePacket(pkt) pkt.DecRef() @@ -718,7 +722,7 @@ func TestReceive(t *testing.T) { nic.testObject.contents = view[header.IPv6MinimumSize:][:payloadLen] pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(view), + Payload: bufferv2.MakeWithData(view), }) ep.HandlePacket(pkt) pkt.DecRef() @@ -1019,7 +1023,7 @@ func TestIPv4FragmentationReceive(t *testing.T) { // Send first segment. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(frag1), + Payload: bufferv2.MakeWithData(frag1), }) ep.HandlePacket(pkt) pkt.DecRef() @@ -1033,7 +1037,7 @@ func TestIPv4FragmentationReceive(t *testing.T) { // Send second segment. pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(frag2), + Payload: bufferv2.MakeWithData(frag2), }) ep.HandlePacket(pkt) pkt.DecRef() @@ -1073,7 +1077,7 @@ func TestIPv6Send(t *testing.T) { // Setup the packet buffer. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(ep.MaxHeaderLength()), - Payload: buffer.NewWithData(payload), + Payload: bufferv2.MakeWithData(payload), }) defer pkt.DecRef() // Issue the write. @@ -1313,7 +1317,7 @@ func TestIPv6ReceiveControl(t *testing.T) { func truncatedPacket(view []byte, trunc, netHdrLen int) *stack.PacketBuffer { v := view[:len(view)-trunc] pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(v), + Payload: bufferv2.MakeWithData(v), }) return pkt } @@ -1361,7 +1365,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum tcpip.NetworkProtocolNumber nicAddr tcpip.AddressWithPrefix remoteAddr tcpip.Address - pktGen func(*testing.T, tcpip.Address) buffer.Buffer + pktGen func(*testing.T, tcpip.Address) bufferv2.Buffer checker func(*testing.T, *stack.PacketBuffer, tcpip.Address) expectedErr tcpip.Error }{ @@ -1371,7 +1375,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum: ipv4.ProtocolNumber, nicAddr: localIPv4AddrWithPrefix, remoteAddr: remoteIPv4Addr, - pktGen: func(t *testing.T, src tcpip.Address) buffer.Buffer { + pktGen: func(t *testing.T, src tcpip.Address) bufferv2.Buffer { totalLen := header.IPv4MinimumSize + len(data) hdr := prependable.New(totalLen) if n := copy(hdr.Prepend(len(data)), data); n != len(data) { @@ -1384,7 +1388,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { SrcAddr: src, DstAddr: remoteIPv4Addr, }) - return buffer.NewWithData(hdr.View()) + return bufferv2.MakeWithData(hdr.View()) }, checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) { if src == header.IPv4Any { @@ -1393,11 +1397,13 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { netHdr := pkt.NetworkHeader() - if len(netHdr.View()) != header.IPv4MinimumSize { - t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.View()), header.IPv4MinimumSize) + if len(netHdr.Slice()) != header.IPv4MinimumSize { + t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.Slice()), header.IPv4MinimumSize) } - checker.IPv4(t, stack.PayloadSince(netHdr), + payload := stack.PayloadSince(netHdr) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(src), checker.DstAddr(remoteIPv4Addr), checker.IPv4HeaderLength(header.IPv4MinimumSize), @@ -1412,7 +1418,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum: ipv4.ProtocolNumber, nicAddr: localIPv4AddrWithPrefix, remoteAddr: remoteIPv4Addr, - pktGen: func(t *testing.T, src tcpip.Address) buffer.Buffer { + pktGen: func(t *testing.T, src tcpip.Address) bufferv2.Buffer { totalLen := header.IPv4MinimumSize + len(data) hdr := prependable.New(totalLen) if n := copy(hdr.Prepend(len(data)), data); n != len(data) { @@ -1426,7 +1432,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { DstAddr: remoteIPv4Addr, }) ip.SetHeaderLength(header.IPv4MinimumSize - 1) - return buffer.NewWithData(hdr.View()) + return bufferv2.MakeWithData(hdr.View()) }, expectedErr: &tcpip.ErrMalformedHeader{}, }, @@ -1436,7 +1442,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum: ipv4.ProtocolNumber, nicAddr: localIPv4AddrWithPrefix, remoteAddr: remoteIPv4Addr, - pktGen: func(t *testing.T, src tcpip.Address) buffer.Buffer { + pktGen: func(t *testing.T, src tcpip.Address) bufferv2.Buffer { ip := header.IPv4(make([]byte, header.IPv4MinimumSize)) ip.Encode(&header.IPv4Fields{ Protocol: transportProto, @@ -1444,7 +1450,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { SrcAddr: src, DstAddr: remoteIPv4Addr, }) - return buffer.NewWithData(ip[:len(ip)-1]) + return bufferv2.MakeWithData(ip[:len(ip)-1]) }, expectedErr: &tcpip.ErrMalformedHeader{}, }, @@ -1454,7 +1460,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum: ipv4.ProtocolNumber, nicAddr: localIPv4AddrWithPrefix, remoteAddr: remoteIPv4Addr, - pktGen: func(t *testing.T, src tcpip.Address) buffer.Buffer { + pktGen: func(t *testing.T, src tcpip.Address) bufferv2.Buffer { ip := header.IPv4(make([]byte, header.IPv4MinimumSize)) ip.Encode(&header.IPv4Fields{ Protocol: transportProto, @@ -1462,7 +1468,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { SrcAddr: src, DstAddr: remoteIPv4Addr, }) - return buffer.NewWithData(ip) + return bufferv2.MakeWithData(ip) }, checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) { if src == header.IPv4Any { @@ -1471,11 +1477,13 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { netHdr := pkt.NetworkHeader() - if len(netHdr.View()) != header.IPv4MinimumSize { - t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.View()), header.IPv4MinimumSize) + if len(netHdr.Slice()) != header.IPv4MinimumSize { + t.Errorf("got len(netHdr.Slice()) = %d, want = %d", len(netHdr.Slice()), header.IPv4MinimumSize) } - checker.IPv4(t, stack.PayloadSince(netHdr), + payload := stack.PayloadSince(netHdr) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(src), checker.DstAddr(remoteIPv4Addr), checker.IPv4HeaderLength(header.IPv4MinimumSize), @@ -1490,7 +1498,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum: ipv4.ProtocolNumber, nicAddr: localIPv4AddrWithPrefix, remoteAddr: remoteIPv4Addr, - pktGen: func(t *testing.T, src tcpip.Address) buffer.Buffer { + pktGen: func(t *testing.T, src tcpip.Address) bufferv2.Buffer { ipHdrLen := int(header.IPv4MinimumSize + ipv4Options.Length()) totalLen := ipHdrLen + len(data) hdr := prependable.New(totalLen) @@ -1505,7 +1513,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { DstAddr: remoteIPv4Addr, Options: ipv4Options, }) - return buffer.NewWithData(hdr.View()) + return bufferv2.MakeWithData(hdr.View()) }, checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) { if src == header.IPv4Any { @@ -1515,11 +1523,13 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { netHdr := pkt.NetworkHeader() hdrLen := int(header.IPv4MinimumSize + ipv4Options.Length()) - if len(netHdr.View()) != hdrLen { - t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.View()), hdrLen) + if len(netHdr.Slice()) != hdrLen { + t.Errorf("got len(netHdr.Slice()) = %d, want = %d", len(netHdr.Slice()), hdrLen) } - checker.IPv4(t, stack.PayloadSince(netHdr), + payload := stack.PayloadSince(netHdr) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(src), checker.DstAddr(remoteIPv4Addr), checker.IPv4HeaderLength(hdrLen), @@ -1535,7 +1545,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum: ipv4.ProtocolNumber, nicAddr: localIPv4AddrWithPrefix, remoteAddr: remoteIPv4Addr, - pktGen: func(t *testing.T, src tcpip.Address) buffer.Buffer { + pktGen: func(t *testing.T, src tcpip.Address) bufferv2.Buffer { ip := header.IPv4(make([]byte, header.IPv4MinimumSize+ipv4Options.Length())) ip.Encode(&header.IPv4Fields{ Protocol: transportProto, @@ -1544,8 +1554,8 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { DstAddr: remoteIPv4Addr, Options: ipv4Options, }) - buf := buffer.NewWithData(ip) - buf.Append(data) + buf := bufferv2.MakeWithData(ip) + buf.Append(bufferv2.NewViewWithData(data)) return buf }, checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) { @@ -1556,11 +1566,13 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { netHdr := pkt.NetworkHeader() hdrLen := int(header.IPv4MinimumSize + ipv4Options.Length()) - if len(netHdr.View()) != hdrLen { - t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.View()), hdrLen) + if len(netHdr.Slice()) != hdrLen { + t.Errorf("got len(netHdr.Slice()) = %d, want = %d", len(netHdr.Slice()), hdrLen) } - checker.IPv4(t, stack.PayloadSince(netHdr), + payload := stack.PayloadSince(netHdr) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(src), checker.DstAddr(remoteIPv4Addr), checker.IPv4HeaderLength(hdrLen), @@ -1576,7 +1588,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum: ipv6.ProtocolNumber, nicAddr: localIPv6AddrWithPrefix, remoteAddr: remoteIPv6Addr, - pktGen: func(t *testing.T, src tcpip.Address) buffer.Buffer { + pktGen: func(t *testing.T, src tcpip.Address) bufferv2.Buffer { totalLen := header.IPv6MinimumSize + len(data) hdr := prependable.New(totalLen) if n := copy(hdr.Prepend(len(data)), data); n != len(data) { @@ -1589,7 +1601,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { SrcAddr: src, DstAddr: remoteIPv6Addr, }) - return buffer.NewWithData(hdr.View()) + return bufferv2.MakeWithData(hdr.View()) }, checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) { if src == header.IPv6Any { @@ -1598,11 +1610,13 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { netHdr := pkt.NetworkHeader() - if len(netHdr.View()) != header.IPv6MinimumSize { - t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.View()), header.IPv6MinimumSize) + if len(netHdr.Slice()) != header.IPv6MinimumSize { + t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.Slice()), header.IPv6MinimumSize) } - checker.IPv6(t, stack.PayloadSince(netHdr), + payload := stack.PayloadSince(netHdr) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(src), checker.DstAddr(remoteIPv6Addr), checker.IPFullLength(uint16(header.IPv6MinimumSize+len(data))), @@ -1616,7 +1630,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum: ipv6.ProtocolNumber, nicAddr: localIPv6AddrWithPrefix, remoteAddr: remoteIPv6Addr, - pktGen: func(t *testing.T, src tcpip.Address) buffer.Buffer { + pktGen: func(t *testing.T, src tcpip.Address) bufferv2.Buffer { totalLen := header.IPv6MinimumSize + len(ipv6FragmentExtHdr) + len(data) hdr := prependable.New(totalLen) if n := copy(hdr.Prepend(len(data)), data); n != len(data) { @@ -1634,7 +1648,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { SrcAddr: src, DstAddr: remoteIPv6Addr, }) - return buffer.NewWithData(hdr.View()) + return bufferv2.MakeWithData(hdr.View()) }, checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) { if src == header.IPv6Any { @@ -1643,11 +1657,13 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { netHdr := pkt.NetworkHeader() - if want := header.IPv6MinimumSize + len(ipv6FragmentExtHdr); len(netHdr.View()) != want { - t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.View()), want) + if want := header.IPv6MinimumSize + len(ipv6FragmentExtHdr); len(netHdr.Slice()) != want { + t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.Slice()), want) } - checker.IPv6(t, stack.PayloadSince(netHdr), + payload := stack.PayloadSince(netHdr) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(src), checker.DstAddr(remoteIPv6Addr), checker.IPFullLength(uint16(header.IPv6MinimumSize+len(ipv6PayloadWithExtHdr))), @@ -1661,7 +1677,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum: ipv6.ProtocolNumber, nicAddr: localIPv6AddrWithPrefix, remoteAddr: remoteIPv6Addr, - pktGen: func(t *testing.T, src tcpip.Address) buffer.Buffer { + pktGen: func(t *testing.T, src tcpip.Address) bufferv2.Buffer { ip := header.IPv6(make([]byte, header.IPv6MinimumSize)) ip.Encode(&header.IPv6Fields{ TransportProtocol: transportProto, @@ -1669,7 +1685,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { SrcAddr: src, DstAddr: remoteIPv6Addr, }) - return buffer.NewWithData(ip) + return bufferv2.MakeWithData(ip) }, checker: func(t *testing.T, pkt *stack.PacketBuffer, src tcpip.Address) { if src == header.IPv6Any { @@ -1678,11 +1694,13 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { netHdr := pkt.NetworkHeader() - if len(netHdr.View()) != header.IPv6MinimumSize { - t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.View()), header.IPv6MinimumSize) + if len(netHdr.Slice()) != header.IPv6MinimumSize { + t.Errorf("got len(netHdr.View()) = %d, want = %d", len(netHdr.Slice()), header.IPv6MinimumSize) } - checker.IPv6(t, stack.PayloadSince(netHdr), + payload := stack.PayloadSince(netHdr) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(src), checker.DstAddr(remoteIPv6Addr), checker.IPFullLength(header.IPv6MinimumSize), @@ -1696,7 +1714,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { protoNum: ipv6.ProtocolNumber, nicAddr: localIPv6AddrWithPrefix, remoteAddr: remoteIPv6Addr, - pktGen: func(t *testing.T, src tcpip.Address) buffer.Buffer { + pktGen: func(t *testing.T, src tcpip.Address) bufferv2.Buffer { ip := header.IPv6(make([]byte, header.IPv6MinimumSize)) ip.Encode(&header.IPv6Fields{ TransportProtocol: transportProto, @@ -1704,7 +1722,7 @@ func TestWriteHeaderIncludedPacket(t *testing.T) { SrcAddr: src, DstAddr: remoteIPv4Addr, }) - return buffer.NewWithData(ip[:len(ip)-1]) + return bufferv2.MakeWithData(ip[:len(ip)-1]) }, expectedErr: &tcpip.ErrMalformedHeader{}, }, @@ -1811,8 +1829,8 @@ func TestICMPInclusionSize(t *testing.T) { DstAddr: localIPv4Addr, }) ip.SetChecksum(^ip.CalculateChecksum()) - buf := buffer.NewWithData(hdr.View()) - buf.Append(payload) + buf := bufferv2.MakeWithData(hdr.View()) + buf.Append(bufferv2.NewViewWithData(payload)) // Take a copy before InjectInbound takes ownership of vv // as vv may be changed during the call. v := buf.Flatten() @@ -1839,8 +1857,8 @@ func TestICMPInclusionSize(t *testing.T) { SrcAddr: src, DstAddr: localIPv6Addr, }) - buf := buffer.NewWithData(hdr.View()) - buf.Append(payload) + buf := bufferv2.MakeWithData(hdr.View()) + buf.Append(bufferv2.NewViewWithData(payload)) // Take a copy before InjectInbound takes ownership of vv // as vv may be changed during the call. v := buf.Flatten() @@ -1857,7 +1875,9 @@ func TestICMPInclusionSize(t *testing.T) { // We already know the entire packet is the right size so we can use its // length to calculate the right payload size to check. expectedPayloadLength := pkt.Size() - header.IPv4MinimumSize - header.ICMPv4MinimumSize - checker.IPv4(t, stack.PayloadSince(pkt.NetworkHeader()), + p := stack.PayloadSince(pkt.NetworkHeader()) + defer p.Release() + checker.IPv4(t, p, checker.SrcAddr(localIPv4Addr), checker.DstAddr(remoteIPv4Addr), checker.IPv4HeaderLength(header.IPv4MinimumSize), @@ -1875,7 +1895,9 @@ func TestICMPInclusionSize(t *testing.T) { // We already know the entire packet is the right size so we can use its // length to calculate the right payload size to check. expectedPayloadLength := pkt.Size() - header.IPv6MinimumSize - header.ICMPv6MinimumSize - checker.IPv6(t, stack.PayloadSince(pkt.NetworkHeader()), + p := stack.PayloadSince(pkt.NetworkHeader()) + defer p.Release() + checker.IPv6(t, p, checker.SrcAddr(localIPv6Addr), checker.DstAddr(remoteIPv6Addr), checker.IPFullLength(uint16(header.IPv6MinimumSize+header.ICMPv6MinimumSize+expectedPayloadLength)), diff --git a/pkg/tcpip/network/ipv4/BUILD b/pkg/tcpip/network/ipv4/BUILD index eedb62cef..4515d2154 100644 --- a/pkg/tcpip/network/ipv4/BUILD +++ b/pkg/tcpip/network/ipv4/BUILD @@ -13,7 +13,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//pkg/atomicbitops", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/sync", "//pkg/tcpip", "//pkg/tcpip/header", @@ -35,7 +35,7 @@ go_test( "main_test.go", ], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/sync", diff --git a/pkg/tcpip/network/ipv4/icmp.go b/pkg/tcpip/network/ipv4/icmp.go index ef939a053..e26079d68 100644 --- a/pkg/tcpip/network/ipv4/icmp.go +++ b/pkg/tcpip/network/ipv4/icmp.go @@ -17,7 +17,7 @@ package ipv4 import ( "fmt" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/header/parse" @@ -176,7 +176,7 @@ func (e *endpoint) handleControl(errInfo stack.TransportError, pkt *stack.Packet func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { received := e.stats.icmp.packetsReceived - h := header.ICMPv4(pkt.TransportHeader().View()) + h := header.ICMPv4(pkt.TransportHeader().Slice()) if len(h) < header.ICMPv4MinimumSize { received.invalid.Increment() return @@ -196,7 +196,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { return } - iph := header.IPv4(pkt.NetworkHeader().View()) + iph := header.IPv4(pkt.NetworkHeader().Slice()) var newOptions header.IPv4Options if opts := iph.Options(); len(opts) != 0 { // RFC 1122 section 3.2.2.6 (page 43) (and similar for other round trip @@ -249,7 +249,8 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { // waiting endpoints. Consider moving responsibility for doing the copy to // DeliverTransportPacket so that is is only done when needed. replyData := stack.PayloadSince(pkt.TransportHeader()) - ipHdr := header.IPv4(pkt.NetworkHeader().View()) + defer replyData.Release() + ipHdr := header.IPv4(pkt.NetworkHeader().Slice()) localAddressBroadcast := pkt.NetworkPacketInfo.LocalAddressBroadcast // It's possible that a raw socket expects to receive this. @@ -307,25 +308,25 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) { // // Take the base of the incoming request IP header but replace the options. replyHeaderLength := uint8(header.IPv4MinimumSize + len(newOptions)) - replyIPHdrBytes := make([]byte, 0, replyHeaderLength) - replyIPHdrBytes = append(replyIPHdrBytes, iph[:header.IPv4MinimumSize]...) - replyIPHdrBytes = append(replyIPHdrBytes, newOptions...) - replyIPHdr := header.IPv4(replyIPHdrBytes) + replyIPHdrView := bufferv2.NewView(int(replyHeaderLength)) + replyIPHdrView.Write(iph[:header.IPv4MinimumSize]) + replyIPHdrView.Write(newOptions) + replyIPHdr := header.IPv4(replyIPHdrView.AsSlice()) replyIPHdr.SetHeaderLength(replyHeaderLength) replyIPHdr.SetSourceAddress(r.LocalAddress()) replyIPHdr.SetDestinationAddress(r.RemoteAddress()) replyIPHdr.SetTTL(r.DefaultTTL()) - replyIPHdr.SetTotalLength(uint16(len(replyIPHdr) + len(replyData))) + replyIPHdr.SetTotalLength(uint16(len(replyIPHdr) + len(replyData.AsSlice()))) replyIPHdr.SetChecksum(0) replyIPHdr.SetChecksum(^replyIPHdr.CalculateChecksum()) - replyICMPHdr := header.ICMPv4(replyData) + replyICMPHdr := header.ICMPv4(replyData.AsSlice()) replyICMPHdr.SetType(header.ICMPv4EchoReply) replyICMPHdr.SetChecksum(0) - replyICMPHdr.SetChecksum(^header.Checksum(replyData, 0)) + replyICMPHdr.SetChecksum(^header.Checksum(replyData.AsSlice(), 0)) - replyBuf := buffer.NewWithData(replyIPHdr) - replyBuf.AppendOwned(replyData) + replyBuf := bufferv2.MakeWithView(replyIPHdrView) + replyBuf.Append(replyData.Clone()) replyPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(r.MaxHeaderLength()), Payload: replyBuf, @@ -483,7 +484,7 @@ func (*icmpReasonHostUnreachable) isICMPReason() {} // possible as well as any error metadata as is available. returnError // expects pkt to hold a valid IPv4 packet as per the wire format. func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliveredLocally bool) tcpip.Error { - origIPHdr := header.IPv4(pkt.NetworkHeader().View()) + origIPHdr := header.IPv4(pkt.NetworkHeader().Slice()) origIPHdrSrc := origIPHdr.SourceAddress() origIPHdrDst := origIPHdr.DestinationAddress() @@ -544,7 +545,7 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliv return &tcpip.ErrNotConnected{} } - transportHeader := pkt.TransportHeader().View() + transportHeader := pkt.TransportHeader().Slice() // Don't respond to icmp error packets. if origIPHdr.Protocol() == uint8(header.ICMPv4ProtocolNumber) { @@ -642,12 +643,12 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliv // required. This is now the payload of the new ICMP packet and no longer // considered a packet in its own right. - var newHeader []byte - newHeader = append(newHeader, origIPHdr...) - newHeader = append(newHeader, transportHeader...) - payload := buffer.NewWithData(newHeader) + payload := bufferv2.MakeWithView(pkt.NetworkHeader().View()) + payload.Append(pkt.TransportHeader().View()) if dataCap := payloadLen - int(payload.Size()); dataCap > 0 { - payload.AppendOwned(pkt.Data().AsRange().Capped(dataCap).ToOwnedView()) + buf := pkt.Data().ToBuffer() + buf.Truncate(int64(dataCap)) + payload.Merge(&buf) } else { payload.Truncate(int64(payloadLen)) } diff --git a/pkg/tcpip/network/ipv4/igmp.go b/pkg/tcpip/network/ipv4/igmp.go index b90e831ef..55dfe7761 100644 --- a/pkg/tcpip/network/ipv4/igmp.go +++ b/pkg/tcpip/network/ipv4/igmp.go @@ -19,7 +19,7 @@ import ( "time" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/network/internal/ip" @@ -188,7 +188,7 @@ func (igmp *igmpState) isSourceIPValidLocked(src tcpip.Address, messageType head // +checklocks:igmp.ep.mu func (igmp *igmpState) isPacketValidLocked(pkt *stack.PacketBuffer, messageType header.IGMPType, hasRouterAlertOption bool) bool { // We can safely assume that the IP header is valid if we got this far. - iph := header.IPv4(pkt.NetworkHeader().View()) + iph := header.IPv4(pkt.NetworkHeader().Slice()) // As per RFC 2236 section 2, // @@ -206,12 +206,12 @@ func (igmp *igmpState) isPacketValidLocked(pkt *stack.PacketBuffer, messageType // +checklocks:igmp.ep.mu func (igmp *igmpState) handleIGMP(pkt *stack.PacketBuffer, hasRouterAlertOption bool) { received := igmp.ep.stats.igmp.packetsReceived - headerView, ok := pkt.Data().PullUp(header.IGMPMinimumSize) + hdr, ok := pkt.Data().PullUp(header.IGMPMinimumSize) if !ok { received.invalid.Increment() return } - h := header.IGMP(headerView) + h := header.IGMP(hdr) // As per RFC 1071 section 1.3, // @@ -225,7 +225,7 @@ func (igmp *igmpState) handleIGMP(pkt *stack.PacketBuffer, hasRouterAlertOption } isValid := func(minimumSize int) bool { - return len(headerView) >= minimumSize && igmp.isPacketValidLocked(pkt, h.Type(), hasRouterAlertOption) + return len(hdr) >= minimumSize && igmp.isPacketValidLocked(pkt, h.Type(), hasRouterAlertOption) } switch h.Type() { @@ -312,14 +312,15 @@ func (igmp *igmpState) handleMembershipReport(groupAddress tcpip.Address) { // // +checklocksread:igmp.ep.mu func (igmp *igmpState) writePacket(destAddress tcpip.Address, groupAddress tcpip.Address, igmpType header.IGMPType) (bool, tcpip.Error) { - igmpData := header.IGMP(make([]byte, header.IGMPReportMinimumSize)) + igmpView := bufferv2.NewViewSize(header.IGMPReportMinimumSize) + igmpData := header.IGMP(igmpView.AsSlice()) igmpData.SetType(igmpType) igmpData.SetGroupAddress(groupAddress) igmpData.SetChecksum(header.IGMPCalculateChecksum(igmpData)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(igmp.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(igmpData), + Payload: bufferv2.MakeWithView(igmpView), }) defer pkt.DecRef() diff --git a/pkg/tcpip/network/ipv4/igmp_test.go b/pkg/tcpip/network/ipv4/igmp_test.go index 959303a06..c589e0487 100644 --- a/pkg/tcpip/network/ipv4/igmp_test.go +++ b/pkg/tcpip/network/ipv4/igmp_test.go @@ -18,7 +18,7 @@ import ( "testing" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" @@ -49,7 +49,8 @@ var ( func validateIgmpPacket(t *testing.T, pkt *stack.PacketBuffer, igmpType header.IGMPType, maxRespTime byte, srcAddr, dstAddr, groupAddress tcpip.Address) { t.Helper() - payload := header.IPv4(stack.PayloadSince(pkt.NetworkHeader())) + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() checker.IPv4(t, payload, checker.SrcAddr(srcAddr), checker.DstAddr(dstAddr), @@ -129,7 +130,7 @@ func createAndInjectIGMPPacket(e *channel.Endpoint, igmpType header.IGMPType, ma igmp.SetGroupAddress(groupAddress) igmp.SetChecksum(header.IGMPCalculateChecksum(igmp)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) e.InjectInbound(ipv4.ProtocolNumber, pkt) pkt.DecRef() diff --git a/pkg/tcpip/network/ipv4/ipv4.go b/pkg/tcpip/network/ipv4/ipv4.go index cd94f8409..4f245f7fe 100644 --- a/pkg/tcpip/network/ipv4/ipv4.go +++ b/pkg/tcpip/network/ipv4/ipv4.go @@ -123,7 +123,7 @@ func (e *endpoint) HandleLinkResolutionFailure(pkt *stack.PacketBuffer) { // handleControl expects the entire offending packet to be in the packet // buffer's data field. pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: pkt.Buffer(), + Payload: pkt.ToBuffer(), }) defer pkt.DecRef() pkt.NICID = e.nic.ID() @@ -450,8 +450,9 @@ func (e *endpoint) addIPHeader(srcAddr, dstAddr tcpip.Address, pkt *stack.Packet func (e *endpoint) handleFragments(_ *stack.Route, networkMTU uint32, pkt *stack.PacketBuffer, handler func(*stack.PacketBuffer) tcpip.Error) (int, int, tcpip.Error) { // Round the MTU down to align to 8 bytes. fragmentPayloadSize := networkMTU &^ 7 - networkHeader := header.IPv4(pkt.NetworkHeader().View()) + networkHeader := header.IPv4(pkt.NetworkHeader().Slice()) pf := fragmentation.MakePacketFragmenter(pkt, fragmentPayloadSize, pkt.AvailableHeaderBytes()+len(networkHeader)) + defer pf.Release() var n int for { @@ -478,7 +479,7 @@ func (e *endpoint) WritePacket(r *stack.Route, params stack.NetworkHeaderParams, } func (e *endpoint) writePacket(r *stack.Route, pkt *stack.PacketBuffer) tcpip.Error { - netHeader := header.IPv4(pkt.NetworkHeader().View()) + netHeader := header.IPv4(pkt.NetworkHeader().Slice()) dstAddr := netHeader.DestinationAddress() // iptables filtering. All packets that reach here are locally @@ -531,14 +532,14 @@ func (e *endpoint) writePacketPostRouting(r *stack.Route, pkt *stack.PacketBuffe stats := e.stats.ip - networkMTU, err := calculateNetworkMTU(e.nic.MTU(), uint32(len(pkt.NetworkHeader().View()))) + networkMTU, err := calculateNetworkMTU(e.nic.MTU(), uint32(len(pkt.NetworkHeader().Slice()))) if err != nil { stats.OutgoingPacketErrors.Increment() return err } if packetMustBeFragmented(pkt, networkMTU) { - h := header.IPv4(pkt.NetworkHeader().View()) + h := header.IPv4(pkt.NetworkHeader().Slice()) if h.Flags()&header.IPv4FlagDontFragment != 0 && pkt.NetworkPacketInfo.IsForwardedPacket { // TODO(gvisor.dev/issue/5919): Handle error condition in which DontFragment // is set but the packet must be fragmented for the non-forwarding case. @@ -613,7 +614,7 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBu // Note that parsing only makes sure that the packet is well formed as per the // wire format. We also want to check if the header's fields are valid before // sending the packet. - if !parse.IPv4(pkt) || !header.IPv4(pkt.NetworkHeader().View()).IsValid(pktSize) { + if !parse.IPv4(pkt) || !header.IPv4(pkt.NetworkHeader().Slice()).IsValid(pktSize) { return &tcpip.ErrMalformedHeader{} } @@ -628,7 +629,7 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBu // // This method should be invoked by the endpoint that received the pkt. func (e *endpoint) forwardPacketWithRoute(route *stack.Route, pkt *stack.PacketBuffer, updateOptions bool) ip.ForwardingError { - h := header.IPv4(pkt.NetworkHeader().View()) + h := header.IPv4(pkt.NetworkHeader().Slice()) stk := e.protocol.stack inNicName := stk.FindNICNameFromID(e.nic.ID()) @@ -646,7 +647,7 @@ func (e *endpoint) forwardPacketWithRoute(route *stack.Route, pkt *stack.PacketB // TODO(https://gvisor.dev/issue/7473): For multicast, only create one deep // copy and then clone. newPkt := pkt.DeepCopyForForwarding(int(route.MaxHeaderLength())) - newHdr := header.IPv4(newPkt.NetworkHeader().View()) + newHdr := header.IPv4(newPkt.NetworkHeader().Slice()) defer newPkt.DecRef() forwardToEp, ok := e.protocol.getEndpointForNIC(route.NICID()) @@ -696,7 +697,7 @@ func (e *endpoint) forwardPacketWithRoute(route *stack.Route, pkt *stack.PacketB // forwardUnicastPacket attempts to forward a packet to its final destination. func (e *endpoint) forwardUnicastPacket(pkt *stack.PacketBuffer) ip.ForwardingError { - h := header.IPv4(pkt.NetworkHeader().View()) + h := header.IPv4(pkt.NetworkHeader().Slice()) dstAddr := h.DestinationAddress() @@ -799,7 +800,7 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { } if e.protocol.stack.HandleLocal() { - addressEndpoint := e.AcquireAssignedAddress(header.IPv4(pkt.NetworkHeader().View()).SourceAddress(), e.nic.Promiscuous(), stack.CanBePrimaryEndpoint) + addressEndpoint := e.AcquireAssignedAddress(header.IPv4(pkt.NetworkHeader().Slice()).SourceAddress(), e.nic.Promiscuous(), stack.CanBePrimaryEndpoint) if addressEndpoint != nil { addressEndpoint.DecRef() @@ -921,7 +922,7 @@ func (e *endpoint) forwardMulticastPacket(h header.IPv4, pkt *stack.PacketBuffer } func (e *endpoint) updateOptionsForForwarding(pkt *stack.PacketBuffer) ip.ForwardingError { - h := header.IPv4(pkt.NetworkHeader().View()) + h := header.IPv4(pkt.NetworkHeader().Slice()) if opts := h.Options(); len(opts) != 0 { newOpts, _, optProblem := e.processIPOptions(pkt, opts, &optionUsageForward{}) if optProblem != nil { @@ -963,7 +964,7 @@ func (e *endpoint) forwardValidatedMulticastPacket(pkt *stack.PacketBuffer, inst // on the proper interface for forwarding. If not, the datagram is // dropped silently. if e.nic.ID() != installedRoute.ExpectedInputInterface { - h := header.IPv4(pkt.NetworkHeader().View()) + h := header.IPv4(pkt.NetworkHeader().Slice()) e.emitMulticastEvent(func(disp stack.MulticastForwardingEventDispatcher) { disp.OnUnexpectedInputInterface(stack.MulticastPacketContext{ stack.UnicastSourceAndMulticastDestination{h.SourceAddress(), h.DestinationAddress()}, @@ -989,7 +990,7 @@ func (e *endpoint) forwardValidatedMulticastPacket(pkt *stack.PacketBuffer, inst // // This method should be invoked by the endpoint that received the pkt. func (e *endpoint) forwardMulticastPacketForOutgoingInterface(pkt *stack.PacketBuffer, outgoingInterface stack.MulticastRouteOutgoingInterface) ip.ForwardingError { - h := header.IPv4(pkt.NetworkHeader().View()) + h := header.IPv4(pkt.NetworkHeader().Slice()) // Per RFC 1812 section 5.2.1.3, // @@ -1133,7 +1134,7 @@ func (e *endpoint) deliverPacketLocally(h header.IPv4, pkt *stack.PacketBuffer, } if h.More() || h.FragmentOffset() != 0 { - if pkt.Data().Size()+len(pkt.TransportHeader().View()) == 0 { + if pkt.Data().Size()+len(pkt.TransportHeader().Slice()) == 0 { // Drop the packet as it's marked as a fragment but has // no payload. stats.ip.MalformedPacketsReceived.Increment() @@ -1195,7 +1196,7 @@ func (e *endpoint) deliverPacketLocally(h header.IPv4, pkt *stack.PacketBuffer, } defer resPkt.DecRef() pkt = resPkt - h = header.IPv4(pkt.NetworkHeader().View()) + h = header.IPv4(pkt.NetworkHeader().Slice()) // The reassembler doesn't take care of fixing up the header, so we need // to do it here. @@ -1466,8 +1467,6 @@ func (p *protocol) MinimumPacketSize() int { } // ParseAddresses implements stack.NetworkProtocol. -// TODO(b/230896518): Remove buffer.View once stack.NetworkProtocol is changed -// to use pkg/buffer.Buffer. func (*protocol) ParseAddresses(v []byte) (src, dst tcpip.Address) { h := header.IPv4(v) return h.SourceAddress(), h.DestinationAddress() @@ -1697,10 +1696,10 @@ func (p *protocol) parseAndValidate(pkt *stack.PacketBuffer) (header.IPv4, bool) return nil, false } - h := header.IPv4(pkt.NetworkHeader().View()) + h := header.IPv4(pkt.NetworkHeader().Slice()) // Do not include the link header's size when calculating the size of the IP // packet. - if !h.IsValid(pkt.Size() - len(pkt.LinkHeader().View())) { + if !h.IsValid(pkt.Size() - len(pkt.LinkHeader().Slice())) { return nil, false } @@ -1738,7 +1737,7 @@ func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNu return 0, false, false } - ipHdr := header.IPv4(pkt.NetworkHeader().View()) + ipHdr := header.IPv4(pkt.NetworkHeader().Slice()) return ipHdr.TransportProtocol(), !ipHdr.More() && ipHdr.FragmentOffset() == 0, true } @@ -1803,7 +1802,7 @@ func calculateNetworkMTU(linkMTU, networkHeaderSize uint32) (uint32, tcpip.Error } func packetMustBeFragmented(pkt *stack.PacketBuffer, networkMTU uint32) bool { - payload := len(pkt.TransportHeader().View()) + pkt.Data().Size() + payload := len(pkt.TransportHeader().Slice()) + pkt.Data().Size() return pkt.GSOOptions.Type == stack.GSONone && uint32(payload) > networkMTU } @@ -2233,7 +2232,7 @@ func (e *endpoint) processIPOptions(pkt *stack.PacketBuffer, opts header.IPv4Opt // tx interfaces. We will also have to take usage into account. localAddress := e.MainAddress().Address if len(localAddress) == 0 { - h := header.IPv4(pkt.NetworkHeader().View()) + h := header.IPv4(pkt.NetworkHeader().Slice()) dstAddr := h.DestinationAddress() if pkt.NetworkPacketInfo.LocalAddressBroadcast || header.IsV4MulticastAddress(dstAddr) { return nil, optionTracker{}, &header.IPv4OptParameterProblem{ diff --git a/pkg/tcpip/network/ipv4/ipv4_test.go b/pkg/tcpip/network/ipv4/ipv4_test.go index 4d19d1df9..15529ff06 100644 --- a/pkg/tcpip/network/ipv4/ipv4_test.go +++ b/pkg/tcpip/network/ipv4/ipv4_test.go @@ -26,7 +26,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" @@ -299,7 +299,7 @@ func newICMPEchoPacket(t *testing.T, srcAddr, dstAddr tcpip.Address, ttl uint8, } pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber @@ -325,7 +325,7 @@ func checkFragements(t *testing.T, ep *channel.Endpoint, expectedFragments []fra } // The forwarded packet's TTL will have been decremented. - ipHeader := header.IPv4(requestPkt.NetworkHeader().View()) + ipHeader := header.IPv4(requestPkt.NetworkHeader().Slice()) ipHeader.SetTTL(ipHeader.TTL() - 1) // Forwarded packets have available header bytes equalling the sum of the @@ -549,7 +549,9 @@ func TestForwarding(t *testing.T) { t.Fatalf("Expected ICMP packet type %d through incoming NIC", test.icmpError.icmpType) } - checker.IPv4(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(incomingIPv4Addr.Address), checker.DstAddr(test.srcAddr), checker.TTL(ipv4.DefaultTTL), @@ -576,7 +578,9 @@ func TestForwarding(t *testing.T) { t.Fatal("Expected ICMP Echo packet through outgoing NIC") } - checker.IPv4(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(test.srcAddr), checker.DstAddr(test.dstAddr), checker.TTL(test.TTL-1), @@ -731,7 +735,9 @@ func TestFragmentForwarding(t *testing.T) { t.Fatalf("Expected ICMP packet type %d through incoming NIC", test.icmpError.icmpType) } - checker.IPv4(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(incomingIPv4Addr.Address), checker.DstAddr(remoteIPv4Addr1), checker.TTL(ipv4.DefaultTTL), @@ -1072,7 +1078,9 @@ func TestMulticastForwardingOptions(t *testing.T) { t.Fatal("Expected ICMP Echo packet through outgoing NIC") } - checker.IPv4(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(remoteIPv4Addr1), checker.DstAddr(multicastIPv4Addr), checker.TTL(packetTTL-1), @@ -1802,7 +1810,7 @@ func TestIPv4Sanity(t *testing.T) { } ip.SetChecksum(^ipHeaderChecksum) requestPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) defer requestPkt.DecRef() e.InjectInbound(header.IPv4ProtocolNumber, requestPkt) @@ -1833,7 +1841,8 @@ func TestIPv4Sanity(t *testing.T) { } // Make sure it's all in one buffer for checker. - replyIPHeader := header.IPv4(stack.PayloadSince(reply.NetworkHeader())) + replyIPHeader := stack.PayloadSince(reply.NetworkHeader()) + defer replyIPHeader.Release() // At this stage we only know it's probably an IP+ICMP header so verify // that much. @@ -1851,7 +1860,7 @@ func TestIPv4Sanity(t *testing.T) { } // OK it's ICMP. We can safely look at the type now. - replyICMPHeader := header.ICMPv4(replyIPHeader.Payload()) + replyICMPHeader := header.ICMPv4(header.IPv4(replyIPHeader.AsSlice()).Payload()) switch replyICMPHeader.Type() { case header.ICMPv4ParamProblem: if !test.shouldFail { @@ -1930,14 +1939,15 @@ func TestIPv4Sanity(t *testing.T) { func compareFragments(packets []*stack.PacketBuffer, sourcePacket *stack.PacketBuffer, mtu uint32, wantFragments []fragmentInfo, proto tcpip.TransportProtocolNumber, withIPHeader bool, expectedAvailableHeaderBytes int) error { // Make a complete array of the sourcePacket packet. var source header.IPv4 - buf := sourcePacket.Buffer() + buf := sourcePacket.ToBuffer() + defer buf.Release() // If the packet to be fragmented contains an IPv4 header, use that header for // validating fragment headers. Else, use the header of the first fragment. if withIPHeader { source = header.IPv4(buf.Flatten()) } else { - source = header.IPv4(packets[0].NetworkHeader().View()) + source = header.IPv4(packets[0].NetworkHeader().Slice()) source = append(source, buf.Flatten()...) } @@ -1948,10 +1958,12 @@ func compareFragments(packets []*stack.PacketBuffer, sourcePacket *stack.PacketB sourceCopy.SetFlagsFragmentOffset(0, 0) sourceCopy.SetTotalLength(0) // Build up an array of the bytes sent. - var reassembledPayload buffer.Buffer + var reassembledPayload bufferv2.Buffer + defer reassembledPayload.Release() for i, packet := range packets { // Confirm that the packet is valid. - allBytes := packet.Buffer() + allBytes := packet.ToBuffer() + defer allBytes.Release() fragmentIPHeader := header.IPv4(allBytes.Flatten()) if !fragmentIPHeader.IsValid(len(fragmentIPHeader)) { return fmt.Errorf("fragment #%d: IP packet is invalid:\n%s", i, hex.Dump(fragmentIPHeader)) @@ -1977,7 +1989,7 @@ func compareFragments(packets []*stack.PacketBuffer, sourcePacket *stack.PacketB sourceCopy.SetFlagsFragmentOffset(sourceCopy.Flags()&^header.IPv4FlagMoreFragments, wantFragments[i].offset) } reassembledPayload.Append(packet.TransportHeader().View()) - reassembledPayload.Append(packet.Data().AsRange().ToOwnedView()) + reassembledPayload.Append(packet.Data().AsRange().ToView()) // Clear out the checksum and length from the ip because we can't compare // it. sourceCopy.SetTotalLength(wantFragments[i].payloadSize + header.IPv4MinimumSize) @@ -2532,7 +2544,7 @@ func TestInvalidFragments(t *testing.T) { } pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(header.IPv4ProtocolNumber, pkt) pkt.DecRef() @@ -2739,7 +2751,7 @@ func TestFragmentReassemblyTimeout(t *testing.T) { NIC: nicID, }}) - var firstFragmentSent buffer.Buffer + var firstFragmentSent bufferv2.Buffer for _, f := range test.fragments { pktSize := header.IPv4MinimumSize hdr := prependable.New(pktSize) @@ -2750,15 +2762,16 @@ func TestFragmentReassemblyTimeout(t *testing.T) { ip.SetChecksum(0) ip.SetChecksum(^ip.CalculateChecksum()) - buf := buffer.NewWithData(hdr.View()) - buf.Append(f.payload) + buf := bufferv2.MakeWithData(hdr.View()) + buf.Append(bufferv2.NewViewWithData(f.payload)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ Payload: buf, }) if firstFragmentSent.Size() == 0 && ip.FragmentOffset() == 0 { - firstFragmentSent = buffer.NewWithData(stack.PayloadSince(pkt.NetworkHeader())) + firstFragmentSent = bufferv2.MakeWithView(stack.PayloadSince(pkt.NetworkHeader())) + defer firstFragmentSent.Release() } e.InjectInbound(header.IPv4ProtocolNumber, pkt) @@ -2781,7 +2794,9 @@ func TestFragmentReassemblyTimeout(t *testing.T) { t.Fatalf("unexpected ICMP error message received: %#v", reply) } - checker.IPv4(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(addr2), checker.DstAddr(addr1), checker.IPFullLength(uint16(header.IPv4MinimumSize+header.ICMPv4MinimumSize+firstFragmentSent.Size())), @@ -3247,8 +3262,8 @@ func TestReceiveFragments(t *testing.T) { }) ip.SetChecksum(^ip.CalculateChecksum()) - buf := buffer.NewWithData(hdr.View()) - buf.Append(frag.payload) + buf := bufferv2.MakeWithData(hdr.View()) + buf.Append(bufferv2.NewViewWithData(frag.payload)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ Payload: buf, }) @@ -3419,7 +3434,7 @@ func TestWriteStats(t *testing.T) { for i := 0; i < nPackets; i++ { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: header.UDPMinimumSize + int(rt.MaxHeaderLength()), - Payload: buffer.Buffer{}, + Payload: bufferv2.Buffer{}, }) defer pkt.DecRef() pkt.TransportHeader().Push(header.UDPMinimumSize) @@ -3550,7 +3565,7 @@ func TestPacketQueuing(t *testing.T) { }) ip.SetChecksum(^ip.CalculateChecksum()) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) defer pkt.DecRef() e.InjectInbound(ipv4.ProtocolNumber, pkt) @@ -3567,7 +3582,9 @@ func TestPacketQueuing(t *testing.T) { if p.EgressRoute.RemoteLinkAddress != host2NICLinkAddr { t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, host2NICLinkAddr) } - checker.IPv4(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address), checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address), checker.ICMPv4( @@ -3596,7 +3613,7 @@ func TestPacketQueuing(t *testing.T) { }) ip.SetChecksum(^ip.CalculateChecksum()) echoPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) defer echoPkt.DecRef() e.InjectInbound(header.IPv4ProtocolNumber, echoPkt) @@ -3613,7 +3630,9 @@ func TestPacketQueuing(t *testing.T) { if p.EgressRoute.RemoteLinkAddress != host2NICLinkAddr { t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, host2NICLinkAddr) } - checker.IPv4(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address), checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address), checker.ICMPv4( @@ -3664,7 +3683,7 @@ func TestPacketQueuing(t *testing.T) { if p.EgressRoute.RemoteLinkAddress != header.EthernetBroadcastAddress { t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, header.EthernetBroadcastAddress) } - rep := header.ARP(p.NetworkHeader().View()) + rep := header.ARP(p.NetworkHeader().Slice()) p.DecRef() if got := rep.Op(); got != header.ARPRequest { t.Errorf("got Op() = %d, want = %d", got, header.ARPRequest) @@ -3691,7 +3710,7 @@ func TestPacketQueuing(t *testing.T) { copy(packet.HardwareAddressTarget(), host1NICLinkAddr) copy(packet.ProtocolAddressTarget(), host1IPv4Addr.AddressWithPrefix.Address) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr), + Payload: bufferv2.MakeWithData(hdr), }) e.InjectInbound(arp.ProtocolNumber, pkt) pkt.DecRef() @@ -3907,7 +3926,9 @@ func TestIcmpRateLimit(t *testing.T) { if got, want := p.NetworkProtocolNumber, header.IPv4ProtocolNumber; got != want { t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", got, want) } - checker.IPv4(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address), checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address), checker.ICMPv4( @@ -3941,7 +3962,7 @@ func TestIcmpRateLimit(t *testing.T) { p := e.Read() if round >= icmpBurst { if p != nil { - t.Errorf("got packet %x in round %d, expected ICMP rate limit to stop it", p.Data().Slices(), round) + t.Errorf("got packet %x in round %d, expected ICMP rate limit to stop it", p.Data().AsRange().ToSlice(), round) p.DecRef() } return @@ -3950,7 +3971,9 @@ func TestIcmpRateLimit(t *testing.T) { t.Fatalf("expected unreachable in round %d, no packet read in endpoint", round) } defer p.DecRef() - checker.IPv4(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv4(t, payload, checker.SrcAddr(host1IPv4Addr.AddressWithPrefix.Address), checker.DstAddr(host2IPv4Addr.AddressWithPrefix.Address), checker.ICMPv4( @@ -3963,7 +3986,7 @@ func TestIcmpRateLimit(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { for round := 0; round < icmpBurst+1; round++ { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(testCase.createPacket()), + Payload: bufferv2.MakeWithData(testCase.createPacket()), }) e.InjectInbound(header.IPv4ProtocolNumber, pkt) pkt.DecRef() diff --git a/pkg/tcpip/network/ipv6/BUILD b/pkg/tcpip/network/ipv6/BUILD index de912f224..793ba9f63 100644 --- a/pkg/tcpip/network/ipv6/BUILD +++ b/pkg/tcpip/network/ipv6/BUILD @@ -15,7 +15,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//pkg/atomicbitops", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/sync", "//pkg/tcpip", "//pkg/tcpip/header", @@ -39,7 +39,7 @@ go_test( ], library = ":ipv6", deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", @@ -67,7 +67,7 @@ go_test( srcs = ["mld_test.go"], deps = [ ":ipv6", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", diff --git a/pkg/tcpip/network/ipv6/icmp.go b/pkg/tcpip/network/ipv6/icmp.go index 4590c978d..c55d46f70 100644 --- a/pkg/tcpip/network/ipv6/icmp.go +++ b/pkg/tcpip/network/ipv6/icmp.go @@ -17,7 +17,7 @@ package ipv6 import ( "fmt" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/stack" @@ -275,7 +275,7 @@ func isMLDValid(pkt *stack.PacketBuffer, iph header.IPv6, routerAlert *header.IP if routerAlert == nil || routerAlert.Value != header.IPv6RouterAlertMLD { return false } - if len(pkt.TransportHeader().View()) < header.ICMPv6HeaderSize+header.MLDMinimumSize { + if len(pkt.TransportHeader().Slice()) < header.ICMPv6HeaderSize+header.MLDMinimumSize { return false } if iph.HopLimit() != header.MLDHopLimit { @@ -290,12 +290,12 @@ func isMLDValid(pkt *stack.PacketBuffer, iph header.IPv6, routerAlert *header.IP func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool, routerAlert *header.IPv6RouterAlertOption) { sent := e.stats.icmp.packetsSent received := e.stats.icmp.packetsReceived - h := header.ICMPv6(pkt.TransportHeader().View()) + h := header.ICMPv6(pkt.TransportHeader().Slice()) if len(h) < header.ICMPv6MinimumSize { received.invalid.Increment() return } - iph := header.IPv6(pkt.NetworkHeader().View()) + iph := header.IPv6(pkt.NetworkHeader().Slice()) srcAddr := iph.SourceAddress() dstAddr := iph.DestinationAddress() @@ -675,7 +675,7 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer, hasFragmentHeader bool, r replyPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(r.MaxHeaderLength()) + header.ICMPv6EchoMinimumSize, - Payload: pkt.Data().AsBuffer(), + Payload: pkt.Data().ToBuffer(), }) defer replyPkt.DecRef() icmp := header.ICMPv6(replyPkt.TransportHeader().Push(header.ICMPv6EchoMinimumSize)) @@ -1043,7 +1043,7 @@ func (*icmpReasonReassemblyTimeout) respondsToMulticast() bool { // returnError takes an error descriptor and generates the appropriate ICMP // error packet for IPv6 and sends it. func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliveredLocally bool) tcpip.Error { - origIPHdr := header.IPv6(pkt.NetworkHeader().View()) + origIPHdr := header.IPv6(pkt.NetworkHeader().Slice()) origIPHdrSrc := origIPHdr.SourceAddress() origIPHdrDst := origIPHdr.DestinationAddress() @@ -1109,7 +1109,7 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliv } if pkt.TransportProtocolNumber == header.ICMPv6ProtocolNumber { - if typ := header.ICMPv6(pkt.TransportHeader().View()).Type(); typ.IsErrorType() || typ == header.ICMPv6RedirectMsg { + if typ := header.ICMPv6(pkt.TransportHeader().Slice()).Type(); typ.IsErrorType() || typ == header.ICMPv6RedirectMsg { return nil } } @@ -1161,13 +1161,13 @@ func (p *protocol) returnError(reason icmpReason, pkt *stack.PacketBuffer, deliv if available < header.IPv6MinimumSize { return nil } - payloadLen := len(network) + len(transport) + pkt.Data().Size() + payloadLen := network.Size() + transport.Size() + pkt.Data().Size() if payloadLen > available { payloadLen = available } - payload := buffer.NewWithData(network) - payload.AppendOwned(transport) - dataBuf := pkt.Data().AsBuffer() + payload := bufferv2.MakeWithView(network) + payload.Append(transport) + dataBuf := pkt.Data().ToBuffer() payload.Merge(&dataBuf) payload.Truncate(int64(payloadLen)) diff --git a/pkg/tcpip/network/ipv6/icmp_test.go b/pkg/tcpip/network/ipv6/icmp_test.go index c58818bcf..417b2c9a9 100644 --- a/pkg/tcpip/network/ipv6/icmp_test.go +++ b/pkg/tcpip/network/ipv6/icmp_test.go @@ -23,7 +23,7 @@ import ( "github.com/google/go-cmp/cmp" "golang.org/x/time/rate" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" @@ -190,8 +190,8 @@ func handleICMPInIPv6(ep stack.NetworkEndpoint, src, dst tcpip.Address, icmp hea ExtensionHeaders: extensionHeaders, }) - buf := buffer.NewWithData(ip) - buf.Append(icmp) + buf := bufferv2.MakeWithData(ip) + buf.Append(bufferv2.NewViewWithData([]byte(icmp))) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ Payload: buf, }) @@ -527,7 +527,7 @@ func routeICMPv6Packet(t *testing.T, clock *faketime.ManualClock, args routeArgs { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: pi.Buffer(), + Payload: pi.ToBuffer(), }) args.dst.InjectInbound(pi.NetworkProtocolNumber, pkt) pkt.DecRef() @@ -544,7 +544,9 @@ func routeICMPv6Packet(t *testing.T, clock *faketime.ManualClock, args routeArgs // Pull the full payload since network header. Needed for header.IPv6 to // extract its payload. - ipv6 := header.IPv6(stack.PayloadSince(pi.NetworkHeader())) + payload := stack.PayloadSince(pi.NetworkHeader()) + defer payload.Release() + ipv6 := header.IPv6(payload.AsSlice()) transProto := tcpip.TransportProtocolNumber(ipv6.NextHeader()) if transProto != header.ICMPv6ProtocolNumber { t.Errorf("unexpected transport protocol number %d", transProto) @@ -785,7 +787,7 @@ func TestICMPChecksumValidationSimple(t *testing.T) { SrcAddr: lladdr1, DstAddr: lladdr0, }) - buf := buffer.NewWithData(append(ip, icmp...)) + buf := bufferv2.MakeWithData(append(ip, icmp...)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ Payload: buf, }) @@ -991,7 +993,7 @@ func TestICMPChecksumValidationWithPayload(t *testing.T) { DstAddr: lladdr0, }) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(ProtocolNumber, pkt) pkt.DecRef() @@ -1182,7 +1184,7 @@ func TestICMPChecksumValidationWithPayloadMultipleViews(t *testing.T) { SrcAddr: lladdr1, DstAddr: lladdr0, }) - buf := buffer.NewWithData(append(hdr.View(), payload...)) + buf := bufferv2.MakeWithData(append(hdr.View(), payload...)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ Payload: buf, }) @@ -1350,7 +1352,9 @@ func TestLinkAddressRequest(t *testing.T) { if diff := cmp.Diff(want, pkt.EgressRoute, cmp.AllowUnexported(want)); diff != "" { t.Errorf("route info mismatch (-want +got):\n%s", diff) } - checker.IPv6(t, stack.PayloadSince(pkt.NetworkHeader()), + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(lladdr1), checker.DstAddr(test.expectedRemoteAddr), checker.TTL(header.NDPHopLimit), @@ -1413,7 +1417,7 @@ func TestPacketQueing(t *testing.T) { DstAddr: host1IPv6Addr.AddressWithPrefix.Address, }) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(ProtocolNumber, pkt) pkt.DecRef() @@ -1430,7 +1434,9 @@ func TestPacketQueing(t *testing.T) { if p.EgressRoute.RemoteLinkAddress != host2NICLinkAddr { t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, host2NICLinkAddr) } - checker.IPv6(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address), checker.ICMPv6( @@ -1462,7 +1468,7 @@ func TestPacketQueing(t *testing.T) { DstAddr: host1IPv6Addr.AddressWithPrefix.Address, }) pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(header.IPv6ProtocolNumber, pktBuf) pktBuf.DecRef() @@ -1479,7 +1485,9 @@ func TestPacketQueing(t *testing.T) { if p.EgressRoute.RemoteLinkAddress != host2NICLinkAddr { t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, host2NICLinkAddr) } - checker.IPv6(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address), checker.ICMPv6( @@ -1532,7 +1540,9 @@ func TestPacketQueing(t *testing.T) { if want := header.EthernetAddressFromMulticastIPv6Address(snmc); p.EgressRoute.RemoteLinkAddress != want { t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, want) } - checker.IPv6(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(snmc), checker.TTL(header.NDPHopLimit), @@ -1571,7 +1581,7 @@ func TestPacketQueing(t *testing.T) { DstAddr: host1IPv6Addr.AddressWithPrefix.Address, }) pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(ProtocolNumber, pktBuf) pktBuf.DecRef() diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go index 6b3f2eb56..d5b8f9ded 100644 --- a/pkg/tcpip/network/ipv6/ipv6.go +++ b/pkg/tcpip/network/ipv6/ipv6.go @@ -25,7 +25,7 @@ import ( "time" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -299,7 +299,7 @@ func (e *endpoint) HandleLinkResolutionFailure(pkt *stack.PacketBuffer) { // handleControl expects the entire offending packet to be in the packet // buffer's data field. pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: pkt.Buffer(), + Payload: pkt.ToBuffer(), }) defer pkt.DecRef() pkt.NICID = e.nic.ID() @@ -729,7 +729,7 @@ func addIPHeader(srcAddr, dstAddr tcpip.Address, pkt *stack.PacketBuffer, params } func packetMustBeFragmented(pkt *stack.PacketBuffer, networkMTU uint32) bool { - payload := len(pkt.TransportHeader().View()) + pkt.Data().Size() + payload := len(pkt.TransportHeader().Slice()) + pkt.Data().Size() return pkt.GSOOptions.Type == stack.GSONone && uint32(payload) > networkMTU } @@ -739,7 +739,7 @@ func packetMustBeFragmented(pkt *stack.PacketBuffer, networkMTU uint32) bool { // original packet. The transport header protocol number is required to avoid // parsing the IPv6 extension headers. func (e *endpoint) handleFragments(r *stack.Route, networkMTU uint32, pkt *stack.PacketBuffer, transProto tcpip.TransportProtocolNumber, handler func(*stack.PacketBuffer) tcpip.Error) (int, int, tcpip.Error) { - networkHeader := header.IPv6(pkt.NetworkHeader().View()) + networkHeader := header.IPv6(pkt.NetworkHeader().Slice()) // TODO(gvisor.dev/issue/3912): Once the Authentication or ESP Headers are // supported for outbound packets, their length should not affect the fragment @@ -754,13 +754,14 @@ func (e *endpoint) handleFragments(r *stack.Route, networkMTU uint32, pkt *stack return 0, 1, &tcpip.ErrMessageTooLong{} } - if fragmentPayloadLen < uint32(len(pkt.TransportHeader().View())) { + if fragmentPayloadLen < uint32(len(pkt.TransportHeader().Slice())) { // As per RFC 8200 Section 4.5, the Transport Header is expected to be small // enough to fit in the first fragment. return 0, 1, &tcpip.ErrMessageTooLong{} } pf := fragmentation.MakePacketFragmenter(pkt, fragmentPayloadLen, calculateFragmentReserve(pkt)) + defer pf.Release() id := e.protocol.ids[hashRoute(r, e.protocol.hashIV)%buckets].Add(1) var n int @@ -801,7 +802,7 @@ func (e *endpoint) WritePacket(r *stack.Route, params stack.NetworkHeaderParams, // We should do this for every packet, rather than only DNATted packets, but // removing this check short circuits broadcasts before they are sent out to // other hosts. - if netHeader := header.IPv6(pkt.NetworkHeader().View()); dstAddr != netHeader.DestinationAddress() { + if netHeader := header.IPv6(pkt.NetworkHeader().Slice()); dstAddr != netHeader.DestinationAddress() { if ep := e.protocol.findEndpointWithAddress(netHeader.DestinationAddress()); ep != nil { // Since we rewrote the packet but it is being routed back to us, we // can safely assume the checksum is valid. @@ -834,7 +835,7 @@ func (e *endpoint) writePacket(r *stack.Route, pkt *stack.PacketBuffer, protocol } stats := e.stats.ip - networkMTU, err := calculateNetworkMTU(e.nic.MTU(), uint32(len(pkt.NetworkHeader().View()))) + networkMTU, err := calculateNetworkMTU(e.nic.MTU(), uint32(len(pkt.NetworkHeader().Slice()))) if err != nil { stats.OutgoingPacketErrors.Increment() return err @@ -893,7 +894,7 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBu // wire format. We also want to check if the header's fields are valid before // sending the packet. proto, _, _, _, ok := parse.IPv6(pkt) - if !ok || !header.IPv6(pkt.NetworkHeader().View()).IsValid(pktSize) { + if !ok || !header.IPv6(pkt.NetworkHeader().Slice()).IsValid(pktSize) { return &tcpip.ErrMalformedHeader{} } @@ -917,7 +918,7 @@ func validateAddressesForForwarding(h header.IPv6) ip.ForwardingError { // forwardUnicastPacket attempts to forward a unicast packet to its final // destination. func (e *endpoint) forwardUnicastPacket(pkt *stack.PacketBuffer) ip.ForwardingError { - h := header.IPv6(pkt.NetworkHeader().View()) + h := header.IPv6(pkt.NetworkHeader().Slice()) if err := validateAddressesForForwarding(h); err != nil { return err @@ -984,7 +985,7 @@ func (e *endpoint) forwardUnicastPacket(pkt *stack.PacketBuffer) ip.ForwardingEr // // This method should be invoked by the endpoint that received the pkt. func (e *endpoint) forwardPacketWithRoute(route *stack.Route, pkt *stack.PacketBuffer) ip.ForwardingError { - h := header.IPv6(pkt.NetworkHeader().View()) + h := header.IPv6(pkt.NetworkHeader().Slice()) stk := e.protocol.stack inNicName := stk.FindNICNameFromID(e.nic.ID()) @@ -1002,7 +1003,7 @@ func (e *endpoint) forwardPacketWithRoute(route *stack.Route, pkt *stack.PacketB // not own it. newPkt := pkt.DeepCopyForForwarding(int(route.MaxHeaderLength())) defer newPkt.DecRef() - newHdr := header.IPv6(newPkt.NetworkHeader().View()) + newHdr := header.IPv6(newPkt.NetworkHeader().Slice()) // As per RFC 8200 section 3, // @@ -1063,7 +1064,7 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { } if e.protocol.stack.HandleLocal() { - addressEndpoint := e.AcquireAssignedAddress(header.IPv6(pkt.NetworkHeader().View()).SourceAddress(), e.nic.Promiscuous(), stack.CanBePrimaryEndpoint) + addressEndpoint := e.AcquireAssignedAddress(header.IPv6(pkt.NetworkHeader().Slice()).SourceAddress(), e.nic.Promiscuous(), stack.CanBePrimaryEndpoint) if addressEndpoint != nil { addressEndpoint.DecRef() @@ -1165,7 +1166,7 @@ func (e *endpoint) forwardValidatedMulticastPacket(pkt *stack.PacketBuffer, inst // on the proper interface for forwarding. If not, the datagram is // dropped silently. if e.nic.ID() != installedRoute.ExpectedInputInterface { - h := header.IPv6(pkt.NetworkHeader().View()) + h := header.IPv6(pkt.NetworkHeader().Slice()) e.emitMulticastEvent(func(disp stack.MulticastForwardingEventDispatcher) { disp.OnUnexpectedInputInterface(stack.MulticastPacketContext{ stack.UnicastSourceAndMulticastDestination{h.SourceAddress(), h.DestinationAddress()}, @@ -1191,7 +1192,7 @@ func (e *endpoint) forwardValidatedMulticastPacket(pkt *stack.PacketBuffer, inst // // This method should be invoked by the endpoint that received the pkt. func (e *endpoint) forwardMulticastPacketForOutgoingInterface(pkt *stack.PacketBuffer, outgoingInterface stack.MulticastRouteOutgoingInterface) ip.ForwardingError { - h := header.IPv6(pkt.NetworkHeader().View()) + h := header.IPv6(pkt.NetworkHeader().Slice()) // Per RFC 1812 section 5.2.1.3, // @@ -1336,6 +1337,7 @@ func (e *endpoint) processExtensionHeader(it *header.IPv6PayloadIterator, pkt ** if done { return true, nil } + defer extHdr.Release() // As per RFC 8200, section 4: // @@ -1405,9 +1407,13 @@ func (e *endpoint) processExtensionHeaders(h header.IPv6, pkt *stack.PacketBuffe // - Any IPv6 header bytes after the first 40 (i.e. extensions). // - The transport header, if present. // - Any other payload data. - buf := buffer.NewWithData(pkt.NetworkHeader().View()[header.IPv6MinimumSize:]) - buf.AppendOwned(pkt.TransportHeader().View()) - dataBuf := pkt.Data().AsBuffer() + v := pkt.NetworkHeader().View() + if v != nil { + v.TrimFront(header.IPv6MinimumSize) + } + buf := bufferv2.MakeWithView(v) + buf.Append(pkt.TransportHeader().View()) + dataBuf := pkt.Data().ToBuffer() buf.Merge(&dataBuf) it := header.MakeIPv6PayloadIterator(header.IPv6ExtensionHeaderIdentifier(h.NextHeader()), buf) @@ -1417,6 +1423,7 @@ func (e *endpoint) processExtensionHeaders(h header.IPv6, pkt *stack.PacketBuffe pkt.IncRef() defer func() { pkt.DecRef() + it.Release() }() var ( @@ -1445,7 +1452,7 @@ func (e *endpoint) processIPv6RawPayloadHeader(extHdr *header.IPv6RawPayloadHead // // For reassembled fragments, pkt.TransportHeader is unset, so this is a // no-op and pkt.Data begins with the transport header. - trim += len(pkt.TransportHeader().View()) + trim += len(pkt.TransportHeader().Slice()) if _, ok := pkt.Data().Consume(trim); !ok { stats.MalformedPacketsReceived.Increment() @@ -1455,7 +1462,7 @@ func (e *endpoint) processIPv6RawPayloadHeader(extHdr *header.IPv6RawPayloadHead proto := tcpip.TransportProtocolNumber(extHdr.Identifier) // If the packet was reassembled from a fragment, it will not have a // transport header set yet. - if len(pkt.TransportHeader().View()) == 0 { + if len(pkt.TransportHeader().Slice()) == 0 { e.protocol.parseTransport(pkt, proto) } @@ -1539,6 +1546,12 @@ func (e *endpoint) processIPv6RoutingExtHeader(extHdr *header.IPv6RoutingExtHdr, func (e *endpoint) processIPv6DestinationOptionsExtHdr(extHdr *header.IPv6DestinationOptionsExtHdr, it *header.IPv6PayloadIterator, pkt *stack.PacketBuffer, dstAddr tcpip.Address) error { stats := e.stats.ip optsIt := extHdr.Iter() + var uopt *header.IPv6UnknownExtHdrOption + defer func() { + if uopt != nil { + uopt.Data.Release() + } + }() for { opt, done, err := optsIt.Next() @@ -1546,6 +1559,9 @@ func (e *endpoint) processIPv6DestinationOptionsExtHdr(extHdr *header.IPv6Destin stats.MalformedPacketsReceived.Increment() return err } + if uo, ok := opt.(*header.IPv6UnknownExtHdrOption); ok { + uopt = uo + } if done { break } @@ -1558,6 +1574,9 @@ func (e *endpoint) processIPv6DestinationOptionsExtHdr(extHdr *header.IPv6Destin return fmt.Errorf("found unknown destination header option = %#v with discard action", opt) case header.IPv6OptionUnknownActionDiscardSendICMPNoMulticastDest: if header.IsV6MulticastAddress(dstAddr) { + if uo, ok := opt.(*header.IPv6UnknownExtHdrOption); ok { + uopt = uo + } return fmt.Errorf("found unknown destination header option %#v with discard action", opt) } fallthrough @@ -1579,6 +1598,10 @@ func (e *endpoint) processIPv6DestinationOptionsExtHdr(extHdr *header.IPv6Destin default: panic(fmt.Sprintf("unrecognized action for an unrecognized Destination extension header option = %#v", opt)) } + if uopt != nil { + uopt.Data.Release() + uopt = nil + } } return nil } @@ -1596,6 +1619,12 @@ func (e *endpoint) processIPv6HopByHopOptionsExtHdr(extHdr *header.IPv6HopByHopO } optsIt := extHdr.Iter() + var uopt *header.IPv6UnknownExtHdrOption + defer func() { + if uopt != nil { + uopt.Data.Release() + } + }() for { opt, done, err := optsIt.Next() @@ -1603,6 +1632,9 @@ func (e *endpoint) processIPv6HopByHopOptionsExtHdr(extHdr *header.IPv6HopByHopO stats.MalformedPacketsReceived.Increment() return err } + if uo, ok := opt.(*header.IPv6UnknownExtHdrOption); ok { + uopt = uo + } if done { break } @@ -1648,6 +1680,10 @@ func (e *endpoint) processIPv6HopByHopOptionsExtHdr(extHdr *header.IPv6HopByHopO panic(fmt.Sprintf("unrecognized action for an unrecognized Hop By Hop extension header option = %#v", opt)) } } + if uopt != nil { + uopt.Data.Release() + uopt = nil + } } return nil } @@ -1660,6 +1696,7 @@ func (e *endpoint) processFragmentExtHdr(extHdr *header.IPv6FragmentExtHdr, it * // will use it to validate that the first fragment holds the upper layer // header. rawPayload := it.AsRawHeader(extHdr.FragmentOffset() != 0 /* consume */) + defer rawPayload.Release() if extHdr.FragmentOffset() == 0 { // Check that the iterator ends with a raw payload as the first fragment @@ -1678,6 +1715,7 @@ func (e *endpoint) processFragmentExtHdr(extHdr *header.IPv6FragmentExtHdr, it * if done { break } + it.Release() lastHdr = it } @@ -1780,7 +1818,8 @@ func (e *endpoint) processFragmentExtHdr(extHdr *header.IPv6FragmentExtHdr, it * // have more extension headers in the reassembled payload, as per RFC // 8200 section 4.5. We also use the NextHeader value from the first // fragment. - *it = header.MakeIPv6PayloadIterator(header.IPv6ExtensionHeaderIdentifier(proto), resPkt.Data().AsBuffer()) + it.Release() + *it = header.MakeIPv6PayloadIterator(header.IPv6ExtensionHeaderIdentifier(proto), resPkt.Data().ToBuffer()) (*pkt).DecRef() *pkt = resPkt } @@ -2505,10 +2544,10 @@ func (p *protocol) parseAndValidate(pkt *stack.PacketBuffer) (header.IPv6, bool) return nil, false } - h := header.IPv6(pkt.NetworkHeader().View()) + h := header.IPv6(pkt.NetworkHeader().Slice()) // Do not include the link header's size when calculating the size of the IP // packet. - if !h.IsValid(pkt.Size() - len(pkt.LinkHeader().View())) { + if !h.IsValid(pkt.Size() - len(pkt.LinkHeader().Slice())) { return nil, false } @@ -2704,7 +2743,7 @@ func NewProtocol(s *stack.Stack) stack.NetworkProtocol { } func calculateFragmentReserve(pkt *stack.PacketBuffer) int { - return pkt.AvailableHeaderBytes() + len(pkt.NetworkHeader().View()) + header.IPv6FragmentHeaderSize + return pkt.AvailableHeaderBytes() + len(pkt.NetworkHeader().Slice()) + header.IPv6FragmentHeaderSize } // hashRoute calculates a hash value for the given route. It uses the source & diff --git a/pkg/tcpip/network/ipv6/ipv6_test.go b/pkg/tcpip/network/ipv6/ipv6_test.go index 910833dd8..97d2916c8 100644 --- a/pkg/tcpip/network/ipv6/ipv6_test.go +++ b/pkg/tcpip/network/ipv6/ipv6_test.go @@ -25,7 +25,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -93,7 +93,7 @@ func testReceiveICMP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst }) pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(ProtocolNumber, pktBuf) pktBuf.DecRef() @@ -153,7 +153,7 @@ func testReceiveUDP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst }) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(ProtocolNumber, pkt) pkt.DecRef() @@ -168,21 +168,24 @@ func testReceiveUDP(t *testing.T, s *stack.Stack, e *channel.Endpoint, src, dst func compareFragments(packets []*stack.PacketBuffer, sourcePacket *stack.PacketBuffer, mtu uint32, wantFragments []fragmentInfo, proto tcpip.TransportProtocolNumber) error { // sourcePacket does not have its IP Header populated. Let's copy the one // from the first fragment. - source := header.IPv6(packets[0].NetworkHeader().View()) + source := header.IPv6(packets[0].NetworkHeader().Slice()) sourceIPHeadersLen := len(source) - buf := sourcePacket.Buffer() - source = append(source, buf.Flatten()...) + view := sourcePacket.ToView() + defer view.Release() + source = append(source, view.AsSlice()...) - var reassembledPayload buffer.Buffer + var reassembledPayload bufferv2.Buffer + defer reassembledPayload.Release() for i, fragment := range packets { // Confirm that the packet is valid. - allBytes := fragment.Buffer() + allBytes := fragment.ToBuffer() + defer allBytes.Release() fragmentIPHeaders := header.IPv6(allBytes.Flatten()) if !fragmentIPHeaders.IsValid(len(fragmentIPHeaders)) { return fmt.Errorf("fragment #%d: IP packet is invalid:\n%s", i, hex.Dump(fragmentIPHeaders)) } - fragmentIPHeadersLength := len(fragment.NetworkHeader().View()) + fragmentIPHeadersLength := len(fragment.NetworkHeader().Slice()) if fragmentIPHeadersLength != sourceIPHeadersLen { return fmt.Errorf("fragment #%d: got fragmentIPHeadersLength = %d, want = %d", i, fragmentIPHeadersLength, sourceIPHeadersLen) } @@ -233,7 +236,7 @@ func compareFragments(packets []*stack.PacketBuffer, sourcePacket *stack.PacketB // Store the reassembled payload as we parse each fragment. The payload // includes the Transport header and everything after. reassembledPayload.Append(fragment.TransportHeader().View()) - reassembledPayload.Append(fragment.Data().AsRange().ToOwnedView()) + reassembledPayload.Append(fragment.Data().AsRange().ToView()) } if diff := cmp.Diff([]byte(source[sourceIPHeadersLen:]), reassembledPayload.Flatten()); diff != "" { @@ -1011,7 +1014,7 @@ func TestReceiveIPv6ExtHdrs(t *testing.T) { } pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(ProtocolNumber, pkt) pkt.DecRef() @@ -1039,24 +1042,24 @@ func TestReceiveIPv6ExtHdrs(t *testing.T) { if p == nil { t.Fatalf("expected packet wasn't written out") } + defer p.DecRef() - // Pack the output packet into a single buffer.View as the checkers + // Pack the output packet into a single bufferv2.View as the checkers // assume that. - buf := p.Buffer() - p.DecRef() - pkt := buf.Flatten() + v := p.ToView() + defer v.Release() + pkt := v.AsSlice() if got, want := len(pkt), header.IPv6FixedHeaderSize+header.ICMPv6MinimumSize+hdr.UsedLength(); got != want { t.Fatalf("got an ICMP packet of size = %d, want = %d", got, want) } - ipHdr := header.IPv6(pkt) - checker.IPv6(t, ipHdr, checker.ICMPv6( + checker.IPv6(t, v, checker.ICMPv6( checker.ICMPv6Type(test.ICMPType), checker.ICMPv6Code(test.ICMPCode))) // We know we are looking at no extension headers in the error ICMP // packets. - icm := header.ICMPv6(ipHdr.Payload()) + icm := header.ICMPv6(header.IPv6(pkt).Payload()) // We know we sent small packets that won't be truncated when reflected // back to us. originalPacket := icm.Payload() @@ -1102,7 +1105,7 @@ type fragmentData struct { srcAddr tcpip.Address dstAddr tcpip.Address nextHdr uint8 - data buffer.Buffer + data []byte } func TestReceiveIPv6Fragments(t *testing.T) { @@ -1175,7 +1178,7 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: uint8(header.UDPProtocolNumber), - data: buffer.NewWithData(ipv6Payload1Addr1ToAddr2), + data: ipv6Payload1Addr1ToAddr2, }, }, expectedPayloads: [][]byte{udpPayload1Addr1ToAddr2}, @@ -1187,12 +1190,10 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( + data: append( // Fragment extension header. - append( - []byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 0}, - ipv6Payload1Addr1ToAddr2..., - ), + []byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 0}, + ipv6Payload1Addr1ToAddr2..., ), }, }, @@ -1205,12 +1206,10 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - []byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 0}, - ipv6Payload3Addr1ToAddr2..., - ), + data: append( + // Fragment extension header. + []byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 0}, + ipv6Payload3Addr1ToAddr2..., ), }, }, @@ -1223,28 +1222,24 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[:64]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[:64]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 8, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[64:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 8, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[64:]..., ), }, }, @@ -1257,28 +1252,24 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 8, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[64:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 8, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[64:]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[:64]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[:64]..., ), }, }, @@ -1291,30 +1282,26 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[:64]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[:64]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 8, More = false, ID = 1 - // NextHeader value is different than the one in the first fragment, so - // this NextHeader should be ignored. - []byte{uint8(header.IPv6NoNextHeaderIdentifier), 0, 0, 64, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[64:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 8, More = false, ID = 1 + // NextHeader value is different than the one in the first fragment, so + // this NextHeader should be ignored. + []byte{uint8(header.IPv6NoNextHeaderIdentifier), 0, 0, 64, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[64:]..., ), }, }, @@ -1327,28 +1314,24 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload3Addr1ToAddr2[:64]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload3Addr1ToAddr2[:64]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 8, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, - ipv6Payload3Addr1ToAddr2[64:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 8, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, + ipv6Payload3Addr1ToAddr2[64:]..., ), }, }, @@ -1361,28 +1344,24 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload3Addr1ToAddr2[:63]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload3Addr1ToAddr2[:63]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 8, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, - ipv6Payload3Addr1ToAddr2[63:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 8, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, + ipv6Payload3Addr1ToAddr2[63:]..., ), }, }, @@ -1395,28 +1374,24 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[:64]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[:64]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 8, More = false, ID = 2 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 2}, - ipv6Payload1Addr1ToAddr2[64:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 8, More = false, ID = 2 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 2}, + ipv6Payload1Addr1ToAddr2[64:]..., ), }, }, @@ -1429,31 +1404,27 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload4Addr1ToAddr2[:udpMaximumSizeMinus15]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload4Addr1ToAddr2[:udpMaximumSizeMinus15]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = udpMaximumSizeMinus15/8, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, - udpMaximumSizeMinus15 >> 8, - udpMaximumSizeMinus15 & 0xff, - 0, 0, 0, 1}, - ipv6Payload4Addr1ToAddr2[udpMaximumSizeMinus15:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = udpMaximumSizeMinus15/8, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, + udpMaximumSizeMinus15 >> 8, + udpMaximumSizeMinus15 & 0xff, + 0, 0, 0, 1}, + ipv6Payload4Addr1ToAddr2[udpMaximumSizeMinus15:]..., ), }, }, @@ -1466,32 +1437,28 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload4Addr1ToAddr2[:udpMaximumSizeMinus15]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload4Addr1ToAddr2[:udpMaximumSizeMinus15]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = udpMaximumSizeMinus15/8, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, - udpMaximumSizeMinus15 >> 8, - (udpMaximumSizeMinus15 & 0xff) + 1, - 0, 0, 0, 1}, + data: append( + // Fragment extension header. + // + // Fragment offset = udpMaximumSizeMinus15/8, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, + udpMaximumSizeMinus15 >> 8, + (udpMaximumSizeMinus15 & 0xff) + 1, + 0, 0, 0, 1}, - ipv6Payload4Addr1ToAddr2[udpMaximumSizeMinus15:]..., - ), + ipv6Payload4Addr1ToAddr2[udpMaximumSizeMinus15:]..., ), }, }, @@ -1504,40 +1471,36 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: routingExtHdrID, - data: buffer.NewWithData( + data: append( + // Routing extension header. + // + // Segments left = 0. + []byte{fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5}, append( - // Routing extension header. + // Fragment extension header. // - // Segments left = 0. - []byte{fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5}, - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[:64]..., - )..., - ), + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[:64]..., + )..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: routingExtHdrID, - data: buffer.NewWithData( + data: append( + // Routing extension header. + // + // Segments left = 0. + []byte{fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5}, append( - // Routing extension header. + // Fragment extension header. // - // Segments left = 0. - []byte{fragmentExtHdrID, 0, 1, 0, 2, 3, 4, 5}, - append( - // Fragment extension header. - // - // Fragment offset = 8, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[64:]..., - )..., - ), + // Fragment offset = 8, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[64:]..., + )..., ), }, }, @@ -1550,41 +1513,37 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: routingExtHdrID, - data: buffer.NewWithData( + data: append( + // Routing extension header. + // + // Segments left = 1. + []byte{fragmentExtHdrID, 0, 1, 1, 2, 3, 4, 5}, append( - // Routing extension header. + // Fragment extension header. // - // Segments left = 1. - []byte{fragmentExtHdrID, 0, 1, 1, 2, 3, 4, 5}, - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[:64]..., - )..., - ), + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[:64]..., + )..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: routingExtHdrID, - data: buffer.NewWithData( - append( - // Routing extension header. - // - // Segments left = 1. - []byte{fragmentExtHdrID, 0, 1, 1, 2, 3, 4, 5}, + data: append( + // Routing extension header. + // + // Segments left = 1. + []byte{fragmentExtHdrID, 0, 1, 1, 2, 3, 4, 5}, - append( - // Fragment extension header. - // - // Fragment offset = 9, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 72, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[64:]..., - )..., - ), + append( + // Fragment extension header. + // + // Fragment offset = 9, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 72, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[64:]..., + )..., ), }, }, @@ -1597,35 +1556,31 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, append( - // Fragment extension header. + // Routing extension header. // - // Fragment offset = 0, More = true, ID = 1 - []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, - append( - // Routing extension header. - // - // Segments left = 0. - []byte{uint8(header.UDPProtocolNumber), 0, 1, 0, 2, 3, 4, 5}, - ipv6Payload1Addr1ToAddr2[:64]..., - )..., - ), + // Segments left = 0. + []byte{uint8(header.UDPProtocolNumber), 0, 1, 0, 2, 3, 4, 5}, + ipv6Payload1Addr1ToAddr2[:64]..., + )..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 9, More = false, ID = 1 - []byte{routingExtHdrID, 0, 0, 72, 0, 0, 0, 1}, + data: append( + // Fragment extension header. + // + // Fragment offset = 9, More = false, ID = 1 + []byte{routingExtHdrID, 0, 0, 72, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[64:]..., - ), + ipv6Payload1Addr1ToAddr2[64:]..., ), }, }, @@ -1638,34 +1593,30 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, append( - // Fragment extension header. + // Routing extension header. // - // Fragment offset = 0, More = true, ID = 1 - []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, - append( - // Routing extension header. - // - // Segments left = 1. - []byte{uint8(header.UDPProtocolNumber), 0, 1, 1, 2, 3, 4, 5}, - ipv6Payload1Addr1ToAddr2[:64]..., - )..., - ), + // Segments left = 1. + []byte{uint8(header.UDPProtocolNumber), 0, 1, 1, 2, 3, 4, 5}, + ipv6Payload1Addr1ToAddr2[:64]..., + )..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 9, More = false, ID = 1 - []byte{routingExtHdrID, 0, 0, 72, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[64:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 9, More = false, ID = 1 + []byte{routingExtHdrID, 0, 0, 72, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[64:]..., ), }, }, @@ -1678,33 +1629,29 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment offset = 0, More = true, ID = 1 - []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, - // Routing extension header (part 1) - // - // Segments left = 0. - []byte{uint8(header.UDPProtocolNumber), 1, 1, 0, 2, 3, 4, 5}..., - ), + data: append( + // Fragment offset = 0, More = true, ID = 1 + []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, + // Routing extension header (part 1) + // + // Segments left = 0. + []byte{uint8(header.UDPProtocolNumber), 1, 1, 0, 2, 3, 4, 5}..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( + data: append( + // Fragment extension header. + // + // Fragment offset = 1, More = false, ID = 1 + []byte{routingExtHdrID, 0, 0, 8, 0, 0, 0, 1}, append( - // Fragment extension header. - // - // Fragment offset = 1, More = false, ID = 1 - []byte{routingExtHdrID, 0, 0, 8, 0, 0, 0, 1}, - append( - // Routing extension header (part 2) - []byte{6, 7, 8, 9, 10, 11, 12, 13}, - ipv6Payload1Addr1ToAddr2..., - )..., - ), + // Routing extension header (part 2) + []byte{6, 7, 8, 9, 10, 11, 12, 13}, + ipv6Payload1Addr1ToAddr2..., + )..., ), }, }, @@ -1717,36 +1664,32 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{routingExtHdrID, 0, 0, 1, 0, 0, 0, 1}, - // Routing extension header (part 1) - // - // Segments left = 1. - []byte{uint8(header.UDPProtocolNumber), 1, 1, 1, 2, 3, 4, 5}..., - ), + // Routing extension header (part 1) + // + // Segments left = 1. + []byte{uint8(header.UDPProtocolNumber), 1, 1, 1, 2, 3, 4, 5}..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( + data: append( + // Fragment extension header. + // + // Fragment offset = 1, More = false, ID = 1 + []byte{routingExtHdrID, 0, 0, 8, 0, 0, 0, 1}, append( - // Fragment extension header. - // - // Fragment offset = 1, More = false, ID = 1 - []byte{routingExtHdrID, 0, 0, 8, 0, 0, 0, 1}, - append( - // Routing extension header (part 2) - []byte{6, 7, 8, 9, 10, 11, 12, 13}, - ipv6Payload1Addr1ToAddr2..., - )..., - ), + // Routing extension header (part 2) + []byte{6, 7, 8, 9, 10, 11, 12, 13}, + ipv6Payload1Addr1ToAddr2..., + )..., ), }, }, @@ -1761,14 +1704,12 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[:64]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[:64]..., ), }, // This fragment has the same ID as the other fragments but is an atomic @@ -1777,29 +1718,25 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 1}, - ipv6Payload2Addr1ToAddr2..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 0, 0, 0, 0, 1}, + ipv6Payload2Addr1ToAddr2..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 8, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, + data: append( + // Fragment extension header. + // + // Fragment offset = 8, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[64:]..., - ), + ipv6Payload1Addr1ToAddr2[64:]..., ), }, }, @@ -1812,56 +1749,48 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[:64]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[:64]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 2 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 2}, - ipv6Payload2Addr1ToAddr2[:32]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 2 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 2}, + ipv6Payload2Addr1ToAddr2[:32]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 8, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[64:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 8, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[64:]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 4, More = false, ID = 2 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 32, 0, 0, 0, 2}, - ipv6Payload2Addr1ToAddr2[32:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 4, More = false, ID = 2 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 32, 0, 0, 0, 2}, + ipv6Payload2Addr1ToAddr2[32:]..., ), }, }, @@ -1874,57 +1803,49 @@ func TestReceiveIPv6Fragments(t *testing.T) { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[:64]..., - ), + ipv6Payload1Addr1ToAddr2[:64]..., ), }, { srcAddr: addr3, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 0, More = true, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, - ipv6Payload1Addr3ToAddr2[:32]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 0, More = true, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 1, 0, 0, 0, 1}, + ipv6Payload1Addr3ToAddr2[:32]..., ), }, { srcAddr: addr1, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 8, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, - ipv6Payload1Addr1ToAddr2[64:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 8, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 64, 0, 0, 0, 1}, + ipv6Payload1Addr1ToAddr2[64:]..., ), }, { srcAddr: addr3, dstAddr: addr2, nextHdr: fragmentExtHdrID, - data: buffer.NewWithData( - append( - // Fragment extension header. - // - // Fragment offset = 4, More = false, ID = 1 - []byte{uint8(header.UDPProtocolNumber), 0, 0, 32, 0, 0, 0, 1}, - ipv6Payload1Addr3ToAddr2[32:]..., - ), + data: append( + // Fragment extension header. + // + // Fragment offset = 4, More = false, ID = 1 + []byte{uint8(header.UDPProtocolNumber), 0, 0, 32, 0, 0, 0, 1}, + ipv6Payload1Addr3ToAddr2[32:]..., ), }, }, @@ -1973,7 +1894,7 @@ func TestReceiveIPv6Fragments(t *testing.T) { // Serialize IPv6 fixed header. ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize)) ip.Encode(&header.IPv6Fields{ - PayloadLength: uint16(f.data.Size()), + PayloadLength: uint16(len(f.data)), // We're lying about transport protocol here so that we can generate // raw extension headers for the tests. TransportProtocol: tcpip.TransportProtocolNumber(f.nextHdr), @@ -1982,8 +1903,8 @@ func TestReceiveIPv6Fragments(t *testing.T) { DstAddr: f.dstAddr, }) - buf := buffer.NewWithData(hdr.View()) - buf.Append(f.data.Flatten()) + buf := bufferv2.MakeWithData(hdr.View()) + buf.Append(bufferv2.NewViewWithData(f.data)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ Payload: buf, }) @@ -2127,15 +2048,15 @@ func TestInvalidIPv6Fragments(t *testing.T) { encodeArgs.ExtensionHeaders = append(encodeArgs.ExtensionHeaders, &f.ipv6FragmentFields) ip.Encode(&encodeArgs) - buf := buffer.NewWithData(hdr.View()) - buf.Append(f.payload) - + buf := bufferv2.MakeWithData(append(hdr.View(), f.payload...)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ Payload: buf, }) if test.expectICMP { - expectICMPPayload = stack.PayloadSince(pkt.NetworkHeader()) + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() + expectICMPPayload = payload.AsSlice() } e.InjectInbound(ProtocolNumber, pkt) @@ -2160,7 +2081,9 @@ func TestInvalidIPv6Fragments(t *testing.T) { t.Fatal("expected ICMP error message missing") } - checker.IPv6(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(addr2), checker.DstAddr(addr1), checker.IPFullLength(uint16(header.IPv6MinimumSize+header.ICMPv6MinimumSize+len(expectICMPPayload))), @@ -2384,15 +2307,15 @@ func TestFragmentReassemblyTimeout(t *testing.T) { fragHDR := header.IPv6Fragment(hdr.View()[header.IPv6MinimumSize:]) - buf := buffer.NewWithData(hdr.View()) - buf.Append(f.payload) - + buf := bufferv2.MakeWithData(append(hdr.View(), f.payload...)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ Payload: buf, }) if firstFragmentSent == nil && fragHDR.FragmentOffset() == 0 { - firstFragmentSent = stack.PayloadSince(pkt.NetworkHeader()) + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() + firstFragmentSent = payload.AsSlice() } e.InjectInbound(ProtocolNumber, pkt) @@ -2415,7 +2338,9 @@ func TestFragmentReassemblyTimeout(t *testing.T) { t.Fatalf("unexpected ICMP error message received: %#v", reply) } - checker.IPv6(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(addr2), checker.DstAddr(addr1), checker.IPFullLength(uint16(header.IPv6MinimumSize+header.ICMPv6MinimumSize+len(firstFragmentSent))), @@ -2547,7 +2472,7 @@ func TestWriteStats(t *testing.T) { for i := 0; i < nPackets; i++ { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: header.UDPMinimumSize + int(rt.MaxHeaderLength()), - Payload: buffer.Buffer{}, + Payload: bufferv2.Buffer{}, }) defer pkt.DecRef() pkt.TransportHeader().Push(header.UDPMinimumSize) @@ -3207,7 +3132,7 @@ func TestForwarding(t *testing.T) { DstAddr: test.dstAddr, }) request := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) incomingEndpoint, ok := endpoints[incomingNICID] @@ -3243,7 +3168,9 @@ func TestForwarding(t *testing.T) { return len(hdr.View()) } - checker.IPv6(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(incomingIPv6Addr.Address), checker.DstAddr(test.srcAddr), checker.TTL(DefaultTTL), @@ -3268,7 +3195,9 @@ func TestForwarding(t *testing.T) { t.Fatal("Expected ICMP Echo Request packet through outgoing NIC") } - checker.IPv6WithExtHdr(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv6WithExtHdr(t, payload, checker.SrcAddr(test.srcAddr), checker.DstAddr(test.dstAddr), checker.TTL(test.TTL-1), @@ -3534,7 +3463,7 @@ func TestMulticastForwarding(t *testing.T) { DstAddr: dstAddr, }) request := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) incomingEndpoint, ok := endpoints[incomingNICID] @@ -3570,7 +3499,9 @@ func TestMulticastForwarding(t *testing.T) { return len(hdr.View()) } - checker.IPv6(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(incomingIPv6Addr.Address), checker.DstAddr(srcAddr), checker.TTL(DefaultTTL), @@ -3595,7 +3526,9 @@ func TestMulticastForwarding(t *testing.T) { t.Fatal("Expected ICMP Echo Request packet through outgoing NIC") } - checker.IPv6WithExtHdr(t, stack.PayloadSince(reply.NetworkHeader()), + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + checker.IPv6WithExtHdr(t, payload, checker.SrcAddr(srcAddr), checker.DstAddr(dstAddr), checker.TTL(packetTTL-1), @@ -3737,7 +3670,9 @@ func TestIcmpRateLimit(t *testing.T) { if got, want := p.NetworkProtocolNumber, header.IPv6ProtocolNumber; got != want { t.Errorf("got p.NetworkProtocolNumber = %d, want = %d", got, want) } - checker.IPv6(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address), checker.ICMPv6( @@ -3777,7 +3712,7 @@ func TestIcmpRateLimit(t *testing.T) { p := e.Read() if round >= icmpBurst { if p != nil { - t.Errorf("got packet %x in round %d, expected ICMP rate limit to stop it", p.Data().Slices(), round) + t.Errorf("got packet %x in round %d, expected ICMP rate limit to stop it", p.Data().AsRange().ToSlice(), round) p.DecRef() } return @@ -3785,7 +3720,9 @@ func TestIcmpRateLimit(t *testing.T) { if p == nil { t.Fatalf("expected unreachable in round %d, no packet read in endpoint", round) } - checker.IPv6(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(host1IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(host2IPv6Addr.AddressWithPrefix.Address), checker.ICMPv6( @@ -3799,7 +3736,7 @@ func TestIcmpRateLimit(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { for round := 0; round < icmpBurst+1; round++ { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(testCase.createPacket()), + Payload: bufferv2.MakeWithData(testCase.createPacket()), }) e.InjectInbound(header.IPv6ProtocolNumber, pkt) pkt.DecRef() diff --git a/pkg/tcpip/network/ipv6/mld.go b/pkg/tcpip/network/ipv6/mld.go index 4c8d66043..a1e95c69f 100644 --- a/pkg/tcpip/network/ipv6/mld.go +++ b/pkg/tcpip/network/ipv6/mld.go @@ -18,7 +18,7 @@ import ( "fmt" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/network/internal/ip" @@ -196,7 +196,9 @@ func (mld *mldState) writePacket(destAddress, groupAddress tcpip.Address, mldTyp panic(fmt.Sprintf("unrecognized mld type = %d", mldType)) } - icmp := header.ICMPv6(make([]byte, header.ICMPv6HeaderSize+header.MLDMinimumSize)) + icmpView := bufferv2.NewViewSize(header.ICMPv6HeaderSize + header.MLDMinimumSize) + + icmp := header.ICMPv6(icmpView.AsSlice()) icmp.SetType(mldType) header.MLD(icmp.MessageBody()).SetMulticastAddress(groupAddress) // As per RFC 2710 section 3, @@ -268,7 +270,7 @@ func (mld *mldState) writePacket(destAddress, groupAddress tcpip.Address, mldTyp pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(mld.ep.MaxHeaderLength()) + extensionHeaders.Length(), - Payload: buffer.NewWithData(icmp), + Payload: bufferv2.MakeWithView(icmpView), }) defer pkt.DecRef() diff --git a/pkg/tcpip/network/ipv6/mld_test.go b/pkg/tcpip/network/ipv6/mld_test.go index 79a5d7fb7..c4c8e279d 100644 --- a/pkg/tcpip/network/ipv6/mld_test.go +++ b/pkg/tcpip/network/ipv6/mld_test.go @@ -21,7 +21,7 @@ import ( "testing" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -43,10 +43,11 @@ var ( globalAddrSNMC = header.SolicitedNodeAddr(globalAddr) ) -func validateMLDPacket(t *testing.T, p []byte, localAddress, remoteAddress tcpip.Address, mldType header.ICMPv6Type, groupAddress tcpip.Address) { +func validateMLDPacket(t *testing.T, v *bufferv2.View, localAddress, remoteAddress tcpip.Address, mldType header.ICMPv6Type, groupAddress tcpip.Address) { t.Helper() - checker.IPv6WithExtHdr(t, p, + defer v.Release() + checker.IPv6WithExtHdr(t, v, checker.IPv6ExtHdr( checker.IPv6HopByHopExtensionHeader(checker.IPv6RouterAlert(header.IPv6RouterAlertMLD)), ), @@ -198,7 +199,9 @@ func TestSendQueuedMLDReports(t *testing.T) { if p := e.Read(); p == nil { t.Fatal("expected DAD packet") } else { - checker.IPv6(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(header.IPv6Any), checker.DstAddr(snmc), checker.TTL(header.NDPHopLimit), @@ -337,7 +340,9 @@ func TestSendQueuedMLDReports(t *testing.T) { t.Fatalf("expected MLD report for %s and %s; addrs = %#v", globalMulticastAddr, linkLocalAddrSNMC, addrs) } - addr := header.IPv6(stack.PayloadSince(p.NetworkHeader())).DestinationAddress() + v := stack.PayloadSince(p.NetworkHeader()) + defer v.Release() + addr := header.IPv6(v.AsSlice()).DestinationAddress() if seen, ok := addrs[addr]; !ok { t.Fatalf("got unexpected packet destined to %s", addr) } else if seen { @@ -345,7 +350,7 @@ func TestSendQueuedMLDReports(t *testing.T) { } addrs[addr] = true - validateMLDPacket(t, stack.PayloadSince(p.NetworkHeader()), linkLocalAddr, addr, header.ICMPv6MulticastListenerReport, addr) + validateMLDPacket(t, v.Clone(), linkLocalAddr, addr, header.ICMPv6MulticastListenerReport, addr) p.DecRef() clock.Advance(ipv6.UnsolicitedReportIntervalMax) @@ -400,7 +405,7 @@ func createAndInjectMLDPacket(e *channel.Endpoint, mldType header.ICMPv6Type, ho })) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) e.InjectInbound(ipv6.ProtocolNumber, pkt) pkt.DecRef() diff --git a/pkg/tcpip/network/ipv6/ndp.go b/pkg/tcpip/network/ipv6/ndp.go index 2ca49b3e8..debd31e5d 100644 --- a/pkg/tcpip/network/ipv6/ndp.go +++ b/pkg/tcpip/network/ipv6/ndp.go @@ -18,7 +18,7 @@ import ( "fmt" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -1849,7 +1849,9 @@ func (ndp *ndpState) startSolicitingRouters() { } } payloadSize := header.ICMPv6HeaderSize + header.NDPRSMinimumSize + optsSerializer.Length() - icmpData := header.ICMPv6(make([]byte, payloadSize)) + icmpView := bufferv2.NewView(payloadSize) + icmpView.Grow(payloadSize) + icmpData := header.ICMPv6(icmpView.AsSlice()) icmpData.SetType(header.ICMPv6RouterSolicit) rs := header.NDPRouterSolicit(icmpData.MessageBody()) rs.Options().Serialize(optsSerializer) @@ -1861,7 +1863,7 @@ func (ndp *ndpState) startSolicitingRouters() { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(ndp.ep.MaxHeaderLength()), - Payload: buffer.NewWithData(icmpData), + Payload: bufferv2.MakeWithView(icmpView), }) defer pkt.DecRef() @@ -1966,7 +1968,9 @@ func (ndp *ndpState) SendDADMessage(addr tcpip.Address, nonce []byte) tcpip.Erro } func (e *endpoint) sendNDPNS(srcAddr, dstAddr, targetAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, opts header.NDPOptionsSerializer) tcpip.Error { - icmp := header.ICMPv6(make([]byte, header.ICMPv6NeighborSolicitMinimumSize+opts.Length())) + icmpView := bufferv2.NewView(header.ICMPv6NeighborSolicitMinimumSize + opts.Length()) + icmpView.Grow(header.ICMPv6NeighborSolicitMinimumSize + opts.Length()) + icmp := header.ICMPv6(icmpView.AsSlice()) icmp.SetType(header.ICMPv6NeighborSolicit) ns := header.NDPNeighborSolicit(icmp.MessageBody()) ns.SetTargetAddress(targetAddr) @@ -1979,7 +1983,7 @@ func (e *endpoint) sendNDPNS(srcAddr, dstAddr, targetAddr tcpip.Address, remoteL pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(e.MaxHeaderLength()), - Payload: buffer.NewWithData(icmp), + Payload: bufferv2.MakeWithView(icmpView), }) defer pkt.DecRef() diff --git a/pkg/tcpip/network/ipv6/ndp_test.go b/pkg/tcpip/network/ipv6/ndp_test.go index cf51155d7..ee1b9ffba 100644 --- a/pkg/tcpip/network/ipv6/ndp_test.go +++ b/pkg/tcpip/network/ipv6/ndp_test.go @@ -22,7 +22,7 @@ import ( "time" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" "gvisor.dev/gvisor/pkg/tcpip/faketime" @@ -188,7 +188,7 @@ func TestNeighborSolicitationWithSourceLinkLayerOption(t *testing.T) { } pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(ProtocolNumber, pktBuf) pktBuf.DecRef() @@ -450,7 +450,7 @@ func TestNeighborSolicitationResponse(t *testing.T) { } pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(ProtocolNumber, pktBuf) pktBuf.DecRef() @@ -488,7 +488,9 @@ func TestNeighborSolicitationResponse(t *testing.T) { t.Errorf("route info mismatch (-want +got):\n%s", diff) } - checker.IPv6(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(nicAddr), checker.DstAddr(respNSDst), checker.TTL(header.NDPHopLimit), @@ -527,7 +529,7 @@ func TestNeighborSolicitationResponse(t *testing.T) { DstAddr: nicAddr, }) pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(ProtocolNumber, pktBuf) pktBuf.DecRef() @@ -553,7 +555,9 @@ func TestNeighborSolicitationResponse(t *testing.T) { t.Errorf("got p.EgressRoute.RemoteLinkAddress = %s, want = %s", p.EgressRoute.RemoteLinkAddress, test.naDstLinkAddr) } - checker.IPv6(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(test.naSrc), checker.DstAddr(test.naDst), checker.TTL(header.NDPHopLimit), @@ -651,7 +655,7 @@ func TestNeighborAdvertisementWithTargetLinkLayerOption(t *testing.T) { t.Fatalf("got invalid = %d, want = 0", got) } pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(ProtocolNumber, pktBuf) pktBuf.DecRef() @@ -710,8 +714,8 @@ func TestNDPValidation(t *testing.T) { DstAddr: lladdr0, ExtensionHeaders: extHdrs, }) - buf := buffer.NewWithData(ip) - buf.Append(payload) + buf := bufferv2.MakeWithData(ip) + buf.Append(bufferv2.NewViewWithData(payload)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ Payload: buf, }) @@ -1027,7 +1031,7 @@ func TestNeighborAdvertisementValidation(t *testing.T) { } pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(header.IPv6ProtocolNumber, pktBuf) pktBuf.DecRef() @@ -1228,7 +1232,7 @@ func TestRouterAdvertValidation(t *testing.T) { } pktBuf := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) e.InjectInbound(header.IPv6ProtocolNumber, pktBuf) pktBuf.DecRef() @@ -1313,7 +1317,9 @@ func TestCheckDuplicateAddress(t *testing.T) { t.Errorf("(i=%d) got p.EgressRoute.RemoteLinkAddress = %s, want = %s", dadPacketsSent, p.EgressRoute.RemoteLinkAddress, remoteLinkAddr) } - checker.IPv6(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(header.IPv6Any), checker.DstAddr(snmc), checker.TTL(header.NDPHopLimit), diff --git a/pkg/tcpip/network/multicast_group_test.go b/pkg/tcpip/network/multicast_group_test.go index c8bd24bff..28e539c1c 100644 --- a/pkg/tcpip/network/multicast_group_test.go +++ b/pkg/tcpip/network/multicast_group_test.go @@ -20,7 +20,7 @@ import ( "testing" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" @@ -83,7 +83,8 @@ var ( func validateMLDPacket(t *testing.T, p *stack.PacketBuffer, remoteAddress tcpip.Address, mldType uint8, maxRespTime byte, groupAddress tcpip.Address) { t.Helper() - payload := header.IPv6(stack.PayloadSince(p.NetworkHeader())) + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() checker.IPv6WithExtHdr(t, payload, checker.IPv6ExtHdr( checker.IPv6HopByHopExtensionHeader(checker.IPv6RouterAlert(header.IPv6RouterAlertMLD)), @@ -104,7 +105,8 @@ func validateMLDPacket(t *testing.T, p *stack.PacketBuffer, remoteAddress tcpip. func validateIGMPPacket(t *testing.T, p *stack.PacketBuffer, remoteAddress tcpip.Address, igmpType uint8, maxRespTime byte, groupAddress tcpip.Address) { t.Helper() - payload := header.IPv4(stack.PayloadSince(p.NetworkHeader())) + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() checker.IPv4(t, payload, checker.SrcAddr(stackIPv4Addr), checker.DstAddr(remoteAddress), @@ -262,7 +264,7 @@ func createAndInjectIGMPPacket(e *channel.Endpoint, igmpType byte, maxRespTime b igmp.SetChecksum(header.IGMPCalculateChecksum(igmp)) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) e.InjectInbound(ipv4.ProtocolNumber, pkt) pkt.DecRef() @@ -303,7 +305,7 @@ func createAndInjectMLDPacket(e *channel.Endpoint, mldType uint8, maxRespDelay b })) pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) e.InjectInbound(ipv6.ProtocolNumber, pkt) pkt.DecRef() @@ -1033,7 +1035,9 @@ func TestMGPWithNICLifecycle(t *testing.T) { getAndCheckGroupAddress: func(t *testing.T, seen map[tcpip.Address]bool, p *stack.PacketBuffer) tcpip.Address { t.Helper() - ipv4 := header.IPv4(stack.PayloadSince(p.NetworkHeader())) + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + ipv4 := header.IPv4(payload.AsSlice()) if got := tcpip.TransportProtocolNumber(ipv4.Protocol()); got != header.IGMPProtocolNumber { t.Fatalf("got ipv4.Protocol() = %d, want = %d", got, header.IGMPProtocolNumber) } @@ -1073,12 +1077,13 @@ func TestMGPWithNICLifecycle(t *testing.T) { }, getAndCheckGroupAddress: func(t *testing.T, seen map[tcpip.Address]bool, p *stack.PacketBuffer) tcpip.Address { t.Helper() - - ipv6 := header.IPv6(stack.PayloadSince(p.NetworkHeader())) + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + ipv6 := header.IPv6(payload.AsSlice()) ipv6HeaderIter := header.MakeIPv6PayloadIterator( header.IPv6ExtensionHeaderIdentifier(ipv6.NextHeader()), - buffer.NewWithData(ipv6.Payload()), + bufferv2.MakeWithData(ipv6.Payload()), ) var transport header.IPv6RawPayloadHeader @@ -1090,6 +1095,7 @@ func TestMGPWithNICLifecycle(t *testing.T) { if done { t.Fatalf("ipv6HeaderIter.Next() = (%T, %t, _), want = (_, false, _)", h, done) } + defer h.Release() if t, ok := h.(header.IPv6RawPayloadHeader); ok { transport = t break diff --git a/pkg/tcpip/socketops.go b/pkg/tcpip/socketops.go index 1bc3723b1..b7dbe45c8 100644 --- a/pkg/tcpip/socketops.go +++ b/pkg/tcpip/socketops.go @@ -16,6 +16,7 @@ package tcpip import ( "gvisor.dev/gvisor/pkg/atomicbitops" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" ) @@ -605,7 +606,7 @@ type SockError struct { Cause SockErrorCause // Payload is the errant packet's payload. - Payload []byte + Payload *bufferv2.View // Dst is the original destination address of the errant packet. Dst FullAddress // Offender is the original sender address of the errant packet. @@ -652,7 +653,7 @@ func (so *SocketOptions) QueueErr(err *SockError) { } // QueueLocalErr queues a local error onto the local queue. -func (so *SocketOptions) QueueLocalErr(err Error, net NetworkProtocolNumber, info uint32, dst FullAddress, payload []byte) { +func (so *SocketOptions) QueueLocalErr(err Error, net NetworkProtocolNumber, info uint32, dst FullAddress, payload *bufferv2.View) { so.QueueErr(&SockError{ Err: err, Cause: &LocalSockError{info: info}, diff --git a/pkg/tcpip/stack/BUILD b/pkg/tcpip/stack/BUILD index d399c12c3..918a62dae 100644 --- a/pkg/tcpip/stack/BUILD +++ b/pkg/tcpip/stack/BUILD @@ -59,7 +59,6 @@ go_library( "packet_buffer.go", "packet_buffer_list.go", "packet_buffer_refs.go", - "packet_buffer_state.go", "packet_buffer_unsafe.go", "pending_packets.go", "rand.go", @@ -75,7 +74,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//pkg/atomicbitops", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/ilist", "//pkg/log", "//pkg/rand", @@ -108,7 +107,7 @@ go_test( shard_count = most_shards, deps = [ ":stack", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/rand", "//pkg/sync", "//pkg/tcpip", @@ -146,7 +145,7 @@ go_test( library = ":stack", deps = [ "//pkg/atomicbitops", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/sync", "//pkg/tcpip", "//pkg/tcpip/faketime", diff --git a/pkg/tcpip/stack/conntrack.go b/pkg/tcpip/stack/conntrack.go index 424238569..90bd2c862 100644 --- a/pkg/tcpip/stack/conntrack.go +++ b/pkg/tcpip/stack/conntrack.go @@ -195,7 +195,7 @@ func (cn *conn) update(pkt *PacketBuffer, reply bool) { return } - tcpHeader := header.TCP(pkt.TransportHeader().View()) + tcpHeader := header.TCP(pkt.TransportHeader().Slice()) // Update the state of tcb. tcb assumes it's always initialized on the // client. However, we only need to know whether the connection is @@ -295,17 +295,17 @@ func getEmbeddedNetAndTransHeaders(pkt *PacketBuffer, netHdrLength int, getNetAn func getHeaders(pkt *PacketBuffer) (netHdr header.Network, transHdr header.Transport, isICMPError bool, ok bool) { switch pkt.TransportProtocolNumber { case header.TCPProtocolNumber: - if tcpHeader := header.TCP(pkt.TransportHeader().View()); len(tcpHeader) >= header.TCPMinimumSize { + if tcpHeader := header.TCP(pkt.TransportHeader().Slice()); len(tcpHeader) >= header.TCPMinimumSize { return pkt.Network(), tcpHeader, false, true } return nil, nil, false, false case header.UDPProtocolNumber: - if udpHeader := header.UDP(pkt.TransportHeader().View()); len(udpHeader) >= header.UDPMinimumSize { + if udpHeader := header.UDP(pkt.TransportHeader().Slice()); len(udpHeader) >= header.UDPMinimumSize { return pkt.Network(), udpHeader, false, true } return nil, nil, false, false case header.ICMPv4ProtocolNumber: - icmpHeader := header.ICMPv4(pkt.TransportHeader().View()) + icmpHeader := header.ICMPv4(pkt.TransportHeader().Slice()) if len(icmpHeader) < header.ICMPv4MinimumSize { return nil, nil, false, false } @@ -333,7 +333,7 @@ func getHeaders(pkt *PacketBuffer) (netHdr header.Network, transHdr header.Trans } return nil, nil, false, false case header.ICMPv6ProtocolNumber: - icmpHeader := header.ICMPv6(pkt.TransportHeader().View()) + icmpHeader := header.ICMPv6(pkt.TransportHeader().Slice()) if len(icmpHeader) < header.ICMPv6MinimumSize { return nil, nil, false, false } @@ -424,15 +424,15 @@ func getTupleIDForEchoPacket(pkt *PacketBuffer, ident uint16, request bool) tupl func getTupleID(pkt *PacketBuffer) (tupleID, getTupleIDDisposition) { switch pkt.TransportProtocolNumber { case header.TCPProtocolNumber: - if transHeader := header.TCP(pkt.TransportHeader().View()); len(transHeader) >= header.TCPMinimumSize { + if transHeader := header.TCP(pkt.TransportHeader().Slice()); len(transHeader) >= header.TCPMinimumSize { return getTupleIDForRegularPacket(pkt.Network(), pkt.NetworkProtocolNumber, transHeader, pkt.TransportProtocolNumber), getTupleIDOKAndAllowNewConn } case header.UDPProtocolNumber: - if transHeader := header.UDP(pkt.TransportHeader().View()); len(transHeader) >= header.UDPMinimumSize { + if transHeader := header.UDP(pkt.TransportHeader().Slice()); len(transHeader) >= header.UDPMinimumSize { return getTupleIDForRegularPacket(pkt.Network(), pkt.NetworkProtocolNumber, transHeader, pkt.TransportProtocolNumber), getTupleIDOKAndAllowNewConn } case header.ICMPv4ProtocolNumber: - icmp := header.ICMPv4(pkt.TransportHeader().View()) + icmp := header.ICMPv4(pkt.TransportHeader().Slice()) if len(icmp) < header.ICMPv4MinimumSize { return tupleID{}, getTupleIDNotOK } @@ -467,7 +467,7 @@ func getTupleID(pkt *PacketBuffer) (tupleID, getTupleIDDisposition) { return tid, getTupleIDOKAndDontAllowNewConn } case header.ICMPv6ProtocolNumber: - icmp := header.ICMPv6(pkt.TransportHeader().View()) + icmp := header.ICMPv6(pkt.TransportHeader().Slice()) if len(icmp) < header.ICMPv6MinimumSize { return tupleID{}, getTupleIDNotOK } @@ -532,7 +532,7 @@ func (ct *ConnTrack) getConnAndUpdate(pkt *PacketBuffer, skipChecksumValidation switch pkt.TransportProtocolNumber { case header.TCPProtocolNumber: _, csumValid, ok := header.TCPValid( - header.TCP(pkt.TransportHeader().View()), + header.TCP(pkt.TransportHeader().Slice()), func() uint16 { return pkt.Data().AsRange().Checksum() }, uint16(pkt.Data().Size()), tid.srcAddr, @@ -543,7 +543,7 @@ func (ct *ConnTrack) getConnAndUpdate(pkt *PacketBuffer, skipChecksumValidation } case header.UDPProtocolNumber: lengthValid, csumValid := header.UDPValid( - header.UDP(pkt.TransportHeader().View()), + header.UDP(pkt.TransportHeader().Slice()), func() uint16 { return pkt.Data().AsRange().Checksum() }, uint16(pkt.Data().Size()), pkt.NetworkProtocolNumber, @@ -944,19 +944,19 @@ func (cn *conn) handlePacket(pkt *PacketBuffer, hook Hook, rt *Route) bool { // not the ICMP packet itself. switch pkt.TransportProtocolNumber { case header.ICMPv4ProtocolNumber: - icmp := header.ICMPv4(pkt.TransportHeader().View()) + icmp := header.ICMPv4(pkt.TransportHeader().Slice()) // TODO(https://gvisor.dev/issue/6788): Incrementally update ICMP checksum. icmp.SetChecksum(0) icmp.SetChecksum(header.ICMPv4Checksum(icmp, pkt.Data().AsRange().Checksum())) - network := header.IPv4(pkt.NetworkHeader().View()) + network := header.IPv4(pkt.NetworkHeader().Slice()) if dnat { network.SetDestinationAddressWithChecksumUpdate(tid.srcAddr) } else { network.SetSourceAddressWithChecksumUpdate(tid.dstAddr) } case header.ICMPv6ProtocolNumber: - network := header.IPv6(pkt.NetworkHeader().View()) + network := header.IPv6(pkt.NetworkHeader().Slice()) srcAddr := network.SourceAddress() dstAddr := network.DestinationAddress() if dnat { @@ -965,7 +965,7 @@ func (cn *conn) handlePacket(pkt *PacketBuffer, hook Hook, rt *Route) bool { srcAddr = tid.dstAddr } - icmp := header.ICMPv6(pkt.TransportHeader().View()) + icmp := header.ICMPv6(pkt.TransportHeader().Slice()) // TODO(https://gvisor.dev/issue/6788): Incrementally update ICMP checksum. icmp.SetChecksum(0) payload := pkt.Data() diff --git a/pkg/tcpip/stack/conntrack_test.go b/pkg/tcpip/stack/conntrack_test.go index 5f2d637b1..c7993193e 100644 --- a/pkg/tcpip/stack/conntrack_test.go +++ b/pkg/tcpip/stack/conntrack_test.go @@ -17,7 +17,7 @@ package stack import ( "testing" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/faketime" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -323,7 +323,7 @@ func genTCPPacket(opts genTCPOpts) *PacketBuffer { packetLen := header.IPv4MinimumSize + uint16(tcpHdrSize) pkt := NewPacketBuffer(PacketBufferOptions{ ReserveHeaderBytes: int(packetLen), - Payload: buffer.NewWithData(opts.data), + Payload: bufferv2.MakeWithData(opts.data), }) pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber pkt.TransportProtocolNumber = header.TCPProtocolNumber diff --git a/pkg/tcpip/stack/forwarding_test.go b/pkg/tcpip/stack/forwarding_test.go index 396a87304..73cc800f0 100644 --- a/pkg/tcpip/stack/forwarding_test.go +++ b/pkg/tcpip/stack/forwarding_test.go @@ -20,7 +20,7 @@ import ( "testing" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/faketime" @@ -85,7 +85,7 @@ func (f *fwdTestNetworkEndpoint) HandlePacket(pkt *PacketBuffer) { return } - netHdr := pkt.NetworkHeader().View() + netHdr := pkt.NetworkHeader().Slice() _, dst := f.proto.ParseAddresses(netHdr) addressEndpoint := f.AcquireAssignedAddress(dst, f.nic.Promiscuous(), CanBePrimaryEndpoint) @@ -104,7 +104,7 @@ func (f *fwdTestNetworkEndpoint) HandlePacket(pkt *PacketBuffer) { pkt = NewPacketBuffer(PacketBufferOptions{ ReserveHeaderBytes: int(r.MaxHeaderLength()), - Payload: pkt.Buffer(), + Payload: pkt.ToBuffer(), }) // TODO(gvisor.dev/issue/1085) Decrease the TTL field in forwarded packets. _ = r.WriteHeaderIncludedPacket(pkt) @@ -426,7 +426,7 @@ func TestForwardingWithStaticResolver(t *testing.T) { buf := make([]byte, 30) buf[dstAddrOffset] = 3 ep1.InjectInbound(fwdTestNetNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) var p *PacketBuffer @@ -470,7 +470,7 @@ func TestForwardingWithFakeResolver(t *testing.T) { buf := make([]byte, 30) buf[dstAddrOffset] = 3 ep1.InjectInbound(fwdTestNetNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) var p *PacketBuffer @@ -504,7 +504,7 @@ func TestForwardingWithNoResolver(t *testing.T) { buf := make([]byte, 30) buf[dstAddrOffset] = 3 ep1.InjectInbound(fwdTestNetNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) clock.Advance(proto.addrResolveDelay) @@ -532,7 +532,7 @@ func TestForwardingResolutionFailsForQueuedPackets(t *testing.T) { buf := make([]byte, 30) buf[dstAddrOffset] = 3 ep1.InjectInbound(fwdTestNetNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) } @@ -573,7 +573,7 @@ func TestForwardingWithFakeResolverPartialTimeout(t *testing.T) { buf := make([]byte, 30) buf[dstAddrOffset] = 4 ep1.InjectInbound(fwdTestNetNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) // Inject an inbound packet to address 3 on NIC 1, and see if it is @@ -581,7 +581,7 @@ func TestForwardingWithFakeResolverPartialTimeout(t *testing.T) { buf = make([]byte, 30) buf[dstAddrOffset] = 3 ep1.InjectInbound(fwdTestNetNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) var p *PacketBuffer @@ -593,8 +593,10 @@ func TestForwardingWithFakeResolverPartialTimeout(t *testing.T) { t.Fatal("packet not forwarded") } - if nh := PayloadSince(p.NetworkHeader()); nh[dstAddrOffset] != 3 { - t.Fatalf("got p.NetworkHeader[dstAddrOffset] = %d, want = 3", nh[dstAddrOffset]) + nh := PayloadSince(p.NetworkHeader()) + defer nh.Release() + if nh.AsSlice()[dstAddrOffset] != 3 { + t.Fatalf("got p.NetworkHeader[dstAddrOffset] = %d, want = 3", nh.AsSlice()[dstAddrOffset]) } // Test that the address resolution happened correctly. @@ -629,7 +631,7 @@ func TestForwardingWithFakeResolverTwoPackets(t *testing.T) { buf := make([]byte, 30) buf[dstAddrOffset] = 3 ep1.InjectInbound(fwdTestNetNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) } @@ -643,8 +645,10 @@ func TestForwardingWithFakeResolverTwoPackets(t *testing.T) { t.Fatal("packet not forwarded") } - if nh := PayloadSince(p.NetworkHeader()); nh[dstAddrOffset] != 3 { - t.Fatalf("got p.NetworkHeader[dstAddrOffset] = %d, want = 3", nh[dstAddrOffset]) + nh := PayloadSince(p.NetworkHeader()) + defer nh.Release() + if nh.AsSlice()[dstAddrOffset] != 3 { + t.Fatalf("got p.NetworkHeader[dstAddrOffset] = %d, want = 3", nh.AsSlice()[dstAddrOffset]) } // Test that the address resolution happened correctly. @@ -682,7 +686,7 @@ func TestForwardingWithFakeResolverManyPackets(t *testing.T) { // Set the packet sequence number. binary.BigEndian.PutUint16(buf[fwdTestNetHeaderLen:], uint16(i)) ep1.InjectInbound(fwdTestNetNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) } @@ -697,13 +701,14 @@ func TestForwardingWithFakeResolverManyPackets(t *testing.T) { } b := PayloadSince(p.NetworkHeader()) - if b[dstAddrOffset] != 3 { - t.Fatalf("got b[dstAddrOffset] = %d, want = 3", b[dstAddrOffset]) + defer b.Release() + if b.AsSlice()[dstAddrOffset] != 3 { + t.Fatalf("got b[dstAddrOffset] = %d, want = 3", b.AsSlice()[dstAddrOffset]) } - if len(b) < fwdTestNetHeaderLen+2 { - t.Fatalf("packet is too short to hold a sequence number: len(b) = %d", b) + if b.Size() < fwdTestNetHeaderLen+2 { + t.Fatalf("packet is too short to hold a sequence number: len(b) = %d", b.Size()) } - seqNumBuf := b[fwdTestNetHeaderLen:] + seqNumBuf := b.AsSlice()[fwdTestNetHeaderLen:] // The first 5 packets should not be forwarded so the sequence number should // start with 5. @@ -747,7 +752,7 @@ func TestForwardingWithFakeResolverManyResolutions(t *testing.T) { buf := make([]byte, 30) buf[dstAddrOffset] = byte(3 + i) ep1.InjectInbound(fwdTestNetNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) } @@ -763,8 +768,10 @@ func TestForwardingWithFakeResolverManyResolutions(t *testing.T) { // The first 5 packets (address 3 to 7) should not be forwarded // because their address resolutions are interrupted. - if nh := PayloadSince(p.NetworkHeader()); nh[dstAddrOffset] < 8 { - t.Fatalf("got p.NetworkHeader[dstAddrOffset] = %d, want p.NetworkHeader[dstAddrOffset] >= 8", nh[dstAddrOffset]) + nh := PayloadSince(p.NetworkHeader()) + defer nh.Release() + if nh.AsSlice()[dstAddrOffset] < 8 { + t.Fatalf("got p.NetworkHeader[dstAddrOffset] = %d, want p.NetworkHeader[dstAddrOffset] >= 8", nh.AsSlice()[dstAddrOffset]) } // Test that the address resolution happened correctly. diff --git a/pkg/tcpip/stack/iptables_targets.go b/pkg/tcpip/stack/iptables_targets.go index cd10746a7..d93670d6b 100644 --- a/pkg/tcpip/stack/iptables_targets.go +++ b/pkg/tcpip/stack/iptables_targets.go @@ -284,11 +284,11 @@ func snatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcp switch pkt.TransportProtocolNumber { case header.UDPProtocolNumber: if port == 0 { - portsOrIdents = targetPortRangeForTCPAndUDP(header.UDP(pkt.TransportHeader().View()).SourcePort()) + portsOrIdents = targetPortRangeForTCPAndUDP(header.UDP(pkt.TransportHeader().Slice()).SourcePort()) } case header.TCPProtocolNumber: if port == 0 { - portsOrIdents = targetPortRangeForTCPAndUDP(header.TCP(pkt.TransportHeader().View()).SourcePort()) + portsOrIdents = targetPortRangeForTCPAndUDP(header.TCP(pkt.TransportHeader().Slice()).SourcePort()) } case header.ICMPv4ProtocolNumber, header.ICMPv6ProtocolNumber: // Allow NAT-ing to any 16-bit value for ICMP's Ident field to match Linux @@ -303,7 +303,7 @@ func snatAction(pkt *PacketBuffer, hook Hook, r *Route, port uint16, address tcp func natAction(pkt *PacketBuffer, hook Hook, r *Route, portsOrIdents portOrIdentRange, address tcpip.Address, dnat bool) (RuleVerdict, int) { // Drop the packet if network and transport header are not set. - if len(pkt.NetworkHeader().View()) == 0 || len(pkt.TransportHeader().View()) == 0 { + if len(pkt.NetworkHeader().Slice()) == 0 || len(pkt.TransportHeader().Slice()) == 0 { return RuleDrop, 0 } diff --git a/pkg/tcpip/stack/iptables_types.go b/pkg/tcpip/stack/iptables_types.go index febd573df..12def5ccb 100644 --- a/pkg/tcpip/stack/iptables_types.go +++ b/pkg/tcpip/stack/iptables_types.go @@ -249,13 +249,13 @@ func (fl IPHeaderFilter) match(pkt *PacketBuffer, hook Hook, inNicName, outNicNa ) switch proto := pkt.NetworkProtocolNumber; proto { case header.IPv4ProtocolNumber: - hdr := header.IPv4(pkt.NetworkHeader().View()) + hdr := header.IPv4(pkt.NetworkHeader().Slice()) transProto = hdr.TransportProtocol() dstAddr = hdr.DestinationAddress() srcAddr = hdr.SourceAddress() case header.IPv6ProtocolNumber: - hdr := header.IPv6(pkt.NetworkHeader().View()) + hdr := header.IPv6(pkt.NetworkHeader().Slice()) transProto = hdr.TransportProtocol() dstAddr = hdr.DestinationAddress() srcAddr = hdr.SourceAddress() diff --git a/pkg/tcpip/stack/ndp_test.go b/pkg/tcpip/stack/ndp_test.go index 52e011345..7462b680c 100644 --- a/pkg/tcpip/stack/ndp_test.go +++ b/pkg/tcpip/stack/ndp_test.go @@ -24,7 +24,7 @@ import ( "time" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" cryptorand "gvisor.dev/gvisor/pkg/rand" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" @@ -717,7 +717,9 @@ func TestDADResolve(t *testing.T) { // As per RFC 4861 section 4.3, a possible option is the Source Link // Layer option, but this option MUST NOT be included when the source // address of the packet is the unspecified address. - checker.IPv6(t, stack.PayloadSince(p.NetworkHeader()), + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(header.IPv6Any), checker.DstAddr(snmc), checker.TTL(header.NDPHopLimit), @@ -756,7 +758,7 @@ func rxNDPSolicit(e *channel.Endpoint, tgt tcpip.Address) { SrcAddr: header.IPv6Any, DstAddr: snmc, }) - e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buffer.NewWithData(hdr.View())})) + e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: bufferv2.MakeWithData(hdr.View())})) } // TestDADFail tests to make sure that the DAD process fails if another node is @@ -808,7 +810,7 @@ func TestDADFail(t *testing.T) { SrcAddr: tgt, DstAddr: header.IPv6AllNodesMulticastAddress, }) - e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buffer.NewWithData(hdr.View())})) + e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: bufferv2.MakeWithData(hdr.View())})) }, getStat: func(s tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter { return s.NeighborAdvert @@ -1271,7 +1273,7 @@ func raBuf(ip tcpip.Address, rl uint16, managedAddress, otherConfigurations bool }) return stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), }) } diff --git a/pkg/tcpip/stack/nic.go b/pkg/tcpip/stack/nic.go index 311d4944d..1537582b6 100644 --- a/pkg/tcpip/stack/nic.go +++ b/pkg/tcpip/stack/nic.go @@ -19,7 +19,6 @@ import ( "reflect" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/buffer" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -766,12 +765,12 @@ func (n *nic) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt *Packe // overlapping slices (e.g. by passing a shallow copy of pkt to the packet // endpoint). packetEPPkt = NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(PayloadSince(pkt.LinkHeader())), + Payload: BufferSince(pkt.LinkHeader()), }) // If a link header was populated in the original packet buffer, then // populate it in the packet buffer we provide to packet endpoints as // packet endpoints inspect link headers. - packetEPPkt.LinkHeader().Consume(len(pkt.LinkHeader().View())) + packetEPPkt.LinkHeader().Consume(len(pkt.LinkHeader().Slice())) if incoming { packetEPPkt.PktType = tcpip.PacketHost @@ -812,12 +811,12 @@ func (n *nic) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt transProto := state.proto - if len(pkt.TransportHeader().View()) == 0 { + if len(pkt.TransportHeader().Slice()) == 0 { n.stats.malformedL4RcvdPackets.Increment() return TransportPacketHandled } - srcPort, dstPort, err := transProto.ParsePorts(pkt.TransportHeader().View()) + srcPort, dstPort, err := transProto.ParsePorts(pkt.TransportHeader().Slice()) if err != nil { n.stats.malformedL4RcvdPackets.Increment() return TransportPacketHandled @@ -828,7 +827,7 @@ func (n *nic) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt panic(fmt.Sprintf("expected network protocol = %d, have = %#v", pkt.NetworkProtocolNumber, n.stack.networkProtocolNumbers())) } - src, dst := netProto.ParseAddresses(pkt.NetworkHeader().View()) + src, dst := netProto.ParseAddresses(pkt.NetworkHeader().Slice()) id := TransportEndpointID{ LocalPort: dstPort, LocalAddress: dst, @@ -895,7 +894,7 @@ func (n *nic) DeliverRawPacket(protocol tcpip.TransportProtocolNumber, pkt *Pack // For ICMPv4 only we validate the header length for compatibility with // raw(7) ICMP_FILTER. The same check is made in Linux here: // https://github.com/torvalds/linux/blob/70585216/net/ipv4/raw.c#L189. - if protocol == header.ICMPv4ProtocolNumber && len(pkt.TransportHeader().View())+pkt.Data().Size() < header.ICMPv4MinimumSize { + if protocol == header.ICMPv4ProtocolNumber && len(pkt.TransportHeader().Slice())+pkt.Data().Size() < header.ICMPv4MinimumSize { return } n.stack.demux.deliverRawPacket(protocol, pkt) diff --git a/pkg/tcpip/stack/nic_test.go b/pkg/tcpip/stack/nic_test.go index 5dfbd6d81..1beb38cf2 100644 --- a/pkg/tcpip/stack/nic_test.go +++ b/pkg/tcpip/stack/nic_test.go @@ -19,7 +19,7 @@ import ( "testing" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/testutil" @@ -184,7 +184,7 @@ func TestDisabledRxStatsWhenNICDisabled(t *testing.T) { } nic.DeliverNetworkPacket(0, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData([]byte{1, 2, 3, 4}), + Payload: bufferv2.MakeWithData([]byte{1, 2, 3, 4}), })) if got := nic.stats.local.DisabledRx.Packets.Value(); got != 1 { @@ -209,7 +209,7 @@ func TestPacketWithUnknownNetworkProtocolNumber(t *testing.T) { // IPv4 isn't recognized since we haven't initialized the NIC with an IPv4 // endpoint. nic.DeliverNetworkPacket(header.IPv4ProtocolNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData([]byte{1, 2, 3, 4}), + Payload: bufferv2.MakeWithData([]byte{1, 2, 3, 4}), })) var count uint64 if got, ok := nic.stats.local.UnknownL3ProtocolRcvdPacketCounts.Get(uint64(header.IPv4ProtocolNumber)); ok { @@ -229,7 +229,7 @@ func TestPacketWithUnknownTransportProtocolNumber(t *testing.T) { // UDP isn't recognized since we haven't initialized the NIC with a UDP // protocol. nic.DeliverTransportPacket(header.UDPProtocolNumber, NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData([]byte{1, 2, 3, 4}), + Payload: bufferv2.MakeWithData([]byte{1, 2, 3, 4}), })) var count uint64 if got, ok := nic.stats.local.UnknownL4ProtocolRcvdPacketCounts.Get(uint64(header.UDPProtocolNumber)); ok { diff --git a/pkg/tcpip/stack/packet_buffer.go b/pkg/tcpip/stack/packet_buffer.go index d1613c6c1..f92f5b0a4 100644 --- a/pkg/tcpip/stack/packet_buffer.go +++ b/pkg/tcpip/stack/packet_buffer.go @@ -17,7 +17,7 @@ import ( "fmt" "io" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -47,7 +47,7 @@ type PacketBufferOptions struct { // Payload is the initial unparsed data for the new packet. If set, it will // be owned by the new packet. - Payload buffer.Buffer + Payload bufferv2.Buffer // IsForwardedPacket identifies that the PacketBuffer being created is for a // forwarded packet. @@ -71,7 +71,7 @@ type PacketBufferOptions struct { // reference count to 1. Owners should call `DecRef()` when they are finished // with the buffer to return it to the pool. // -// Internal structure: A PacketBuffer holds a pointer to buffer.Buffer, which +// Internal structure: A PacketBuffer holds a pointer to bufferv2.Buffer, which // exposes a logically-contiguous byte storage. The underlying storage structure // is abstracted out, and should not be a concern here for most of the time. // @@ -107,7 +107,7 @@ type PacketBuffer struct { // buf is the underlying buffer for the packet. See struct level docs for // details. - buf buffer.Buffer `state:".([]byte)"` + buf bufferv2.Buffer reserved int pushed int consumed int @@ -173,7 +173,8 @@ func NewPacketBuffer(opts PacketBufferOptions) *PacketBuffer { pk := pkPool.Get().(*PacketBuffer) pk.reset() if opts.ReserveHeaderBytes != 0 { - pk.buf.AppendOwned(make([]byte, opts.ReserveHeaderBytes)) + v := bufferv2.NewViewSize(opts.ReserveHeaderBytes) + pk.buf.Append(v) pk.reserved = opts.ReserveHeaderBytes } if opts.Payload.Size() > 0 { @@ -200,6 +201,7 @@ func (pk *PacketBuffer) DecRef() { pk.onRelease() } + pk.buf.Release() pkPool.Put(pk) }) } @@ -273,23 +275,35 @@ func (pk *PacketBuffer) Data() PacketData { return PacketData{pk: pk} } -// Slices returns the underlying storage of the whole packet. -func (pk *PacketBuffer) Slices() [][]byte { +// AsSlices returns the underlying storage of the whole packet. +func (pk *PacketBuffer) AsSlices() [][]byte { var views [][]byte offset := pk.headerOffset() - pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v []byte) { - views = append(views, v) + pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v *bufferv2.View) { + views = append(views, v.AsSlice()) }) return views } -// Buffer returns the underlying storage of the whole packet. -func (pk *PacketBuffer) Buffer() buffer.Buffer { +// ToBuffer returns a caller-owned copy of the underlying storage of the whole +// packet. +func (pk *PacketBuffer) ToBuffer() bufferv2.Buffer { b := pk.buf.Clone() b.TrimFront(int64(pk.headerOffset())) return b } +// ToView returns a caller-owned copy of the underlying storage of the whole +// packet as a view. +func (pk *PacketBuffer) ToView() *bufferv2.View { + p := bufferv2.NewView(int(pk.buf.Size())) + offset := pk.headerOffset() + pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v *bufferv2.View) { + p.Write(v.AsSlice()) + }) + return p +} + func (pk *PacketBuffer) headerOffset() int { return pk.reserved - pk.pushed } @@ -313,7 +327,8 @@ func (pk *PacketBuffer) push(typ headerType, size int) []byte { pk.pushed += size h.offset = -pk.pushed h.length = size - return pk.headerView(typ) + view := pk.headerView(typ) + return view.AsSlice() } func (pk *PacketBuffer) consume(typ headerType, size int) (v []byte, consumed bool) { @@ -327,13 +342,14 @@ func (pk *PacketBuffer) consume(typ headerType, size int) (v []byte, consumed bo h.offset = pk.consumed h.length = size pk.consumed += size - return pk.headerView(typ), true + view := pk.headerView(typ) + return view.AsSlice(), true } -func (pk *PacketBuffer) headerView(typ headerType) []byte { +func (pk *PacketBuffer) headerView(typ headerType) bufferv2.View { h := &pk.headers[typ] if h.length == 0 { - return nil + return bufferv2.View{} } v, ok := pk.buf.PullUp(pk.headerOffsetOf(typ), h.length) if !ok { @@ -375,7 +391,7 @@ func (pk *PacketBuffer) ReserveHeaderBytes(reserved int) { panic(fmt.Sprintf("ReserveHeaderBytes(...) called on packet with reserved=%d, want reserved=0", pk.reserved)) } pk.reserved = reserved - pk.buf.PrependOwned(make([]byte, reserved)) + pk.buf.Prepend(bufferv2.NewViewSize(reserved)) } // Network returns the network header as a header.Network. @@ -384,9 +400,9 @@ func (pk *PacketBuffer) ReserveHeaderBytes(reserved int) { func (pk *PacketBuffer) Network() header.Network { switch netProto := pk.NetworkProtocolNumber; netProto { case header.IPv4ProtocolNumber: - return header.IPv4(pk.NetworkHeader().View()) + return header.IPv4(pk.NetworkHeader().Slice()) case header.IPv6ProtocolNumber: - return header.IPv6(pk.NetworkHeader().View()) + return header.IPv6(pk.NetworkHeader().Slice()) default: panic(fmt.Sprintf("unknown network protocol number %d", netProto)) } @@ -416,12 +432,12 @@ func (pk *PacketBuffer) CloneToInbound() *PacketBuffer { func (pk *PacketBuffer) DeepCopyForForwarding(reservedHeaderBytes int) *PacketBuffer { newPk := NewPacketBuffer(PacketBufferOptions{ ReserveHeaderBytes: reservedHeaderBytes, - Payload: buffer.NewWithData(PayloadSince(pk.NetworkHeader())), + Payload: BufferSince(pk.NetworkHeader()), IsForwardedPacket: true, }) { - consumeBytes := len(pk.NetworkHeader().View()) + consumeBytes := len(pk.NetworkHeader().Slice()) if _, consumed := newPk.NetworkHeader().Consume(consumeBytes); !consumed { panic(fmt.Sprintf("expected to consume network header %d bytes from new packet", consumeBytes)) } @@ -429,7 +445,7 @@ func (pk *PacketBuffer) DeepCopyForForwarding(reservedHeaderBytes int) *PacketBu } { - consumeBytes := len(pk.TransportHeader().View()) + consumeBytes := len(pk.TransportHeader().Slice()) if _, consumed := newPk.TransportHeader().Consume(consumeBytes); !consumed { panic(fmt.Sprintf("expected to consume transport header %d bytes from new packet", consumeBytes)) } @@ -459,9 +475,22 @@ type PacketHeader struct { typ headerType } -// View returns the underlying storage of h. -func (h PacketHeader) View() []byte { - return h.pk.headerView(h.typ) +// View returns an caller-owned copy of the underlying storage of h as a +// *bufferv2.View. +func (h PacketHeader) View() *bufferv2.View { + view := h.pk.headerView(h.typ) + if view.Size() == 0 { + return nil + } + return view.Clone() +} + +// Slice returns the underlying storage of h as a []byte. The returned slice +// should not be modified if the underlying packet could be shared, cloned, or +// borrowed. +func (h PacketHeader) Slice() []byte { + view := h.pk.headerView(h.typ) + return view.AsSlice() } // Push pushes size bytes in the front of its residing packet, and returns the @@ -487,10 +516,13 @@ type PacketData struct { pk *PacketBuffer } -// PullUp returns a contiguous view of size bytes from the beginning of d. -// Callers should not write to or keep the view for later use. -func (d PacketData) PullUp(size int) ([]byte, bool) { - return d.pk.buf.PullUp(d.pk.dataOffset(), size) +// PullUp returns a contiguous slice of size bytes from the beginning of d. +// Callers should not keep the view for later use. Callers can write to the +// returned slice if they have singular ownership over the underlying +// Buffer. +func (d PacketData) PullUp(size int) (b []byte, ok bool) { + view, ok := d.pk.buf.PullUp(d.pk.dataOffset(), size) + return view.AsSlice(), ok } // Consume is the same as PullUp except that is additionally consumes the @@ -506,19 +538,25 @@ func (d PacketData) Consume(size int) ([]byte, bool) { // ReadTo reads bytes from d to dst. It also removes these bytes from d // unless peek is true. func (d PacketData) ReadTo(dst io.Writer, peek bool) (int, error) { - var err error - done := 0 - for _, v := range d.Slices() { + var ( + err error + done int + ) + offset := d.pk.dataOffset() + d.pk.buf.SubApply(offset, int(d.pk.buf.Size())-offset, func(v *bufferv2.View) { + if err != nil { + return + } var n int - n, err = dst.Write(v) + n, err = dst.Write(v.AsSlice()) done += n if err != nil { - break + return } - if n != len(v) { - panic(fmt.Sprintf("io.Writer.Write succeeded with incomplete write: %d != %d", n, len(v))) + if n != v.Size() { + panic(fmt.Sprintf("io.Writer.Write succeeded with incomplete write: %d != %d", n, v.Size())) } - } + }) if !peek { d.pk.buf.TrimFront(int64(done)) } @@ -530,26 +568,11 @@ func (d PacketData) CapLength(length int) { if length < 0 { panic("length < 0") } - if currLength := d.Size(); currLength > length { - trim := currLength - length - d.pk.buf.Remove(int(d.pk.buf.Size())-trim, trim) - } + d.pk.buf.Truncate(int64(length + d.pk.dataOffset())) } -// Slices returns the underlying storage of d in a slice of Views. Caller should -// not modify the returned slice. -func (d PacketData) Slices() [][]byte { - var views [][]byte - offset := d.pk.dataOffset() - d.pk.buf.SubApply(offset, int(d.pk.buf.Size())-offset, func(v []byte) { - views = append(views, v) - }) - return views -} - -// AsBuffer returns the underlying storage of d in a buffer.Buffer. Caller -// should not modify the returned buffer. -func (d PacketData) AsBuffer() buffer.Buffer { +// ToBuffer returns the underlying storage of d in a bufferv2.Buffer. +func (d PacketData) ToBuffer() bufferv2.Buffer { buf := d.pk.buf.Clone() offset := d.pk.dataOffset() buf.TrimFront(int64(offset)) @@ -557,13 +580,13 @@ func (d PacketData) AsBuffer() buffer.Buffer { } // AppendView appends v into d, taking the ownership of v. -func (d PacketData) AppendView(v []byte) { - d.pk.buf.AppendOwned(v) +func (d PacketData) AppendView(v *bufferv2.View) { + d.pk.buf.Append(v) } // MergeBuffer merges b into d and clears b. -func (d PacketData) MergeBuffer(b buffer.Buffer) { - d.pk.buf.Merge(&b) +func (d PacketData) MergeBuffer(b *bufferv2.Buffer) { + d.pk.buf.Merge(b) } // MergeFragment appends the data portion of frag to dst. It modifies @@ -573,9 +596,9 @@ func MergeFragment(dst, frag *PacketBuffer) { dst.buf.Merge(&frag.buf) } -// ReadFromBuffer moves at most count bytes from the beginning of src to the end +// ReadFrom moves at most count bytes from the beginning of src to the end // of d and returns the number of bytes moved. -func (d PacketData) ReadFromBuffer(src *buffer.Buffer, count int) int { +func (d PacketData) ReadFrom(src *bufferv2.Buffer, count int) int { toRead := int64(count) if toRead > src.Size() { toRead = src.Size() @@ -587,11 +610,14 @@ func (d PacketData) ReadFromBuffer(src *buffer.Buffer, count int) int { return int(toRead) } -// AppendRange appends and takes ownership of the data in r. -func (d PacketData) AppendRange(r Range) { - r.iterate(func(b []byte) { - d.pk.buf.AppendOwned(b) - }) +// ReadFromPacketData moves count bytes from the beginning of oth to the end of +// d. +func (d PacketData) ReadFromPacketData(oth PacketData, count int) { + buf := oth.ToBuffer() + buf.Truncate(int64(count)) + d.MergeBuffer(&buf) + oth.TrimFront(count) + buf.Release() } // Merge clears headers in oth and merges its data with d. @@ -600,35 +626,15 @@ func (d PacketData) Merge(oth PacketData) { d.pk.buf.Merge(&oth.pk.buf) } -// ReadFrom moves at most count bytes from the beginning of src to the end -// of d. -func (d PacketData) ReadFrom(src PacketData, count int) { - done := 0 - for _, v := range src.Slices() { - if len(v) < count { - count -= len(v) - done += len(v) - // Use AppendOwned to avoid the cost of copying data between buffers. - // This is safe because the buffers are trimmed out of src at the end - // of the function anyways. - d.pk.buf.AppendOwned(v) - } else { - v = v[:count] - count -= len(v) - done += len(v) - d.pk.buf.Append(v) - break - } - } - src.TrimFront(done) -} - // TrimFront removes up to count bytes from the front of d's payload. func (d PacketData) TrimFront(count int) { if count > d.Size() { count = d.Size() } - d.pk.buf.Remove(d.pk.dataOffset(), count) + buf := d.pk.Data().ToBuffer() + buf.TrimFront(int64(count)) + d.pk.buf.Truncate(int64(d.pk.dataOffset())) + d.pk.buf.Merge(&buf) } // Size returns the number of bytes in the data payload of the packet. @@ -683,62 +689,48 @@ func (r Range) Capped(max int) Range { } } -// AsView returns the backing storage of r if possible. It will allocate a new -// View if r spans multiple pieces internally. Caller should not write to the -// returned View in any way. -func (r Range) AsView() []byte { - var allocated bool - var v []byte - r.iterate(func(b []byte) { - if v == nil { - // v has not been assigned, allowing first view to be returned. - v = b - } else { - // v has been assigned. This range spans more than a view, a new view - // needs to be allocated. - if !allocated { - allocated = true - all := make([]byte, 0, r.length) - all = append(all, v...) - v = all - } - v = append(v, b...) - } - }) - return v -} - -// ToOwnedView returns a owned copy of data in r. -func (r Range) ToOwnedView() []byte { +// ToSlice returns a caller-owned copy of data in r. +func (r Range) ToSlice() []byte { if r.length == 0 { return nil } all := make([]byte, 0, r.length) - r.iterate(func(b []byte) { - all = append(all, b...) + r.iterate(func(v *bufferv2.View) { + all = append(all, v.AsSlice()...) }) return all } +// ToView returns a caller-owned copy of data in r. +func (r Range) ToView() *bufferv2.View { + if r.length == 0 { + return nil + } + newV := bufferv2.NewView(r.length) + r.iterate(func(v *bufferv2.View) { + newV.Write(v.AsSlice()) + }) + return newV +} + // Checksum calculates the RFC 1071 checksum for the underlying bytes of r. func (r Range) Checksum() uint16 { var c header.Checksumer - r.iterate(c.Add) + r.iterate(func(v *bufferv2.View) { + c.Add(v.AsSlice()) + }) return c.Checksum() } // iterate calls fn for each piece in r. fn is always called with a non-empty // slice. -func (r Range) iterate(fn func([]byte)) { +func (r Range) iterate(fn func(*bufferv2.View)) { r.pk.buf.SubApply(r.offset, r.length, fn) } -// PayloadSince returns packet payload starting from and including a particular -// header. -// -// The returned View is owned by the caller - its backing buffer is separate -// from the packet header's underlying packet buffer. -func PayloadSince(h PacketHeader) []byte { +// PayloadSince returns a caller-owned view containing the payload starting from +// and including a particular header. +func PayloadSince(h PacketHeader) *bufferv2.View { offset := h.pk.headerOffset() for i := headerType(0); i < h.typ; i++ { offset += h.pk.headers[i].length @@ -747,5 +739,17 @@ func PayloadSince(h PacketHeader) []byte { pk: h.pk, offset: offset, length: int(h.pk.buf.Size()) - offset, - }.ToOwnedView() + }.ToView() +} + +// BufferSince returns a caller-owned view containing the packet payload +// starting from and including a particular header. +func BufferSince(h PacketHeader) bufferv2.Buffer { + offset := h.pk.headerOffset() + for i := headerType(0); i < h.typ; i++ { + offset += h.pk.headers[i].length + } + clone := h.pk.buf.Clone() + clone.TrimFront(int64(offset)) + return clone } diff --git a/pkg/tcpip/stack/packet_buffer_state.go b/pkg/tcpip/stack/packet_buffer_state.go deleted file mode 100644 index ad7b45cf0..000000000 --- a/pkg/tcpip/stack/packet_buffer_state.go +++ /dev/null @@ -1,28 +0,0 @@ -// 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 stack - -// saveBuf is invoked by stateify. -func (pk *PacketBuffer) saveBuf() []byte { - var bytes []byte - pk.buf.Apply(func(v []byte) { - bytes = append(bytes, v...) - }) - return bytes -} - -// loadBuf is invoked by stateify. -func (pk *PacketBuffer) loadBuf(data []byte) { - pk.buf.Append(data) -} diff --git a/pkg/tcpip/stack/packet_buffer_test.go b/pkg/tcpip/stack/packet_buffer_test.go index 233fa166e..e6e4fd81c 100644 --- a/pkg/tcpip/stack/packet_buffer_test.go +++ b/pkg/tcpip/stack/packet_buffer_test.go @@ -18,7 +18,7 @@ import ( "fmt" "testing" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip/header" ) @@ -77,7 +77,7 @@ func TestPacketHeaderPush(t *testing.T) { ReserveHeaderBytes: test.reserved, // Make a copy of data to make sure our truth data won't be taint by // PacketBuffer. - Payload: buffer.NewWithData(test.data), + Payload: bufferv2.MakeWithData(test.data), }) allHdrSize := len(test.link) + len(test.network) + len(test.transport) @@ -85,7 +85,7 @@ func TestPacketHeaderPush(t *testing.T) { // Check the initial values for packet. checkInitialPacketBuffer(t, pk, PacketBufferOptions{ ReserveHeaderBytes: test.reserved, - Payload: buffer.NewWithData(test.data), + Payload: bufferv2.MakeWithData(test.data), }) // Push headers. @@ -149,12 +149,12 @@ func TestPacketHeaderConsume(t *testing.T) { pk := NewPacketBuffer(PacketBufferOptions{ // Make a copy of data to make sure our truth data won't be taint by // PacketBuffer. - Payload: buffer.NewWithData(test.data), + Payload: bufferv2.MakeWithData(test.data), }) // Check the initial values for packet. checkInitialPacketBuffer(t, pk, PacketBufferOptions{ - Payload: buffer.NewWithData(test.data), + Payload: bufferv2.MakeWithData(test.data), }) // Consume headers. @@ -206,7 +206,7 @@ func TestPacketHeaderConsumeDataTooShort(t *testing.T) { pk := NewPacketBuffer(PacketBufferOptions{ // Make a copy of data to make sure our truth data won't be taint by // PacketBuffer. - Payload: buffer.NewWithData(data), + Payload: bufferv2.MakeWithData(data), }) // Consume should fail if pkt.Data is too short. @@ -222,7 +222,7 @@ func TestPacketHeaderConsumeDataTooShort(t *testing.T) { // Check packet should look the same as initial packet. checkInitialPacketBuffer(t, pk, PacketBufferOptions{ - Payload: buffer.NewWithData(data), + Payload: bufferv2.MakeWithData(data), }) } @@ -239,7 +239,7 @@ func TestPacketHeaderPushConsumeMixed(t *testing.T) { initData = append(initData, data...) pk := NewPacketBuffer(PacketBufferOptions{ ReserveHeaderBytes: len(link), - Payload: buffer.NewWithData(initData), + Payload: bufferv2.MakeWithData(initData), }) // 1. Consume network header @@ -267,7 +267,7 @@ func TestPacketHeaderPushConsumeMixedTooLong(t *testing.T) { initData := concatViews(network, data) pk := NewPacketBuffer(PacketBufferOptions{ ReserveHeaderBytes: len(link), - Payload: buffer.NewWithData(initData), + Payload: bufferv2.MakeWithData(initData), }) // 1. Push link header @@ -316,7 +316,7 @@ func TestPacketHeaderConsumeCalledAtMostOnce(t *testing.T) { const headerSize = 10 pk := NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(make([]byte, headerSize*int(numHeaderType))), + Payload: bufferv2.MakeWithData(make([]byte, headerSize*int(numHeaderType))), }) for _, h := range []PacketHeader{ @@ -373,7 +373,7 @@ func TestPacketHeaderConsumeThenPushPanics(t *testing.T) { const headerSize = 10 pk := NewPacketBuffer(PacketBufferOptions{ - Payload: buffer.NewWithData(make([]byte, headerSize*int(numHeaderType))), + Payload: bufferv2.MakeWithData(make([]byte, headerSize*int(numHeaderType))), }) for _, h := range []PacketHeader{ @@ -494,19 +494,11 @@ func TestPacketBufferData(t *testing.T) { s := "APPEND" pkt := tc.makePkt(t) - pkt.Data().AppendView([]byte(s)) + pkt.Data().AppendView(bufferv2.NewViewWithData([]byte(s))) checkData(t, pkt, []byte(tc.data+s)) }) - t.Run("AppendRange", func(t *testing.T) { - pkt1 := tc.makePkt(t) - pkt2 := tc.makePkt(t) - subRangeStart := 2 - pkt1.Data().AppendRange(pkt2.Data().AsRange().SubRange(subRangeStart)) - checkData(t, pkt1, []byte(tc.data+tc.data[subRangeStart:])) - }) - t.Run("Merge", func(t *testing.T) { pkt1 := tc.makePkt(t) pkt2 := tc.makePkt(t) @@ -518,25 +510,6 @@ func TestPacketBufferData(t *testing.T) { } }) - t.Run("ReadFrom", func(t *testing.T) { - for _, n := range []int{0, 1, 2, 7, 10, 14, 20} { - t.Run(fmt.Sprintf("%dbytes", n), func(t *testing.T) { - pkt1 := tc.makePkt(t) - pkt2 := tc.makePkt(t) - pkt1.Data().ReadFrom(pkt2.Data(), n) - - want1 := tc.data - want2 := "" - if n < len(tc.data) { - want1 = tc.data[:n] - want2 = tc.data[n:] - } - checkData(t, pkt1, []byte(tc.data+want1)) - checkData(t, pkt2, []byte(want2)) - }) - } - }) - t.Run("TrimFront", func(t *testing.T) { for _, n := range []int{0, 1, 2, 7, 10, 14, 20} { t.Run(fmt.Sprintf("%dbytes", n), func(t *testing.T) { @@ -554,13 +527,13 @@ func TestPacketBufferData(t *testing.T) { // ReadFromBuffer for _, n := range []int{0, 1, 2, 7, 10, 14, 20} { - t.Run(fmt.Sprintf("ReadFromBuffer%d", n), func(t *testing.T) { + t.Run(fmt.Sprintf("ReadFrom%d", n), func(t *testing.T) { s := "TO READ" s += s - srcBuf := buffer.NewWithData([]byte(s)) + srcBuf := bufferv2.MakeWithData([]byte(s)) pkt := tc.makePkt(t) - pkt.Data().ReadFromBuffer(&srcBuf, n) + pkt.Data().ReadFrom(&srcBuf, n) if n < len(s) { s = s[:n] @@ -588,18 +561,34 @@ func checkPacketContents(t *testing.T, prefix string, pk *PacketBuffer, want pac // Data. checkData(t, pk, want.data) // Whole packet. - checkViewEqual(t, prefix+"pk.Slices()", - concatViews(pk.Slices()...), + checkViewEqual(t, prefix+"pk.AsSlices()", + concatViews(pk.AsSlices()...), concatViews(want.link, want.network, want.transport, want.data)) // PayloadSince. + link := PayloadSince(pk.LinkHeader()) checkViewEqual(t, prefix+"PayloadSince(LinkHeader)", - PayloadSince(pk.LinkHeader()), + link.AsSlice(), concatViews(want.link, want.network, want.transport, want.data)) + net := PayloadSince(pk.NetworkHeader()) checkViewEqual(t, prefix+"PayloadSince(NetworkHeader)", - PayloadSince(pk.NetworkHeader()), + net.AsSlice(), concatViews(want.network, want.transport, want.data)) + trans := PayloadSince(pk.TransportHeader()) checkViewEqual(t, prefix+"PayloadSince(TransportHeader)", - PayloadSince(pk.TransportHeader()), + trans.AsSlice(), + concatViews(want.transport, want.data)) + // BufferSince. + linkBuf := BufferSince(pk.LinkHeader()) + checkViewEqual(t, prefix+"PayloadSince(LinkHeader)", + linkBuf.Flatten(), + concatViews(want.link, want.network, want.transport, want.data)) + netBuf := BufferSince(pk.NetworkHeader()) + checkViewEqual(t, prefix+"PayloadSince(NetworkHeader)", + netBuf.Flatten(), + concatViews(want.network, want.transport, want.data)) + transBuf := BufferSince(pk.TransportHeader()) + checkViewEqual(t, prefix+"PayloadSince(TransportHeader)", + transBuf.Flatten(), concatViews(want.transport, want.data)) } @@ -626,7 +615,7 @@ func checkInitialPacketBuffer(t *testing.T, pk *PacketBuffer, opts PacketBufferO func checkPacketHeader(t *testing.T, name string, h PacketHeader, want []byte) { t.Helper() - checkViewEqual(t, name+".View()", h.View(), want) + checkViewEqual(t, name+".Slice()", h.Slice(), want) } func checkViewEqual(t *testing.T, what string, got, want []byte) { @@ -638,8 +627,8 @@ func checkViewEqual(t *testing.T, what string, got, want []byte) { func checkData(t *testing.T, pkt *PacketBuffer, want []byte) { t.Helper() - if got := concatViews(pkt.Data().Slices()...); !bytes.Equal(got, want) { - t.Errorf("pkt.Data().Views() = 0x%x, want 0x%x", got, want) + if got := pkt.Data().AsRange().ToSlice(); !bytes.Equal(got, want) { + t.Errorf("pkt.Data().Slices() = 0x%x, want 0x%x", got, want) } if got := pkt.Data().Size(); got != len(want) { t.Errorf("pkt.Data().Size() = %d, want %d", got, len(want)) @@ -678,21 +667,18 @@ func checkRange(t *testing.T, r Range, data []byte) { if got, want := r.Size(), len(data); got != want { t.Errorf("r.Size() = %d, want %d", got, want) } - if got := r.AsView(); !bytes.Equal(got, data) { - t.Errorf("r.AsView() = %x, want %x", got, data) - } - if got := r.ToOwnedView(); !bytes.Equal(got, data) { - t.Errorf("r.ToOwnedView() = %x, want %x", got, data) + if got := r.ToSlice(); !bytes.Equal(got, data) { + t.Errorf("r.AsSlice() = %x, want %x", got, data) } if got, want := r.Checksum(), header.Checksum(data, 0 /* initial */); got != want { t.Errorf("r.Checksum() = %x, want %x", got, want) } } -func buf(pieces ...string) buffer.Buffer { - b := buffer.Buffer{} +func buf(pieces ...string) bufferv2.Buffer { + b := bufferv2.Buffer{} for _, p := range pieces { - b.AppendOwned([]byte(p)) + b.Append(bufferv2.NewViewWithData([]byte(p))) } return b } diff --git a/pkg/tcpip/stack/registration.go b/pkg/tcpip/stack/registration.go index 35c742e96..e21d94510 100644 --- a/pkg/tcpip/stack/registration.go +++ b/pkg/tcpip/stack/registration.go @@ -18,6 +18,7 @@ import ( "fmt" "time" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/waiter" @@ -197,7 +198,7 @@ type TransportProtocol interface { // ParsePorts returns the source and destination ports stored in a // packet of this protocol. - ParsePorts(v []byte) (src, dst uint16, err tcpip.Error) + ParsePorts(b []byte) (src, dst uint16, err tcpip.Error) // HandleUnknownDestinationPacket handles packets targeted at this // protocol that don't match any existing endpoint. For example, @@ -867,7 +868,7 @@ type NetworkProtocol interface { // ParseAddresses returns the source and destination addresses stored in a // packet of this protocol. - ParseAddresses(v []byte) (src, dst tcpip.Address) + ParseAddresses(b []byte) (src, dst tcpip.Address) // NewEndpoint creates a new endpoint of this protocol. NewEndpoint(nic NetworkInterface, dispatcher TransportDispatcher) NetworkEndpoint @@ -1145,7 +1146,7 @@ type InjectableLinkEndpoint interface { // link. // // dest is used by endpoints with multiple raw destinations. - InjectOutbound(dest tcpip.Address, packet []byte) tcpip.Error + InjectOutbound(dest tcpip.Address, packet *bufferv2.View) tcpip.Error } // DADResult is a marker interface for the result of a duplicate address diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index dc0fa7acf..414f662b9 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -29,7 +29,7 @@ import ( "golang.org/x/time/rate" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/log" cryptorand "gvisor.dev/gvisor/pkg/rand" "gvisor.dev/gvisor/pkg/sync" @@ -1808,7 +1808,7 @@ func (s *Stack) unregisterPacketEndpointLocked(nicID tcpip.NICID, netProto tcpip // WritePacketToRemote writes a payload on the specified NIC using the provided // network protocol and remote link address. -func (s *Stack) WritePacketToRemote(nicID tcpip.NICID, remote tcpip.LinkAddress, netProto tcpip.NetworkProtocolNumber, payload buffer.Buffer) tcpip.Error { +func (s *Stack) WritePacketToRemote(nicID tcpip.NICID, remote tcpip.LinkAddress, netProto tcpip.NetworkProtocolNumber, payload bufferv2.Buffer) tcpip.Error { s.mu.Lock() nic, ok := s.nics[nicID] s.mu.Unlock() @@ -1826,7 +1826,7 @@ func (s *Stack) WritePacketToRemote(nicID tcpip.NICID, remote tcpip.LinkAddress, // WriteRawPacket writes data directly to the specified NIC without adding any // headers. -func (s *Stack) WriteRawPacket(nicID tcpip.NICID, proto tcpip.NetworkProtocolNumber, payload buffer.Buffer) tcpip.Error { +func (s *Stack) WriteRawPacket(nicID tcpip.NICID, proto tcpip.NetworkProtocolNumber, payload bufferv2.Buffer) tcpip.Error { s.mu.RLock() nic, ok := s.nics[nicID] s.mu.RUnlock() diff --git a/pkg/tcpip/stack/stack_test.go b/pkg/tcpip/stack/stack_test.go index 7a38c3f08..98bd529e8 100644 --- a/pkg/tcpip/stack/stack_test.go +++ b/pkg/tcpip/stack/stack_test.go @@ -28,7 +28,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/rand" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" @@ -128,7 +128,7 @@ func (f *fakeNetworkEndpoint) HandlePacket(pkt *stack.PacketBuffer) { } // Increment the received packet count in the protocol descriptor. - netHdr := pkt.NetworkHeader().View() + netHdr := pkt.NetworkHeader().Slice() dst := tcpip.Address(netHdr[dstAddrOffset:][:1]) addressEndpoint := f.AcquireAssignedAddress(dst, f.nic.Promiscuous(), stack.CanBePrimaryEndpoint) @@ -575,7 +575,7 @@ func TestNetworkReceive(t *testing.T) { // Make sure packet with wrong address is not delivered. buf[dstAddrOffset] = 3 ep.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeNet.packetCount[1] != 0 { t.Errorf("packetCount[1] = %d, want %d", fakeNet.packetCount[1], 0) @@ -587,7 +587,7 @@ func TestNetworkReceive(t *testing.T) { // Make sure packet is delivered to first endpoint. buf[dstAddrOffset] = 1 ep.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeNet.packetCount[1] != 1 { t.Errorf("packetCount[1] = %d, want %d", fakeNet.packetCount[1], 1) @@ -599,7 +599,7 @@ func TestNetworkReceive(t *testing.T) { // Make sure packet is delivered to second endpoint. buf[dstAddrOffset] = 2 ep.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeNet.packetCount[1] != 1 { t.Errorf("packetCount[1] = %d, want %d", fakeNet.packetCount[1], 1) @@ -610,7 +610,7 @@ func TestNetworkReceive(t *testing.T) { // Make sure packet is not delivered if protocol number is wrong. ep.InjectInbound(fakeNetNumber-1, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeNet.packetCount[1] != 1 { t.Errorf("packetCount[1] = %d, want %d", fakeNet.packetCount[1], 1) @@ -622,7 +622,7 @@ func TestNetworkReceive(t *testing.T) { // Make sure packet that is too small is dropped. buf = buf[:2] ep.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeNet.packetCount[1] != 1 { t.Errorf("packetCount[1] = %d, want %d", fakeNet.packetCount[1], 1) @@ -644,7 +644,7 @@ func sendTo(s *stack.Stack, addr tcpip.Address, payload []byte) tcpip.Error { func send(r *stack.Route, payload []byte) tcpip.Error { return r.WritePacket(stack.NetworkHeaderParams{Protocol: fakeTransNumber, TTL: 123, TOS: stack.DefaultTOS}, stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(r.MaxHeaderLength()), - Payload: buffer.NewWithData(payload), + Payload: bufferv2.MakeWithData(payload), })) } @@ -701,7 +701,7 @@ func testFailingRecv(t *testing.T, fakeNet *fakeNetworkProtocol, localAddrByte b func testRecvInternal(t *testing.T, fakeNet *fakeNetworkProtocol, localAddrByte byte, ep *channel.Endpoint, buf []byte, want int) { t.Helper() ep.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if got := fakeNet.PacketCount(localAddrByte); got != want { t.Errorf("receive packet count: got = %d, want %d", got, want) @@ -1799,7 +1799,7 @@ func TestExternalSendWithHandleLocal(t *testing.T) { TOS: stack.DefaultTOS, }, stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(r.MaxHeaderLength()), - Payload: buffer.NewWithData(make([]byte, 10)), + Payload: bufferv2.MakeWithData(make([]byte, 10)), })); err != nil { t.Fatalf("r.WritePacket(nil, _, _): %s", err) } @@ -2573,7 +2573,7 @@ func TestNICStats(t *testing.T) { // Inbound packet. rxBuffer := make([]byte, nic.rxByteCount) ep.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(rxBuffer), + Payload: bufferv2.MakeWithData(rxBuffer), })) if got, want := nicStats.Rx.Packets.Value(), uint64(1); got != want { t.Errorf("got Rx.Packets.Value() = %d, want = %d", got, want) @@ -5272,7 +5272,7 @@ func TestWritePacketToRemote(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - if err := s.WritePacketToRemote(nicID, linkAddr2, test.protocol, buffer.NewWithData(test.payload)); err != nil { + if err := s.WritePacketToRemote(nicID, linkAddr2, test.protocol, bufferv2.MakeWithData(test.payload)); err != nil { t.Fatalf("s.WritePacketToRemote(_, _, _, _) = %s", err) } @@ -5287,14 +5287,14 @@ func TestWritePacketToRemote(t *testing.T) { if pkt.EgressRoute.RemoteLinkAddress != linkAddr2 { t.Fatalf("pkt.EgressRoute.RemoteAddress = %s, want %s", pkt.EgressRoute.RemoteLinkAddress, linkAddr2) } - if diff := cmp.Diff(pkt.Data().AsRange().ToOwnedView(), test.payload); diff != "" { + if diff := cmp.Diff(pkt.Data().AsRange().ToSlice(), test.payload); diff != "" { t.Errorf("pkt.Data mismatch (-want +got):\n%s", diff) } }) } t.Run("InvalidNICID", func(t *testing.T) { - err := s.WritePacketToRemote(234, linkAddr2, header.IPv4ProtocolNumber, buffer.NewWithData([]byte{1})) + err := s.WritePacketToRemote(234, linkAddr2, header.IPv4ProtocolNumber, bufferv2.MakeWithData([]byte{1})) if _, ok := err.(*tcpip.ErrUnknownDevice); !ok { t.Fatalf("s.WritePacketToRemote(_, _, _, _) = %s, want = %s", err, &tcpip.ErrUnknownDevice{}) } diff --git a/pkg/tcpip/stack/transport_demuxer_test.go b/pkg/tcpip/stack/transport_demuxer_test.go index 9461c90f0..f206c0963 100644 --- a/pkg/tcpip/stack/transport_demuxer_test.go +++ b/pkg/tcpip/stack/transport_demuxer_test.go @@ -21,7 +21,7 @@ import ( "strconv" "testing" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/channel" @@ -139,7 +139,7 @@ func (c *testContext) sendV4Packet(payload []byte, h *headers, linkEpID tcpip.NI // Inject packet. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) c.linkEps[linkEpID].InjectInbound(ipv4.ProtocolNumber, pkt) } @@ -176,7 +176,7 @@ func (c *testContext) sendV6Packet(payload []byte, h *headers, linkEpID tcpip.NI // Inject packet. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) c.linkEps[linkEpID].InjectInbound(ipv6.ProtocolNumber, pkt) } diff --git a/pkg/tcpip/stack/transport_test.go b/pkg/tcpip/stack/transport_test.go index b99624154..5ac859b8d 100644 --- a/pkg/tcpip/stack/transport_test.go +++ b/pkg/tcpip/stack/transport_test.go @@ -19,7 +19,7 @@ import ( "io" "testing" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/link/channel" "gvisor.dev/gvisor/pkg/tcpip/ports" @@ -105,7 +105,7 @@ func (f *fakeTransportEndpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(f.route.MaxHeaderLength()) + fakeTransHeaderLen, - Payload: buffer.NewWithData(v), + Payload: bufferv2.MakeWithData(v), }) _ = pkt.TransportHeader().Push(fakeTransHeaderLen) if err := f.route.WritePacket(stack.NetworkHeaderParams{Protocol: fakeTransNumber, TTL: 123, TOS: stack.DefaultTOS}, pkt); err != nil { @@ -220,7 +220,7 @@ func (f *fakeTransportEndpoint) HandlePacket(id stack.TransportEndpointID, pkt * return } - netHdr := pkt.NetworkHeader().View() + netHdr := pkt.NetworkHeader().Slice() route, err := f.proto.stack.FindRoute(pkt.NICID, tcpip.Address(netHdr[dstAddrOffset]), tcpip.Address(netHdr[srcAddrOffset]), pkt.NetworkProtocolNumber, false /* multicastLoop */) if err != nil { return @@ -399,7 +399,7 @@ func TestTransportReceive(t *testing.T) { buf[0] = 1 buf[2] = 0 linkEP.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeTrans.packetCount != 0 { t.Errorf("packetCount = %d, want %d", fakeTrans.packetCount, 0) @@ -410,7 +410,7 @@ func TestTransportReceive(t *testing.T) { buf[1] = 3 buf[2] = byte(fakeTransNumber) linkEP.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeTrans.packetCount != 0 { t.Errorf("packetCount = %d, want %d", fakeTrans.packetCount, 0) @@ -421,7 +421,7 @@ func TestTransportReceive(t *testing.T) { buf[1] = 2 buf[2] = byte(fakeTransNumber) linkEP.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeTrans.packetCount != 1 { t.Errorf("packetCount = %d, want %d", fakeTrans.packetCount, 1) @@ -483,7 +483,7 @@ func TestTransportControlReceive(t *testing.T) { buf[fakeNetHeaderLen+1] = 1 buf[fakeNetHeaderLen+2] = 0 linkEP.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeTrans.controlCount != 0 { t.Errorf("controlCount = %d, want %d", fakeTrans.controlCount, 0) @@ -494,7 +494,7 @@ func TestTransportControlReceive(t *testing.T) { buf[fakeNetHeaderLen+1] = 1 buf[fakeNetHeaderLen+2] = byte(fakeTransNumber) linkEP.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeTrans.controlCount != 0 { t.Errorf("controlCount = %d, want %d", fakeTrans.controlCount, 0) @@ -505,7 +505,7 @@ func TestTransportControlReceive(t *testing.T) { buf[fakeNetHeaderLen+1] = 1 buf[fakeNetHeaderLen+2] = byte(fakeTransNumber) linkEP.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), })) if fakeTrans.controlCount != 1 { t.Errorf("controlCount = %d, want %d", fakeTrans.controlCount, 1) diff --git a/pkg/tcpip/tests/integration/BUILD b/pkg/tcpip/tests/integration/BUILD index af10d9dbe..23380ce93 100644 --- a/pkg/tcpip/tests/integration/BUILD +++ b/pkg/tcpip/tests/integration/BUILD @@ -7,6 +7,7 @@ go_test( size = "small", srcs = ["forward_test.go"], deps = [ + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/checker", "//pkg/tcpip/header", @@ -29,7 +30,7 @@ go_test( size = "small", srcs = ["iptables_test.go"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/checker", "//pkg/tcpip/header", @@ -55,7 +56,7 @@ go_test( size = "small", srcs = ["link_resolution_test.go"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/checker", "//pkg/tcpip/faketime", @@ -82,7 +83,7 @@ go_test( size = "small", srcs = ["loopback_test.go"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/checker", "//pkg/tcpip/header", @@ -106,7 +107,7 @@ go_test( size = "small", srcs = ["multicast_broadcast_test.go"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/checker", "//pkg/tcpip/header", diff --git a/pkg/tcpip/tests/integration/forward_test.go b/pkg/tcpip/tests/integration/forward_test.go index 0edc60a6b..edbffcb27 100644 --- a/pkg/tcpip/tests/integration/forward_test.go +++ b/pkg/tcpip/tests/integration/forward_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -45,8 +46,8 @@ func rxICMPv6EchoRequest(e *channel.Endpoint, src, dst tcpip.Address) { utils.RxICMPv6EchoRequest(e, src, dst, ttl) } -func forwardedICMPv4EchoRequestChecker(t *testing.T, b []byte, src, dst tcpip.Address) { - checker.IPv4(t, b, +func forwardedICMPv4EchoRequestChecker(t *testing.T, v *bufferv2.View, src, dst tcpip.Address) { + checker.IPv4(t, v, checker.SrcAddr(src), checker.DstAddr(dst), checker.TTL(ttl-1), @@ -54,8 +55,8 @@ func forwardedICMPv4EchoRequestChecker(t *testing.T, b []byte, src, dst tcpip.Ad checker.ICMPv4Type(header.ICMPv4Echo))) } -func forwardedICMPv6EchoRequestChecker(t *testing.T, b []byte, src, dst tcpip.Address) { - checker.IPv6(t, b, +func forwardedICMPv6EchoRequestChecker(t *testing.T, v *bufferv2.View, src, dst tcpip.Address) { + checker.IPv6(t, v, checker.SrcAddr(src), checker.DstAddr(dst), checker.TTL(ttl-1), @@ -361,7 +362,7 @@ func TestUnicastForwarding(t *testing.T) { srcAddr, dstAddr tcpip.Address rx func(*channel.Endpoint, tcpip.Address, tcpip.Address) expectForward bool - checker func(*testing.T, []byte) + checker func(*testing.T, *bufferv2.View) }{ { name: "IPv4 link-local source", @@ -383,8 +384,8 @@ func TestUnicastForwarding(t *testing.T) { dstAddr: utils.Ipv4Addr2.AddressWithPrefix.Address, rx: rxICMPv4EchoRequest, expectForward: true, - checker: func(t *testing.T, b []byte) { - forwardedICMPv4EchoRequestChecker(t, b, utils.RemoteIPv4Addr, utils.Ipv4Addr2.AddressWithPrefix.Address) + checker: func(t *testing.T, v *bufferv2.View) { + forwardedICMPv4EchoRequestChecker(t, v, utils.RemoteIPv4Addr, utils.Ipv4Addr2.AddressWithPrefix.Address) }, }, { @@ -407,8 +408,8 @@ func TestUnicastForwarding(t *testing.T) { dstAddr: utils.Ipv6Addr2.AddressWithPrefix.Address, rx: rxICMPv6EchoRequest, expectForward: true, - checker: func(t *testing.T, b []byte) { - forwardedICMPv6EchoRequestChecker(t, b, utils.RemoteIPv6Addr, utils.Ipv6Addr2.AddressWithPrefix.Address) + checker: func(t *testing.T, v *bufferv2.View) { + forwardedICMPv6EchoRequestChecker(t, v, utils.RemoteIPv6Addr, utils.Ipv6Addr2.AddressWithPrefix.Address) }, }, } @@ -473,7 +474,9 @@ func TestUnicastForwarding(t *testing.T) { } if test.expectForward { - test.checker(t, stack.PayloadSince(p.NetworkHeader())) + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + test.checker(t, payload) p.DecRef() } }) @@ -490,15 +493,15 @@ func TestPerInterfaceForwarding(t *testing.T) { name string srcAddr, dstAddr tcpip.Address rx func(*channel.Endpoint, tcpip.Address, tcpip.Address) - checker func(*testing.T, []byte) + checker func(*testing.T, *bufferv2.View) }{ { name: "IPv4 unicast", srcAddr: utils.RemoteIPv4Addr, dstAddr: utils.Ipv4Addr2.AddressWithPrefix.Address, rx: rxICMPv4EchoRequest, - checker: func(t *testing.T, b []byte) { - forwardedICMPv4EchoRequestChecker(t, b, utils.RemoteIPv4Addr, utils.Ipv4Addr2.AddressWithPrefix.Address) + checker: func(t *testing.T, v *bufferv2.View) { + forwardedICMPv4EchoRequestChecker(t, v, utils.RemoteIPv4Addr, utils.Ipv4Addr2.AddressWithPrefix.Address) }, }, { @@ -506,8 +509,8 @@ func TestPerInterfaceForwarding(t *testing.T) { srcAddr: utils.RemoteIPv6Addr, dstAddr: utils.Ipv6Addr2.AddressWithPrefix.Address, rx: rxICMPv6EchoRequest, - checker: func(t *testing.T, b []byte) { - forwardedICMPv6EchoRequestChecker(t, b, utils.RemoteIPv6Addr, utils.Ipv6Addr2.AddressWithPrefix.Address) + checker: func(t *testing.T, v *bufferv2.View) { + forwardedICMPv6EchoRequestChecker(t, v, utils.RemoteIPv6Addr, utils.Ipv6Addr2.AddressWithPrefix.Address) }, }, } @@ -635,7 +638,9 @@ func TestPerInterfaceForwarding(t *testing.T) { t.Errorf("got otherNICEP.Read() = (%#v, %t), want = (_, %t)", p, ok, subTest.expectForwarding) } if p != nil { - test.checker(t, stack.PayloadSince(p.NetworkHeader())) + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + test.checker(t, payload) p.DecRef() } }) diff --git a/pkg/tcpip/tests/integration/iptables_test.go b/pkg/tcpip/tests/integration/iptables_test.go index 8d7fb1318..bd4f272e0 100644 --- a/pkg/tcpip/tests/integration/iptables_test.go +++ b/pkg/tcpip/tests/integration/iptables_test.go @@ -21,7 +21,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -119,7 +119,7 @@ func genPacketV6() *stack.PacketBuffer { SrcAddr: srcAddrV6, DstAddr: dstAddrV6, }) - buf := buffer.NewWithData(hdr.View()) + buf := bufferv2.MakeWithData(hdr.View()) return stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf}) } @@ -140,7 +140,7 @@ func genPacketV4() *stack.PacketBuffer { }) ip.SetChecksum(0) ip.SetChecksum(^ip.CalculateChecksum()) - buf := buffer.NewWithData(hdr.View()) + buf := bufferv2.MakeWithData(hdr.View()) return stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf}) } @@ -362,7 +362,7 @@ func (*udpSourcePortMatcher) Name() string { } func (m *udpSourcePortMatcher) Match(_ stack.Hook, pkt *stack.PacketBuffer, _, _ string) (matches, hotdrop bool) { - udp := header.UDP(pkt.TransportHeader().View()) + udp := header.UDP(pkt.TransportHeader().Slice()) if len(udp) < header.UDPMinimumSize { // Drop immediately as the packet is invalid. return false, true @@ -664,8 +664,8 @@ func rxICMPv6EchoReply(e *channel.Endpoint, src, dst tcpip.Address) { utils.RxICMPv6EchoReply(e, src, dst, ttl) } -func forwardedICMPv4EchoReplyChecker(t *testing.T, b []byte, src, dst tcpip.Address) { - checker.IPv4(t, b, +func forwardedICMPv4EchoReplyChecker(t *testing.T, v *bufferv2.View, src, dst tcpip.Address) { + checker.IPv4(t, v, checker.SrcAddr(src), checker.DstAddr(dst), checker.TTL(ttl-1), @@ -673,8 +673,8 @@ func forwardedICMPv4EchoReplyChecker(t *testing.T, b []byte, src, dst tcpip.Addr checker.ICMPv4Type(header.ICMPv4EchoReply))) } -func forwardedICMPv6EchoReplyChecker(t *testing.T, b []byte, src, dst tcpip.Address) { - checker.IPv6(t, b, +func forwardedICMPv6EchoReplyChecker(t *testing.T, v *bufferv2.View, src, dst tcpip.Address) { + checker.IPv6(t, v, checker.SrcAddr(src), checker.DstAddr(dst), checker.TTL(ttl-1), @@ -723,7 +723,7 @@ func TestForwardingHook(t *testing.T) { local bool srcAddr, dstAddr tcpip.Address rx func(*channel.Endpoint, tcpip.Address, tcpip.Address) - checker func(*testing.T, []byte) + checker func(*testing.T, *bufferv2.View) }{ { name: "IPv4 remote", @@ -732,8 +732,8 @@ func TestForwardingHook(t *testing.T) { srcAddr: utils.RemoteIPv4Addr, dstAddr: utils.Ipv4Addr2.AddressWithPrefix.Address, rx: rxICMPv4EchoReply, - checker: func(t *testing.T, b []byte) { - forwardedICMPv4EchoReplyChecker(t, b, utils.RemoteIPv4Addr, utils.Ipv4Addr2.AddressWithPrefix.Address) + checker: func(t *testing.T, v *bufferv2.View) { + forwardedICMPv4EchoReplyChecker(t, v, utils.RemoteIPv4Addr, utils.Ipv4Addr2.AddressWithPrefix.Address) }, }, { @@ -751,8 +751,8 @@ func TestForwardingHook(t *testing.T) { srcAddr: utils.RemoteIPv6Addr, dstAddr: utils.Ipv6Addr2.AddressWithPrefix.Address, rx: rxICMPv6EchoReply, - checker: func(t *testing.T, b []byte) { - forwardedICMPv6EchoReplyChecker(t, b, utils.RemoteIPv6Addr, utils.Ipv6Addr2.AddressWithPrefix.Address) + checker: func(t *testing.T, v *bufferv2.View) { + forwardedICMPv6EchoReplyChecker(t, v, utils.RemoteIPv6Addr, utils.Ipv6Addr2.AddressWithPrefix.Address) }, }, { @@ -941,7 +941,9 @@ func TestForwardingHook(t *testing.T) { t.Fatalf("got e2.Read() = %#v, want = (_ == nil) = %t", p, expectTransmitPacket) } if expectTransmitPacket { - test.checker(t, stack.PayloadSince(p.NetworkHeader())) + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + test.checker(t, payload) p.DecRef() } }) @@ -965,7 +967,7 @@ func TestFilteringEchoPacketsWithLocalForwarding(t *testing.T) { name string netProto tcpip.NetworkProtocolNumber rx func(*channel.Endpoint) - checker func(*testing.T, []byte) + checker func(*testing.T, *bufferv2.View) }{ { name: "IPv4", @@ -973,8 +975,8 @@ func TestFilteringEchoPacketsWithLocalForwarding(t *testing.T) { rx: func(e *channel.Endpoint) { utils.RxICMPv4EchoRequest(e, utils.RemoteIPv4Addr, utils.Ipv4Addr2.AddressWithPrefix.Address, ttl) }, - checker: func(t *testing.T, b []byte) { - checker.IPv4(t, b, + checker: func(t *testing.T, v *bufferv2.View) { + checker.IPv4(t, v, checker.SrcAddr(utils.Ipv4Addr2.AddressWithPrefix.Address), checker.DstAddr(utils.RemoteIPv4Addr), checker.ICMPv4( @@ -987,8 +989,8 @@ func TestFilteringEchoPacketsWithLocalForwarding(t *testing.T) { rx: func(e *channel.Endpoint) { utils.RxICMPv6EchoRequest(e, utils.RemoteIPv6Addr, utils.Ipv6Addr2.AddressWithPrefix.Address, ttl) }, - checker: func(t *testing.T, b []byte) { - checker.IPv6(t, b, + checker: func(t *testing.T, v *bufferv2.View) { + checker.IPv6(t, v, checker.SrcAddr(utils.Ipv6Addr2.AddressWithPrefix.Address), checker.DstAddr(utils.RemoteIPv6Addr), checker.ICMPv6( @@ -1180,7 +1182,9 @@ func TestFilteringEchoPacketsWithLocalForwarding(t *testing.T) { t.Errorf("got e1.Read() = %#v, want = (_ == nil) = %t", p, expectPacket) } if p != nil { - test.checker(t, stack.PayloadSince(p.NetworkHeader())) + payload := stack.PayloadSince(p.NetworkHeader()) + defer payload.Release() + test.checker(t, payload) p.DecRef() } if p := e2.Read(); p != nil { @@ -1378,7 +1382,7 @@ func TestNATEcho(t *testing.T) { return icmpv4Packet(srcAddr, dstAddr, icmpType, ident) } - checkV4EchoPkt := func(t *testing.T, v []byte, srcAddr, dstAddr tcpip.Address, reply bool) { + checkV4EchoPkt := func(t *testing.T, v *bufferv2.View, srcAddr, dstAddr tcpip.Address, reply bool) { t.Helper() icmpType := header.ICMPv4Echo @@ -1405,7 +1409,7 @@ func TestNATEcho(t *testing.T) { return icmpv6Packet(srcAddr, dstAddr, icmpType, ident) } - checkV6EchoPkt := func(t *testing.T, v []byte, srcAddr, dstAddr tcpip.Address, reply bool) { + checkV6EchoPkt := func(t *testing.T, v *bufferv2.View, srcAddr, dstAddr tcpip.Address, reply bool) { t.Helper() icmpType := header.ICMPv6EchoRequest @@ -1434,7 +1438,7 @@ func TestNATEcho(t *testing.T) { netProto tcpip.NetworkProtocolNumber transProto tcpip.TransportProtocolNumber echoPkt func(srcAddr, dstAddr tcpip.Address, reply bool) []byte - checkEchoPkt func(t *testing.T, v []byte, srcAddr, dstAddr tcpip.Address, reply bool) + checkEchoPkt func(t *testing.T, v *bufferv2.View, srcAddr, dstAddr tcpip.Address, reply bool) natTypes []natTypeTest }{ @@ -1528,13 +1532,15 @@ func TestNATEcho(t *testing.T) { // Send and check the Echo Request. { ep2.InjectInbound(test.netProto, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(test.echoPkt(natTypeTest.requestSrc, natTypeTest.requestDst, false /* reply */)), + Payload: bufferv2.MakeWithData(test.echoPkt(natTypeTest.requestSrc, natTypeTest.requestDst, false /* reply */)), })) pkt := ep1.Read() if pkt == nil { t.Fatal("expected to read a packet on ep1") } - test.checkEchoPkt(t, stack.PayloadSince(pkt.NetworkHeader()), natTypeTest.expectedRequestSrc, natTypeTest.expectedRequestDst, false /* reply */) + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() + test.checkEchoPkt(t, payload, natTypeTest.expectedRequestSrc, natTypeTest.expectedRequestDst, false /* reply */) pkt.DecRef() } @@ -1545,13 +1551,15 @@ func TestNATEcho(t *testing.T) { // Send and check the Echo Reply. { ep1.InjectInbound(test.netProto, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(test.echoPkt(natTypeTest.expectedRequestDst, natTypeTest.expectedRequestSrc, true /* reply */)), + Payload: bufferv2.MakeWithData(test.echoPkt(natTypeTest.expectedRequestDst, natTypeTest.expectedRequestSrc, true /* reply */)), })) pkt := ep2.Read() if pkt == nil { t.Fatal("expected to read a packet on ep2") } - test.checkEchoPkt(t, stack.PayloadSince(pkt.NetworkHeader()), natTypeTest.requestDst, natTypeTest.requestSrc, true /* reply */) + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() + test.checkEchoPkt(t, payload, natTypeTest.requestDst, natTypeTest.requestSrc, true /* reply */) pkt.DecRef() } }) @@ -2183,7 +2191,7 @@ func TestNATICMPError(t *testing.T) { name string proto tcpip.TransportProtocolNumber buf []byte - checkNATed func(*testing.T, []byte) + checkNATed func(*testing.T, *bufferv2.View) } tests := []struct { @@ -2192,7 +2200,7 @@ func TestNATICMPError(t *testing.T) { host1Addr tcpip.Address icmpError func(*testing.T, []byte, uint8) []byte decrementTTL func([]byte) - checkNATedError func(*testing.T, []byte, []byte, uint8) + checkNATedError func(*testing.T, *bufferv2.View, []byte, uint8) transportTypes []transportTypeTest icmpTypes []icmpTypeTest @@ -2225,7 +2233,7 @@ func TestNATICMPError(t *testing.T) { ip.SetChecksum(0) ip.SetChecksum(^ip.CalculateChecksum()) }, - checkNATedError: func(t *testing.T, v []byte, original []byte, icmpType uint8) { + checkNATedError: func(t *testing.T, v *bufferv2.View, original []byte, icmpType uint8) { checker.IPv4(t, v, checker.SrcAddr(utils.RouterNIC2IPv4Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host2IPv4Addr.AddressWithPrefix.Address), @@ -2243,7 +2251,7 @@ func TestNATICMPError(t *testing.T) { buf: func() []byte { return udpv4Packet(utils.Host2IPv4Addr.AddressWithPrefix.Address, utils.RouterNIC2IPv4Addr.AddressWithPrefix.Address, srcPort, dstPort, dataSize) }(), - checkNATed: func(t *testing.T, v []byte) { + checkNATed: func(t *testing.T, v *bufferv2.View) { checker.IPv4(t, v, checker.SrcAddr(utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host1IPv4Addr.AddressWithPrefix.Address), @@ -2260,7 +2268,7 @@ func TestNATICMPError(t *testing.T) { buf: func() []byte { return tcpv4Packet(utils.Host2IPv4Addr.AddressWithPrefix.Address, utils.RouterNIC2IPv4Addr.AddressWithPrefix.Address, srcPort, dstPort, dataSize) }(), - checkNATed: func(t *testing.T, v []byte) { + checkNATed: func(t *testing.T, v *bufferv2.View) { checker.IPv4(t, v, checker.SrcAddr(utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host1IPv4Addr.AddressWithPrefix.Address), @@ -2331,7 +2339,7 @@ func TestNATICMPError(t *testing.T) { ip := header.IPv6(v) ip.SetHopLimit(ip.HopLimit() - 1) }, - checkNATedError: func(t *testing.T, v []byte, original []byte, icmpType uint8) { + checkNATedError: func(t *testing.T, v *bufferv2.View, original []byte, icmpType uint8) { checker.IPv6(t, v, checker.SrcAddr(utils.RouterNIC2IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host2IPv6Addr.AddressWithPrefix.Address), @@ -2348,7 +2356,7 @@ func TestNATICMPError(t *testing.T) { buf: func() []byte { return udpv6Packet(utils.Host2IPv6Addr.AddressWithPrefix.Address, utils.RouterNIC2IPv6Addr.AddressWithPrefix.Address, srcPort, dstPort, dataSize) }(), - checkNATed: func(t *testing.T, v []byte) { + checkNATed: func(t *testing.T, v *bufferv2.View) { checker.IPv6(t, v, checker.SrcAddr(utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host1IPv6Addr.AddressWithPrefix.Address), @@ -2365,7 +2373,7 @@ func TestNATICMPError(t *testing.T) { buf: func() []byte { return tcpv6Packet(utils.Host2IPv6Addr.AddressWithPrefix.Address, utils.RouterNIC2IPv6Addr.AddressWithPrefix.Address, srcPort, dstPort, dataSize) }(), - checkNATed: func(t *testing.T, v []byte) { + checkNATed: func(t *testing.T, v *bufferv2.View) { checker.IPv6(t, v, checker.SrcAddr(utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host1IPv6Addr.AddressWithPrefix.Address), @@ -2511,7 +2519,7 @@ func TestNATICMPError(t *testing.T) { buf := transportType.buf ep2.InjectInbound(test.netProto, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(append([]byte{}, buf...)), + Payload: bufferv2.MakeWithData(append([]byte{}, buf...)), })) { @@ -2520,17 +2528,18 @@ func TestNATICMPError(t *testing.T) { t.Fatal("expected to read a packet on ep1") } pktView := stack.PayloadSince(pkt.NetworkHeader()) + defer pktView.Release() pkt.DecRef() transportType.checkNATed(t, pktView) if t.Failed() { t.FailNow() } - pktView = pktView[:len(pktView)-trimTest.trimLen] + pktSlice := pktView.AsSlice()[:pktView.Size()-trimTest.trimLen] buf = buf[:len(buf)-trimTest.trimLen] ep1.InjectInbound(test.netProto, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(test.icmpError(t, pktView, icmpType.val)), + Payload: bufferv2.MakeWithData(test.icmpError(t, pktSlice, icmpType.val)), })) } @@ -2543,7 +2552,9 @@ func TestNATICMPError(t *testing.T) { return } test.decrementTTL(buf) - test.checkNATedError(t, stack.PayloadSince(pkt.NetworkHeader()), buf, icmpType.val) + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() + test.checkNATedError(t, payload, buf, icmpType.val) pkt.DecRef() }) } @@ -2610,7 +2621,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { name string proto tcpip.TransportProtocolNumber buf func(tcpip.Address, uint16) []byte - checkNATed func(*testing.T, []byte, uint16, bool, portOrIdentRange) + checkNATed func(*testing.T, *bufferv2.View, uint16, bool, portOrIdentRange) srcPortOrIdentRanges []srcPortOrIdentRangeTest } @@ -2652,7 +2663,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { buf: func(srcAddr tcpip.Address, srcPort uint16) []byte { return udpv4Packet(srcAddr, utils.Host1IPv4Addr.AddressWithPrefix.Address, srcPort, dstPort, 0 /* dataSize */) }, - checkNATed: func(t *testing.T, v []byte, originalSrcPort uint16, firstPacket bool, expectedRange portOrIdentRange) { + checkNATed: func(t *testing.T, v *bufferv2.View, originalSrcPort uint16, firstPacket bool, expectedRange portOrIdentRange) { checker.IPv4(t, v, checker.SrcAddr(utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host1IPv4Addr.AddressWithPrefix.Address), @@ -2662,7 +2673,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { ) if !t.Failed() { - compareSrcPortOrIdent(t, header.UDP(header.IPv4(v).Payload()).SourcePort(), originalSrcPort, firstPacket, expectedRange) + compareSrcPortOrIdent(t, header.UDP(header.IPv4(v.AsSlice()).Payload()).SourcePort(), originalSrcPort, firstPacket, expectedRange) } }, srcPortOrIdentRanges: srcPortRanges, @@ -2673,7 +2684,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { buf: func(srcAddr tcpip.Address, srcPort uint16) []byte { return tcpv4Packet(srcAddr, utils.Host1IPv4Addr.AddressWithPrefix.Address, srcPort, dstPort, 0 /* dataSize */) }, - checkNATed: func(t *testing.T, v []byte, originalSrcPort uint16, firstPacket bool, expectedRange portOrIdentRange) { + checkNATed: func(t *testing.T, v *bufferv2.View, originalSrcPort uint16, firstPacket bool, expectedRange portOrIdentRange) { checker.IPv4(t, v, checker.SrcAddr(utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host1IPv4Addr.AddressWithPrefix.Address), @@ -2683,7 +2694,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { ) if !t.Failed() { - compareSrcPortOrIdent(t, header.TCP(header.IPv4(v).Payload()).SourcePort(), originalSrcPort, firstPacket, expectedRange) + compareSrcPortOrIdent(t, header.TCP(header.IPv4(v.AsSlice()).Payload()).SourcePort(), originalSrcPort, firstPacket, expectedRange) } }, srcPortOrIdentRanges: srcPortRanges, @@ -2694,7 +2705,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { buf: func(srcAddr tcpip.Address, ident uint16) []byte { return icmpv4Packet(srcAddr, utils.Host1IPv4Addr.AddressWithPrefix.Address, header.ICMPv4Echo, ident) }, - checkNATed: func(t *testing.T, v []byte, originalIdent uint16, firstPacket bool, expectedRange portOrIdentRange) { + checkNATed: func(t *testing.T, v *bufferv2.View, originalIdent uint16, firstPacket bool, expectedRange portOrIdentRange) { checker.IPv4(t, v, checker.SrcAddr(utils.RouterNIC1IPv4Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host1IPv4Addr.AddressWithPrefix.Address), @@ -2705,7 +2716,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { ) if !t.Failed() { - compareSrcPortOrIdent(t, header.ICMPv4(header.IPv4(v).Payload()).Ident(), originalIdent, firstPacket, expectedRange) + compareSrcPortOrIdent(t, header.ICMPv4(header.IPv4(v.AsSlice()).Payload()).Ident(), originalIdent, firstPacket, expectedRange) } }, srcPortOrIdentRanges: identRanges, @@ -2728,7 +2739,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { buf: func(srcAddr tcpip.Address, srcPort uint16) []byte { return udpv6Packet(srcAddr, utils.Host1IPv6Addr.AddressWithPrefix.Address, srcPort, dstPort, 0 /* dataSize */) }, - checkNATed: func(t *testing.T, v []byte, originalSrcPort uint16, firstPacket bool, expectedRange portOrIdentRange) { + checkNATed: func(t *testing.T, v *bufferv2.View, originalSrcPort uint16, firstPacket bool, expectedRange portOrIdentRange) { checker.IPv6(t, v, checker.SrcAddr(utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host1IPv6Addr.AddressWithPrefix.Address), @@ -2738,7 +2749,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { ) if !t.Failed() { - compareSrcPortOrIdent(t, header.UDP(header.IPv6(v).Payload()).SourcePort(), originalSrcPort, firstPacket, expectedRange) + compareSrcPortOrIdent(t, header.UDP(header.IPv6(v.AsSlice()).Payload()).SourcePort(), originalSrcPort, firstPacket, expectedRange) } }, srcPortOrIdentRanges: srcPortRanges, @@ -2749,7 +2760,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { buf: func(srcAddr tcpip.Address, srcPort uint16) []byte { return tcpv6Packet(srcAddr, utils.Host1IPv6Addr.AddressWithPrefix.Address, srcPort, dstPort, 0 /* dataSize */) }, - checkNATed: func(t *testing.T, v []byte, originalSrcPort uint16, firstPacket bool, expectedRange portOrIdentRange) { + checkNATed: func(t *testing.T, v *bufferv2.View, originalSrcPort uint16, firstPacket bool, expectedRange portOrIdentRange) { checker.IPv6(t, v, checker.SrcAddr(utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host1IPv6Addr.AddressWithPrefix.Address), @@ -2759,7 +2770,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { ) if !t.Failed() { - compareSrcPortOrIdent(t, header.TCP(header.IPv6(v).Payload()).SourcePort(), originalSrcPort, firstPacket, expectedRange) + compareSrcPortOrIdent(t, header.TCP(header.IPv6(v.AsSlice()).Payload()).SourcePort(), originalSrcPort, firstPacket, expectedRange) } }, srcPortOrIdentRanges: srcPortRanges, @@ -2770,7 +2781,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { buf: func(srcAddr tcpip.Address, ident uint16) []byte { return icmpv6Packet(srcAddr, utils.Host1IPv6Addr.AddressWithPrefix.Address, header.ICMPv6EchoRequest, ident) }, - checkNATed: func(t *testing.T, v []byte, originalIdent uint16, firstPacket bool, expectedRange portOrIdentRange) { + checkNATed: func(t *testing.T, v *bufferv2.View, originalIdent uint16, firstPacket bool, expectedRange portOrIdentRange) { checker.IPv6(t, v, checker.SrcAddr(utils.RouterNIC1IPv6Addr.AddressWithPrefix.Address), checker.DstAddr(utils.Host1IPv6Addr.AddressWithPrefix.Address), @@ -2780,7 +2791,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { ) if !t.Failed() { - compareSrcPortOrIdent(t, header.ICMPv6(header.IPv6(v).Payload()).Ident(), originalIdent, firstPacket, expectedRange) + compareSrcPortOrIdent(t, header.ICMPv6(header.IPv6(v.AsSlice()).Payload()).Ident(), originalIdent, firstPacket, expectedRange) } }, srcPortOrIdentRanges: identRanges, @@ -2878,7 +2889,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { for i, srcAddr := range test.srcAddrs { t.Run(fmt.Sprintf("Packet#%d", i), func(t *testing.T) { ep2.InjectInbound(test.netProto, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(transportType.buf(srcAddr, srcPortOrIdent)), + Payload: bufferv2.MakeWithData(transportType.buf(srcAddr, srcPortOrIdent)), })) pkt := ep1.Read() @@ -2886,6 +2897,7 @@ func TestSNATHandlePortOrIdentConflicts(t *testing.T) { t.Fatal("expected to read a packet on ep1") } pktView := stack.PayloadSince(pkt.NetworkHeader()) + defer pktView.Release() pkt.DecRef() transportType.checkNATed(t, pktView, srcPortOrIdent, i == 0, srcPortOrIdentRange.targetRange) }) @@ -3031,7 +3043,7 @@ func (m *icmpv4Matcher) Match(_ stack.Hook, pkt *stack.PacketBuffer, _, _ string return false, false } - return header.ICMPv4(pkt.TransportHeader().View()).Type() == m.icmpType, false + return header.ICMPv4(pkt.TransportHeader().Slice()).Type() == m.icmpType, false } type icmpv6Matcher struct { @@ -3047,7 +3059,7 @@ func (m *icmpv6Matcher) Match(_ stack.Hook, pkt *stack.PacketBuffer, _, _ string return false, false } - return header.ICMPv6(pkt.TransportHeader().View()).Type() == m.icmpType, false + return header.ICMPv6(pkt.TransportHeader().Slice()).Type() == m.icmpType, false } func TestRejectWith(t *testing.T) { @@ -3078,7 +3090,7 @@ func TestRejectWith(t *testing.T) { name string netProto tcpip.NetworkProtocolNumber rxICMPEchoRequest func(tcpip.Address) []byte - icmpChecker func(*testing.T, []byte, tcpip.Address, uint8, uint8, []byte) + icmpChecker func(*testing.T, *bufferv2.View, tcpip.Address, uint8, uint8, []byte) natHooks []natHook @@ -3091,7 +3103,7 @@ func TestRejectWith(t *testing.T) { netProto: header.IPv4ProtocolNumber, rxICMPEchoRequest: rxICMPv4EchoRequest, - icmpChecker: func(t *testing.T, v []byte, dstAddr tcpip.Address, icmpType, icmpCode uint8, origPayload []byte) { + icmpChecker: func(t *testing.T, v *bufferv2.View, dstAddr tcpip.Address, icmpType, icmpCode uint8, origPayload []byte) { t.Helper() checker.IPv4(t, v, @@ -3178,7 +3190,7 @@ func TestRejectWith(t *testing.T) { netProto: header.IPv6ProtocolNumber, rxICMPEchoRequest: rxICMPv6EchoRequest, - icmpChecker: func(t *testing.T, v []byte, dstAddr tcpip.Address, icmpType, icmpCode uint8, origPayload []byte) { + icmpChecker: func(t *testing.T, v *bufferv2.View, dstAddr tcpip.Address, icmpType, icmpCode uint8, origPayload []byte) { t.Helper() checker.IPv6(t, v, @@ -3280,7 +3292,7 @@ func TestRejectWith(t *testing.T) { func() { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(test.rxICMPEchoRequest(natHook.dstAddr)), + Payload: bufferv2.MakeWithData(test.rxICMPEchoRequest(natHook.dstAddr)), }) defer pkt.DecRef() ep1.InjectInbound(test.netProto, pkt) @@ -3291,9 +3303,11 @@ func TestRejectWith(t *testing.T) { if pkt == nil { t.Fatal("expected to read a packet on ep1") } + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() test.icmpChecker( t, - stack.PayloadSince(pkt.NetworkHeader()), + payload, natHook.errorICMPDstAddr, test.errorICMPType, rejectWith.errorICMPCode, @@ -3411,7 +3425,7 @@ func genTCP4(offset int8) *stack.PacketBuffer { ip.SetChecksum(0) ip.SetChecksum(^ip.CalculateChecksum()) - buf := buffer.NewWithData(append([]byte{}, hdr.View()...)) + buf := bufferv2.MakeWithData(append([]byte{}, hdr.View()...)) return stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf}) } @@ -3437,7 +3451,7 @@ func genTCP6(offset int8) *stack.PacketBuffer { DstAddr: dstAddrV6, }) - buf := buffer.NewWithData(append([]byte{}, hdr.View()...)) + buf := bufferv2.MakeWithData(append([]byte{}, hdr.View()...)) return stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf}) } @@ -3468,7 +3482,7 @@ func genUDP4(offset int8) *stack.PacketBuffer { ip.SetChecksum(0) ip.SetChecksum(^ip.CalculateChecksum()) - buf := buffer.NewWithData(append([]byte{}, hdr.View()...)) + buf := bufferv2.MakeWithData(append([]byte{}, hdr.View()...)) return stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf}) } @@ -3493,6 +3507,6 @@ func genUDP6(offset int8) *stack.PacketBuffer { DstAddr: dstAddrV6, }) - buf := buffer.NewWithData(append([]byte{}, hdr.View()...)) + buf := bufferv2.MakeWithData(append([]byte{}, hdr.View()...)) return stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf}) } diff --git a/pkg/tcpip/tests/integration/link_resolution_test.go b/pkg/tcpip/tests/integration/link_resolution_test.go index 7dedee499..754a59541 100644 --- a/pkg/tcpip/tests/integration/link_resolution_test.go +++ b/pkg/tcpip/tests/integration/link_resolution_test.go @@ -24,7 +24,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" "gvisor.dev/gvisor/pkg/tcpip/faketime" @@ -367,6 +367,7 @@ func TestTCPLinkResolutionFailure(t *testing.T) { if sockErr == nil { t.Fatalf("got sockOpts.DequeueErr() = nil, want = non-nil") } + defer sockErr.Payload.Release() sockErrCmpOpts := []cmp.Option{ cmpopts.IgnoreUnexported(tcpip.SockError{}), @@ -438,7 +439,7 @@ func TestForwardingWithLinkResolutionFailure(t *testing.T) { if request.EgressRoute.RemoteLinkAddress != header.EthernetBroadcastAddress { t.Errorf("got request.EgressRoute.RemoteLinkAddress = %s, want = %s", request.EgressRoute.RemoteLinkAddress, header.EthernetBroadcastAddress) } - rep := header.ARP(request.NetworkHeader().View()) + rep := header.ARP(request.NetworkHeader().Slice()) if got := rep.Op(); got != header.ARPRequest { t.Errorf("got Op() = %d, want = %d", got, header.ARPRequest) } @@ -463,7 +464,9 @@ func TestForwardingWithLinkResolutionFailure(t *testing.T) { t.Errorf("got remote link address = %s, want = %s", request.EgressRoute.RemoteLinkAddress, want) } - checker.IPv6(t, stack.PayloadSince(request.NetworkHeader()), + payload := stack.PayloadSince(request.NetworkHeader()) + defer payload.Release() + checker.IPv6(t, payload, checker.SrcAddr(src), checker.DstAddr(snmc), checker.TTL(header.NDPHopLimit), @@ -472,8 +475,8 @@ func TestForwardingWithLinkResolutionFailure(t *testing.T) { )) } - icmpv4Checker := func(t *testing.T, b []byte, src, dst tcpip.Address) { - checker.IPv4(t, b, + icmpv4Checker := func(t *testing.T, v *bufferv2.View, src, dst tcpip.Address) { + checker.IPv4(t, v, checker.SrcAddr(src), checker.DstAddr(dst), checker.TTL(ipv4.DefaultTTL), @@ -485,8 +488,8 @@ func TestForwardingWithLinkResolutionFailure(t *testing.T) { ) } - icmpv6Checker := func(t *testing.T, b []byte, src, dst tcpip.Address) { - checker.IPv6(t, b, + icmpv6Checker := func(t *testing.T, v *bufferv2.View, src, dst tcpip.Address) { + checker.IPv6(t, v, checker.SrcAddr(src), checker.DstAddr(dst), checker.TTL(ipv6.DefaultTTL), @@ -508,7 +511,7 @@ func TestForwardingWithLinkResolutionFailure(t *testing.T) { transportProtocol func(*stack.Stack) stack.TransportProtocol rx func(*channel.Endpoint, tcpip.Address, tcpip.Address) linkResolutionRequestChecker func(*testing.T, *stack.PacketBuffer, tcpip.Address, tcpip.Address) - icmpReplyChecker func(*testing.T, []byte, tcpip.Address, tcpip.Address) + icmpReplyChecker func(*testing.T, *bufferv2.View, tcpip.Address, tcpip.Address) mtu uint32 }{ { @@ -635,7 +638,9 @@ func TestForwardingWithLinkResolutionFailure(t *testing.T) { t.Fatal("expected ICMP packet through incoming NIC") } - test.icmpReplyChecker(t, stack.PayloadSince(reply.NetworkHeader()), test.incomingAddr.Address, test.sourceAddr) + payload := stack.PayloadSince(reply.NetworkHeader()) + defer payload.Release() + test.icmpReplyChecker(t, payload, test.incomingAddr.Address, test.sourceAddr) reply.DecRef() // Since link resolution failed, we don't expect the packet to be @@ -953,7 +958,7 @@ func TestWritePacketsLinkResolution(t *testing.T) { for _, d := range data { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: header.UDPMinimumSize + int(r.MaxHeaderLength()), - Payload: buffer.NewWithData([]byte{d}), + Payload: bufferv2.MakeWithData([]byte{d}), }) pkt.TransportProtocolNumber = udp.ProtocolNumber length := uint16(pkt.Data().Size() + header.UDPMinimumSize) diff --git a/pkg/tcpip/tests/integration/loopback_test.go b/pkg/tcpip/tests/integration/loopback_test.go index 80060544c..5e98f3d64 100644 --- a/pkg/tcpip/tests/integration/loopback_test.go +++ b/pkg/tcpip/tests/integration/loopback_test.go @@ -20,7 +20,7 @@ import ( "time" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -315,7 +315,7 @@ func TestLoopbackSubnetLifetimeBoundToAddr(t *testing.T) { data := []byte{1, 2, 3, 4} if err := r.WritePacket(params, stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(r.MaxHeaderLength()), - Payload: buffer.NewWithData(data), + Payload: bufferv2.MakeWithData(data), })); err != nil { t.Fatalf("r.WritePacket(%#v, _): %s", params, err) } @@ -327,7 +327,7 @@ func TestLoopbackSubnetLifetimeBoundToAddr(t *testing.T) { { err := r.WritePacket(params, stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(r.MaxHeaderLength()), - Payload: buffer.NewWithData(data), + Payload: bufferv2.MakeWithData(data), })) if _, ok := err.(*tcpip.ErrInvalidEndpointState); !ok { t.Fatalf("got r.WritePacket(%#v, _) = %s, want = %s", params, err, &tcpip.ErrInvalidEndpointState{}) diff --git a/pkg/tcpip/tests/integration/multicast_broadcast_test.go b/pkg/tcpip/tests/integration/multicast_broadcast_test.go index d327ce5dd..0a538b821 100644 --- a/pkg/tcpip/tests/integration/multicast_broadcast_test.go +++ b/pkg/tcpip/tests/integration/multicast_broadcast_test.go @@ -19,7 +19,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -158,7 +158,9 @@ func TestPingMulticastBroadcast(t *testing.T) { t.Errorf("got pkt.EgressRoute.RemoteAddress = %s, want = %s", pkt.EgressRoute.RemoteAddress, test.srcAddr) } - src, dst := s.NetworkProtocolInstance(test.protoNum).ParseAddresses(stack.PayloadSince(pkt.NetworkHeader())) + v := stack.PayloadSince(pkt.NetworkHeader()) + defer v.Release() + src, dst := s.NetworkProtocolInstance(test.protoNum).ParseAddresses(v.AsSlice()) if src != test.expectedSrc { t.Errorf("got pkt source = %s, want = %s", src, test.expectedSrc) } @@ -198,7 +200,7 @@ func rxIPv4UDP(e *channel.Endpoint, src, dst tcpip.Address, data []byte) { ip.SetChecksum(^ip.CalculateChecksum()) e.InjectInbound(header.IPv4ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), })) } @@ -226,7 +228,7 @@ func rxIPv6UDP(e *channel.Endpoint, src, dst tcpip.Address, data []byte) { }) e.InjectInbound(header.IPv6ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(hdr.View()), + Payload: bufferv2.MakeWithData(hdr.View()), })) } diff --git a/pkg/tcpip/tests/integration/multicast_forward_test.go b/pkg/tcpip/tests/integration/multicast_forward_test.go index 33559b5b9..26da29ec2 100644 --- a/pkg/tcpip/tests/integration/multicast_forward_test.go +++ b/pkg/tcpip/tests/integration/multicast_forward_test.go @@ -166,9 +166,11 @@ func getEndpointAddr(protocol tcpip.NetworkProtocolNumber, addrType endpointAddr } func checkEchoRequest(t *testing.T, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer, srcAddr, dstAddr tcpip.Address, ttl uint8) { + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() switch protocol { case ipv4.ProtocolNumber: - checker.IPv4(t, stack.PayloadSince(pkt.NetworkHeader()), + checker.IPv4(t, payload, checker.SrcAddr(srcAddr), checker.DstAddr(dstAddr), checker.TTL(ttl), @@ -177,7 +179,7 @@ func checkEchoRequest(t *testing.T, protocol tcpip.NetworkProtocolNumber, pkt *s ), ) case ipv6.ProtocolNumber: - checker.IPv6(t, stack.PayloadSince(pkt.NetworkHeader()), + checker.IPv6(t, payload, checker.SrcAddr(srcAddr), checker.DstAddr(dstAddr), checker.TTL(ttl), @@ -191,9 +193,11 @@ func checkEchoRequest(t *testing.T, protocol tcpip.NetworkProtocolNumber, pkt *s } func checkEchoReply(t *testing.T, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer, srcAddr, dstAddr tcpip.Address) { + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() switch protocol { case ipv4.ProtocolNumber: - checker.IPv4(t, stack.PayloadSince(pkt.NetworkHeader()), + checker.IPv4(t, payload, checker.SrcAddr(srcAddr), checker.DstAddr(dstAddr), checker.ICMPv4( @@ -201,7 +205,7 @@ func checkEchoReply(t *testing.T, protocol tcpip.NetworkProtocolNumber, pkt *sta ), ) case ipv6.ProtocolNumber: - checker.IPv6(t, stack.PayloadSince(pkt.NetworkHeader()), + checker.IPv6(t, payload, checker.SrcAddr(srcAddr), checker.DstAddr(dstAddr), checker.ICMPv6( diff --git a/pkg/tcpip/tests/utils/BUILD b/pkg/tcpip/tests/utils/BUILD index cfdd447e8..299b59e85 100644 --- a/pkg/tcpip/tests/utils/BUILD +++ b/pkg/tcpip/tests/utils/BUILD @@ -8,7 +8,7 @@ go_library( srcs = ["utils.go"], visibility = ["//pkg/tcpip/tests:__subpackages__"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/header", "//pkg/tcpip/link/channel", diff --git a/pkg/tcpip/tests/utils/utils.go b/pkg/tcpip/tests/utils/utils.go index d21b66f2f..5f0b9d00c 100644 --- a/pkg/tcpip/tests/utils/utils.go +++ b/pkg/tcpip/tests/utils/utils.go @@ -18,7 +18,7 @@ package utils import ( "testing" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/channel" @@ -209,7 +209,7 @@ var _ stack.LinkEndpoint = (*EndpointWithDestinationCheck)(nil) // DeliverNetworkPacket implements stack.NetworkDispatcher. func (e *EndpointWithDestinationCheck) DeliverNetworkPacket(proto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { - if dst := header.Ethernet(pkt.LinkHeader().View()).DestinationAddress(); dst == e.Endpoint.LinkAddress() || dst == header.EthernetBroadcastAddress || header.IsMulticastEthernetAddress(dst) { + if dst := header.Ethernet(pkt.LinkHeader().Slice()).DestinationAddress(); dst == e.Endpoint.LinkAddress() || dst == header.EthernetBroadcastAddress || header.IsMulticastEthernetAddress(dst) { e.Endpoint.DeliverNetworkPacket(proto, pkt) } } @@ -379,7 +379,7 @@ func ICMPv4Echo(src, dst tcpip.Address, ttl uint8, ty header.ICMPv4Type) []byte // the provided endpoint. func RxICMPv4EchoRequest(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8) { newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(ICMPv4Echo(src, dst, ttl, header.ICMPv4Echo)), + Payload: bufferv2.MakeWithData(ICMPv4Echo(src, dst, ttl, header.ICMPv4Echo)), }) defer newPkt.DecRef() e.InjectInbound(header.IPv4ProtocolNumber, newPkt) @@ -389,7 +389,7 @@ func RxICMPv4EchoRequest(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8) // the provided endpoint. func RxICMPv4EchoReply(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8) { newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(ICMPv4Echo(src, dst, ttl, header.ICMPv4EchoReply)), + Payload: bufferv2.MakeWithData(ICMPv4Echo(src, dst, ttl, header.ICMPv4EchoReply)), }) defer newPkt.DecRef() e.InjectInbound(header.IPv4ProtocolNumber, newPkt) @@ -423,7 +423,7 @@ func ICMPv6Echo(src, dst tcpip.Address, ttl uint8, ty header.ICMPv6Type) []byte // the provided endpoint. func RxICMPv6EchoRequest(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8) { newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(ICMPv6Echo(src, dst, ttl, header.ICMPv6EchoRequest)), + Payload: bufferv2.MakeWithData(ICMPv6Echo(src, dst, ttl, header.ICMPv6EchoRequest)), }) defer newPkt.DecRef() e.InjectInbound(header.IPv6ProtocolNumber, newPkt) @@ -433,7 +433,7 @@ func RxICMPv6EchoRequest(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8) // the provided endpoint. func RxICMPv6EchoReply(e *channel.Endpoint, src, dst tcpip.Address, ttl uint8) { newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(ICMPv6Echo(src, dst, ttl, header.ICMPv6EchoReply)), + Payload: bufferv2.MakeWithData(ICMPv6Echo(src, dst, ttl, header.ICMPv6EchoReply)), }) defer newPkt.DecRef() e.InjectInbound(header.IPv6ProtocolNumber, newPkt) diff --git a/pkg/tcpip/transport/icmp/BUILD b/pkg/tcpip/transport/icmp/BUILD index e32fbf70a..dbca4db57 100644 --- a/pkg/tcpip/transport/icmp/BUILD +++ b/pkg/tcpip/transport/icmp/BUILD @@ -25,7 +25,7 @@ go_library( ], visibility = ["//visibility:public"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/log", "//pkg/sleep", "//pkg/sync", diff --git a/pkg/tcpip/transport/icmp/endpoint.go b/pkg/tcpip/transport/icmp/endpoint.go index f17ebcea8..4d26400f8 100644 --- a/pkg/tcpip/transport/icmp/endpoint.go +++ b/pkg/tcpip/transport/icmp/endpoint.go @@ -19,8 +19,7 @@ import ( "io" "time" - "gvisor.dev/gvisor/pkg/buffer" - "gvisor.dev/gvisor/pkg/log" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -337,11 +336,12 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp } defer ctx.Release() - // TODO(https://gvisor.dev/issue/6538): Avoid this allocation. - v := make([]byte, p.Len()) - if _, err := io.ReadFull(p, v); err != nil { + v := bufferv2.NewView(p.Len()) + defer v.Release() + if _, err := io.CopyN(v, p, int64(p.Len())); err != nil { return 0, &tcpip.ErrBadBuffer{} } + n := v.Size() switch netProto, pktInfo := e.net.NetProto(), ctx.PacketInfo(); netProto { case header.IPv4ProtocolNumber: @@ -357,7 +357,7 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp panic(fmt.Sprintf("unhandled network protocol = %d", netProto)) } - return int64(len(v)), nil + return int64(n), nil } var _ tcpip.SocketOptionsHandler = (*endpoint)(nil) @@ -400,13 +400,12 @@ func (e *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) tcpip.Error { return e.net.GetSockOpt(opt) } -func send4(s *stack.Stack, ctx *network.WriteContext, ident uint16, data []byte, maxHeaderLength uint16) tcpip.Error { - if len(data) < header.ICMPv4MinimumSize { - log.Infof("len(data) is smaller than min size") +func send4(s *stack.Stack, ctx *network.WriteContext, ident uint16, data *bufferv2.View, maxHeaderLength uint16) tcpip.Error { + if data.Size() < header.ICMPv4MinimumSize { return &tcpip.ErrInvalidEndpointState{} } - pkt := ctx.TryNewPacketBuffer(header.ICMPv4MinimumSize+int(maxHeaderLength), buffer.Buffer{}) + pkt := ctx.TryNewPacketBuffer(header.ICMPv4MinimumSize+int(maxHeaderLength), bufferv2.Buffer{}) if pkt == nil { return &tcpip.ErrWouldBlock{} } @@ -414,11 +413,11 @@ func send4(s *stack.Stack, ctx *network.WriteContext, ident uint16, data []byte, icmpv4 := header.ICMPv4(pkt.TransportHeader().Push(header.ICMPv4MinimumSize)) pkt.TransportProtocolNumber = header.ICMPv4ProtocolNumber - copy(icmpv4, data) + copy(icmpv4, data.AsSlice()) // Set the ident to the user-specified port. Sequence number should // already be set by the user. icmpv4.SetIdent(ident) - data = data[header.ICMPv4MinimumSize:] + data.TrimFront(header.ICMPv4MinimumSize) // Linux performs these basic checks. if icmpv4.Type() != header.ICMPv4Echo || icmpv4.Code() != 0 { @@ -426,8 +425,8 @@ func send4(s *stack.Stack, ctx *network.WriteContext, ident uint16, data []byte, } icmpv4.SetChecksum(0) - icmpv4.SetChecksum(^header.Checksum(icmpv4, header.Checksum(data, 0))) - pkt.Data().AppendView(data) + icmpv4.SetChecksum(^header.Checksum(icmpv4, header.Checksum(data.AsSlice(), 0))) + pkt.Data().AppendView(data.Clone()) // Because this icmp endpoint is implemented in the transport layer, we can // only increment the 'stack-wide' stats but we can't increment the @@ -443,12 +442,12 @@ func send4(s *stack.Stack, ctx *network.WriteContext, ident uint16, data []byte, return nil } -func send6(s *stack.Stack, ctx *network.WriteContext, ident uint16, data []byte, src, dst tcpip.Address, maxHeaderLength uint16) tcpip.Error { - if len(data) < header.ICMPv6EchoMinimumSize { +func send6(s *stack.Stack, ctx *network.WriteContext, ident uint16, data *bufferv2.View, src, dst tcpip.Address, maxHeaderLength uint16) tcpip.Error { + if data.Size() < header.ICMPv6EchoMinimumSize { return &tcpip.ErrInvalidEndpointState{} } - pkt := ctx.TryNewPacketBuffer(header.ICMPv6MinimumSize+int(maxHeaderLength), buffer.Buffer{}) + pkt := ctx.TryNewPacketBuffer(header.ICMPv6MinimumSize+int(maxHeaderLength), bufferv2.Buffer{}) if pkt == nil { return &tcpip.ErrWouldBlock{} } @@ -456,16 +455,16 @@ func send6(s *stack.Stack, ctx *network.WriteContext, ident uint16, data []byte, icmpv6 := header.ICMPv6(pkt.TransportHeader().Push(header.ICMPv6MinimumSize)) pkt.TransportProtocolNumber = header.ICMPv6ProtocolNumber - copy(icmpv6, data) + copy(icmpv6, data.AsSlice()) // Set the ident. Sequence number is provided by the user. icmpv6.SetIdent(ident) - data = data[header.ICMPv6MinimumSize:] + data.TrimFront(header.ICMPv6MinimumSize) if icmpv6.Type() != header.ICMPv6EchoRequest || icmpv6.Code() != 0 { return &tcpip.ErrInvalidEndpointState{} } - pkt.Data().AppendView(data) + pkt.Data().AppendView(data.Clone()) dataRange := pkt.Data().AsRange() icmpv6.SetChecksum(header.ICMPv6Checksum(header.ICMPv6ChecksumParams{ Header: icmpv6, @@ -695,14 +694,14 @@ func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketB // Only accept echo replies. switch e.net.NetProto() { case header.IPv4ProtocolNumber: - h := header.ICMPv4(pkt.TransportHeader().View()) + h := header.ICMPv4(pkt.TransportHeader().Slice()) if len(h) < header.ICMPv4MinimumSize || h.Type() != header.ICMPv4EchoReply { e.stack.Stats().DroppedPackets.Increment() e.stats.ReceiveErrors.MalformedPacketsReceived.Increment() return } case header.IPv6ProtocolNumber: - h := header.ICMPv6(pkt.TransportHeader().View()) + h := header.ICMPv6(pkt.TransportHeader().Slice()) if len(h) < header.ICMPv6MinimumSize || h.Type() != header.ICMPv6EchoReply { e.stack.Stats().DroppedPackets.Increment() e.stats.ReceiveErrors.MalformedPacketsReceived.Increment() @@ -754,15 +753,15 @@ func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketB packet.tosOrTClass, _ = net.TOS() switch pkt.NetworkProtocolNumber { case header.IPv4ProtocolNumber: - packet.ttlOrHopLimit = header.IPv4(pkt.NetworkHeader().View()).TTL() + packet.ttlOrHopLimit = header.IPv4(pkt.NetworkHeader().Slice()).TTL() case header.IPv6ProtocolNumber: - packet.ttlOrHopLimit = header.IPv6(pkt.NetworkHeader().View()).HopLimit() + packet.ttlOrHopLimit = header.IPv6(pkt.NetworkHeader().Slice()).HopLimit() } // ICMP socket's data includes ICMP header but no others. Trim all other // headers from the front of the packet. - pktBuf := pkt.Buffer() - pktBuf.TrimFront(int64(pkt.HeaderSize() - len(pkt.TransportHeader().View()))) + pktBuf := pkt.ToBuffer() + pktBuf.TrimFront(int64(pkt.HeaderSize() - len(pkt.TransportHeader().Slice()))) packet.data = stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: pktBuf}) e.rcvList.PushBack(packet) diff --git a/pkg/tcpip/transport/icmp/icmp_test.go b/pkg/tcpip/transport/icmp/icmp_test.go index 870207a81..cd630e3a6 100644 --- a/pkg/tcpip/transport/icmp/icmp_test.go +++ b/pkg/tcpip/transport/icmp/icmp_test.go @@ -144,12 +144,11 @@ func TestWriteUnboundWithBindToDevice(t *testing.T) { if p == nil { t.Fatalf("got defaultEP.Read(_) = _, false; want = _, true (packet wasn't written out)") } + defer p.DecRef() + v := p.ToView() + defer v.Release() - pkbuf := p.Buffer() - b := pkbuf.Flatten() - p.DecRef() - - checker.IPv4(t, b, []checker.NetworkChecker{ + checker.IPv4(t, v, []checker.NetworkChecker{ checker.SrcAddr(localV4Addr1), checker.DstAddr(remoteV4Addr), checker.ICMPv4( @@ -193,12 +192,11 @@ func TestWriteUnboundWithBindToDevice(t *testing.T) { if p == nil { t.Fatalf("got alternateEP.Read(_) = _, false; want = _, true (packet wasn't written out)") } + defer p.DecRef() + v := p.ToView() + defer v.Release() - pkbuf := p.Buffer() - b := pkbuf.Flatten() - p.DecRef() - - checker.IPv4(t, b, []checker.NetworkChecker{ + checker.IPv4(t, v, []checker.NetworkChecker{ checker.SrcAddr(localV4Addr2), checker.DstAddr(remoteV4Addr), checker.ICMPv4( @@ -232,12 +230,11 @@ func TestWriteUnboundWithBindToDevice(t *testing.T) { if p == nil { t.Fatalf("got defaultEP.Read(_) = _, false; want = _, true (packet wasn't written out)") } + defer p.DecRef() + v := p.ToView() + defer v.Release() - pkbuf := p.Buffer() - b := pkbuf.Flatten() - p.DecRef() - - checker.IPv4(t, b, []checker.NetworkChecker{ + checker.IPv4(t, v, []checker.NetworkChecker{ checker.SrcAddr(localV4Addr1), checker.DstAddr(remoteV4Addr), checker.ICMPv4( diff --git a/pkg/tcpip/transport/internal/network/BUILD b/pkg/tcpip/transport/internal/network/BUILD index 540c98091..b38bf365d 100644 --- a/pkg/tcpip/transport/internal/network/BUILD +++ b/pkg/tcpip/transport/internal/network/BUILD @@ -15,7 +15,7 @@ go_library( ], deps = [ "//pkg/atomicbitops", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/sync", "//pkg/tcpip", "//pkg/tcpip/header", @@ -31,7 +31,7 @@ go_test( srcs = ["endpoint_test.go"], deps = [ ":network", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", diff --git a/pkg/tcpip/transport/internal/network/endpoint.go b/pkg/tcpip/transport/internal/network/endpoint.go index 724114ba0..5ccb41c91 100644 --- a/pkg/tcpip/transport/internal/network/endpoint.go +++ b/pkg/tcpip/transport/internal/network/endpoint.go @@ -20,7 +20,7 @@ import ( "fmt" "gvisor.dev/gvisor/pkg/atomicbitops" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -269,7 +269,7 @@ func (c *WriteContext) PacketInfo() WritePacketInfo { // // If this method returns nil, the caller should wait for the endpoint to become // writable. -func (c *WriteContext) TryNewPacketBuffer(reserveHdrBytes int, data buffer.Buffer) *stack.PacketBuffer { +func (c *WriteContext) TryNewPacketBuffer(reserveHdrBytes int, data bufferv2.Buffer) *stack.PacketBuffer { e := c.e e.sendBufferSizeInUseMu.Lock() diff --git a/pkg/tcpip/transport/internal/network/endpoint_test.go b/pkg/tcpip/transport/internal/network/endpoint_test.go index 2bf9340c2..142e5a52b 100644 --- a/pkg/tcpip/transport/internal/network/endpoint_test.go +++ b/pkg/tcpip/transport/internal/network/endpoint_test.go @@ -20,7 +20,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -50,16 +50,16 @@ func TestEndpointStateTransitions(t *testing.T) { const nicID = 1 data := []byte{1, 2, 4, 5} - v4Checker := func(t *testing.T, b []byte) { - checker.IPv4(t, b, + v4Checker := func(t *testing.T, v *bufferv2.View) { + checker.IPv4(t, v, checker.SrcAddr(ipv4NICAddr), checker.DstAddr(ipv4RemoteAddr), checker.IPPayload(data), ) } - v6Checker := func(t *testing.T, b []byte) { - checker.IPv6(t, b, + v6Checker := func(t *testing.T, v *bufferv2.View) { + checker.IPv6(t, v, checker.SrcAddr(ipv6NICAddr), checker.DstAddr(ipv6RemoteAddr), checker.IPPayload(data), @@ -76,7 +76,7 @@ func TestEndpointStateTransitions(t *testing.T) { expectedBoundAddr tcpip.Address remoteAddr tcpip.Address expectedRemoteAddr tcpip.Address - checker func(*testing.T, []byte) + checker func(*testing.T, *bufferv2.View) }{ { name: "IPv4", @@ -205,7 +205,7 @@ func TestEndpointStateTransitions(t *testing.T) { } injectPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ ReserveHeaderBytes: int(info.MaxHeaderLength), - Payload: buffer.NewWithData(data), + Payload: bufferv2.MakeWithData(data), }) defer injectPkt.DecRef() if err := ctx.WritePacket(injectPkt, false /* headerIncluded */); err != nil { @@ -214,7 +214,9 @@ func TestEndpointStateTransitions(t *testing.T) { if pkt := e.Read(); pkt == nil { t.Fatalf("expected packet to be read from link endpoint") } else { - test.checker(t, stack.PayloadSince(pkt.NetworkHeader())) + payload := stack.PayloadSince(pkt.NetworkHeader()) + defer payload.Release() + test.checker(t, payload) pkt.DecRef() } diff --git a/pkg/tcpip/transport/packet/BUILD b/pkg/tcpip/transport/packet/BUILD index 017e6feb9..1c44ac673 100644 --- a/pkg/tcpip/transport/packet/BUILD +++ b/pkg/tcpip/transport/packet/BUILD @@ -24,7 +24,7 @@ go_library( ], visibility = ["//visibility:public"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/log", "//pkg/sleep", "//pkg/sync", diff --git a/pkg/tcpip/transport/packet/endpoint.go b/pkg/tcpip/transport/packet/endpoint.go index e58a9da9a..f82e36517 100644 --- a/pkg/tcpip/transport/packet/endpoint.go +++ b/pkg/tcpip/transport/packet/endpoint.go @@ -28,7 +28,7 @@ import ( "io" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -234,21 +234,21 @@ func (ep *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tc return 0, &tcpip.ErrInvalidOptionValue{} } - // TODO(https://gvisor.dev/issue/6538): Avoid this allocation. - payloadBytes := make([]byte, p.Len()) - if _, err := io.ReadFull(p, payloadBytes); err != nil { + var payload bufferv2.Buffer + if _, err := payload.WriteFromReader(p, int64(p.Len())); err != nil { return 0, &tcpip.ErrBadBuffer{} } + payloadSz := payload.Size() if err := func() tcpip.Error { if ep.cooked { - return ep.stack.WritePacketToRemote(nicID, remote, proto, buffer.NewWithData(payloadBytes)) + return ep.stack.WritePacketToRemote(nicID, remote, proto, payload) } - return ep.stack.WriteRawPacket(nicID, proto, buffer.NewWithData(payloadBytes)) + return ep.stack.WriteRawPacket(nicID, proto, payload) }(); err != nil { return 0, err } - return int64(len(payloadBytes)), nil + return payloadSz, nil } // Disconnect implements tcpip.Endpoint.Disconnect. Packet sockets cannot be @@ -444,17 +444,17 @@ func (ep *endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtoc receivedAt: ep.stack.Clock().Now(), } - if len(pkt.LinkHeader().View()) != 0 { - hdr := header.Ethernet(pkt.LinkHeader().View()) + if len(pkt.LinkHeader().Slice()) != 0 { + hdr := header.Ethernet(pkt.LinkHeader().Slice()) rcvdPkt.senderAddr.Addr = tcpip.Address(hdr.SourceAddress()) } // Raw packet endpoints include link-headers in received packets. - pktBuf := pkt.Buffer() + pktBuf := pkt.ToBuffer() if ep.cooked { // Cooked packet endpoints don't include the link-headers in received // packets. - pktBuf.TrimFront(int64(len(pkt.LinkHeader().View()) + len(pkt.VirtioNetHeader().View()))) + pktBuf.TrimFront(int64(len(pkt.LinkHeader().Slice()) + len(pkt.VirtioNetHeader().Slice()))) } rcvdPkt.data = stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: pktBuf}) diff --git a/pkg/tcpip/transport/raw/BUILD b/pkg/tcpip/transport/raw/BUILD index 7b4435d39..b9088c45f 100644 --- a/pkg/tcpip/transport/raw/BUILD +++ b/pkg/tcpip/transport/raw/BUILD @@ -25,7 +25,7 @@ go_library( ], visibility = ["//visibility:public"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/log", "//pkg/sleep", "//pkg/sync", diff --git a/pkg/tcpip/transport/raw/endpoint.go b/pkg/tcpip/transport/raw/endpoint.go index 131a94734..4580dd79b 100644 --- a/pkg/tcpip/transport/raw/endpoint.go +++ b/pkg/tcpip/transport/raw/endpoint.go @@ -30,7 +30,7 @@ import ( "io" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -349,25 +349,27 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp return 0, &tcpip.ErrMessageTooLong{} } - // TODO(https://gvisor.dev/issue/6538): Avoid this allocation. - payloadBytes := make([]byte, p.Len()) - if _, err := io.ReadFull(p, payloadBytes); err != nil { + var payload bufferv2.Buffer + defer payload.Release() + if _, err := payload.WriteFromReader(p, int64(p.Len())); err != nil { return 0, &tcpip.ErrBadBuffer{} } + payloadSz := payload.Size() if packetInfo := ctx.PacketInfo(); packetInfo.NetProto == header.IPv6ProtocolNumber && ipv6ChecksumOffset >= 0 { // Make sure we can fit the checksum. - if len(payloadBytes) < ipv6ChecksumOffset+header.ChecksumSize { + if payload.Size() < int64(ipv6ChecksumOffset+header.ChecksumSize) { return 0, &tcpip.ErrInvalidOptionValue{} } - xsum := header.PseudoHeaderChecksum(e.transProto, packetInfo.LocalAddress, packetInfo.RemoteAddress, uint16(len(payloadBytes))) - header.PutChecksum(payloadBytes[ipv6ChecksumOffset:], 0) - xsum = header.Checksum(payloadBytes, xsum) - header.PutChecksum(payloadBytes[ipv6ChecksumOffset:], ^xsum) + payloadView, _ := payload.PullUp(ipv6ChecksumOffset, int(payload.Size())-ipv6ChecksumOffset) + xsum := header.PseudoHeaderChecksum(e.transProto, packetInfo.LocalAddress, packetInfo.RemoteAddress, uint16(payload.Size())) + header.PutChecksum(payloadView.AsSlice(), 0) + xsum = header.ChecksumBuffer(payload, xsum) + header.PutChecksum(payloadView.AsSlice(), ^xsum) } - pkt := ctx.TryNewPacketBuffer(int(ctx.PacketInfo().MaxHeaderLength), buffer.NewWithData(payloadBytes)) + pkt := ctx.TryNewPacketBuffer(int(ctx.PacketInfo().MaxHeaderLength), payload.Clone()) if pkt == nil { return 0, &tcpip.ErrWouldBlock{} } @@ -377,7 +379,7 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp return 0, err } - return int64(len(payloadBytes)), nil + return payloadSz, nil } // Disconnect implements tcpip.Endpoint.Disconnect. @@ -658,9 +660,9 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { packet.tosOrTClass, _ = pkt.Network().TOS() switch pkt.NetworkProtocolNumber { case header.IPv4ProtocolNumber: - packet.ttlOrHopLimit = header.IPv4(pkt.NetworkHeader().View()).TTL() + packet.ttlOrHopLimit = header.IPv4(pkt.NetworkHeader().Slice()).TTL() case header.IPv6ProtocolNumber: - packet.ttlOrHopLimit = header.IPv6(pkt.NetworkHeader().View()).HopLimit() + packet.ttlOrHopLimit = header.IPv6(pkt.NetworkHeader().Slice()).HopLimit() } // Raw IPv4 endpoints return the IP header, but IPv6 endpoints do not. @@ -670,16 +672,17 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { // // TODO(https://gvisor.dev/issue/6517): Avoid the copy once S/R supports // overlapping slices. - transportHeader := pkt.TransportHeader().View() - var combinedBuf buffer.Buffer + transportHeader := pkt.TransportHeader().Slice() + var combinedBuf bufferv2.Buffer + defer combinedBuf.Release() switch info.NetProto { case header.IPv4ProtocolNumber: - networkHeader := pkt.NetworkHeader().View() - headers := make([]byte, 0, len(networkHeader)+len(transportHeader)) - headers = append(headers, networkHeader...) - headers = append(headers, transportHeader...) - combinedBuf = buffer.NewWithData(headers) - pktBuf := pkt.Data().AsBuffer() + networkHeader := pkt.NetworkHeader().Slice() + headers := bufferv2.NewView(len(networkHeader) + len(transportHeader)) + headers.Write(networkHeader) + headers.Write(transportHeader) + combinedBuf = bufferv2.MakeWithView(headers) + pktBuf := pkt.Data().ToBuffer() combinedBuf.Merge(&pktBuf) case header.IPv6ProtocolNumber: if e.transProto == header.ICMPv6ProtocolNumber { @@ -692,8 +695,8 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { } } - combinedBuf = buffer.NewWithData(transportHeader) - pktBuf := pkt.Data().AsBuffer() + combinedBuf = bufferv2.MakeWithView(pkt.TransportHeader().View()) + pktBuf := pkt.Data().ToBuffer() combinedBuf.Merge(&pktBuf) if checksumOffset := e.ipv6ChecksumOffset; checksumOffset >= 0 { @@ -714,7 +717,7 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { panic(fmt.Sprintf("unrecognized protocol number = %d", info.NetProto)) } - packet.data = stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: combinedBuf}) + packet.data = stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: combinedBuf.Clone()}) packet.receivedAt = e.stack.Clock().Now() e.rcvList.PushBack(packet) diff --git a/pkg/tcpip/transport/tcp/BUILD b/pkg/tcpip/transport/tcp/BUILD index f68ff29df..792f1c809 100644 --- a/pkg/tcpip/transport/tcp/BUILD +++ b/pkg/tcpip/transport/tcp/BUILD @@ -71,7 +71,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//pkg/atomicbitops", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/log", "//pkg/rand", "//pkg/refsvfs2", @@ -101,6 +101,7 @@ go_test( ], library = ":tcp", deps = [ + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/sleep", diff --git a/pkg/tcpip/transport/tcp/connect.go b/pkg/tcpip/transport/tcp/connect.go index 4164c25ed..da082d887 100644 --- a/pkg/tcpip/transport/tcp/connect.go +++ b/pkg/tcpip/transport/tcp/connect.go @@ -868,7 +868,7 @@ func sendTCPBatch(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer, gso sta shouldSplitPacket := i != n-1 if shouldSplitPacket { splitPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ReserveHeaderBytes: hdrSize}) - splitPkt.Data().ReadFrom(pkt.Data(), packetSize) + splitPkt.Data().ReadFromPacketData(pkt.Data(), packetSize) pkt = splitPkt } pkt.Hash = tf.txHash diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index a43f7d815..e960d6ef8 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -25,6 +25,7 @@ import ( "time" "gvisor.dev/gvisor/pkg/atomicbitops" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sleep" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" @@ -1492,7 +1493,7 @@ func (e *endpoint) isEndpointWritableLocked() (int, tcpip.Error) { // readFromPayloader reads a slice from the Payloader. // +checklocks:e.mu // +checklocks:e.sndQueueInfo.sndQueueMu -func (e *endpoint) readFromPayloader(p tcpip.Payloader, opts tcpip.WriteOptions, avail int) ([]byte, tcpip.Error) { +func (e *endpoint) readFromPayloader(p tcpip.Payloader, opts tcpip.WriteOptions, avail int) (bufferv2.Buffer, tcpip.Error) { // We can release locks while copying data. // // This is not possible if atomic is set, because we can't allow the @@ -1507,18 +1508,18 @@ func (e *endpoint) readFromPayloader(p tcpip.Payloader, opts tcpip.WriteOptions, } // Fetch data. + var payload bufferv2.Buffer if l := p.Len(); l < avail { avail = l } if avail == 0 { - return nil, nil + return payload, nil } - v := make([]byte, avail) - n, err := p.Read(v) - if err != nil && err != io.EOF { - return nil, &tcpip.ErrBadBuffer{} + if _, err := payload.WriteFromReader(p, int64(avail)); err != nil { + payload.Release() + return bufferv2.Buffer{}, &tcpip.ErrBadBuffer{} } - return v[:n], nil + return payload, nil } // queueSegment reads data from the payloader and returns a segment to be sent. @@ -1533,13 +1534,13 @@ func (e *endpoint) queueSegment(p tcpip.Payloader, opts tcpip.WriteOptions) (*se return nil, 0, err } - v, err := e.readFromPayloader(p, opts, avail) + buf, err := e.readFromPayloader(p, opts, avail) if err != nil { return nil, 0, err } // Do not queue zero length segments. - if len(v) == 0 { + if buf.Size() == 0 { return nil, 0, nil } @@ -1550,23 +1551,25 @@ func (e *endpoint) queueSegment(p tcpip.Payloader, opts tcpip.WriteOptions) (*se avail, err := e.isEndpointWritableLocked() if err != nil { e.stats.WriteErrors.WriteClosed.Increment() + buf.Release() return nil, 0, err } - // Discard any excess data copied in due to avail being reduced due - // to a simultaneous write call to the socket. - if avail < len(v) { - v = v[:avail] + // A simultaneous call to write on the socket can reduce avail. Discard + // excess data copied if this is the case. + if int64(avail) < buf.Size() { + buf.Truncate(int64(avail)) } } // Add data to the send queue. - s := newOutgoingSegment(e.TransportEndpointInfo.ID, e.stack.Clock(), v) - e.sndQueueInfo.SndBufUsed += len(v) + size := int(buf.Size()) + s := newOutgoingSegment(e.TransportEndpointInfo.ID, e.stack.Clock(), buf) + e.sndQueueInfo.SndBufUsed += size s.IncRef() e.snd.writeList.PushBack(s) - return s, len(v), nil + return s, size, nil } // Write writes data to the endpoint's peer. @@ -2489,7 +2492,7 @@ func (e *endpoint) shutdownLocked(flags tcpip.ShutdownFlags) tcpip.Error { } // Queue fin segment. - s := newOutgoingSegment(e.TransportEndpointInfo.ID, e.stack.Clock(), nil) + s := newOutgoingSegment(e.TransportEndpointInfo.ID, e.stack.Clock(), bufferv2.Buffer{}) e.snd.writeList.PushBack(s) // Mark endpoint as closed. e.sndQueueInfo.SndClosed = true @@ -2811,7 +2814,7 @@ func (e *endpoint) onICMPError(err tcpip.Error, transErr stack.TransportError, p Cause: transErr, // Linux passes the payload with the TCP header. We don't know if the TCP // header even exists, it may not for fragmented packets. - Payload: pkt.Data().AsRange().ToOwnedView(), + Payload: pkt.Data().AsRange().ToView(), Dst: tcpip.FullAddress{ NIC: pkt.NICID, Addr: e.TransportEndpointInfo.ID.RemoteAddress, diff --git a/pkg/tcpip/transport/tcp/segment.go b/pkg/tcpip/transport/tcp/segment.go index e6a3dbbc3..eb99e86c0 100644 --- a/pkg/tcpip/transport/tcp/segment.go +++ b/pkg/tcpip/transport/tcp/segment.go @@ -18,6 +18,7 @@ import ( "fmt" "io" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/seqnum" @@ -85,7 +86,7 @@ type segment struct { } func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt *stack.PacketBuffer) (*segment, error) { - hdr := header.TCP(pkt.TransportHeader().View()) + hdr := header.TCP(pkt.TransportHeader().Slice()) netHdr := pkt.Network() csum, csumValid, ok := header.TCPValid( hdr, @@ -120,19 +121,17 @@ func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt *st return s, nil } -func newOutgoingSegment(id stack.TransportEndpointID, clock tcpip.Clock, v []byte) *segment { +func newOutgoingSegment(id stack.TransportEndpointID, clock tcpip.Clock, buf bufferv2.Buffer) *segment { s := &segment{ id: id, } s.InitRefs() s.rcvdTime = clock.NowMonotonic() - s.pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{}) - s.pkt.Data().AppendView(v) + s.pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf}) s.dataMemSize = s.pkt.MemSize() return s } -// clone creates a shallow clone of s not including its pkt. func (s *segment) clone() *segment { t := &segment{ id: s.id, @@ -148,7 +147,7 @@ func (s *segment) clone() *segment { dataMemSize: s.dataMemSize, } t.InitRefs() - t.pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{}) + t.pkt = s.pkt.Clone() return t } diff --git a/pkg/tcpip/transport/tcp/segment_test.go b/pkg/tcpip/transport/tcp/segment_test.go index 76d1773a0..9240a7d79 100644 --- a/pkg/tcpip/transport/tcp/segment_test.go +++ b/pkg/tcpip/transport/tcp/segment_test.go @@ -18,6 +18,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip/faketime" "gvisor.dev/gvisor/pkg/tcpip/stack" ) @@ -43,9 +44,9 @@ func checkSegmentSize(t *testing.T, name string, seg *segment, want segmentSizeW func TestSegmentMerge(t *testing.T) { var clock faketime.NullClock id := stack.TransportEndpointID{} - seg1 := newOutgoingSegment(id, &clock, make([]byte, 10)) + seg1 := newOutgoingSegment(id, &clock, bufferv2.MakeWithView(bufferv2.NewViewSize(10))) defer seg1.DecRef() - seg2 := newOutgoingSegment(id, &clock, make([]byte, 20)) + seg2 := newOutgoingSegment(id, &clock, bufferv2.MakeWithView(bufferv2.NewViewSize(20))) defer seg2.DecRef() checkSegmentSize(t, "seg1", seg1, segmentSizeWants{ diff --git a/pkg/tcpip/transport/tcp/snd.go b/pkg/tcpip/transport/tcp/snd.go index c99e84e56..3f20cbe21 100644 --- a/pkg/tcpip/transport/tcp/snd.go +++ b/pkg/tcpip/transport/tcp/snd.go @@ -587,7 +587,7 @@ func (s *sender) splitSeg(seg *segment, size int) { } // Split this segment up. nSeg := seg.clone() - nSeg.pkt.Data().AppendRange(seg.pkt.Data().AsRange().SubRange(size)) + nSeg.pkt.Data().TrimFront(size) nSeg.sequenceNumber.UpdateForward(seqnum.Size(size)) s.writeList.InsertAfter(seg, nSeg) diff --git a/pkg/tcpip/transport/tcp/test/e2e/BUILD b/pkg/tcpip/transport/tcp/test/e2e/BUILD index 0e9a09138..f92c8afef 100644 --- a/pkg/tcpip/transport/tcp/test/e2e/BUILD +++ b/pkg/tcpip/transport/tcp/test/e2e/BUILD @@ -9,7 +9,7 @@ go_test( shard_count = more_shards, deps = [ ":e2e", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/rand", "//pkg/refs", "//pkg/refsvfs2", @@ -133,6 +133,7 @@ go_test( srcs = ["tcp_rack_test.go"], deps = [ ":e2e", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", @@ -150,6 +151,7 @@ go_test( srcs = ["tcp_sack_test.go"], deps = [ ":e2e", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", diff --git a/pkg/tcpip/transport/tcp/test/e2e/dual_stack_test.go b/pkg/tcpip/transport/tcp/test/e2e/dual_stack_test.go index 7df7f01d4..b2e618a21 100644 --- a/pkg/tcpip/transport/tcp/test/e2e/dual_stack_test.go +++ b/pkg/tcpip/transport/tcp/test/e2e/dual_stack_test.go @@ -198,7 +198,9 @@ func TestV4RefuseOnV6Only(t *testing.T) { }) // Receive the RST reply. - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), @@ -234,7 +236,9 @@ func TestV6RefuseOnBoundToV4Mapped(t *testing.T) { }) // Receive the RST reply. - checker.IPv6(t, c.GetV6Packet(), + p := c.GetV6Packet() + defer p.Release() + checker.IPv6(t, p, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), @@ -264,10 +268,11 @@ func testV4Accept(t *testing.T, c *context.Context) { }) // Receive the SYN-ACK reply. - b := c.GetPacket() - tcp := header.TCP(header.IPv4(b).Payload()) + v := c.GetPacket() + defer v.Release() + tcp := header.TCP(header.IPv4(v.AsSlice()).Payload()) iss := seqnum.Value(tcp.SequenceNumber()) - checker.IPv4(t, b, + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), @@ -320,8 +325,9 @@ func testV4Accept(t *testing.T, c *context.Context) { data := "Don't panic" r.Reset(data) nep.Write(&r, tcpip.WriteOptions{}) - b = c.GetPacket() - tcp = header.IPv4(b).Payload() + v = c.GetPacket() + defer v.Release() + tcp = header.IPv4(v.AsSlice()).Payload() if string(tcp.Payload()) != data { t.Fatalf("Unexpected data: got %v, want %v", string(tcp.Payload()), data) } @@ -398,10 +404,11 @@ func TestV6AcceptOnV6(t *testing.T) { }) // Receive the SYN-ACK reply. - b := c.GetV6Packet() - tcp := header.TCP(header.IPv6(b).Payload()) + v := c.GetV6Packet() + defer v.Release() + tcp := header.TCP(header.IPv6(v.AsSlice()).Payload()) iss := seqnum.Value(tcp.SequenceNumber()) - checker.IPv6(t, b, + checker.IPv6(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), @@ -493,8 +500,9 @@ func testV4ListenClose(t *testing.T, c *context.Context) { // Each of these ACKs will cause a syn-cookie based connection to be // accepted and delivered to the listening endpoint. for i := 0; i < n; i++ { - b := c.GetPacket() - tcp := header.TCP(header.IPv4(b).Payload()) + v := c.GetPacket() + defer v.Release() + tcp := header.TCP(header.IPv4(v.AsSlice()).Payload()) iss := seqnum.Value(tcp.SequenceNumber()) // Send ACK. c.SendPacket(nil, &context.Headers{ diff --git a/pkg/tcpip/transport/tcp/test/e2e/e2e.go b/pkg/tcpip/transport/tcp/test/e2e/e2e.go index ed4d27d1f..693be90bc 100644 --- a/pkg/tcpip/transport/tcp/test/e2e/e2e.go +++ b/pkg/tcpip/transport/tcp/test/e2e/e2e.go @@ -69,11 +69,12 @@ func CheckBrokenUpWrite(t *testing.T, c *context.Context, maxPayload int) { numPackets := 0 iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) for bytesReceived != dataLen { - b := c.GetPacket() + v := c.GetPacket() + defer v.Release() numPackets++ - tcpHdr := header.TCP(header.IPv4(b).Payload()) + tcpHdr := header.TCP(header.IPv4(v.AsSlice()).Payload()) payloadLen := len(tcpHdr.Payload()) - checker.IPv4(t, b, + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS)+1+uint32(bytesReceived)), @@ -202,14 +203,15 @@ func TestV4Connect(t *testing.T, c *context.Context, checkers ...checker.Network } // Receive SYN packet. - b := c.GetPacket() + v := c.GetPacket() + defer v.Release() synCheckers := append(checkers, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagSyn), )) - checker.IPv4(t, b, synCheckers...) + checker.IPv4(t, v, synCheckers...) - tcp := header.TCP(header.IPv4(b).Payload()) + tcp := header.TCP(header.IPv4(v.AsSlice()).Payload()) c.IRS = seqnum.Value(tcp.SequenceNumber()) iss := seqnum.Value(789) @@ -229,7 +231,10 @@ func TestV4Connect(t *testing.T, c *context.Context, checkers ...checker.Network checker.TCPSeqNum(uint32(c.IRS)+1), checker.TCPAckNum(uint32(iss)+1), )) - checker.IPv4(t, c.GetPacket(), ackCheckers...) + + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, ackCheckers...) // Wait for connection to be established. select { @@ -255,14 +260,15 @@ func TestV6Connect(t *testing.T, c *context.Context, checkers ...checker.Network } // Receive SYN packet. - b := c.GetV6Packet() + v := c.GetV6Packet() + defer v.Release() synCheckers := append(checkers, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagSyn), )) - checker.IPv6(t, b, synCheckers...) + checker.IPv6(t, v, synCheckers...) - tcp := header.TCP(header.IPv6(b).Payload()) + tcp := header.TCP(header.IPv6(v.AsSlice()).Payload()) c.IRS = seqnum.Value(tcp.SequenceNumber()) iss := seqnum.Value(789) @@ -282,7 +288,9 @@ func TestV6Connect(t *testing.T, c *context.Context, checkers ...checker.Network checker.TCPSeqNum(uint32(c.IRS)+1), checker.TCPAckNum(uint32(iss)+1), )) - checker.IPv6(t, c.GetV6Packet(), ackCheckers...) + v = c.GetV6Packet() + defer v.Release() + checker.IPv6(t, v, ackCheckers...) // Wait for connection to be established. select { diff --git a/pkg/tcpip/transport/tcp/test/e2e/forwarder_test.go b/pkg/tcpip/transport/tcp/test/e2e/forwarder_test.go index 07bc4679e..c5b0cbb88 100644 --- a/pkg/tcpip/transport/tcp/test/e2e/forwarder_test.go +++ b/pkg/tcpip/transport/tcp/test/e2e/forwarder_test.go @@ -137,8 +137,9 @@ func TestForwarderFailedConnect(t *testing.T) { // Receive the SYN-ACK reply. Make sure MSS and other expected options // are present. - b := c.GetPacket() - tcp := header.TCP(header.IPv4(b).Payload()) + v := c.GetPacket() + defer v.Release() + tcp := header.TCP(header.IPv4(v.AsSlice()).Payload()) c.IRS = seqnum.Value(tcp.SequenceNumber()) tcpCheckers := []checker.TransportChecker{ @@ -147,7 +148,7 @@ func TestForwarderFailedConnect(t *testing.T) { checker.TCPFlags(header.TCPFlagAck | header.TCPFlagSyn), checker.TCPAckNum(uint32(iss) + 1), } - checker.IPv4(t, b, checker.TCP(tcpCheckers...)) + checker.IPv4(t, v, checker.TCP(tcpCheckers...)) // Now send an active RST to abort the handshake. c.SendPacket(nil, &context.Headers{ diff --git a/pkg/tcpip/transport/tcp/test/e2e/tcp_rack_test.go b/pkg/tcpip/transport/tcp/test/e2e/tcp_rack_test.go index 35872ddc8..98e76a38c 100644 --- a/pkg/tcpip/transport/tcp/test/e2e/tcp_rack_test.go +++ b/pkg/tcpip/transport/tcp/test/e2e/tcp_rack_test.go @@ -21,6 +21,7 @@ import ( "testing" "time" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -332,8 +333,10 @@ func TestNoTLPRecoveryOnDSACK(t *testing.T) { if err := c.EP.GetSockOpt(&info); err != nil { t.Fatalf("GetSockOpt failed: %v", err) } - if p := c.GetPacketWithTimeout(info.RTO); p != nil { + var p *bufferv2.View + if p = c.GetPacketWithTimeout(info.RTO); p != nil { t.Errorf("received an unexpected packet: %v", p) + p.Release() } metricPollFn := func() error { diff --git a/pkg/tcpip/transport/tcp/test/e2e/tcp_sack_test.go b/pkg/tcpip/transport/tcp/test/e2e/tcp_sack_test.go index 6e6c50c92..b188911ea 100644 --- a/pkg/tcpip/transport/tcp/test/e2e/tcp_sack_test.go +++ b/pkg/tcpip/transport/tcp/test/e2e/tcp_sack_test.go @@ -23,6 +23,7 @@ import ( "testing" "time" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -717,7 +718,7 @@ func verifySpuriousRecoveryMetric(t *testing.T, c *context.Context, numSpuriousR } } -func checkReceivedPacket(t *testing.T, c *context.Context, tcpHdr header.TCP, bytesRead uint32, b, data []byte) { +func checkReceivedPacket(t *testing.T, c *context.Context, tcpHdr header.TCP, bytesRead uint32, b *bufferv2.View, data []byte) { payloadLen := uint32(len(tcpHdr.Payload())) checker.IPv4(t, b, checker.TCP( @@ -773,7 +774,8 @@ func TestDetectSpuriousRecoveryWithRTO(t *testing.T) { var bytesRead uint32 for i := 0; i < numPackets; i++ { b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) checkReceivedPacket(t, c, tcpHdr, bytesRead, b, data) // Get options only for the first packet. This will be sent with @@ -859,7 +861,8 @@ func TestSACKDetectSpuriousRecoveryWithDupACK(t *testing.T) { var bytesRead uint32 for i := 0; i < numPackets; i++ { b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) checkReceivedPacket(t, c, tcpHdr, bytesRead, b, data) // Get options only for the first packet. This will be sent with diff --git a/pkg/tcpip/transport/tcp/test/e2e/tcp_test.go b/pkg/tcpip/transport/tcp/test/e2e/tcp_test.go index 59cf6606f..1d0786a69 100644 --- a/pkg/tcpip/transport/tcp/test/e2e/tcp_test.go +++ b/pkg/tcpip/transport/tcp/test/e2e/tcp_test.go @@ -25,7 +25,7 @@ import ( "time" "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/rand" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" @@ -177,6 +177,7 @@ func TestConnectICMPError(t *testing.T) { } syn := c.GetPacket() + defer syn.Release() checker.IPv4(t, syn, checker.TCP(checker.TCPFlags(header.TCPFlagSyn))) wep := ep.(interface { @@ -207,7 +208,9 @@ func TestConnectICMPError(t *testing.T) { AckNum: c.IRS + 1, }) - checker.IPv4(t, c.GetPacket(), checker.TCP( + b := c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+1)), @@ -335,8 +338,9 @@ func TestTCPResetsSentIncrement(t *testing.T) { }) // Receive the SYN-ACK reply. - b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + v := c.GetPacket() + defer v.Release() + tcpHdr := header.TCP(header.IPv4(v.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) ackHeaders := &context.Headers{ @@ -352,7 +356,8 @@ func TestTCPResetsSentIncrement(t *testing.T) { // Send ACK. c.SendPacket(nil, ackHeaders) - c.GetPacket() + v = c.GetPacket() + defer v.Release() metricPollFn := func() error { if got := stats.TCP.ResetsSent.Value(); got != want { @@ -383,8 +388,9 @@ func TestTCPResetsSentNoICMP(t *testing.T) { }) // Receive whatever comes back. - b := c.GetPacket() - ipHdr := header.IPv4(b) + v := c.GetPacket() + defer v.Release() + ipHdr := header.IPv4(v.AsSlice()) if got, want := ipHdr.Protocol(), uint8(header.TCPProtocolNumber); got != want { t.Errorf("unexpected protocol, got = %d, want = %d", got, want) } @@ -427,8 +433,9 @@ func TestTCPResetSentForACKWhenNotUsingSynCookies(t *testing.T) { }) // Receive the SYN-ACK reply. - b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + v := c.GetPacket() + defer v.Release() + tcpHdr := header.TCP(header.IPv4(v.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) ackHeaders := &context.Headers{ @@ -470,7 +477,9 @@ func TestTCPResetSentForACKWhenNotUsingSynCookies(t *testing.T) { } c.EP.Close() - checker.IPv4(t, c.GetPacket(), checker.TCP( + b := c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+1)), @@ -487,7 +496,8 @@ func TestTCPResetSentForACKWhenNotUsingSynCookies(t *testing.T) { c.SendPacket(nil, finHeaders) // Get the ACK to the FIN we just sent. - c.GetPacket() + b = c.GetPacket() + defer b.Release() // Since an active close was done we need to wait for a little more than // tcpLingerTimeout for the port reservations to be released and the @@ -501,7 +511,9 @@ func TestTCPResetSentForACKWhenNotUsingSynCookies(t *testing.T) { // rejected. c.SendPacket(nil, ackHeaders) - checker.IPv4(t, c.GetPacket(), checker.TCP( + b = c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+1)), @@ -601,7 +613,9 @@ func TestConnectResetAfterClose(t *testing.T) { // to complete closure of sender, but don't send our own FIN. ep.Close() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, c.GetPacket(), + b := c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.TCP( checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS)+1), @@ -633,14 +647,15 @@ func TestConnectResetAfterClose(t *testing.T) { }) for { - b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + v := c.GetPacket() + defer v.Release() + tcpHdr := header.TCP(header.IPv4(v.AsSlice()).Payload()) if tcpHdr.Flags() == header.TCPFlagAck|header.TCPFlagFin { // This is a retransmit of the FIN, ignore it. continue } - checker.IPv4(t, b, + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), // RST is always generated with sndNxt which if the FIN @@ -683,7 +698,9 @@ func TestCurrentConnectedIncrement(t *testing.T) { ep.Close() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, c.GetPacket(), + b := c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.TCP( checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS)+1), @@ -718,7 +735,9 @@ func TestCurrentConnectedIncrement(t *testing.T) { }) // Check that the stack acks the FIN. - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -767,7 +786,9 @@ func TestClosingWithEnqueuedSegments(t *testing.T) { }) // Get the ACK for the FIN we sent. - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS)+1), @@ -788,7 +809,9 @@ func TestClosingWithEnqueuedSegments(t *testing.T) { ep.Close() // Get the FIN - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS)+1), @@ -848,7 +871,9 @@ func TestClosingWithEnqueuedSegments(t *testing.T) { // Check if the endpoint was moved to CLOSED and netstack sent a reset in // response to the ACK packet that we sent after last-ACK. - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS)+2), @@ -895,7 +920,9 @@ func TestSimpleReceive(t *testing.T) { } // Check that ACK is received. - checker.IPv4(t, c.GetPacket(), + b := c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.TCP( checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS)+1), @@ -925,7 +952,9 @@ func TestUserSuppliedMSSOnConnect(t *testing.T) { }, connectAddr: context.TestAddr, checker: func(t *testing.T, c *context.Context, mss uint16, ws int) { - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagSyn), checker.TCPSynOptions(header.TCPSynOptions{MSS: mss, WS: ws}))) @@ -939,7 +968,9 @@ func TestUserSuppliedMSSOnConnect(t *testing.T) { }, connectAddr: context.TestV6Addr, checker: func(t *testing.T, c *context.Context, mss uint16, ws int) { - checker.IPv6(t, c.GetV6Packet(), checker.TCP( + v := c.GetV6Packet() + defer v.Release() + checker.IPv6(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagSyn), checker.TCPSynOptions(header.TCPSynOptions{MSS: mss, WS: ws}))) @@ -1026,7 +1057,9 @@ func TestUserSuppliedMSSOnListenAccept(t *testing.T) { c.SendPacket(nil, h) }, checker: func(t *testing.T, c *context.Context, srcPort, mss uint16) { - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(srcPort), checker.TCPFlags(header.TCPFlagSyn|header.TCPFlagAck), checker.TCPSynOptions(header.TCPSynOptions{MSS: mss, WS: -1}))) @@ -1042,7 +1075,9 @@ func TestUserSuppliedMSSOnListenAccept(t *testing.T) { c.SendV6Packet(nil, h) }, checker: func(t *testing.T, c *context.Context, srcPort, mss uint16) { - checker.IPv6(t, c.GetV6Packet(), checker.TCP( + v := c.GetV6Packet() + defer v.Release() + checker.IPv6(t, v, checker.TCP( checker.DstPort(srcPort), checker.TCPFlags(header.TCPFlagSyn|header.TCPFlagAck), checker.TCPSynOptions(header.TCPSynOptions{MSS: mss, WS: -1}))) @@ -1142,7 +1177,9 @@ func TestSendRstOnListenerRxSynAckV4(t *testing.T) { AckNum: 200, }) - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagRst), checker.TCPSeqNum(200))) @@ -1170,7 +1207,9 @@ func TestSendRstOnListenerRxSynAckV6(t *testing.T) { AckNum: 200, }) - checker.IPv6(t, c.GetV6Packet(), checker.TCP( + v := c.GetV6Packet() + defer v.Release() + checker.IPv6(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagRst), checker.TCPSeqNum(200))) @@ -1267,8 +1306,9 @@ func TestNoSynCookieOnFailedHandshakes(t *testing.T) { }) // Receive the SYN-ACK reply. - b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + v := c.GetPacket() + defer v.Release() + tcpHdr := header.TCP(header.IPv4(v.AsSlice()).Payload()) iss := seqnum.Value(tcpHdr.SequenceNumber()) tcpCheckers := []checker.TransportChecker{ checker.SrcPort(context.StackPort), @@ -1281,7 +1321,7 @@ func TestNoSynCookieOnFailedHandshakes(t *testing.T) { }), } - checker.IPv4(t, b, checker.TCP(tcpCheckers...)) + checker.IPv4(t, v, checker.TCP(tcpCheckers...)) // Send a RST to abort the handshake. c.SendPacket(nil, &context.Headers{ @@ -1337,7 +1377,9 @@ func TestTCPAckBeforeAcceptV4(t *testing.T) { }) // Receive ACK for the data we sent. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagAck), checker.TCPSeqNum(uint32(iss+1)), @@ -1382,7 +1424,9 @@ func TestTCPAckBeforeAcceptV6(t *testing.T) { }) // Receive ACK for the data we sent. - checker.IPv6(t, c.GetV6Packet(), checker.TCP( + v := c.GetV6Packet() + defer v.Release() + checker.IPv6(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagAck), checker.TCPSeqNum(uint32(iss+1)), @@ -1413,7 +1457,9 @@ func TestSendRstOnListenerRxAckV4(t *testing.T) { AckNum: 200, }) - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagRst), checker.TCPSeqNum(200))) @@ -1441,7 +1487,9 @@ func TestSendRstOnListenerRxAckV6(t *testing.T) { AckNum: 200, }) - checker.IPv6(t, c.GetV6Packet(), checker.TCP( + v := c.GetV6Packet() + defer v.Release() + checker.IPv6(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagRst), checker.TCPSeqNum(200))) @@ -1476,11 +1524,13 @@ func TestListenShutdown(t *testing.T) { }) // Expect the listening endpoint to reset the connection. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlags(header.TCPFlagAck|header.TCPFlagRst), - )) + + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlags(header.TCPFlagAck|header.TCPFlagRst), + )) } func TestListenerReadinessOnEvent(t *testing.T) { @@ -1601,11 +1651,12 @@ func TestListenCloseWhileConnect(t *testing.T) { c.EP.Close() // Expect the listening endpoint to reset the connection. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlags(header.TCPFlagAck|header.TCPFlagRst), - )) + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlags(header.TCPFlagAck|header.TCPFlagRst), + )) } func TestTOSV4(t *testing.T) { @@ -1642,9 +1693,10 @@ func TestTOSV4(t *testing.T) { } // Check that data is received. - b := c.GetPacket() + p := c.GetPacket() + defer p.Release() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, b, + checker.IPv4(t, p, checker.PayloadLen(len(data)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -1655,8 +1707,8 @@ func TestTOSV4(t *testing.T) { checker.TOS(tos, 0), ) - if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) { - t.Errorf("got data = %x, want = %x", p, data) + if b := p.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, b) { + t.Errorf("got data = %x, want = %x", p.AsSlice(), data) } } @@ -1692,6 +1744,7 @@ func TestTrafficClassV6(t *testing.T) { // Check that data is received. b := c.GetV6Packet() + defer b.Release() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) checker.IPv6(t, b, checker.PayloadLen(len(data)+header.TCPMinimumSize), @@ -1704,7 +1757,7 @@ func TestTrafficClassV6(t *testing.T) { checker.TOS(tos, 0), ) - if p := b[header.IPv6MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) { + if p := b.AsSlice()[header.IPv6MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) { t.Errorf("got data = %x, want = %x", p, data) } } @@ -1738,8 +1791,9 @@ func TestConnectBindToDevice(t *testing.T) { } // Receive SYN packet. - b := c.GetPacket() - checker.IPv4(t, b, + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagSyn), @@ -1748,7 +1802,7 @@ func TestConnectBindToDevice(t *testing.T) { if got, want := tcp.EndpointState(c.EP.State()), tcp.StateSynSent; got != want { t.Fatalf("unexpected endpoint state: want %s, got %s", want, got) } - tcpHdr := header.TCP(header.IPv4(b).Payload()) + tcpHdr := header.TCP(header.IPv4(v.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) iss := seqnum.Value(context.TestInitialSequenceNumber) @@ -1763,7 +1817,8 @@ func TestConnectBindToDevice(t *testing.T) { TCPOpts: nil, }) - c.GetPacket() + v = c.GetPacket() + defer v.Release() if got, want := tcp.EndpointState(c.EP.State()), test.want; got != want { t.Fatalf("unexpected endpoint state: want %s, got %s", want, got) } @@ -1799,8 +1854,9 @@ func TestShutdownConnectingSocket(t *testing.T) { } // Check the SYN packet. - b := c.GetPacket() - checker.IPv4(t, b, + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagSyn), @@ -1864,8 +1920,9 @@ func TestSynSent(t *testing.T) { } // Receive SYN packet. - b := c.GetPacket() - checker.IPv4(t, b, + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagSyn), @@ -1875,7 +1932,7 @@ func TestSynSent(t *testing.T) { if got, want := tcp.EndpointState(c.EP.State()), tcp.StateSynSent; got != want { t.Fatalf("got State() = %s, want %s", got, want) } - tcpHdr := header.TCP(header.IPv4(b).Payload()) + tcpHdr := header.TCP(header.IPv4(v.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) if test.reset { @@ -1948,13 +2005,14 @@ func TestOutOfOrderReceive(t *testing.T) { }) // Check that we get an ACK specifying which seqnum is expected. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)), - checker.TCPFlags(header.TCPFlagAck), - ), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)), + checker.TCPFlags(header.TCPFlagAck), + ), ) // Wait 200ms and check that no data has been received. @@ -1980,13 +2038,14 @@ func TestOutOfOrderReceive(t *testing.T) { } // Check that the whole data is acknowledged. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)+uint32(len(data))), - checker.TCPFlags(header.TCPFlagAck), - ), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)+uint32(len(data))), + checker.TCPFlags(header.TCPFlagAck), + ), ) } @@ -2013,13 +2072,14 @@ func TestOutOfOrderFlood(t *testing.T) { RcvWnd: 30000, }) - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)), - checker.TCPFlags(header.TCPFlagAck), - ), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)), + checker.TCPFlags(header.TCPFlagAck), + ), ) } @@ -2034,13 +2094,14 @@ func TestOutOfOrderFlood(t *testing.T) { RcvWnd: 30000, }) - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)), - checker.TCPFlags(header.TCPFlagAck), - ), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)), + checker.TCPFlags(header.TCPFlagAck), + ), ) // Now send the expected packet with initial sequence number. @@ -2054,13 +2115,14 @@ func TestOutOfOrderFlood(t *testing.T) { }) // Check that only packet with initial sequence number is acknowledged. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)+3), - checker.TCPFlags(header.TCPFlagAck), - ), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)+3), + checker.TCPFlags(header.TCPFlagAck), + ), ) } @@ -2096,26 +2158,28 @@ func TestRstOnCloseWithUnreadData(t *testing.T) { } // Check that ACK is received, this happens regardless of the read. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)+uint32(len(data))), - checker.TCPFlags(header.TCPFlagAck), - ), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)+uint32(len(data))), + checker.TCPFlags(header.TCPFlagAck), + ), ) // Now that we know we have unread data, let's just close the connection // and verify that netstack sends an RST rather than a FIN. c.EP.Close() - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlags(header.TCPFlagAck|header.TCPFlagRst), - // We shouldn't consume a sequence number on RST. - checker.TCPSeqNum(uint32(c.IRS)+1), - )) + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlags(header.TCPFlagAck|header.TCPFlagRst), + // We shouldn't consume a sequence number on RST. + checker.TCPSeqNum(uint32(c.IRS)+1), + )) // The RST puts the endpoint into an error state. if got, want := tcp.EndpointState(c.EP.State()), tcp.StateError; got != want { t.Errorf("unexpected endpoint state: want %s, got %s", want, got) @@ -2165,13 +2229,14 @@ func TestRstOnCloseWithUnreadDataFinConvertRst(t *testing.T) { } // Check that ACK is received, this happens regardless of the read. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)+uint32(len(data))), - checker.TCPFlags(header.TCPFlagAck), - ), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)+uint32(len(data))), + checker.TCPFlags(header.TCPFlagAck), + ), ) // Cause a FIN to be generated. @@ -2180,12 +2245,13 @@ func TestRstOnCloseWithUnreadDataFinConvertRst(t *testing.T) { } // Make sure we get the FIN but DON't ACK IT. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlags(header.TCPFlagAck|header.TCPFlagFin), - checker.TCPSeqNum(uint32(c.IRS)+1), - )) + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlags(header.TCPFlagAck|header.TCPFlagFin), + checker.TCPSeqNum(uint32(c.IRS)+1), + )) if got, want := tcp.EndpointState(c.EP.State()), tcp.StateFinWait1; got != want { t.Errorf("unexpected endpoint state: want %s, got %s", want, got) @@ -2198,15 +2264,16 @@ func TestRstOnCloseWithUnreadDataFinConvertRst(t *testing.T) { } // Make sure we get the RST - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlags(header.TCPFlagAck|header.TCPFlagRst), - // RST is always generated with sndNxt which if the FIN - // has been sent will be 1 higher than the sequence - // number of the FIN itself. - checker.TCPSeqNum(uint32(c.IRS)+2), - )) + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlags(header.TCPFlagAck|header.TCPFlagRst), + // RST is always generated with sndNxt which if the FIN + // has been sent will be 1 higher than the sequence + // number of the FIN itself. + checker.TCPSeqNum(uint32(c.IRS)+2), + )) // The RST puts the endpoint into an error state. if got, want := tcp.EndpointState(c.EP.State()), tcp.StateError; got != want { t.Errorf("unexpected endpoint state: want %s, got %s", want, got) @@ -2283,14 +2350,15 @@ func TestFullWindowReceive(t *testing.T) { } // Check that data is acknowledged, and window goes to zero. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)+uint32(len(data))), - checker.TCPFlags(header.TCPFlagAck), - checker.TCPWindow(0), - ), + b := c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)+uint32(len(data))), + checker.TCPFlags(header.TCPFlagAck), + checker.TCPWindow(0), + ), ) // Receive data and check it. @@ -2305,14 +2373,15 @@ func TestFullWindowReceive(t *testing.T) { } // Check that we get an ACK for the newly non-zero window. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)+uint32(len(data))), - checker.TCPFlags(header.TCPFlagAck), - checker.TCPWindow(10), - ), + b = c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)+uint32(len(data))), + checker.TCPFlags(header.TCPFlagAck), + checker.TCPWindow(10), + ), ) } @@ -2571,7 +2640,8 @@ func TestSmallSegReceiveWindowAdvertisement(t *testing.T) { iss = iss.Add(payloadLen) pkt := c.GetPacket() - return uint32(header.TCP(header.IPv4(pkt).Payload()).WindowSize()) << c.RcvdWindowScale + defer pkt.Release() + return uint32(header.TCP(header.IPv4(pkt.AsSlice()).Payload()).WindowSize()) << c.RcvdWindowScale } // Read the advertised receive window with the ACK for payload. @@ -2651,6 +2721,7 @@ func TestNoWindowShrinking(t *testing.T) { // Verify that the ACK does not shrink the window. pkt := c.GetPacket() + defer pkt.Release() iss = iss.Add(1) checker.IPv4(t, pkt, checker.TCP( @@ -2661,7 +2732,7 @@ func TestNoWindowShrinking(t *testing.T) { ), ) // Stash the initial window. - initialWnd := header.TCP(header.IPv4(pkt).Payload()).WindowSize() << c.RcvdWindowScale + initialWnd := header.TCP(header.IPv4(pkt.AsSlice()).Payload()).WindowSize() << c.RcvdWindowScale initialLastAcceptableSeq := iss.Add(seqnum.Size(initialWnd)) // Now shrink the receive buffer to half its original size. c.EP.SocketOptions().SetReceiveBufferSize(int64(rcvBufSize), true /* notify */) @@ -2680,6 +2751,7 @@ func TestNoWindowShrinking(t *testing.T) { // Verify that the ACK does not shrink the window. pkt = c.GetPacket() + defer pkt.Release() checker.IPv4(t, pkt, checker.TCP( checker.DstPort(context.TestPort), @@ -2688,7 +2760,7 @@ func TestNoWindowShrinking(t *testing.T) { checker.TCPFlags(header.TCPFlagAck), ), ) - newWnd := header.TCP(header.IPv4(pkt).Payload()).WindowSize() << c.RcvdWindowScale + newWnd := header.TCP(header.IPv4(pkt.AsSlice()).Payload()).WindowSize() << c.RcvdWindowScale newLastAcceptableSeq := iss.Add(seqnum.Size(newWnd)) if newLastAcceptableSeq.LessThan(initialLastAcceptableSeq) { t.Fatalf("receive window shrunk unexpectedly got: %d, want >= %d", newLastAcceptableSeq, initialLastAcceptableSeq) @@ -2706,14 +2778,15 @@ func TestNoWindowShrinking(t *testing.T) { }) iss = iss.Add(seqnum.Size(rcvBufSize / 2)) - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)), - checker.TCPFlags(header.TCPFlagAck), - checker.TCPWindow(0), - ), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)), + checker.TCPFlags(header.TCPFlagAck), + checker.TCPWindow(0), + ), ) // Receive data and check it. @@ -2724,14 +2797,15 @@ func TestNoWindowShrinking(t *testing.T) { // Check that we get an ACK for the newly non-zero window, which is the new // receive buffer size we set after the connection was established. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)), - checker.TCPFlags(header.TCPFlagAck), - checker.TCPWindow(uint16(rcvBufSize/2)>>c.RcvdWindowScale), - ), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)), + checker.TCPFlags(header.TCPFlagAck), + checker.TCPWindow(uint16(rcvBufSize/2)>>c.RcvdWindowScale), + ), ) } @@ -2750,6 +2824,7 @@ func TestSimpleSend(t *testing.T) { // Check that data is received. b := c.GetPacket() + defer b.Release() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) checker.IPv4(t, b, checker.PayloadLen(len(data)+header.TCPMinimumSize), @@ -2761,7 +2836,7 @@ func TestSimpleSend(t *testing.T) { ), ) - if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) { + if p := b.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) { t.Fatalf("got data = %v, want = %v", p, data) } @@ -2791,6 +2866,7 @@ func TestZeroWindowSend(t *testing.T) { // Check if we got a zero-window probe. b := c.GetPacket() + defer b.Release() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) checker.IPv4(t, b, checker.PayloadLen(header.TCPMinimumSize), @@ -2814,6 +2890,7 @@ func TestZeroWindowSend(t *testing.T) { // Check that data is received. b = c.GetPacket() + defer b.Release() checker.IPv4(t, b, checker.PayloadLen(len(data)+header.TCPMinimumSize), checker.TCP( @@ -2824,7 +2901,7 @@ func TestZeroWindowSend(t *testing.T) { ), ) - if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) { + if p := b.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) { t.Fatalf("got data = %v, want = %v", p, data) } @@ -2860,6 +2937,7 @@ func TestScaledWindowConnect(t *testing.T) { // Check that data is received, and that advertised window is 0x5fff, // that is, that it is scaled. b := c.GetPacket() + defer b.Release() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) checker.IPv4(t, b, checker.PayloadLen(len(data)+header.TCPMinimumSize), @@ -2892,6 +2970,7 @@ func TestNonScaledWindowConnect(t *testing.T) { // Check that data is received, and that advertised window is 0xffff, // that is, that it's not scaled. b := c.GetPacket() + defer b.Release() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) checker.IPv4(t, b, checker.PayloadLen(len(data)+header.TCPMinimumSize), @@ -2964,6 +3043,7 @@ func TestScaledWindowAccept(t *testing.T) { // Check that data is received, and that advertised window is 0x5fff, // that is, that it is scaled. b := c.GetPacket() + defer b.Release() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) checker.IPv4(t, b, checker.PayloadLen(len(data)+header.TCPMinimumSize), @@ -3036,6 +3116,7 @@ func TestNonScaledWindowAccept(t *testing.T) { // Check that data is received, and that advertised window is 0xffff, // that is, that it's not scaled. b := c.GetPacket() + defer b.Release() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) checker.IPv4(t, b, checker.PayloadLen(len(data)+header.TCPMinimumSize), @@ -3080,6 +3161,7 @@ func TestZeroScaledWindowReceive(t *testing.T) { }) sent += len(data) pkt := c.GetPacket() + defer pkt.Release() checker.IPv4(t, pkt, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( @@ -3090,7 +3172,7 @@ func TestZeroScaledWindowReceive(t *testing.T) { ), ) // Don't reduce window to zero here. - if wnd := int(header.TCP(header.IPv4(pkt).Payload()).WindowSize()); wnd<>ws)), checker.TCPFlags(header.TCPFlagAck), - ), - ) + )) } func TestSegmentMerging(t *testing.T) { @@ -3218,6 +3302,7 @@ func TestSegmentMerging(t *testing.T) { iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) for i := 0; i < tcp.InitialCwnd; i++ { b := c.GetPacket() + defer b.Release() checker.IPv4(t, b, checker.PayloadLen(header.TCPMinimumSize+1), checker.TCP( @@ -3241,6 +3326,7 @@ func TestSegmentMerging(t *testing.T) { // Check that data is received. b := c.GetPacket() + defer b.Release() checker.IPv4(t, b, checker.PayloadLen(len(allData)+header.TCPMinimumSize), checker.TCP( @@ -3251,7 +3337,7 @@ func TestSegmentMerging(t *testing.T) { ), ) - if got := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(got, allData) { + if got := b.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(got, allData) { t.Fatalf("got data = %v, want = %v", got, allData) } @@ -3291,6 +3377,7 @@ func TestDelay(t *testing.T) { for _, want := range [][]byte{allData[:1], allData[1:]} { // Check that data is received. b := c.GetPacket() + defer b.Release() checker.IPv4(t, b, checker.PayloadLen(len(want)+header.TCPMinimumSize), checker.TCP( @@ -3301,7 +3388,7 @@ func TestDelay(t *testing.T) { ), ) - if got := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(got, want) { + if got := b.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(got, want) { t.Fatalf("got data = %v, want = %v", got, want) } @@ -3339,6 +3426,7 @@ func TestUndelay(t *testing.T) { iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) // Check that data is received. first := c.GetPacket() + defer first.Release() checker.IPv4(t, first, checker.PayloadLen(len(allData[0])+header.TCPMinimumSize), checker.TCP( @@ -3349,7 +3437,7 @@ func TestUndelay(t *testing.T) { ), ) - if got, want := first[header.IPv4MinimumSize+header.TCPMinimumSize:], allData[0]; !bytes.Equal(got, want) { + if got, want := first.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize:], allData[0]; !bytes.Equal(got, want) { t.Fatalf("got first packet's data = %v, want = %v", got, want) } @@ -3362,6 +3450,7 @@ func TestUndelay(t *testing.T) { // Check that data is received. second := c.GetPacket() + defer second.Release() checker.IPv4(t, second, checker.PayloadLen(len(allData[1])+header.TCPMinimumSize), checker.TCP( @@ -3372,7 +3461,7 @@ func TestUndelay(t *testing.T) { ), ) - if got, want := second[header.IPv4MinimumSize+header.TCPMinimumSize:], allData[1]; !bytes.Equal(got, want) { + if got, want := second.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize:], allData[1]; !bytes.Equal(got, want) { t.Fatalf("got second packet's data = %v, want = %v", got, want) } @@ -3425,6 +3514,7 @@ func TestMSSNotDelayed(t *testing.T) { for i, data := range allData { // Check that data is received. packet := c.GetPacket() + defer packet.Release() checker.IPv4(t, packet, checker.PayloadLen(len(data)+header.TCPMinimumSize), checker.TCP( @@ -3435,7 +3525,7 @@ func TestMSSNotDelayed(t *testing.T) { ), ) - if got, want := packet[header.IPv4MinimumSize+header.TCPMinimumSize:], data; !bytes.Equal(got, want) { + if got, want := packet.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize:], data; !bytes.Equal(got, want) { t.Fatalf("got packet #%d's data = %v, want = %v", i+1, got, want) } @@ -3502,9 +3592,13 @@ func TestDefaultTTL(t *testing.T) { checkTTL := func(ttl uint8) { if test.protoNum == ipv4.ProtocolNumber { - checker.IPv4(t, c.GetPacket(), checker.TTL(ttl)) + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TTL(ttl)) } else { - checker.IPv6(t, c.GetV6Packet(), checker.TTL(ttl)) + v := c.GetV6Packet() + defer v.Release() + checker.IPv6(t, v, checker.TTL(ttl)) } } @@ -3563,9 +3657,13 @@ func TestSetTTL(t *testing.T) { // Receive SYN packet. if test.protoNum == ipv4.ProtocolNumber { - checker.IPv4(t, c.GetPacket(), checker.TTL(wantTTL)) + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TTL(wantTTL)) } else { - checker.IPv6(t, c.GetV6Packet(), checker.TTL(wantTTL)) + v := c.GetV6Packet() + defer v.Release() + checker.IPv6(t, v, checker.TTL(wantTTL)) } }) } @@ -3746,6 +3844,7 @@ func TestSynOptionsOnActiveConnect(t *testing.T) { // Receive SYN packet. b := c.GetPacket() + defer b.Release() mss := uint16(mtu - header.IPv4MinimumSize - header.TCPMinimumSize) checker.IPv4(t, b, checker.TCP( @@ -3755,19 +3854,20 @@ func TestSynOptionsOnActiveConnect(t *testing.T) { ), ) - tcpHdr := header.TCP(header.IPv4(b).Payload()) + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) // Wait for retransmit. time.Sleep(1 * time.Second) - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlags(header.TCPFlagSyn), - checker.SrcPort(tcpHdr.SourcePort()), - checker.TCPSeqNum(tcpHdr.SequenceNumber()), - checker.TCPSynOptions(header.TCPSynOptions{MSS: mss, WS: wndScale}), - ), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlags(header.TCPFlagSyn), + checker.SrcPort(tcpHdr.SourcePort()), + checker.TCPSeqNum(tcpHdr.SequenceNumber()), + checker.TCPSynOptions(header.TCPSynOptions{MSS: mss, WS: wndScale}), + ), ) // Send SYN-ACK. @@ -3782,13 +3882,14 @@ func TestSynOptionsOnActiveConnect(t *testing.T) { }) // Receive ACK packet. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlags(header.TCPFlagAck), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)+1), - ), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlags(header.TCPFlagAck), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)+1), + ), ) // Wait for connection to be established. @@ -3956,12 +4057,12 @@ func TestMaxRetransmitsTimeout(t *testing.T) { // Expect first transmit and MaxRetries retransmits. for i := 0; i < numRetries+1; i++ { - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlags(header.TCPFlagAck|header.TCPFlagPsh), - ), - ) + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlags(header.TCPFlagAck|header.TCPFlagPsh), + )) } select { case <-notifyCh: @@ -3976,12 +4077,12 @@ func TestMaxRetransmitsTimeout(t *testing.T) { Flags: header.TCPFlagAck, }) - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlags(header.TCPFlagRst), - ), - ) + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlags(header.TCPFlagRst), + )) if got := c.Stack().Stats().TCP.EstablishedTimedout.Value(); got != 1 { t.Errorf("got c.Stack().Stats().TCP.EstablishedTimedout.Value() = %d, want = 1", got) @@ -4014,21 +4115,22 @@ func TestMaxRTO(t *testing.T) { if err != nil { t.Fatalf("Write failed: %s", err) } - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlagsMatch(header.TCPFlagAck, ^header.TCPFlagPsh), - ), - ) + + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlagsMatch(header.TCPFlagAck, ^header.TCPFlagPsh), + )) const numRetransmits = 2 for i := 0; i < numRetransmits; i++ { start := time.Now() - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlagsMatch(header.TCPFlagAck, ^header.TCPFlagPsh), - ), - ) + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlagsMatch(header.TCPFlagAck, ^header.TCPFlagPsh), + )) if elapsed := time.Since(start); elapsed.Round(time.Second).Seconds() != rto.Seconds() { t.Errorf("Retransmit interval not capped to MaxRTO(%s). %s", rto, elapsed) } @@ -4058,12 +4160,12 @@ func TestZeroSizedWriteRetransmit(t *testing.T) { // Do not ACK the packet and expect an original transmit and a // retransmit. This should not cause a panic. for i := 0; i < 2; i++ { - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPFlagsMatch(header.TCPFlagAck, ^header.TCPFlagPsh), - ), - ) + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPFlagsMatch(header.TCPFlagAck, ^header.TCPFlagPsh), + )) } } @@ -4101,6 +4203,7 @@ func TestRetransmitIPv4IDUniqueness(t *testing.T) { t.Fatalf("Write failed: %s", err) } pkt := c.GetPacket() + defer pkt.Release() checker.IPv4(t, pkt, checker.FragmentFlags(0), checker.TCP( @@ -4108,11 +4211,12 @@ func TestRetransmitIPv4IDUniqueness(t *testing.T) { checker.TCPFlagsMatch(header.TCPFlagAck, ^header.TCPFlagPsh), ), ) - idSet := map[uint16]struct{}{header.IPv4(pkt).ID(): {}} + idSet := map[uint16]struct{}{header.IPv4(pkt.AsSlice()).ID(): {}} // Expect two retransmitted packets, and that all packets received have // unique IPv4 ID values. for i := 0; i <= 2; i++ { pkt := c.GetPacket() + defer pkt.Release() checker.IPv4(t, pkt, checker.FragmentFlags(0), checker.TCP( @@ -4120,7 +4224,7 @@ func TestRetransmitIPv4IDUniqueness(t *testing.T) { checker.TCPFlagsMatch(header.TCPFlagAck, ^header.TCPFlagPsh), ), ) - id := header.IPv4(pkt).ID() + id := header.IPv4(pkt.AsSlice()).ID() if _, exists := idSet[id]; exists { t.Fatalf("duplicate IPv4 ID=%d found in retransmitted packet", id) } @@ -4142,7 +4246,9 @@ func TestFinImmediately(t *testing.T) { } iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4163,7 +4269,9 @@ func TestFinImmediately(t *testing.T) { }) // Check that the stack acks the FIN. - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4186,7 +4294,10 @@ func TestFinRetransmit(t *testing.T) { } iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, c.GetPacket(), + + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4197,7 +4308,9 @@ func TestFinRetransmit(t *testing.T) { ) // Don't acknowledge yet. We should get a retransmit of the FIN. - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4218,7 +4331,9 @@ func TestFinRetransmit(t *testing.T) { }) // Check that the stack acks the FIN. - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4245,7 +4360,9 @@ func TestFinWithNoPendingData(t *testing.T) { next := uint32(c.IRS) + 1 iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(len(view)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4270,7 +4387,9 @@ func TestFinWithNoPendingData(t *testing.T) { t.Fatalf("Shutdown failed: %s", err) } - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4292,7 +4411,9 @@ func TestFinWithNoPendingData(t *testing.T) { }) // Check that the stack acks the FIN. - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4323,7 +4444,9 @@ func TestFinWithPendingDataCwndFull(t *testing.T) { next := uint32(c.IRS) + 1 iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) for i := tcp.InitialCwnd; i > 0; i-- { - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(len(view)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4342,7 +4465,9 @@ func TestFinWithPendingDataCwndFull(t *testing.T) { t.Fatalf("Shutdown failed: %s", err) } - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(len(view)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4362,7 +4487,9 @@ func TestFinWithPendingDataCwndFull(t *testing.T) { RcvWnd: 30000, }) - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4383,7 +4510,9 @@ func TestFinWithPendingDataCwndFull(t *testing.T) { RcvWnd: 30000, }) - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4410,7 +4539,9 @@ func TestFinWithPendingData(t *testing.T) { next := uint32(c.IRS) + 1 iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(len(view)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4436,7 +4567,9 @@ func TestFinWithPendingData(t *testing.T) { t.Fatalf("Write failed: %s", err) } - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(len(view)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4452,7 +4585,9 @@ func TestFinWithPendingData(t *testing.T) { t.Fatalf("Shutdown failed: %s", err) } - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4473,7 +4608,9 @@ func TestFinWithPendingData(t *testing.T) { RcvWnd: 30000, }) - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4501,7 +4638,9 @@ func TestFinWithPartialAck(t *testing.T) { next := uint32(c.IRS) + 1 iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(len(view)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4522,7 +4661,9 @@ func TestFinWithPartialAck(t *testing.T) { }) // Check that we get an ACK for the fin. - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4538,7 +4679,9 @@ func TestFinWithPartialAck(t *testing.T) { t.Fatalf("Write failed: %s", err) } - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(len(view)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4554,7 +4697,9 @@ func TestFinWithPartialAck(t *testing.T) { t.Fatalf("Shutdown failed: %s", err) } - checker.IPv4(t, c.GetPacket(), + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4649,7 +4794,9 @@ func scaledSendWindow(t *testing.T, scale uint8) { } // Check that only data that fits in the scaled window is sent. - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen((1<>4)*4)] = 0x4 - c.SendSegment(buffer.NewWithData(tcpbuf)) + segbuf := bufferv2.MakeWithData(tcpbuf) + defer segbuf.Release() + c.SendSegment(bufferv2.MakeWithData(tcpbuf)) if got := stats.TCP.ChecksumErrors.Value(); got != want { t.Errorf("got stats.TCP.ChecksumErrors.Value() = %d, want = %d", got, want) @@ -4790,6 +4942,7 @@ func TestReceivedSegmentQueuing(t *testing.T) { last := iss.Add(seqnum.Size(200 * len(data))) for { b := c.GetPacket() + defer b.Release() checker.IPv4(t, b, checker.TCP( checker.DstPort(context.TestPort), @@ -4797,7 +4950,7 @@ func TestReceivedSegmentQueuing(t *testing.T) { checker.TCPFlags(header.TCPFlagAck), ), ) - tcpHdr := header.TCP(header.IPv4(b).Payload()) + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) ack := seqnum.Value(tcpHdr.AckNumber()) if ack == last { break @@ -4840,7 +4993,9 @@ func TestReadAfterClosedState(t *testing.T) { } iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, c.GetPacket(), + b := c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -4866,7 +5021,9 @@ func TestReadAfterClosedState(t *testing.T) { }) // Check that ACK is received. - checker.IPv4(t, c.GetPacket(), + b = c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.TCP( checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS)+2), @@ -5031,7 +5188,9 @@ func TestTimeWaitAssassination(t *testing.T) { c.CreateConnected(context.TestInitialSequenceNumber, 30000, -1) c.EP.Close() - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(port), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+1)), @@ -5512,13 +5671,15 @@ func TestPathMTUDiscovery(t *testing.T) { t.Fatalf("Write failed: %s", err) } - receivePackets := func(c *context.Context, sizes []int, which int, seqNum uint32) []byte { - var ret []byte + receivePackets := func(c *context.Context, sizes []int, which int, seqNum uint32) *bufferv2.View { + var ret *bufferv2.View iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) for i, size := range sizes { p := c.GetPacket() if i == which { ret = p + } else { + defer p.Release() } checker.IPv4(t, p, checker.PayloadLen(size+header.TCPMinimumSize), @@ -5537,11 +5698,13 @@ func TestPathMTUDiscovery(t *testing.T) { // Receive three packets. sizes := []int{maxPayload, maxPayload, writeSize - 2*maxPayload} first := receivePackets(c, sizes, 0, uint32(c.IRS)+1) + defer first.Release() // Send "packet too big" messages back to netstack. const newMTU = 1200 const newMaxPayload = newMTU - header.IPv4MinimumSize - header.TCPMinimumSize - mtu := []byte{0, 0, newMTU / 256, newMTU % 256} + mtu := bufferv2.NewViewWithData([]byte{0, 0, newMTU / 256, newMTU % 256}) + defer mtu.Release() c.SendICMPPacket(header.ICMPv4DstUnreachable, header.ICMPv4FragmentationNeeded, mtu, first, newMTU) // See retransmitted packets. None exceeding the new max. @@ -5765,6 +5928,7 @@ func TestKeepalive(t *testing.T) { iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) for i := 0; i < 10; i++ { b := c.GetPacket() + defer b.Release() checker.IPv4(t, b, checker.TCP( checker.DstPort(context.TestPort), @@ -5799,7 +5963,9 @@ func TestKeepalive(t *testing.T) { } next := uint32(c.IRS) + 1 - checker.IPv4(t, c.GetPacket(), + b := c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.PayloadLen(len(view)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -5811,7 +5977,9 @@ func TestKeepalive(t *testing.T) { // Wait for the packet to be retransmitted. Verify that no keepalives // were sent. - checker.IPv4(t, c.GetPacket(), + b = c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.PayloadLen(len(view)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -5837,7 +6005,8 @@ func TestKeepalive(t *testing.T) { // Now receive 5 keepalives, but don't ACK them. The connection // should be reset after 5. for i := 0; i < 5; i++ { - b := c.GetPacket() + b = c.GetPacket() + defer b.Release() checker.IPv4(t, b, checker.TCP( checker.DstPort(context.TestPort), @@ -5865,7 +6034,9 @@ func TestKeepalive(t *testing.T) { RcvWnd: 30000, }) - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP(checker.DstPort(context.TestPort), checker.TCPSeqNum(next), checker.TCPAckNum(uint32(0)), checker.TCPFlags(header.TCPFlagRst)), ) @@ -5900,7 +6071,8 @@ func executeHandshake(t *testing.T, c *context.Context, srcPort uint16, synCooki // Receive the SYN-ACK reply. b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) iss = seqnum.Value(tcpHdr.SequenceNumber()) tcpCheckers := []checker.TransportChecker{ checker.SrcPort(context.StackPort), @@ -5953,7 +6125,8 @@ func executeV6Handshake(t *testing.T, c *context.Context, srcPort uint16, synCoo // Receive the SYN-ACK reply. b := c.GetV6Packet() - tcpHdr := header.TCP(header.IPv6(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv6(b.AsSlice()).Payload()) iss = seqnum.Value(tcpHdr.SequenceNumber()) tcpCheckers := []checker.TransportChecker{ checker.SrcPort(context.StackPort), @@ -6088,7 +6261,8 @@ func TestListenBacklogFull(t *testing.T) { r.Reset(data) newEP.Write(&r, tcpip.WriteOptions{}) b := c.GetPacket() - tcp := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcp := header.TCP(header.IPv4(b.AsSlice()).Payload()) if string(tcp.Payload()) != data { t.Fatalf("unexpected data: got %s, want %s", string(tcp.Payload()), data) } @@ -6196,7 +6370,9 @@ func TestListenNoAcceptNonUnicastV4(t *testing.T) { SeqNum: irs, RcvWnd: 30000, }, context.TestAddr, context.StackAddr) - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), @@ -6296,7 +6472,9 @@ func TestListenNoAcceptNonUnicastV6(t *testing.T) { SeqNum: irs, RcvWnd: 30000, }, context.TestV6Addr, context.StackV6Addr) - checker.IPv6(t, c.GetV6Packet(), + v := c.GetV6Packet() + defer v.Release() + checker.IPv6(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), @@ -6341,7 +6519,8 @@ func TestListenSynRcvdQueueFull(t *testing.T) { // Receive the SYN-ACK reply. b := c.GetPacket() - tcp := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcp := header.TCP(header.IPv4(b.AsSlice()).Payload()) iss := seqnum.Value(tcp.SequenceNumber()) tcpCheckers := []checker.TransportChecker{ checker.SrcPort(context.StackPort), @@ -6401,7 +6580,8 @@ func TestListenSynRcvdQueueFull(t *testing.T) { r.Reset(data) newEP.Write(&r, tcpip.WriteOptions{}) pkt := c.GetPacket() - tcp = header.IPv4(pkt).Payload() + defer pkt.Release() + tcp = header.IPv4(pkt.AsSlice()).Payload() if string(tcp.Payload()) != data { t.Fatalf("unexpected data: got %s, want %s", string(tcp.Payload()), data) } @@ -6518,7 +6698,9 @@ func TestSYNRetransmit(t *testing.T) { checker.TCPFlags(header.TCPFlagAck | header.TCPFlagSyn), checker.TCPAckNum(uint32(irs) + 1), } - checker.IPv4(t, c.GetPacket(), checker.TCP(tcpCheckers...)) + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP(tcpCheckers...)) } func TestSynRcvdBadSeqNumber(t *testing.T) { @@ -6554,7 +6736,8 @@ func TestSynRcvdBadSeqNumber(t *testing.T) { // Receive the SYN-ACK reply. b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) iss := seqnum.Value(tcpHdr.SequenceNumber()) tcpCheckers := []checker.TransportChecker{ checker.SrcPort(context.StackPort), @@ -6577,6 +6760,7 @@ func TestSynRcvdBadSeqNumber(t *testing.T) { // Should receive an ACK with the expected SEQ number b = c.GetPacket() + defer b.Release() tcpCheckers = []checker.TransportChecker{ checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), @@ -6620,7 +6804,8 @@ func TestSynRcvdBadSeqNumber(t *testing.T) { } pkt := c.GetPacket() - tcpHdr = header.IPv4(pkt).Payload() + defer pkt.Release() + tcpHdr = header.IPv4(pkt.AsSlice()).Payload() if string(tcpHdr.Payload()) != data { t.Fatalf("unexpected data: got %s, want %s", string(tcpHdr.Payload()), data) } @@ -6791,7 +6976,9 @@ func TestListenDropIncrement(t *testing.T) { Flags: header.TCPFlagSyn, SeqNum: irs, }) - checker.IPv4(t, c.GetPacket(), checker.TCP(checker.SrcPort(context.StackPort), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP(checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagAck|header.TCPFlagSyn), checker.TCPAckNum(uint32(irs)+1), @@ -6928,7 +7115,8 @@ func TestReceiveBufferAutoTuningApplicationLimited(t *testing.T) { rawEP.SendPacketWithTS(make([]byte, tcp.SegOverheadSize), tsVal) pkt := rawEP.VerifyAndReturnACKWithTS(tsVal) - rcvWnd := header.TCP(header.IPv4(pkt).Payload()).WindowSize() + defer pkt.Release() + rcvWnd := header.TCP(header.IPv4(pkt.AsSlice()).Payload()).WindowSize() time.Sleep(25 * time.Millisecond) @@ -6963,7 +7151,8 @@ func TestReceiveBufferAutoTuningApplicationLimited(t *testing.T) { // Since we sent almost the full receive buffer worth of data (some may have // been dropped due to segment overheads), we should get a zero window back. pkt = c.GetPacket() - tcpHdr := header.TCP(header.IPv4(pkt).Payload()) + defer pkt.Release() + tcpHdr := header.TCP(header.IPv4(pkt.AsSlice()).Payload()) gotRcvWnd := tcpHdr.WindowSize() wantAckNum := tcpHdr.AckNumber() if got, want := int(gotRcvWnd), 0; got != want { @@ -6987,6 +7176,7 @@ func TestReceiveBufferAutoTuningApplicationLimited(t *testing.T) { // under thread santizer this test can end up sending more than 1 // ack, 1 for the non-zero window p := c.GetPacket() + defer p.Release() checker.IPv4(t, p, checker.TCP( checker.TCPAckNum(wantAckNum), func(t *testing.T, h header.Transport) { @@ -7048,7 +7238,8 @@ func TestReceiveBufferAutoTuning(t *testing.T) { rawEP.SendPacketWithTS(nil, tsVal) rawEP.NextSeqNum++ pkt := rawEP.VerifyAndReturnACKWithTS(tsVal) - curRcvWnd := int(header.TCP(header.IPv4(pkt).Payload()).WindowSize()) << c.WindowScale + defer pkt.Release() + curRcvWnd := int(header.TCP(header.IPv4(pkt.AsSlice()).Payload()).WindowSize()) << c.WindowScale scaleRcvWnd := func(rcvWnd int) uint16 { return uint16(rcvWnd >> c.WindowScale) } @@ -7089,6 +7280,7 @@ func TestReceiveBufferAutoTuning(t *testing.T) { time.Sleep(1 * time.Millisecond) lastACK := c.GetPacket() + defer lastACK.Release() // Discard any intermediate ACKs and only check the last ACK we get in a // short time period of few ms. for { @@ -7097,9 +7289,10 @@ func TestReceiveBufferAutoTuning(t *testing.T) { if pkt == nil { break } + defer pkt.Release() lastACK = pkt } - if got, want := int(header.TCP(header.IPv4(lastACK).Payload()).WindowSize()), int(scaleRcvWnd(curRcvWnd)); got > want { + if got, want := int(header.TCP(header.IPv4(lastACK.AsSlice()).Payload()).WindowSize()), int(scaleRcvWnd(curRcvWnd)); got > want { t.Fatalf("advertised window got: %d, want <= %d", got, want) } @@ -7136,6 +7329,7 @@ func TestReceiveBufferAutoTuning(t *testing.T) { // Read loop above could generate an ACK if the window had dropped to // zero and then read had opened it up. lastACK := c.GetPacket() + defer lastACK.Release() // Discard any intermediate ACKs and only check the last ACK we get in a // short time period of few ms. for { @@ -7144,9 +7338,10 @@ func TestReceiveBufferAutoTuning(t *testing.T) { if pkt == nil { break } + defer pkt.Release() lastACK = pkt } - curRcvWnd = int(header.TCP(header.IPv4(lastACK).Payload()).WindowSize()) << c.WindowScale + curRcvWnd = int(header.TCP(header.IPv4(lastACK.AsSlice()).Payload()).WindowSize()) << c.WindowScale // If thew new current window is close maxReceiveBufferSize then terminate // the loop. This can happen before all iterations are done due to timing // differences when running the test. @@ -7278,7 +7473,8 @@ func TestTCPTimeWaitRSTIgnored(t *testing.T) { // Receive the SYN-ACK reply. b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) ackHeaders := &context.Headers{ @@ -7313,7 +7509,10 @@ func TestTCPTimeWaitRSTIgnored(t *testing.T) { } c.EP.Close() - checker.IPv4(t, c.GetPacket(), checker.TCP( + + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+1)), @@ -7331,7 +7530,10 @@ func TestTCPTimeWaitRSTIgnored(t *testing.T) { c.SendPacket(nil, finHeaders) // Get the ACK to the FIN we just sent. - checker.IPv4(t, c.GetPacket(), checker.TCP( + + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+2)), @@ -7360,7 +7562,9 @@ func TestTCPTimeWaitRSTIgnored(t *testing.T) { AckNum: c.IRS + 3, }) - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+2)), @@ -7397,7 +7601,8 @@ func TestTCPTimeWaitOutOfOrder(t *testing.T) { // Receive the SYN-ACK reply. b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) ackHeaders := &context.Headers{ @@ -7432,7 +7637,10 @@ func TestTCPTimeWaitOutOfOrder(t *testing.T) { } c.EP.Close() - checker.IPv4(t, c.GetPacket(), checker.TCP( + + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+1)), @@ -7450,7 +7658,9 @@ func TestTCPTimeWaitOutOfOrder(t *testing.T) { c.SendPacket(nil, finHeaders) // Get the ACK to the FIN we just sent. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+2)), @@ -7467,7 +7677,9 @@ func TestTCPTimeWaitOutOfOrder(t *testing.T) { AckNum: c.IRS + 3, }) - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+2)), @@ -7504,7 +7716,8 @@ func TestTCPTimeWaitNewSyn(t *testing.T) { // Receive the SYN-ACK reply. b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) ackHeaders := &context.Headers{ @@ -7539,7 +7752,10 @@ func TestTCPTimeWaitNewSyn(t *testing.T) { } c.EP.Close() - checker.IPv4(t, c.GetPacket(), checker.TCP( + + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+1)), @@ -7557,7 +7773,9 @@ func TestTCPTimeWaitNewSyn(t *testing.T) { c.SendPacket(nil, finHeaders) // Get the ACK to the FIN we just sent. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+2)), @@ -7598,7 +7816,8 @@ func TestTCPTimeWaitNewSyn(t *testing.T) { // Receive the SYN-ACK reply. b = c.GetPacket() - tcpHdr = header.IPv4(b).Payload() + defer b.Release() + tcpHdr = header.IPv4(b.AsSlice()).Payload() c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) ackHeaders = &context.Headers{ @@ -7668,7 +7887,8 @@ func TestTCPTimeWaitDuplicateFINExtendsTimeWait(t *testing.T) { // Receive the SYN-ACK reply. b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) ackHeaders := &context.Headers{ @@ -7703,7 +7923,9 @@ func TestTCPTimeWaitDuplicateFINExtendsTimeWait(t *testing.T) { } c.EP.Close() - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+1)), @@ -7721,7 +7943,9 @@ func TestTCPTimeWaitDuplicateFINExtendsTimeWait(t *testing.T) { c.SendPacket(nil, finHeaders) // Get the ACK to the FIN we just sent. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+2)), @@ -7736,7 +7960,9 @@ func TestTCPTimeWaitDuplicateFINExtendsTimeWait(t *testing.T) { c.SendPacket(nil, finHeaders) // Get the ACK to the FIN we just sent. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+2)), @@ -7765,7 +7991,9 @@ func TestTCPTimeWaitDuplicateFINExtendsTimeWait(t *testing.T) { // Receive the RST that should be generated as there is no valid // endpoint. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(ackHeaders.AckNum)), @@ -7817,7 +8045,8 @@ func TestTCPCloseWithData(t *testing.T) { // Receive the SYN-ACK reply. b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) ackHeaders := &context.Headers{ @@ -7865,7 +8094,9 @@ func TestTCPCloseWithData(t *testing.T) { c.SendPacket(nil, finHeaders) // Get the ACK to the FIN we just sent. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+1)), @@ -7883,6 +8114,7 @@ func TestTCPCloseWithData(t *testing.T) { // Check that data is received. b = c.GetPacket() + defer b.Release() checker.IPv4(t, b, checker.PayloadLen(len(data)+header.TCPMinimumSize), checker.TCP( @@ -7893,13 +8125,15 @@ func TestTCPCloseWithData(t *testing.T) { ), ) - if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) { + if p := b.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize:]; !bytes.Equal(data, p) { t.Errorf("got data = %x, want = %x", p, data) } c.EP.Close() // Check the FIN. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(c.IRS+1)+uint32(len(data))), @@ -7945,7 +8179,9 @@ func TestTCPCloseWithData(t *testing.T) { c.SendPacket(nil, ackHeaders) // Check the RST. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPSeqNum(uint32(ackHeaders.AckNum)), @@ -7988,7 +8224,9 @@ func TestTCPUserTimeout(t *testing.T) { next := uint32(c.IRS) + 1 iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, c.GetPacket(), + b := c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.PayloadLen(len(view)+header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -8024,13 +8262,14 @@ func TestTCPUserTimeout(t *testing.T) { RcvWnd: 30000, }) - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(next), - checker.TCPAckNum(uint32(0)), - checker.TCPFlags(header.TCPFlagRst), - ), + b = c.GetPacket() + defer b.Release() + checker.IPv4(t, b, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(next), + checker.TCPAckNum(uint32(0)), + checker.TCPFlags(header.TCPFlagRst), + ), ) ept := endpointTester{c.EP} @@ -8082,6 +8321,7 @@ func TestKeepaliveWithUserTimeout(t *testing.T) { // Now receive 1 keepalives, but don't ACK it. b := c.GetPacket() + defer b.Release() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) checker.IPv4(t, b, checker.TCP( @@ -8109,13 +8349,14 @@ func TestKeepaliveWithUserTimeout(t *testing.T) { RcvWnd: 30000, }) - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS+1)), - checker.TCPAckNum(uint32(0)), - checker.TCPFlags(header.TCPFlagRst), - ), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS+1)), + checker.TCPAckNum(uint32(0)), + checker.TCPFlags(header.TCPFlagRst), + ), ) ept.CheckReadError(t, &tcpip.ErrTimeout{}) @@ -8154,6 +8395,7 @@ func TestIncreaseWindowOnRead(t *testing.T) { sent += len(data) remain -= len(data) pkt := c.GetPacket() + defer pkt.Release() checker.IPv4(t, pkt, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( @@ -8164,7 +8406,7 @@ func TestIncreaseWindowOnRead(t *testing.T) { ), ) // Break once the window drops below e2e.DefaultMTU/2 - if wnd := header.TCP(header.IPv4(pkt).Payload()).WindowSize(); wnd < e2e.DefaultMTU/2 { + if wnd := header.TCP(header.IPv4(pkt.AsSlice()).Payload()).WindowSize(); wnd < e2e.DefaultMTU/2 { break } } @@ -8185,7 +8427,9 @@ func TestIncreaseWindowOnRead(t *testing.T) { } // After reading > MSS worth of data, we surely crossed MSS. See the ack: - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -8223,7 +8467,9 @@ func TestIncreaseWindowOnBufferResize(t *testing.T) { }) sent += len(data) remain -= len(data) - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -8238,7 +8484,9 @@ func TestIncreaseWindowOnBufferResize(t *testing.T) { // Increasing the buffer from should generate an ACK, // since window grew from small value to larger equal MSS c.EP.SocketOptions().SetReceiveBufferSize(rcvBuf*4, true /* notify */) - checker.IPv4(t, c.GetPacket(), + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.PayloadLen(header.TCPMinimumSize), checker.TCP( checker.DstPort(context.TestPort), @@ -8287,7 +8535,9 @@ func TestTCPDeferAccept(t *testing.T) { }) // Receive ACK for the data we sent. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagAck), checker.TCPSeqNum(uint32(iss+1)), @@ -8302,7 +8552,9 @@ func TestTCPDeferAccept(t *testing.T) { aep.Close() // Closing aep without reading the data should trigger a RST. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagRst|header.TCPFlagAck), checker.TCPSeqNum(uint32(iss+1)), @@ -8340,7 +8592,9 @@ func TestTCPDeferAcceptTimeout(t *testing.T) { time.Sleep(tcpDeferAccept + 100*time.Millisecond) // On timeout expiry we should get a SYN-ACK retransmission. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagAck|header.TCPFlagSyn), @@ -8356,7 +8610,9 @@ func TestTCPDeferAcceptTimeout(t *testing.T) { }) // Receive ACK for the data we sent. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagAck), @@ -8372,7 +8628,9 @@ func TestTCPDeferAcceptTimeout(t *testing.T) { aep.Close() // Closing aep without reading the data should trigger a RST. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.SrcPort(context.StackPort), checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagRst|header.TCPFlagAck), @@ -8399,7 +8657,9 @@ func TestResetDuringClose(t *testing.T) { }) // Receive ACK for the data we sent. - checker.IPv4(t, c.GetPacket(), checker.TCP( + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( checker.DstPort(context.TestPort), checker.TCPFlags(header.TCPFlagAck), checker.TCPSeqNum(uint32(irs.Add(1))), @@ -8778,7 +9038,8 @@ func TestTimestampSynCookies(t *testing.T) { }) // Get the TSVal of SYN-ACK. b := c.GetPacket() - tcpHdr := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) initialTSVal := tcpHdr.ParsedOptions().TSVal // derive the tsOffset. @@ -8826,7 +9087,9 @@ func TestTimestampSynCookies(t *testing.T) { // The endpoint should have a correct TSOffset so that the received TSVal // should match our expectation. - if got, want := header.TCP(header.IPv4(c.GetPacket()).Payload()).ParsedOptions().TSVal, tsNow()+tsOffset; got != want { + p := c.GetPacket() + defer p.Release() + if got, want := header.TCP(header.IPv4(p.AsSlice()).Payload()).ParsedOptions().TSVal, tsNow()+tsOffset; got != want { t.Fatalf("got TSVal = %d, want %d", got, want) } } @@ -8933,26 +9196,26 @@ func TestReleaseDanglingEndpoints(t *testing.T) { // dangling. ep.Close() iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1) - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+1), - checker.TCPAckNum(uint32(iss)), - checker.TCPFlags(header.TCPFlagAck|header.TCPFlagFin), - ), - ) + v := c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+1), + checker.TCPAckNum(uint32(iss)), + checker.TCPFlags(header.TCPFlagAck|header.TCPFlagFin), + )) tcpip.ReleaseDanglingEndpoints() // ReleaseDanglingEndpoints should abort the half-closed endpoint causing // a RST to be sent. - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+2), - checker.TCPAckNum(uint32(iss)), - checker.TCPFlags(header.TCPFlagRst|header.TCPFlagAck), - ), - ) + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+2), + checker.TCPAckNum(uint32(iss)), + checker.TCPFlags(header.TCPFlagRst|header.TCPFlagAck), + )) // Now send an ACK and it should trigger a RST as the endpoint is aborted. c.SendPacket(nil, &context.Headers{ @@ -8964,14 +9227,14 @@ func TestReleaseDanglingEndpoints(t *testing.T) { RcvWnd: 30000, }) - checker.IPv4(t, c.GetPacket(), - checker.TCP( - checker.DstPort(context.TestPort), - checker.TCPSeqNum(uint32(c.IRS)+2), - checker.TCPAckNum(0), - checker.TCPFlags(header.TCPFlagRst), - ), - ) + v = c.GetPacket() + defer v.Release() + checker.IPv4(t, v, checker.TCP( + checker.DstPort(context.TestPort), + checker.TCPSeqNum(uint32(c.IRS)+2), + checker.TCPAckNum(0), + checker.TCPFlags(header.TCPFlagRst), + )) } func TestMain(m *testing.M) { diff --git a/pkg/tcpip/transport/tcp/test/e2e/tcp_timestamp_test.go b/pkg/tcpip/transport/tcp/test/e2e/tcp_timestamp_test.go index 6aa7887fe..543a23d2c 100644 --- a/pkg/tcpip/transport/tcp/test/e2e/tcp_timestamp_test.go +++ b/pkg/tcpip/transport/tcp/test/e2e/tcp_timestamp_test.go @@ -165,6 +165,7 @@ func timeStampEnabledAccept(t *testing.T, cookieEnabled bool, wndScale int, wndS // Check that data is received and that the timestamp option TSEcr field // matches the expected value. b := c.GetPacket() + defer b.Release() checker.IPv4(t, b, // Add 12 bytes for the timestamp option + 2 NOPs to align at 4 // byte boundary. @@ -228,6 +229,7 @@ func timeStampDisabledAccept(t *testing.T, cookieEnabled bool, wndScale int, wnd // Check that data is received and that the timestamp option is disabled // when SYN cookies are enabled/disabled. b := c.GetPacket() + defer b.Release() checker.IPv4(t, b, checker.PayloadLen(len(data)+header.TCPMinimumSize), checker.TCP( diff --git a/pkg/tcpip/transport/tcp/testing/context/BUILD b/pkg/tcpip/transport/tcp/testing/context/BUILD index 6ed2a6ff3..2aa9ccbbc 100644 --- a/pkg/tcpip/transport/tcp/testing/context/BUILD +++ b/pkg/tcpip/transport/tcp/testing/context/BUILD @@ -10,7 +10,7 @@ go_library( "//visibility:public", ], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/tcpip", "//pkg/tcpip/checker", "//pkg/tcpip/header", diff --git a/pkg/tcpip/transport/tcp/testing/context/context.go b/pkg/tcpip/transport/tcp/testing/context/context.go index 27608ba82..d5e1b0926 100644 --- a/pkg/tcpip/transport/tcp/testing/context/context.go +++ b/pkg/tcpip/transport/tcp/testing/context/context.go @@ -22,7 +22,7 @@ import ( "testing" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -320,7 +320,7 @@ func (c *Context) CheckNoPacket(errMsg string) { // that it is an IPv4 packet with the expected source and destination // addresses. If no packet is received in the specified timeout it will return // nil. -func (c *Context) GetPacketWithTimeout(timeout time.Duration) []byte { +func (c *Context) GetPacketWithTimeout(timeout time.Duration) *bufferv2.View { c.t.Helper() ctx, cancel := context.WithTimeout(context.Background(), timeout) @@ -343,21 +343,20 @@ func (c *Context) GetPacketWithTimeout(timeout time.Duration) []byte { c.t.Fatalf("got pkt.TransportProtocolNumber = %d, want = %d", got, want) } - buf := pkt.Buffer() - b := buf.Flatten() + view := pkt.ToView() if pkt.GSOOptions.Type != stack.GSONone && pkt.GSOOptions.L3HdrLen != header.IPv4MinimumSize { c.t.Errorf("got L3HdrLen = %d, want = %d", pkt.GSOOptions.L3HdrLen, header.IPv4MinimumSize) } - checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr)) - return b + checker.IPv4(c.t, view, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr)) + return view } // GetPacket reads a packet from the link layer endpoint and verifies // that it is an IPv4 packet with the expected source and destination // addresses. -func (c *Context) GetPacket() []byte { +func (c *Context) GetPacket() *bufferv2.View { c.t.Helper() p := c.GetPacketWithTimeout(5 * time.Second) @@ -373,7 +372,7 @@ func (c *Context) GetPacket() []byte { // and verifies that it is an IPv4 packet with the expected source // and destination address. If no packet is available it will return // nil immediately. -func (c *Context) GetPacketNonBlocking() []byte { +func (c *Context) GetPacketNonBlocking() *bufferv2.View { c.t.Helper() pkt := c.linkEP.Read() @@ -394,24 +393,23 @@ func (c *Context) GetPacketNonBlocking() []byte { c.t.Fatalf("got pkt.TransportProtocolNumber = %d, want = %d", got, want) } - buf := pkt.Buffer() - b := buf.Flatten() + view := pkt.ToView() - checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr)) - return b + checker.IPv4(c.t, view, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr)) + return view } // SendICMPPacket builds and sends an ICMPv4 packet via the link layer endpoint. -func (c *Context) SendICMPPacket(typ header.ICMPv4Type, code header.ICMPv4Code, p1, p2 []byte, maxTotalSize int) { +func (c *Context) SendICMPPacket(typ header.ICMPv4Type, code header.ICMPv4Code, p1, p2 *bufferv2.View, maxTotalSize int) { // Allocate a buffer data and headers. - buf := make([]byte, header.IPv4MinimumSize+header.ICMPv4PayloadOffset+len(p2)) - if len(buf) > maxTotalSize { - buf = buf[:maxTotalSize] + buf := bufferv2.NewViewSize(header.IPv4MinimumSize + header.ICMPv4PayloadOffset + p2.Size()) + if buf.Size() > maxTotalSize { + buf.CapLength(maxTotalSize) } - ip := header.IPv4(buf) + ip := header.IPv4(buf.AsSlice()) ip.Encode(&header.IPv4Fields{ - TotalLength: uint16(len(buf)), + TotalLength: uint16(buf.Size()), TTL: 65, Protocol: uint8(header.ICMPv4ProtocolNumber), SrcAddr: TestAddr, @@ -419,32 +417,32 @@ func (c *Context) SendICMPPacket(typ header.ICMPv4Type, code header.ICMPv4Code, }) ip.SetChecksum(^ip.CalculateChecksum()) - icmp := header.ICMPv4(buf[header.IPv4MinimumSize:]) + icmp := header.ICMPv4(buf.AsSlice()[header.IPv4MinimumSize:]) icmp.SetType(typ) icmp.SetCode(code) const icmpv4VariableHeaderOffset = 4 - copy(icmp[icmpv4VariableHeaderOffset:], p1) - copy(icmp[header.ICMPv4PayloadOffset:], p2) + copy(icmp[icmpv4VariableHeaderOffset:], p1.AsSlice()) + copy(icmp[header.ICMPv4PayloadOffset:], p2.AsSlice()) icmp.SetChecksum(0) checksum := ^header.Checksum(icmp, 0 /* initial */) icmp.SetChecksum(checksum) // Inject packet. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithView(buf), }) defer pkt.DecRef() c.linkEP.InjectInbound(ipv4.ProtocolNumber, pkt) } // BuildSegment builds a TCP segment based on the given Headers and payload. -func (c *Context) BuildSegment(payload []byte, h *Headers) buffer.Buffer { +func (c *Context) BuildSegment(payload []byte, h *Headers) bufferv2.Buffer { return c.BuildSegmentWithAddrs(payload, h, TestAddr, StackAddr) } // BuildSegmentWithAddrs builds a TCP segment based on the given Headers, // payload and source and destination IPv4 addresses. -func (c *Context) BuildSegmentWithAddrs(payload []byte, h *Headers, src, dst tcpip.Address) buffer.Buffer { +func (c *Context) BuildSegmentWithAddrs(payload []byte, h *Headers, src, dst tcpip.Address) bufferv2.Buffer { // Allocate a buffer for data and headers. buf := make([]byte, header.TCPMinimumSize+header.IPv4MinimumSize+len(h.TCPOpts)+len(payload)) copy(buf[len(buf)-len(payload):], payload) @@ -481,12 +479,12 @@ func (c *Context) BuildSegmentWithAddrs(payload []byte, h *Headers, src, dst tcp t.SetChecksum(^t.CalculateChecksum(xsum)) // Inject packet. - return buffer.NewWithData(buf) + return bufferv2.MakeWithData(buf) } // SendSegment sends a TCP segment that has already been built and written to a // buffer.VectorisedView. -func (c *Context) SendSegment(s buffer.Buffer) { +func (c *Context) SendSegment(s bufferv2.Buffer) { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ Payload: s, }) @@ -557,8 +555,9 @@ func (c *Context) ReceiveAndCheckPacket(data []byte, offset, size int) { func (c *Context) ReceiveAndCheckPacketWithOptions(data []byte, offset, size, optlen int) { c.t.Helper() - b := c.GetPacket() - checker.IPv4(c.t, b, + v := c.GetPacket() + defer v.Release() + checker.IPv4(c.t, v, checker.PayloadLen(size+header.TCPMinimumSize+optlen), checker.TCP( checker.DstPort(TestPort), @@ -569,7 +568,7 @@ func (c *Context) ReceiveAndCheckPacketWithOptions(data []byte, offset, size, op ) pdata := data[offset:][:size] - if p := b[header.IPv4MinimumSize+header.TCPMinimumSize+optlen:]; bytes.Compare(pdata, p) != 0 { + if p := v.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize+optlen:]; bytes.Compare(pdata, p) != 0 { c.t.Fatalf("Data is different: expected %v, got %v", pdata, p) } } @@ -581,11 +580,12 @@ func (c *Context) ReceiveAndCheckPacketWithOptions(data []byte, offset, size, op func (c *Context) ReceiveNonBlockingAndCheckPacket(data []byte, offset, size int) bool { c.t.Helper() - b := c.GetPacketNonBlocking() - if b == nil { + v := c.GetPacketNonBlocking() + if v == nil { return false } - checker.IPv4(c.t, b, + defer v.Release() + checker.IPv4(c.t, v, checker.PayloadLen(size+header.TCPMinimumSize), checker.TCP( checker.DstPort(TestPort), @@ -596,7 +596,7 @@ func (c *Context) ReceiveNonBlockingAndCheckPacket(data []byte, offset, size int ) pdata := data[offset:][:size] - if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; bytes.Compare(pdata, p) != 0 { + if p := v.AsSlice()[header.IPv4MinimumSize+header.TCPMinimumSize:]; bytes.Compare(pdata, p) != 0 { c.t.Fatalf("Data is different: expected %v, got %v", pdata, p) } return true @@ -617,7 +617,7 @@ func (c *Context) CreateV6Endpoint(v6only bool) { // GetV6Packet reads a single packet from the link layer endpoint of the context // and asserts that it is an IPv6 Packet with the expected src/dest addresses. -func (c *Context) GetV6Packet() []byte { +func (c *Context) GetV6Packet() *bufferv2.View { c.t.Helper() ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) @@ -632,11 +632,10 @@ func (c *Context) GetV6Packet() []byte { if got, want := pkt.NetworkProtocolNumber, ipv6.ProtocolNumber; got != want { c.t.Fatalf("got pkt.NetworkProtocolNumber = %d, want = %d", got, want) } - buf := pkt.Buffer() - b := buf.Flatten() + v := pkt.ToView() - checker.IPv6(c.t, b, checker.SrcAddr(StackV6Addr), checker.DstAddr(TestV6Addr)) - return b + checker.IPv6(c.t, v, checker.SrcAddr(StackV6Addr), checker.DstAddr(TestV6Addr)) + return v } // SendV6Packet builds and sends an IPv6 Packet via the link layer endpoint of @@ -685,7 +684,7 @@ func (c *Context) SendV6PacketWithAddrs(payload []byte, h *Headers, src, dst tcp // Inject packet. pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) defer pkt.DecRef() c.linkEP.InjectInbound(ipv6.ProtocolNumber, pkt) @@ -719,6 +718,7 @@ func (c *Context) Connect(iss seqnum.Value, rcvWnd seqnum.Size, options []byte) // Receive SYN packet. b := c.GetPacket() + defer b.Release() checker.IPv4(c.t, b, checker.TCP( checker.DstPort(TestPort), @@ -729,7 +729,7 @@ func (c *Context) Connect(iss seqnum.Value, rcvWnd seqnum.Size, options []byte) c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) } - tcpHdr := header.TCP(header.IPv4(b).Payload()) + tcpHdr := header.TCP(header.IPv4(b.AsSlice()).Payload()) synOpts := header.ParseSynOptions(tcpHdr.Options(), false /* isAck */) c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) @@ -744,7 +744,9 @@ func (c *Context) Connect(iss seqnum.Value, rcvWnd seqnum.Size, options []byte) }) // Receive ACK packet. - checker.IPv4(c.t, c.GetPacket(), + b = c.GetPacket() + defer b.Release() + checker.IPv4(c.t, b, checker.TCP( checker.DstPort(TestPort), checker.TCPFlags(header.TCPFlagAck), @@ -838,7 +840,7 @@ func (r *RawEndpoint) SendPacket(payload []byte, opts []byte) { // VerifyAndReturnACKWithTS verifies that the tsEcr field int he ACK matches // the provided tsVal as well as returns the original packet. -func (r *RawEndpoint) VerifyAndReturnACKWithTS(tsVal uint32) []byte { +func (r *RawEndpoint) VerifyAndReturnACKWithTS(tsVal uint32) *bufferv2.View { r.C.t.Helper() // Read ACK and verify that tsEcr of ACK packet is [1,2,3,4] ackPacket := r.C.GetPacket() @@ -852,7 +854,7 @@ func (r *RawEndpoint) VerifyAndReturnACKWithTS(tsVal uint32) []byte { ), ) // Store the parsed TSVal from the ack as recentTS. - tcpSeg := header.TCP(header.IPv4(ackPacket).Payload()) + tcpSeg := header.TCP(header.IPv4(ackPacket.AsSlice()).Payload()) opts := tcpSeg.ParsedOptions() r.RecentTS = opts.TSVal return ackPacket @@ -862,7 +864,8 @@ func (r *RawEndpoint) VerifyAndReturnACKWithTS(tsVal uint32) []byte { // tsVal. func (r *RawEndpoint) VerifyACKWithTS(tsVal uint32) { r.C.t.Helper() - _ = r.VerifyAndReturnACKWithTS(tsVal) + p := r.VerifyAndReturnACKWithTS(tsVal) + p.Release() } // VerifyACKRcvWnd verifies that the window advertised by the incoming ACK @@ -870,6 +873,7 @@ func (r *RawEndpoint) VerifyACKWithTS(tsVal uint32) { func (r *RawEndpoint) VerifyACKRcvWnd(rcvWnd uint16) { r.C.t.Helper() ackPacket := r.C.GetPacket() + defer ackPacket.Release() checker.IPv4(r.C.t, ackPacket, checker.TCP( checker.DstPort(r.SrcPort), @@ -891,6 +895,7 @@ func (r *RawEndpoint) VerifyACKHasSACK(sackBlocks []header.SACKBlock) { // Read ACK and verify that the TCP options in the segment do // not contain a SACK block. ackPacket := r.C.GetPacket() + defer ackPacket.Release() checker.IPv4(r.C.t, ackPacket, checker.TCP( checker.DstPort(r.SrcPort), @@ -938,6 +943,7 @@ func (c *Context) CreateConnectedWithOptions(wantOptions header.TCPSynOptions, d } // Receive SYN packet. b := c.GetPacket() + defer b.Release() // Validate that the syn has the timestamp option and a valid // TS value. mss := uint16(c.linkEP.MTU() - header.IPv4MinimumSize - header.TCPMinimumSize) @@ -957,7 +963,7 @@ func (c *Context) CreateConnectedWithOptions(wantOptions header.TCPSynOptions, d c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) } - tcpSeg := header.TCP(header.IPv4(b).Payload()) + tcpSeg := header.TCP(header.IPv4(b.AsSlice()).Payload()) synOptions := header.ParseSynOptions(tcpSeg.Options(), false) // Build options w/ tsVal to be sent in the SYN-ACK. @@ -993,11 +999,12 @@ func (c *Context) CreateConnectedWithOptions(wantOptions header.TCPSynOptions, d }) // Read ACK. - var ackPacket []byte + var ackPacket *bufferv2.View // Ignore retransimitted SYN packets. for { packet := c.GetPacket() - if header.TCP(header.IPv4(packet).Payload()).Flags()&header.TCPFlagSyn != 0 { + defer packet.Release() + if header.TCP(header.IPv4(packet.AsSlice()).Payload()).Flags()&header.TCPFlagSyn != 0 { checker.IPv4(c.t, packet, synChecker) } else { ackPacket = packet @@ -1024,7 +1031,7 @@ func (c *Context) CreateConnectedWithOptions(wantOptions header.TCPSynOptions, d checker.IPv4(c.t, ackPacket, checker.TCP(tcpCheckers...)) - ackSeg := header.TCP(header.IPv4(ackPacket).Payload()) + ackSeg := header.TCP(header.IPv4(ackPacket.AsSlice()).Payload()) ackOptions := ackSeg.ParsedOptions() // Wait for connection to be established. @@ -1183,7 +1190,8 @@ func (c *Context) PassiveConnectWithOptions(maxPayload, wndScale int, synOptions // Receive the SYN-ACK reply. Make sure MSS and other expected options // are present. b := c.GetPacket() - tcp := header.TCP(header.IPv4(b).Payload()) + defer b.Release() + tcp := header.TCP(header.IPv4(b.AsSlice()).Payload()) rcvdSynOptions := header.ParseSynOptions(tcp.Options(), true /* isAck */) c.IRS = seqnum.Value(tcp.SequenceNumber()) diff --git a/pkg/tcpip/transport/testing/context/BUILD b/pkg/tcpip/transport/testing/context/BUILD index 5544e547c..911922273 100644 --- a/pkg/tcpip/transport/testing/context/BUILD +++ b/pkg/tcpip/transport/testing/context/BUILD @@ -13,7 +13,7 @@ go_library( "//visibility:public", ], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/refsvfs2", "//pkg/tcpip", "//pkg/tcpip/checker", diff --git a/pkg/tcpip/transport/testing/context/context.go b/pkg/tcpip/transport/testing/context/context.go index 1fe473e78..ee18b4619 100644 --- a/pkg/tcpip/transport/testing/context/context.go +++ b/pkg/tcpip/transport/testing/context/context.go @@ -23,7 +23,7 @@ import ( "github.com/google/go-cmp/cmp" "golang.org/x/time/rate" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" @@ -253,7 +253,7 @@ func (c *Context) CheckEndpointReadStats(incr uint64, want *tcpip.TransportEndpo // InjectPacket injects a packet into the context's link endpoint. func (c *Context) InjectPacket(netProto tcpip.NetworkProtocolNumber, buf []byte) { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - Payload: buffer.NewWithData(buf), + Payload: bufferv2.MakeWithData(buf), }) defer pkt.DecRef() c.LinkEP.InjectInbound(netProto, pkt) diff --git a/pkg/tcpip/transport/testing/context/flow.go b/pkg/tcpip/transport/testing/context/flow.go index 9512b18f8..b1269261a 100644 --- a/pkg/tcpip/transport/testing/context/flow.go +++ b/pkg/tcpip/transport/testing/context/flow.go @@ -18,6 +18,7 @@ import ( "fmt" "testing" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/checker" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -271,7 +272,7 @@ func (flow TestFlow) SockProto() tcpip.NetworkProtocolNumber { } // CheckerFn returns the correct network checker for the current TestFlow. -func (flow TestFlow) CheckerFn() func(*testing.T, []byte, ...checker.NetworkChecker) { +func (flow TestFlow) CheckerFn() func(*testing.T, *bufferv2.View, ...checker.NetworkChecker) { if flow.IsV4() { return checker.IPv4 } diff --git a/pkg/tcpip/transport/udp/BUILD b/pkg/tcpip/transport/udp/BUILD index 3e82461bf..9cbb03246 100644 --- a/pkg/tcpip/transport/udp/BUILD +++ b/pkg/tcpip/transport/udp/BUILD @@ -26,7 +26,8 @@ go_library( ], visibility = ["//visibility:public"], deps = [ - "//pkg/buffer", + "//pkg/bufferv2", + "//pkg/log", "//pkg/sleep", "//pkg/sync", "//pkg/tcpip", @@ -47,6 +48,7 @@ go_test( srcs = ["udp_test.go"], deps = [ ":udp", + "//pkg/bufferv2", "//pkg/refs", "//pkg/refsvfs2", "//pkg/tcpip", diff --git a/pkg/tcpip/transport/udp/endpoint.go b/pkg/tcpip/transport/udp/endpoint.go index 41d7233fc..c9a43240f 100644 --- a/pkg/tcpip/transport/udp/endpoint.go +++ b/pkg/tcpip/transport/udp/endpoint.go @@ -21,7 +21,7 @@ import ( "math" "time" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" @@ -432,16 +432,16 @@ func (e *endpoint) prepareForWrite(p tcpip.Payloader, opts tcpip.WriteOptions) ( return udpPacketInfo{}, &tcpip.ErrMessageTooLong{} } - // TODO(https://gvisor.dev/issue/6538): Avoid this allocation. - v := make([]byte, p.Len()) - if _, err := io.ReadFull(p, v); err != nil { + var buf bufferv2.Buffer + if _, err := buf.WriteFromReader(p, int64(p.Len())); err != nil { + buf.Release() ctx.Release() return udpPacketInfo{}, &tcpip.ErrBadBuffer{} } return udpPacketInfo{ ctx: ctx, - data: v, + data: buf, localPort: e.localPort, remotePort: dst.Port, }, nil @@ -469,8 +469,9 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp } defer udpInfo.ctx.Release() + dataSz := udpInfo.data.Size() pktInfo := udpInfo.ctx.PacketInfo() - pkt := udpInfo.ctx.TryNewPacketBuffer(header.UDPMinimumSize+int(pktInfo.MaxHeaderLength), buffer.NewWithData(udpInfo.data)) + pkt := udpInfo.ctx.TryNewPacketBuffer(header.UDPMinimumSize+int(pktInfo.MaxHeaderLength), udpInfo.data) if pkt == nil { return 0, &tcpip.ErrWouldBlock{} } @@ -528,7 +529,7 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, tcp // Track count of packets sent. e.stack.Stats().UDP.PacketsSent.Increment() - return int64(len(udpInfo.data)), nil + return int64(dataSz), nil } // OnReuseAddressSet implements tcpip.SocketOptionsHandler. @@ -588,7 +589,7 @@ func (e *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) tcpip.Error { // udpPacketInfo holds information needed to send a UDP packet. type udpPacketInfo struct { ctx network.WriteContext - data []byte + data bufferv2.Buffer localPort uint16 remotePort uint16 } @@ -902,7 +903,7 @@ func (e *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask { // endpoint. func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) { // Get the header then trim it from the view. - hdr := header.UDP(pkt.TransportHeader().View()) + hdr := header.UDP(pkt.TransportHeader().Slice()) netHdr := pkt.Network() lengthValid, csumValid := header.UDPValid( hdr, @@ -970,9 +971,9 @@ func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketB packet.tosOrTClass, _ = pkt.Network().TOS() switch pkt.NetworkProtocolNumber { case header.IPv4ProtocolNumber: - packet.ttlOrHopLimit = header.IPv4(pkt.NetworkHeader().View()).TTL() + packet.ttlOrHopLimit = header.IPv4(pkt.NetworkHeader().Slice()).TTL() case header.IPv6ProtocolNumber: - packet.ttlOrHopLimit = header.IPv6(pkt.NetworkHeader().View()).HopLimit() + packet.ttlOrHopLimit = header.IPv6(pkt.NetworkHeader().Slice()).HopLimit() } // TODO(gvisor.dev/issue/3556): r.LocalAddress may be a multicast or broadcast @@ -1010,10 +1011,10 @@ func (e *endpoint) onICMPError(err tcpip.Error, transErr stack.TransportError, p if recvErr { // Linux passes the payload without the UDP header. - var payload []byte - udp := header.UDP(pkt.Data().AsRange().ToOwnedView()) + payload := pkt.Data().AsRange().ToView() + udp := header.UDP(payload.AsSlice()) if len(udp) >= header.UDPMinimumSize { - payload = udp.Payload() + payload.TrimFront(header.UDPMinimumSize) } id := e.net.Info().ID diff --git a/pkg/tcpip/transport/udp/protocol.go b/pkg/tcpip/transport/udp/protocol.go index 6a15e3b79..8b4368908 100644 --- a/pkg/tcpip/transport/udp/protocol.go +++ b/pkg/tcpip/transport/udp/protocol.go @@ -78,7 +78,7 @@ func (*protocol) ParsePorts(v []byte) (src, dst uint16, err tcpip.Error) { // HandleUnknownDestinationPacket handles packets that are targeted at this // protocol but don't match any existing endpoint. func (p *protocol) HandleUnknownDestinationPacket(id stack.TransportEndpointID, pkt *stack.PacketBuffer) stack.UnknownDestinationPacketDisposition { - hdr := header.UDP(pkt.TransportHeader().View()) + hdr := header.UDP(pkt.TransportHeader().Slice()) netHdr := pkt.Network() lengthValid, csumValid := header.UDPValid( hdr, diff --git a/pkg/tcpip/transport/udp/udp_test.go b/pkg/tcpip/transport/udp/udp_test.go index 56603e636..64bab33d9 100644 --- a/pkg/tcpip/transport/udp/udp_test.go +++ b/pkg/tcpip/transport/udp/udp_test.go @@ -24,6 +24,7 @@ import ( "os" "testing" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/refsvfs2" "gvisor.dev/gvisor/pkg/tcpip" @@ -602,8 +603,8 @@ func testWriteAndVerifyInternal(c *context.Context, flow context.TestFlow, setDe c.T.Errorf("got p.TransportProtocolNumber = %d, want = %d", got, want) } - buf := p.Buffer() - b := buf.Flatten() + v := p.ToView() + defer v.Release() h := flow.MakeHeader4Tuple(context.Outgoing) checkers = append( @@ -612,13 +613,13 @@ func testWriteAndVerifyInternal(c *context.Context, flow context.TestFlow, setDe checker.DstAddr(h.Dst.Addr), checker.UDP(checker.DstPort(h.Dst.Port)), ) - flow.CheckerFn()(c.T, b, checkers...) + flow.CheckerFn()(c.T, v, checkers...) var udpH header.UDP if flow.IsV4() { - udpH = header.IPv4(b).Payload() + udpH = header.IPv4(v.AsSlice()).Payload() } else { - udpH = header.IPv6(b).Payload() + udpH = header.IPv6(v.AsSlice()).Payload() } if !bytes.Equal(payload, udpH.Payload()) { c.T.Fatalf("Bad payload: got %x, want %x", udpH.Payload(), payload) @@ -1536,21 +1537,23 @@ func TestV4UnknownDestination(t *testing.T) { t.Fatalf("packet wasn't written out") } - buf := p.Buffer() + buf := p.ToBuffer() + defer buf.Release() p.DecRef() pkt := buf.Flatten() if got, want := len(pkt), header.IPv4MinimumProcessableDatagramSize; got > want { t.Fatalf("got an ICMP packet of size: %d, want: sz <= %d", got, want) } - hdr := header.IPv4(pkt) + hdr := bufferv2.NewViewWithData(pkt) + defer hdr.Release() checker.IPv4(t, hdr, checker.ICMPv4( checker.ICMPv4Type(header.ICMPv4DstUnreachable), checker.ICMPv4Code(header.ICMPv4PortUnreachable))) // We need to compare the included data part of the UDP packet that is in // the ICMP packet with the matching original data. - icmpPkt := header.ICMPv4(hdr.Payload()) + icmpPkt := header.ICMPv4(header.IPv4(hdr.AsSlice()).Payload()) payloadIPHeader := header.IPv4(icmpPkt.Payload()) incomingHeaderLength := header.IPv4MinimumSize + header.UDPMinimumSize wantLen := len(payload) @@ -1631,19 +1634,21 @@ func TestV6UnknownDestination(t *testing.T) { t.Fatalf("packet wasn't written out") } - buf := p.Buffer() + buf := p.ToBuffer() + defer buf.Release() p.DecRef() pkt := buf.Flatten() if got, want := len(pkt), header.IPv6MinimumMTU; got > want { t.Fatalf("got an ICMP packet of size: %d, want: sz <= %d", got, want) } - hdr := header.IPv6(pkt) + hdr := bufferv2.NewViewWithData(pkt) + defer hdr.Release() checker.IPv6(t, hdr, checker.ICMPv6( checker.ICMPv6Type(header.ICMPv6DstUnreachable), checker.ICMPv6Code(header.ICMPv6PortUnreachable))) - icmpPkt := header.ICMPv6(hdr.Payload()) + icmpPkt := header.ICMPv6(header.IPv6(hdr.AsSlice()).Payload()) payloadIPHeader := header.IPv6(icmpPkt.Payload()) wantLen := len(payload) if tc.largePayload { @@ -2183,6 +2188,7 @@ func TestChecksumWithZeroValueOnesComplementSum(t *testing.T) { } v := stack.PayloadSince(pkt.NetworkHeader()) + defer v.Release() pkt.DecRef() checker.IPv6(t, v, checker.UDP()) @@ -2197,7 +2203,7 @@ func TestChecksumWithZeroValueOnesComplementSum(t *testing.T) { // The resulting ones complement will be C' = C - C so we know C' will be // zero. The stack should never send a zero value though so we expect all // ones below. - binary.BigEndian.PutUint16(payload[:], header.UDP(header.IPv6(v).Payload()).Checksum()) + binary.BigEndian.PutUint16(payload[:], header.UDP(header.IPv6(v.AsSlice()).Payload()).Checksum()) } { @@ -2220,10 +2226,11 @@ func TestChecksumWithZeroValueOnesComplementSum(t *testing.T) { defer pkt.DecRef() v := stack.PayloadSince(pkt.NetworkHeader()) - checker.IPv6(t, stack.PayloadSince(pkt.NetworkHeader()), checker.UDP(checker.TransportChecksum(math.MaxUint16))) + defer v.Release() + checker.IPv6(t, v, checker.UDP(checker.TransportChecksum(math.MaxUint16))) // Make sure the all ones checksum is valid. - hdr := header.IPv6(v) + hdr := header.IPv6(v.AsSlice()) udp := header.UDP(hdr.Payload()) if src, dst, payloadXsum := hdr.SourceAddress(), hdr.DestinationAddress(), header.Checksum(udp.Payload(), 0); !udp.IsChecksumValid(src, dst, payloadXsum) { t.Errorf("got udp.IsChecksumValid(%s, %s, %d) = false, want = true", src, dst, payloadXsum) diff --git a/test/packetimpact/testbench/BUILD b/test/packetimpact/testbench/BUILD index 61a20adae..680d928e6 100644 --- a/test/packetimpact/testbench/BUILD +++ b/test/packetimpact/testbench/BUILD @@ -18,7 +18,7 @@ go_library( deps = [ "//pkg/abi/linux", "//pkg/binary", - "//pkg/buffer", + "//pkg/bufferv2", "//pkg/hostarch", "//pkg/tcpip", "//pkg/tcpip/header", diff --git a/test/packetimpact/testbench/layers.go b/test/packetimpact/testbench/layers.go index e36e4d4a9..3fc89818f 100644 --- a/test/packetimpact/testbench/layers.go +++ b/test/packetimpact/testbench/layers.go @@ -24,7 +24,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "go.uber.org/multierr" - "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/bufferv2" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/header" ) @@ -1113,15 +1113,15 @@ func totalLength(l Layer) int { return totalLength } -// payload returns a buffer.VectorisedView of l's payload. -func payload(l Layer) (buffer.Buffer, error) { - var payloadBytes buffer.Buffer +// payload returns a bufferv2.Buffer of l's payload. +func payload(l Layer) (bufferv2.Buffer, error) { + var payloadBytes bufferv2.Buffer for current := l.next(); current != nil; current = current.next() { payload, err := current.ToBytes() if err != nil { - return buffer.Buffer{}, fmt.Errorf("can't get bytes for next header: %s", payload) + return bufferv2.Buffer{}, fmt.Errorf("can't get bytes for next header: %s", payload) } - payloadBytes.AppendOwned(payload) + payloadBytes.Append(bufferv2.NewViewWithData(payload)) } return payloadBytes, nil }