diff options
Diffstat (limited to 'pkg/tcpip/stack/packet_buffer_test.go')
-rw-r--r-- | pkg/tcpip/stack/packet_buffer_test.go | 655 |
1 files changed, 0 insertions, 655 deletions
diff --git a/pkg/tcpip/stack/packet_buffer_test.go b/pkg/tcpip/stack/packet_buffer_test.go deleted file mode 100644 index c376ed1a1..000000000 --- a/pkg/tcpip/stack/packet_buffer_test.go +++ /dev/null @@ -1,655 +0,0 @@ -// Copyright 2020 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package stack - -import ( - "bytes" - "fmt" - "testing" - - "gvisor.dev/gvisor/pkg/tcpip/buffer" - "gvisor.dev/gvisor/pkg/tcpip/header" -) - -func TestPacketHeaderPush(t *testing.T) { - for _, test := range []struct { - name string - reserved int - link []byte - network []byte - transport []byte - data []byte - }{ - { - name: "construct empty packet", - }, - { - name: "construct link header only packet", - reserved: 60, - link: makeView(10), - }, - { - name: "construct link and network header only packet", - reserved: 60, - link: makeView(10), - network: makeView(20), - }, - { - name: "construct header only packet", - reserved: 60, - link: makeView(10), - network: makeView(20), - transport: makeView(30), - }, - { - name: "construct data only packet", - data: makeView(40), - }, - { - name: "construct L3 packet", - reserved: 60, - network: makeView(20), - transport: makeView(30), - data: makeView(40), - }, - { - name: "construct L2 packet", - reserved: 60, - link: makeView(10), - network: makeView(20), - transport: makeView(30), - data: makeView(40), - }, - } { - t.Run(test.name, func(t *testing.T) { - pk := NewPacketBuffer(PacketBufferOptions{ - ReserveHeaderBytes: test.reserved, - // Make a copy of data to make sure our truth data won't be taint by - // PacketBuffer. - Data: buffer.NewViewFromBytes(test.data).ToVectorisedView(), - }) - - allHdrSize := len(test.link) + len(test.network) + len(test.transport) - - // Check the initial values for packet. - checkInitialPacketBuffer(t, pk, PacketBufferOptions{ - ReserveHeaderBytes: test.reserved, - Data: buffer.View(test.data).ToVectorisedView(), - }) - - // Push headers. - if v := test.transport; len(v) > 0 { - copy(pk.TransportHeader().Push(len(v)), v) - } - if v := test.network; len(v) > 0 { - copy(pk.NetworkHeader().Push(len(v)), v) - } - if v := test.link; len(v) > 0 { - copy(pk.LinkHeader().Push(len(v)), v) - } - - // Check the after values for packet. - if got, want := pk.ReservedHeaderBytes(), test.reserved; got != want { - t.Errorf("After pk.ReservedHeaderBytes() = %d, want %d", got, want) - } - if got, want := pk.AvailableHeaderBytes(), test.reserved-allHdrSize; got != want { - t.Errorf("After pk.AvailableHeaderBytes() = %d, want %d", got, want) - } - if got, want := pk.HeaderSize(), allHdrSize; got != want { - t.Errorf("After pk.HeaderSize() = %d, want %d", got, want) - } - if got, want := pk.Size(), allHdrSize+len(test.data); got != want { - t.Errorf("After pk.Size() = %d, want %d", got, want) - } - // Check the after state. - checkPacketContents(t, "After ", pk, packetContents{ - link: test.link, - network: test.network, - transport: test.transport, - data: test.data, - }) - }) - } -} - -func TestPacketHeaderConsume(t *testing.T) { - for _, test := range []struct { - name string - data []byte - link int - network int - transport int - }{ - { - name: "parse L2 packet", - data: concatViews(makeView(10), makeView(20), makeView(30), makeView(40)), - link: 10, - network: 20, - transport: 30, - }, - { - name: "parse L3 packet", - data: concatViews(makeView(20), makeView(30), makeView(40)), - network: 20, - transport: 30, - }, - } { - t.Run(test.name, func(t *testing.T) { - pk := NewPacketBuffer(PacketBufferOptions{ - // Make a copy of data to make sure our truth data won't be taint by - // PacketBuffer. - Data: buffer.NewViewFromBytes(test.data).ToVectorisedView(), - }) - - // Check the initial values for packet. - checkInitialPacketBuffer(t, pk, PacketBufferOptions{ - Data: buffer.View(test.data).ToVectorisedView(), - }) - - // Consume headers. - if size := test.link; size > 0 { - if _, ok := pk.LinkHeader().Consume(size); !ok { - t.Fatalf("pk.LinkHeader().Consume() = false, want true") - } - } - if size := test.network; size > 0 { - if _, ok := pk.NetworkHeader().Consume(size); !ok { - t.Fatalf("pk.NetworkHeader().Consume() = false, want true") - } - } - if size := test.transport; size > 0 { - if _, ok := pk.TransportHeader().Consume(size); !ok { - t.Fatalf("pk.TransportHeader().Consume() = false, want true") - } - } - - allHdrSize := test.link + test.network + test.transport - - // Check the after values for packet. - if got, want := pk.ReservedHeaderBytes(), 0; got != want { - t.Errorf("After pk.ReservedHeaderBytes() = %d, want %d", got, want) - } - if got, want := pk.AvailableHeaderBytes(), 0; got != want { - t.Errorf("After pk.AvailableHeaderBytes() = %d, want %d", got, want) - } - if got, want := pk.HeaderSize(), allHdrSize; got != want { - t.Errorf("After pk.HeaderSize() = %d, want %d", got, want) - } - if got, want := pk.Size(), len(test.data); got != want { - t.Errorf("After pk.Size() = %d, want %d", got, want) - } - // Check the after state of pk. - checkPacketContents(t, "After ", pk, packetContents{ - link: test.data[:test.link], - network: test.data[test.link:][:test.network], - transport: test.data[test.link+test.network:][:test.transport], - data: test.data[allHdrSize:], - }) - }) - } -} - -func TestPacketHeaderConsumeDataTooShort(t *testing.T) { - data := makeView(10) - - pk := NewPacketBuffer(PacketBufferOptions{ - // Make a copy of data to make sure our truth data won't be taint by - // PacketBuffer. - Data: buffer.NewViewFromBytes(data).ToVectorisedView(), - }) - - // Consume should fail if pkt.Data is too short. - if _, ok := pk.LinkHeader().Consume(11); ok { - t.Fatalf("pk.LinkHeader().Consume() = _, true; want _, false") - } - if _, ok := pk.NetworkHeader().Consume(11); ok { - t.Fatalf("pk.NetworkHeader().Consume() = _, true; want _, false") - } - if _, ok := pk.TransportHeader().Consume(11); ok { - t.Fatalf("pk.TransportHeader().Consume() = _, true; want _, false") - } - - // Check packet should look the same as initial packet. - checkInitialPacketBuffer(t, pk, PacketBufferOptions{ - Data: buffer.View(data).ToVectorisedView(), - }) -} - -// This is a very obscure use-case seen in the code that verifies packets -// before sending them out. It tries to parse the headers to verify. -// PacketHeader was initially not designed to mix Push() and Consume(), but it -// works and it's been relied upon. Include a test here. -func TestPacketHeaderPushConsumeMixed(t *testing.T) { - link := makeView(10) - network := makeView(20) - data := makeView(30) - - initData := append([]byte(nil), network...) - initData = append(initData, data...) - pk := NewPacketBuffer(PacketBufferOptions{ - ReserveHeaderBytes: len(link), - Data: buffer.NewViewFromBytes(initData).ToVectorisedView(), - }) - - // 1. Consume network header - gotNetwork, ok := pk.NetworkHeader().Consume(len(network)) - if !ok { - t.Fatalf("pk.NetworkHeader().Consume(%d) = _, false; want _, true", len(network)) - } - checkViewEqual(t, "gotNetwork", gotNetwork, network) - - // 2. Push link header - copy(pk.LinkHeader().Push(len(link)), link) - - checkPacketContents(t, "" /* prefix */, pk, packetContents{ - link: link, - network: network, - data: data, - }) -} - -func TestPacketHeaderPushConsumeMixedTooLong(t *testing.T) { - link := makeView(10) - network := makeView(20) - data := makeView(30) - - initData := concatViews(network, data) - pk := NewPacketBuffer(PacketBufferOptions{ - ReserveHeaderBytes: len(link), - Data: buffer.NewViewFromBytes(initData).ToVectorisedView(), - }) - - // 1. Push link header - copy(pk.LinkHeader().Push(len(link)), link) - - checkPacketContents(t, "" /* prefix */, pk, packetContents{ - link: link, - data: initData, - }) - - // 2. Consume network header, with a number of bytes too large. - gotNetwork, ok := pk.NetworkHeader().Consume(len(initData) + 1) - if ok { - t.Fatalf("pk.NetworkHeader().Consume(%d) = %q, true; want _, false", len(initData)+1, gotNetwork) - } - - checkPacketContents(t, "" /* prefix */, pk, packetContents{ - link: link, - data: initData, - }) -} - -func TestPacketHeaderPushCalledAtMostOnce(t *testing.T) { - const headerSize = 10 - - pk := NewPacketBuffer(PacketBufferOptions{ - ReserveHeaderBytes: headerSize * int(numHeaderType), - }) - - for _, h := range []PacketHeader{ - pk.TransportHeader(), - pk.NetworkHeader(), - pk.LinkHeader(), - } { - t.Run("PushedTwice/"+h.typ.String(), func(t *testing.T) { - h.Push(headerSize) - - defer func() { recover() }() - h.Push(headerSize) - t.Fatal("Second push should have panicked") - }) - } -} - -func TestPacketHeaderConsumeCalledAtMostOnce(t *testing.T) { - const headerSize = 10 - - pk := NewPacketBuffer(PacketBufferOptions{ - Data: makeView(headerSize * int(numHeaderType)).ToVectorisedView(), - }) - - for _, h := range []PacketHeader{ - pk.LinkHeader(), - pk.NetworkHeader(), - pk.TransportHeader(), - } { - t.Run("ConsumedTwice/"+h.typ.String(), func(t *testing.T) { - if _, ok := h.Consume(headerSize); !ok { - t.Fatal("First consume should succeed") - } - - defer func() { recover() }() - h.Consume(headerSize) - t.Fatal("Second consume should have panicked") - }) - } -} - -func TestPacketHeaderPushThenConsumePanics(t *testing.T) { - const headerSize = 10 - - pk := NewPacketBuffer(PacketBufferOptions{ - ReserveHeaderBytes: headerSize * int(numHeaderType), - }) - - for _, h := range []PacketHeader{ - pk.TransportHeader(), - pk.NetworkHeader(), - pk.LinkHeader(), - } { - t.Run(h.typ.String(), func(t *testing.T) { - h.Push(headerSize) - - defer func() { recover() }() - h.Consume(headerSize) - t.Fatal("Consume should have panicked") - }) - } -} - -func TestPacketHeaderConsumeThenPushPanics(t *testing.T) { - const headerSize = 10 - - pk := NewPacketBuffer(PacketBufferOptions{ - Data: makeView(headerSize * int(numHeaderType)).ToVectorisedView(), - }) - - for _, h := range []PacketHeader{ - pk.LinkHeader(), - pk.NetworkHeader(), - pk.TransportHeader(), - } { - t.Run(h.typ.String(), func(t *testing.T) { - h.Consume(headerSize) - - defer func() { recover() }() - h.Push(headerSize) - t.Fatal("Push should have panicked") - }) - } -} - -func TestPacketBufferData(t *testing.T) { - for _, tc := range []struct { - name string - makePkt func(*testing.T) *PacketBuffer - data string - }{ - { - name: "inbound packet", - makePkt: func(*testing.T) *PacketBuffer { - pkt := NewPacketBuffer(PacketBufferOptions{ - Data: vv("aabbbbccccccDATA"), - }) - pkt.LinkHeader().Consume(2) - pkt.NetworkHeader().Consume(4) - pkt.TransportHeader().Consume(6) - return pkt - }, - data: "DATA", - }, - { - name: "outbound packet", - makePkt: func(*testing.T) *PacketBuffer { - pkt := NewPacketBuffer(PacketBufferOptions{ - ReserveHeaderBytes: 12, - Data: vv("DATA"), - }) - copy(pkt.TransportHeader().Push(6), []byte("cccccc")) - copy(pkt.NetworkHeader().Push(4), []byte("bbbb")) - copy(pkt.LinkHeader().Push(2), []byte("aa")) - return pkt - }, - data: "DATA", - }, - } { - t.Run(tc.name, func(t *testing.T) { - // PullUp - for _, n := range []int{1, len(tc.data)} { - t.Run(fmt.Sprintf("PullUp%d", n), func(t *testing.T) { - pkt := tc.makePkt(t) - v, ok := pkt.Data().PullUp(n) - wantV := []byte(tc.data)[:n] - if !ok || !bytes.Equal(v, wantV) { - t.Errorf("pkt.Data().PullUp(%d) = %q, %t; want %q, true", n, v, ok, wantV) - } - }) - } - t.Run("PullUpOutOfBounds", func(t *testing.T) { - n := len(tc.data) + 1 - pkt := tc.makePkt(t) - v, ok := pkt.Data().PullUp(n) - if ok || v != nil { - t.Errorf("pkt.Data().PullUp(%d) = %q, %t; want nil, false", n, v, ok) - } - }) - - // Consume. - for _, n := range []int{1, len(tc.data)} { - t.Run(fmt.Sprintf("Consume%d", n), func(t *testing.T) { - pkt := tc.makePkt(t) - v, ok := pkt.Data().Consume(n) - if !ok { - t.Fatalf("Consume failed") - } - if want := []byte(tc.data)[:n]; !bytes.Equal(v, want) { - t.Fatalf("pkt.Data().Consume(n) = 0x%x, want 0x%x", v, want) - } - - checkData(t, pkt, []byte(tc.data)[n:]) - }) - } - - // CapLength - for _, n := range []int{0, 1, len(tc.data)} { - t.Run(fmt.Sprintf("CapLength%d", n), func(t *testing.T) { - pkt := tc.makePkt(t) - pkt.Data().CapLength(n) - - want := []byte(tc.data) - if n < len(want) { - want = want[:n] - } - checkData(t, pkt, want) - }) - } - - // Views - t.Run("Views", func(t *testing.T) { - pkt := tc.makePkt(t) - checkData(t, pkt, []byte(tc.data)) - }) - - // AppendView - t.Run("AppendView", func(t *testing.T) { - s := "APPEND" - - pkt := tc.makePkt(t) - pkt.Data().AppendView(buffer.View(s)) - - checkData(t, pkt, []byte(tc.data+s)) - }) - - // ReadFromVV - for _, n := range []int{0, 1, 2, 7, 10, 14, 20} { - t.Run(fmt.Sprintf("ReadFromVV%d", n), func(t *testing.T) { - s := "TO READ" - srcVV := vv(s, s) - s += s - - pkt := tc.makePkt(t) - pkt.Data().ReadFromVV(&srcVV, n) - - if n < len(s) { - s = s[:n] - } - checkData(t, pkt, []byte(tc.data+s)) - }) - } - - // ExtractVV - t.Run("ExtractVV", func(t *testing.T) { - pkt := tc.makePkt(t) - extractedVV := pkt.Data().ExtractVV() - - got := extractedVV.ToOwnedView() - want := []byte(tc.data) - if !bytes.Equal(got, want) { - t.Errorf("pkt.Data().ExtractVV().ToOwnedView() = %q, want %q", got, want) - } - }) - }) - } -} - -type packetContents struct { - link buffer.View - network buffer.View - transport buffer.View - data buffer.View -} - -func checkPacketContents(t *testing.T, prefix string, pk *PacketBuffer, want packetContents) { - t.Helper() - // Headers. - checkPacketHeader(t, prefix+"pk.LinkHeader", pk.LinkHeader(), want.link) - checkPacketHeader(t, prefix+"pk.NetworkHeader", pk.NetworkHeader(), want.network) - checkPacketHeader(t, prefix+"pk.TransportHeader", pk.TransportHeader(), want.transport) - // Data. - checkData(t, pk, want.data) - // Whole packet. - checkViewEqual(t, prefix+"pk.Views()", - concatViews(pk.Views()...), - concatViews(want.link, want.network, want.transport, want.data)) - // PayloadSince. - checkViewEqual(t, prefix+"PayloadSince(LinkHeader)", - PayloadSince(pk.LinkHeader()), - concatViews(want.link, want.network, want.transport, want.data)) - checkViewEqual(t, prefix+"PayloadSince(NetworkHeader)", - PayloadSince(pk.NetworkHeader()), - concatViews(want.network, want.transport, want.data)) - checkViewEqual(t, prefix+"PayloadSince(TransportHeader)", - PayloadSince(pk.TransportHeader()), - concatViews(want.transport, want.data)) -} - -func checkInitialPacketBuffer(t *testing.T, pk *PacketBuffer, opts PacketBufferOptions) { - t.Helper() - reserved := opts.ReserveHeaderBytes - if got, want := pk.ReservedHeaderBytes(), reserved; got != want { - t.Errorf("Initial pk.ReservedHeaderBytes() = %d, want %d", got, want) - } - if got, want := pk.AvailableHeaderBytes(), reserved; got != want { - t.Errorf("Initial pk.AvailableHeaderBytes() = %d, want %d", got, want) - } - if got, want := pk.HeaderSize(), 0; got != want { - t.Errorf("Initial pk.HeaderSize() = %d, want %d", got, want) - } - data := opts.Data.ToView() - if got, want := pk.Size(), len(data); got != want { - t.Errorf("Initial pk.Size() = %d, want %d", got, want) - } - checkPacketContents(t, "Initial ", pk, packetContents{ - data: data, - }) -} - -func checkPacketHeader(t *testing.T, name string, h PacketHeader, want []byte) { - t.Helper() - checkViewEqual(t, name+".View()", h.View(), want) -} - -func checkViewEqual(t *testing.T, what string, got, want buffer.View) { - t.Helper() - if !bytes.Equal(got, want) { - t.Errorf("%s = %x, want %x", what, got, want) - } -} - -func checkData(t *testing.T, pkt *PacketBuffer, want []byte) { - t.Helper() - if got := concatViews(pkt.Data().Views()...); !bytes.Equal(got, want) { - t.Errorf("pkt.Data().Views() = 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)) - } - - t.Run("AsRange", func(t *testing.T) { - // Full range - checkRange(t, pkt.Data().AsRange(), want) - - // SubRange - for _, off := range []int{0, 1, len(want), len(want) + 1} { - t.Run(fmt.Sprintf("SubRange%d", off), func(t *testing.T) { - // Empty when off is greater than the size of range. - var sub []byte - if off < len(want) { - sub = want[off:] - } - checkRange(t, pkt.Data().AsRange().SubRange(off), sub) - }) - } - - // Capped - for _, n := range []int{0, 1, len(want), len(want) + 1} { - t.Run(fmt.Sprintf("Capped%d", n), func(t *testing.T) { - sub := want - if n < len(sub) { - sub = sub[:n] - } - checkRange(t, pkt.Data().AsRange().Capped(n), sub) - }) - } - }) -} - -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, want := r.Checksum(), header.Checksum(data, 0 /* initial */); got != want { - t.Errorf("r.Checksum() = %x, want %x", got, want) - } -} - -func vv(pieces ...string) buffer.VectorisedView { - var views []buffer.View - var size int - for _, p := range pieces { - v := buffer.View([]byte(p)) - size += len(v) - views = append(views, v) - } - return buffer.NewVectorisedView(size, views) -} - -func makeView(size int) buffer.View { - b := byte(size) - return bytes.Repeat([]byte{b}, size) -} - -func concatViews(views ...buffer.View) buffer.View { - var all buffer.View - for _, v := range views { - all = append(all, v...) - } - return all -} |