gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/stack/packet_buffer_test.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at //
     6  //     http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package stack
    15  
    16  import (
    17  	"bytes"
    18  	"fmt"
    19  	"testing"
    20  
    21  	"gvisor.dev/gvisor/pkg/buffer"
    22  )
    23  
    24  func TestPacketHeaderPush(t *testing.T) {
    25  	for _, test := range []struct {
    26  		name      string
    27  		reserved  int
    28  		link      []byte
    29  		network   []byte
    30  		transport []byte
    31  		data      []byte
    32  	}{
    33  		{
    34  			name: "construct empty packet",
    35  		},
    36  		{
    37  			name:     "construct link header only packet",
    38  			reserved: 60,
    39  			link:     makeView(10),
    40  		},
    41  		{
    42  			name:     "construct link and network header only packet",
    43  			reserved: 60,
    44  			link:     makeView(10),
    45  			network:  makeView(20),
    46  		},
    47  		{
    48  			name:      "construct header only packet",
    49  			reserved:  60,
    50  			link:      makeView(10),
    51  			network:   makeView(20),
    52  			transport: makeView(30),
    53  		},
    54  		{
    55  			name: "construct data only packet",
    56  			data: makeView(40),
    57  		},
    58  		{
    59  			name:      "construct L3 packet",
    60  			reserved:  60,
    61  			network:   makeView(20),
    62  			transport: makeView(30),
    63  			data:      makeView(40),
    64  		},
    65  		{
    66  			name:      "construct L2 packet",
    67  			reserved:  60,
    68  			link:      makeView(10),
    69  			network:   makeView(20),
    70  			transport: makeView(30),
    71  			data:      makeView(40),
    72  		},
    73  	} {
    74  		t.Run(test.name, func(t *testing.T) {
    75  			pk := NewPacketBuffer(PacketBufferOptions{
    76  				ReserveHeaderBytes: test.reserved,
    77  				// Make a copy of data to make sure our truth data won't be taint by
    78  				// PacketBuffer.
    79  				Payload: buffer.MakeWithData(test.data),
    80  			})
    81  
    82  			allHdrSize := len(test.link) + len(test.network) + len(test.transport)
    83  
    84  			// Check the initial values for packet.
    85  			checkInitialPacketBuffer(t, pk, PacketBufferOptions{
    86  				ReserveHeaderBytes: test.reserved,
    87  				Payload:            buffer.MakeWithData(test.data),
    88  			})
    89  
    90  			// Push headers.
    91  			if v := test.transport; len(v) > 0 {
    92  				copy(pk.TransportHeader().Push(len(v)), v)
    93  			}
    94  			if v := test.network; len(v) > 0 {
    95  				copy(pk.NetworkHeader().Push(len(v)), v)
    96  			}
    97  			if v := test.link; len(v) > 0 {
    98  				copy(pk.LinkHeader().Push(len(v)), v)
    99  			}
   100  
   101  			// Check the after values for packet.
   102  			if got, want := pk.ReservedHeaderBytes(), test.reserved; got != want {
   103  				t.Errorf("After pk.ReservedHeaderBytes() = %d, want %d", got, want)
   104  			}
   105  			if got, want := pk.AvailableHeaderBytes(), test.reserved-allHdrSize; got != want {
   106  				t.Errorf("After pk.AvailableHeaderBytes() = %d, want %d", got, want)
   107  			}
   108  			if got, want := pk.HeaderSize(), allHdrSize; got != want {
   109  				t.Errorf("After pk.HeaderSize() = %d, want %d", got, want)
   110  			}
   111  			if got, want := pk.Size(), allHdrSize+len(test.data); got != want {
   112  				t.Errorf("After pk.Size() = %d, want %d", got, want)
   113  			}
   114  			// Check the after state.
   115  			checkPacketContents(t, "After ", pk, packetContents{
   116  				link:      test.link,
   117  				network:   test.network,
   118  				transport: test.transport,
   119  				data:      test.data,
   120  			})
   121  		})
   122  	}
   123  }
   124  
   125  func TestPacketHeaderConsume(t *testing.T) {
   126  	for _, test := range []struct {
   127  		name      string
   128  		data      []byte
   129  		link      int
   130  		network   int
   131  		transport int
   132  	}{
   133  		{
   134  			name:      "parse L2 packet",
   135  			data:      concatViews(makeView(10), makeView(20), makeView(30), makeView(40)),
   136  			link:      10,
   137  			network:   20,
   138  			transport: 30,
   139  		},
   140  		{
   141  			name:      "parse L3 packet",
   142  			data:      concatViews(makeView(20), makeView(30), makeView(40)),
   143  			network:   20,
   144  			transport: 30,
   145  		},
   146  	} {
   147  		t.Run(test.name, func(t *testing.T) {
   148  			pk := NewPacketBuffer(PacketBufferOptions{
   149  				// Make a copy of data to make sure our truth data won't be taint by
   150  				// PacketBuffer.
   151  				Payload: buffer.MakeWithData(test.data),
   152  			})
   153  
   154  			// Check the initial values for packet.
   155  			checkInitialPacketBuffer(t, pk, PacketBufferOptions{
   156  				Payload: buffer.MakeWithData(test.data),
   157  			})
   158  
   159  			// Consume headers.
   160  			if size := test.link; size > 0 {
   161  				if _, ok := pk.LinkHeader().Consume(size); !ok {
   162  					t.Fatalf("pk.LinkHeader().Consume() = false, want true")
   163  				}
   164  			}
   165  			if size := test.network; size > 0 {
   166  				if _, ok := pk.NetworkHeader().Consume(size); !ok {
   167  					t.Fatalf("pk.NetworkHeader().Consume() = false, want true")
   168  				}
   169  			}
   170  			if size := test.transport; size > 0 {
   171  				if _, ok := pk.TransportHeader().Consume(size); !ok {
   172  					t.Fatalf("pk.TransportHeader().Consume() = false, want true")
   173  				}
   174  			}
   175  
   176  			allHdrSize := test.link + test.network + test.transport
   177  
   178  			// Check the after values for packet.
   179  			if got, want := pk.ReservedHeaderBytes(), 0; got != want {
   180  				t.Errorf("After pk.ReservedHeaderBytes() = %d, want %d", got, want)
   181  			}
   182  			if got, want := pk.AvailableHeaderBytes(), 0; got != want {
   183  				t.Errorf("After pk.AvailableHeaderBytes() = %d, want %d", got, want)
   184  			}
   185  			if got, want := pk.HeaderSize(), allHdrSize; got != want {
   186  				t.Errorf("After pk.HeaderSize() = %d, want %d", got, want)
   187  			}
   188  			if got, want := pk.Size(), len(test.data); got != want {
   189  				t.Errorf("After pk.Size() = %d, want %d", got, want)
   190  			}
   191  			// Check the after state of pk.
   192  			checkPacketContents(t, "After ", pk, packetContents{
   193  				link:      test.data[:test.link],
   194  				network:   test.data[test.link:][:test.network],
   195  				transport: test.data[test.link+test.network:][:test.transport],
   196  				data:      test.data[allHdrSize:],
   197  			})
   198  		})
   199  	}
   200  }
   201  
   202  func TestPacketHeaderConsumeDataTooShort(t *testing.T) {
   203  	data := makeView(10)
   204  
   205  	pk := NewPacketBuffer(PacketBufferOptions{
   206  		// Make a copy of data to make sure our truth data won't be taint by
   207  		// PacketBuffer.
   208  		Payload: buffer.MakeWithData(data),
   209  	})
   210  
   211  	// Consume should fail if pkt.Data is too short.
   212  	if _, ok := pk.LinkHeader().Consume(11); ok {
   213  		t.Fatalf("pk.LinkHeader().Consume() = _, true; want _, false")
   214  	}
   215  	if _, ok := pk.NetworkHeader().Consume(11); ok {
   216  		t.Fatalf("pk.NetworkHeader().Consume() = _, true; want _, false")
   217  	}
   218  	if _, ok := pk.TransportHeader().Consume(11); ok {
   219  		t.Fatalf("pk.TransportHeader().Consume() = _, true; want _, false")
   220  	}
   221  
   222  	// Check packet should look the same as initial packet.
   223  	checkInitialPacketBuffer(t, pk, PacketBufferOptions{
   224  		Payload: buffer.MakeWithData(data),
   225  	})
   226  }
   227  
   228  // This is a very obscure use-case seen in the code that verifies packets
   229  // before sending them out. It tries to parse the headers to verify.
   230  // PacketHeader was initially not designed to mix Push() and Consume(), but it
   231  // works and it's been relied upon. Include a test here.
   232  func TestPacketHeaderPushConsumeMixed(t *testing.T) {
   233  	link := makeView(10)
   234  	network := makeView(20)
   235  	data := makeView(30)
   236  
   237  	initData := append([]byte(nil), network...)
   238  	initData = append(initData, data...)
   239  	pk := NewPacketBuffer(PacketBufferOptions{
   240  		ReserveHeaderBytes: len(link),
   241  		Payload:            buffer.MakeWithData(initData),
   242  	})
   243  
   244  	// 1. Consume network header
   245  	gotNetwork, ok := pk.NetworkHeader().Consume(len(network))
   246  	if !ok {
   247  		t.Fatalf("pk.NetworkHeader().Consume(%d) = _, false; want _, true", len(network))
   248  	}
   249  	checkViewEqual(t, "gotNetwork", gotNetwork, network)
   250  
   251  	// 2. Push link header
   252  	copy(pk.LinkHeader().Push(len(link)), link)
   253  
   254  	checkPacketContents(t, "" /* prefix */, pk, packetContents{
   255  		link:    link,
   256  		network: network,
   257  		data:    data,
   258  	})
   259  }
   260  
   261  func TestPacketHeaderPushConsumeMixedTooLong(t *testing.T) {
   262  	link := makeView(10)
   263  	network := makeView(20)
   264  	data := makeView(30)
   265  
   266  	initData := concatViews(network, data)
   267  	pk := NewPacketBuffer(PacketBufferOptions{
   268  		ReserveHeaderBytes: len(link),
   269  		Payload:            buffer.MakeWithData(initData),
   270  	})
   271  
   272  	// 1. Push link header
   273  	copy(pk.LinkHeader().Push(len(link)), link)
   274  
   275  	checkPacketContents(t, "" /* prefix */, pk, packetContents{
   276  		link: link,
   277  		data: initData,
   278  	})
   279  
   280  	// 2. Consume network header, with a number of bytes too large.
   281  	gotNetwork, ok := pk.NetworkHeader().Consume(len(initData) + 1)
   282  	if ok {
   283  		t.Fatalf("pk.NetworkHeader().Consume(%d) = %q, true; want _, false", len(initData)+1, gotNetwork)
   284  	}
   285  
   286  	checkPacketContents(t, "" /* prefix */, pk, packetContents{
   287  		link: link,
   288  		data: initData,
   289  	})
   290  }
   291  
   292  func TestPacketHeaderPushCalledAtMostOnce(t *testing.T) {
   293  	const headerSize = 10
   294  
   295  	pk := NewPacketBuffer(PacketBufferOptions{
   296  		ReserveHeaderBytes: headerSize * int(numHeaderType),
   297  	})
   298  
   299  	for _, h := range []PacketHeader{
   300  		pk.TransportHeader(),
   301  		pk.NetworkHeader(),
   302  		pk.LinkHeader(),
   303  	} {
   304  		t.Run("PushedTwice/"+h.typ.String(), func(t *testing.T) {
   305  			h.Push(headerSize)
   306  
   307  			defer func() { recover() }()
   308  			h.Push(headerSize)
   309  			t.Fatal("Second push should have panicked")
   310  		})
   311  	}
   312  }
   313  
   314  func TestPacketHeaderConsumeCalledAtMostOnce(t *testing.T) {
   315  	const headerSize = 10
   316  
   317  	pk := NewPacketBuffer(PacketBufferOptions{
   318  		Payload: buffer.MakeWithData(make([]byte, headerSize*int(numHeaderType))),
   319  	})
   320  
   321  	for _, h := range []PacketHeader{
   322  		pk.LinkHeader(),
   323  		pk.NetworkHeader(),
   324  		pk.TransportHeader(),
   325  	} {
   326  		t.Run("ConsumedTwice/"+h.typ.String(), func(t *testing.T) {
   327  			if _, ok := h.Consume(headerSize); !ok {
   328  				t.Fatal("First consume should succeed")
   329  			}
   330  
   331  			defer func() { recover() }()
   332  			h.Consume(headerSize)
   333  			t.Fatal("Second consume should have panicked")
   334  		})
   335  	}
   336  }
   337  
   338  func TestReserveHeadersAllowsPush(t *testing.T) {
   339  	link1 := makeView(10)
   340  	pk := NewPacketBuffer(PacketBufferOptions{})
   341  	pk.ReserveHeaderBytes(len(link1))
   342  
   343  	copy(pk.LinkHeader().Push(len(link1)), link1)
   344  	checkPacketContents(t, "" /* prefix */, pk, packetContents{
   345  		link: link1,
   346  	})
   347  }
   348  
   349  func TestPacketHeaderPushThenConsumePanics(t *testing.T) {
   350  	const headerSize = 10
   351  
   352  	pk := NewPacketBuffer(PacketBufferOptions{
   353  		ReserveHeaderBytes: headerSize * int(numHeaderType),
   354  	})
   355  
   356  	for _, h := range []PacketHeader{
   357  		pk.TransportHeader(),
   358  		pk.NetworkHeader(),
   359  		pk.LinkHeader(),
   360  	} {
   361  		t.Run(h.typ.String(), func(t *testing.T) {
   362  			h.Push(headerSize)
   363  
   364  			defer func() { recover() }()
   365  			h.Consume(headerSize)
   366  			t.Fatal("Consume should have panicked")
   367  		})
   368  	}
   369  }
   370  
   371  func TestPacketHeaderConsumeThenPushPanics(t *testing.T) {
   372  	const headerSize = 10
   373  
   374  	pk := NewPacketBuffer(PacketBufferOptions{
   375  		Payload: buffer.MakeWithData(make([]byte, headerSize*int(numHeaderType))),
   376  	})
   377  
   378  	for _, h := range []PacketHeader{
   379  		pk.LinkHeader(),
   380  		pk.NetworkHeader(),
   381  		pk.TransportHeader(),
   382  	} {
   383  		t.Run(h.typ.String(), func(t *testing.T) {
   384  			h.Consume(headerSize)
   385  
   386  			defer func() { recover() }()
   387  			h.Push(headerSize)
   388  			t.Fatal("Push should have panicked")
   389  		})
   390  	}
   391  }
   392  
   393  func TestPacketBufferData(t *testing.T) {
   394  	for _, tc := range []struct {
   395  		name    string
   396  		makePkt func(*testing.T) *PacketBuffer
   397  		data    string
   398  	}{
   399  		{
   400  			name: "inbound packet",
   401  			makePkt: func(*testing.T) *PacketBuffer {
   402  				pkt := NewPacketBuffer(PacketBufferOptions{
   403  					Payload: buf("aabbbbccccccDATA"),
   404  				})
   405  				pkt.LinkHeader().Consume(2)
   406  				pkt.NetworkHeader().Consume(4)
   407  				pkt.TransportHeader().Consume(6)
   408  				return pkt
   409  			},
   410  			data: "DATA",
   411  		},
   412  		{
   413  			name: "outbound packet",
   414  			makePkt: func(*testing.T) *PacketBuffer {
   415  				pkt := NewPacketBuffer(PacketBufferOptions{
   416  					ReserveHeaderBytes: 12,
   417  					Payload:            buf("DATA"),
   418  				})
   419  				copy(pkt.TransportHeader().Push(6), []byte("cccccc"))
   420  				copy(pkt.NetworkHeader().Push(4), []byte("bbbb"))
   421  				copy(pkt.LinkHeader().Push(2), []byte("aa"))
   422  				return pkt
   423  			},
   424  			data: "DATA",
   425  		},
   426  	} {
   427  		t.Run(tc.name, func(t *testing.T) {
   428  			// PullUp
   429  			t.Run("PullUp", func(t *testing.T) {
   430  				for _, n := range []int{1, len(tc.data)} {
   431  					t.Run(fmt.Sprintf("%dbytes", n), func(t *testing.T) {
   432  						pkt := tc.makePkt(t)
   433  						v, ok := pkt.Data().PullUp(n)
   434  						wantV := []byte(tc.data)[:n]
   435  						if !ok || !bytes.Equal(v, wantV) {
   436  							t.Errorf("pkt.Data().PullUp(%d) = %q, %t; want %q, true", n, v, ok, wantV)
   437  						}
   438  					})
   439  				}
   440  			})
   441  
   442  			t.Run("PullUpOutOfBounds", func(t *testing.T) {
   443  				n := len(tc.data) + 1
   444  				pkt := tc.makePkt(t)
   445  				v, ok := pkt.Data().PullUp(n)
   446  				if ok || v != nil {
   447  					t.Errorf("pkt.Data().PullUp(%d) = %q, %t; want nil, false", n, v, ok)
   448  				}
   449  			})
   450  
   451  			// Consume.
   452  			t.Run("Consume", func(t *testing.T) {
   453  				for _, n := range []int{1, len(tc.data)} {
   454  					t.Run(fmt.Sprintf("%dbytes", n), func(t *testing.T) {
   455  						pkt := tc.makePkt(t)
   456  						v, ok := pkt.Data().Consume(n)
   457  						if !ok {
   458  							t.Fatalf("Consume failed")
   459  						}
   460  						if want := []byte(tc.data)[:n]; !bytes.Equal(v, want) {
   461  							t.Fatalf("pkt.Data().Consume(n) = 0x%x, want 0x%x", v, want)
   462  						}
   463  
   464  						checkData(t, pkt, []byte(tc.data)[n:])
   465  					})
   466  				}
   467  			})
   468  
   469  			// CapLength
   470  			t.Run("CapLength", func(t *testing.T) {
   471  				for _, n := range []int{0, 1, len(tc.data)} {
   472  					t.Run("%dbytes", func(t *testing.T) {
   473  						pkt := tc.makePkt(t)
   474  						pkt.Data().CapLength(n)
   475  
   476  						want := []byte(tc.data)
   477  						if n < len(want) {
   478  							want = want[:n]
   479  						}
   480  						checkData(t, pkt, want)
   481  					})
   482  				}
   483  			})
   484  
   485  			// Views
   486  			t.Run("Views", func(t *testing.T) {
   487  				pkt := tc.makePkt(t)
   488  				checkData(t, pkt, []byte(tc.data))
   489  			})
   490  
   491  			// AppendView
   492  			t.Run("AppendView", func(t *testing.T) {
   493  				s := "APPEND"
   494  
   495  				pkt := tc.makePkt(t)
   496  				pkt.Data().AppendView(buffer.NewViewWithData([]byte(s)))
   497  
   498  				checkData(t, pkt, []byte(tc.data+s))
   499  			})
   500  
   501  			t.Run("Merge", func(t *testing.T) {
   502  				pkt1 := tc.makePkt(t)
   503  				pkt2 := tc.makePkt(t)
   504  				pkt1.Data().Merge(pkt2.Data())
   505  
   506  				checkData(t, pkt1, []byte(tc.data+tc.data))
   507  				if pkt2.buf.Size() != 0 {
   508  					t.Errorf("pkt.buf.Size() = %v, want %v", 0, pkt2.buf.Size())
   509  				}
   510  			})
   511  
   512  			t.Run("TrimFront", func(t *testing.T) {
   513  				for _, n := range []int{0, 1, 2, 7, 10, 14, 20} {
   514  					t.Run(fmt.Sprintf("%dbytes", n), func(t *testing.T) {
   515  						pkt := tc.makePkt(t)
   516  						pkt.Data().TrimFront(n)
   517  
   518  						want := ""
   519  						if n < len(tc.data) {
   520  							want = tc.data[n:]
   521  						}
   522  						checkData(t, pkt, []byte(want))
   523  					})
   524  				}
   525  			})
   526  
   527  			// ReadFromBuffer
   528  			for _, n := range []int{0, 1, 2, 7, 10, 14, 20} {
   529  				t.Run(fmt.Sprintf("ReadFrom%d", n), func(t *testing.T) {
   530  					s := "TO READ"
   531  					s += s
   532  					srcBuf := buffer.MakeWithData([]byte(s))
   533  
   534  					pkt := tc.makePkt(t)
   535  					pkt.Data().ReadFrom(&srcBuf, n)
   536  
   537  					if n < len(s) {
   538  						s = s[:n]
   539  					}
   540  					checkData(t, pkt, []byte(tc.data+s))
   541  				})
   542  			}
   543  		})
   544  	}
   545  }
   546  
   547  func TestPacketBufferId(t *testing.T) {
   548  	pk := NewPacketBuffer(PacketBufferOptions{
   549  		ReserveHeaderBytes: 12,
   550  	})
   551  
   552  	id := pk.ID()
   553  	// The ID should be stable
   554  	if idAgain := pk.ID(); idAgain != id {
   555  		t.Errorf("pk.ID() = %d, want %d", idAgain, id)
   556  	}
   557  
   558  	// Shallow copies have the same ID.
   559  	pkShallowCopy := pk
   560  	if shallowCopyID := pkShallowCopy.ID(); shallowCopyID != id {
   561  		t.Errorf("pkShallowCopy.ID() = %d, want %d", shallowCopyID, id)
   562  	}
   563  
   564  	// Clones have different IDs.
   565  	pkClone := pk.Clone()
   566  	if cloneID := pkClone.ID(); cloneID == id {
   567  		t.Errorf("pkClone.ID() = %d = pk.ID(), but pk = %#v, pkClone = %#v", cloneID, pk, pkClone)
   568  	}
   569  
   570  	pk2 := NewPacketBuffer(PacketBufferOptions{ReserveHeaderBytes: 12})
   571  	if id2 := pk2.ID(); id2 == id {
   572  		t.Errorf("pk2.ID() = %d = pk.ID(), but pk = %#v, pk2 = %#v", id2, pk, pk2)
   573  	}
   574  }
   575  
   576  type packetContents struct {
   577  	link      []byte
   578  	network   []byte
   579  	transport []byte
   580  	data      []byte
   581  }
   582  
   583  func checkPacketContents(t *testing.T, prefix string, pk *PacketBuffer, want packetContents) {
   584  	t.Helper()
   585  	// Headers.
   586  	checkPacketHeader(t, prefix+"pk.LinkHeader", pk.LinkHeader(), want.link)
   587  	checkPacketHeader(t, prefix+"pk.NetworkHeader", pk.NetworkHeader(), want.network)
   588  	checkPacketHeader(t, prefix+"pk.TransportHeader", pk.TransportHeader(), want.transport)
   589  	// Data.
   590  	checkData(t, pk, want.data)
   591  	// Whole packet.
   592  	checkViewEqual(t, prefix+"pk.AsSlices()",
   593  		concatViews(pk.AsSlices()...),
   594  		concatViews(want.link, want.network, want.transport, want.data))
   595  	// PayloadSince.
   596  	link := PayloadSince(pk.LinkHeader())
   597  	checkViewEqual(t, prefix+"PayloadSince(LinkHeader)",
   598  		link.AsSlice(),
   599  		concatViews(want.link, want.network, want.transport, want.data))
   600  	net := PayloadSince(pk.NetworkHeader())
   601  	checkViewEqual(t, prefix+"PayloadSince(NetworkHeader)",
   602  		net.AsSlice(),
   603  		concatViews(want.network, want.transport, want.data))
   604  	trans := PayloadSince(pk.TransportHeader())
   605  	checkViewEqual(t, prefix+"PayloadSince(TransportHeader)",
   606  		trans.AsSlice(),
   607  		concatViews(want.transport, want.data))
   608  	// BufferSince.
   609  	linkBuf := BufferSince(pk.LinkHeader())
   610  	checkViewEqual(t, prefix+"PayloadSince(LinkHeader)",
   611  		linkBuf.Flatten(),
   612  		concatViews(want.link, want.network, want.transport, want.data))
   613  	netBuf := BufferSince(pk.NetworkHeader())
   614  	checkViewEqual(t, prefix+"PayloadSince(NetworkHeader)",
   615  		netBuf.Flatten(),
   616  		concatViews(want.network, want.transport, want.data))
   617  	transBuf := BufferSince(pk.TransportHeader())
   618  	checkViewEqual(t, prefix+"PayloadSince(TransportHeader)",
   619  		transBuf.Flatten(),
   620  		concatViews(want.transport, want.data))
   621  }
   622  
   623  func checkInitialPacketBuffer(t *testing.T, pk *PacketBuffer, opts PacketBufferOptions) {
   624  	t.Helper()
   625  	reserved := opts.ReserveHeaderBytes
   626  	if got, want := pk.ReservedHeaderBytes(), reserved; got != want {
   627  		t.Errorf("Initial pk.ReservedHeaderBytes() = %d, want %d", got, want)
   628  	}
   629  	if got, want := pk.AvailableHeaderBytes(), reserved; got != want {
   630  		t.Errorf("Initial pk.AvailableHeaderBytes() = %d, want %d", got, want)
   631  	}
   632  	if got, want := pk.HeaderSize(), 0; got != want {
   633  		t.Errorf("Initial pk.HeaderSize() = %d, want %d", got, want)
   634  	}
   635  	data := opts.Payload.Flatten()
   636  	if got, want := pk.Size(), len(data); got != want {
   637  		t.Errorf("Initial pk.Size() = %d, want %d", got, want)
   638  	}
   639  	checkPacketContents(t, "Initial ", pk, packetContents{
   640  		data: data,
   641  	})
   642  }
   643  
   644  func checkPacketHeader(t *testing.T, name string, h PacketHeader, want []byte) {
   645  	t.Helper()
   646  	checkViewEqual(t, name+".Slice()", h.Slice(), want)
   647  }
   648  
   649  func checkViewEqual(t *testing.T, what string, got, want []byte) {
   650  	t.Helper()
   651  	if !bytes.Equal(got, want) {
   652  		t.Errorf("%s = %x, want %x", what, got, want)
   653  	}
   654  }
   655  
   656  func checkData(t *testing.T, pkt *PacketBuffer, want []byte) {
   657  	t.Helper()
   658  	if got := pkt.Data().AsRange().ToSlice(); !bytes.Equal(got, want) {
   659  		t.Errorf("pkt.Data().Slices() = 0x%x, want 0x%x", got, want)
   660  	}
   661  	if got := pkt.Data().Size(); got != len(want) {
   662  		t.Errorf("pkt.Data().Size() = %d, want %d", got, len(want))
   663  	}
   664  
   665  	t.Run("AsRange", func(t *testing.T) {
   666  		// Full range
   667  		checkRange(t, pkt.Data().AsRange(), want)
   668  
   669  		// SubRange
   670  		for _, off := range []int{0, 1, len(want), len(want) + 1} {
   671  			t.Run(fmt.Sprintf("SubRange%d", off), func(t *testing.T) {
   672  				// Empty when off is greater than the size of range.
   673  				var sub []byte
   674  				if off < len(want) {
   675  					sub = want[off:]
   676  				}
   677  				checkRange(t, pkt.Data().AsRange().SubRange(off), sub)
   678  			})
   679  		}
   680  
   681  		// Capped
   682  		for _, n := range []int{0, 1, len(want), len(want) + 1} {
   683  			t.Run(fmt.Sprintf("Capped%d", n), func(t *testing.T) {
   684  				sub := want
   685  				if n < len(sub) {
   686  					sub = sub[:n]
   687  				}
   688  				checkRange(t, pkt.Data().AsRange().Capped(n), sub)
   689  			})
   690  		}
   691  	})
   692  }
   693  
   694  func checkRange(t *testing.T, r Range, data []byte) {
   695  	if got, want := r.Size(), len(data); got != want {
   696  		t.Errorf("r.Size() = %d, want %d", got, want)
   697  	}
   698  	if got := r.ToSlice(); !bytes.Equal(got, data) {
   699  		t.Errorf("r.AsSlice() = %x, want %x", got, data)
   700  	}
   701  }
   702  
   703  func buf(pieces ...string) buffer.Buffer {
   704  	b := buffer.Buffer{}
   705  	for _, p := range pieces {
   706  		b.Append(buffer.NewViewWithData([]byte(p)))
   707  	}
   708  	return b
   709  }
   710  
   711  func makeView(size int) []byte {
   712  	b := byte(size)
   713  	return bytes.Repeat([]byte{b}, size)
   714  }
   715  
   716  func concatViews(views ...[]byte) []byte {
   717  	var all []byte
   718  	for _, v := range views {
   719  		all = append(all, v...)
   720  	}
   721  	return all
   722  }