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

     1  // Copyright 2019 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  	"fmt"
    18  	"io"
    19  
    20  	"gvisor.dev/gvisor/pkg/buffer"
    21  	"gvisor.dev/gvisor/pkg/sync"
    22  	"gvisor.dev/gvisor/pkg/tcpip"
    23  	"gvisor.dev/gvisor/pkg/tcpip/header"
    24  )
    25  
    26  type headerType int
    27  
    28  const (
    29  	virtioNetHeader headerType = iota
    30  	linkHeader
    31  	networkHeader
    32  	transportHeader
    33  	numHeaderType
    34  )
    35  
    36  var pkPool = sync.Pool{
    37  	New: func() any {
    38  		return &PacketBuffer{}
    39  	},
    40  }
    41  
    42  // PacketBufferOptions specifies options for PacketBuffer creation.
    43  type PacketBufferOptions struct {
    44  	// ReserveHeaderBytes is the number of bytes to reserve for headers. Total
    45  	// number of bytes pushed onto the headers must not exceed this value.
    46  	ReserveHeaderBytes int
    47  
    48  	// Payload is the initial unparsed data for the new packet. If set, it will
    49  	// be owned by the new packet.
    50  	Payload buffer.Buffer
    51  
    52  	// IsForwardedPacket identifies that the PacketBuffer being created is for a
    53  	// forwarded packet.
    54  	IsForwardedPacket bool
    55  
    56  	// OnRelease is a function to be run when the packet buffer is no longer
    57  	// referenced (released back to the pool).
    58  	OnRelease func()
    59  }
    60  
    61  // A PacketBuffer contains all the data of a network packet.
    62  //
    63  // As a PacketBuffer traverses up the stack, it may be necessary to pass it to
    64  // multiple endpoints.
    65  //
    66  // The whole packet is expected to be a series of bytes in the following order:
    67  // LinkHeader, NetworkHeader, TransportHeader, and Data. Any of them can be
    68  // empty. Use of PacketBuffer in any other order is unsupported.
    69  //
    70  // PacketBuffer must be created with NewPacketBuffer, which sets the initial
    71  // reference count to 1. Owners should call `DecRef()` when they are finished
    72  // with the buffer to return it to the pool.
    73  //
    74  // Internal structure: A PacketBuffer holds a pointer to buffer.Buffer, which
    75  // exposes a logically-contiguous byte storage. The underlying storage structure
    76  // is abstracted out, and should not be a concern here for most of the time.
    77  //
    78  //	|- reserved ->|
    79  //								|--->| consumed (incoming)
    80  //	0             V    V
    81  //	+--------+----+----+--------------------+
    82  //	|        |    |    | current data ...   | (buf)
    83  //	+--------+----+----+--------------------+
    84  //					 ^    |
    85  //					 |<---| pushed (outgoing)
    86  //
    87  // When a PacketBuffer is created, a `reserved` header region can be specified,
    88  // which stack pushes headers in this region for an outgoing packet. There could
    89  // be no such region for an incoming packet, and `reserved` is 0. The value of
    90  // `reserved` never changes in the entire lifetime of the packet.
    91  //
    92  // Outgoing Packet: When a header is pushed, `pushed` gets incremented by the
    93  // pushed length, and the current value is stored for each header. PacketBuffer
    94  // subtracts this value from `reserved` to compute the starting offset of each
    95  // header in `buf`.
    96  //
    97  // Incoming Packet: When a header is consumed (a.k.a. parsed), the current
    98  // `consumed` value is stored for each header, and it gets incremented by the
    99  // consumed length. PacketBuffer adds this value to `reserved` to compute the
   100  // starting offset of each header in `buf`.
   101  //
   102  // +stateify savable
   103  type PacketBuffer struct {
   104  	_ sync.NoCopy
   105  
   106  	packetBufferRefs
   107  
   108  	// buf is the underlying buffer for the packet. See struct level docs for
   109  	// details.
   110  	buf      buffer.Buffer
   111  	reserved int
   112  	pushed   int
   113  	consumed int
   114  
   115  	// headers stores metadata about each header.
   116  	headers [numHeaderType]headerInfo
   117  
   118  	// NetworkProtocolNumber is only valid when NetworkHeader().View().IsEmpty()
   119  	// returns false.
   120  	// TODO(gvisor.dev/issue/3574): Remove the separately passed protocol
   121  	// numbers in registration APIs that take a PacketBuffer.
   122  	NetworkProtocolNumber tcpip.NetworkProtocolNumber
   123  
   124  	// TransportProtocol is only valid if it is non zero.
   125  	// TODO(gvisor.dev/issue/3810): This and the network protocol number should
   126  	// be moved into the headerinfo. This should resolve the validity issue.
   127  	TransportProtocolNumber tcpip.TransportProtocolNumber
   128  
   129  	// Hash is the transport layer hash of this packet. A value of zero
   130  	// indicates no valid hash has been set.
   131  	Hash uint32
   132  
   133  	// Owner is implemented by task to get the uid and gid.
   134  	// Only set for locally generated packets.
   135  	Owner tcpip.PacketOwner
   136  
   137  	// The following fields are only set by the qdisc layer when the packet
   138  	// is added to a queue.
   139  	EgressRoute RouteInfo
   140  	GSOOptions  GSO
   141  
   142  	// snatDone indicates if the packet's source has been manipulated as per
   143  	// iptables NAT table.
   144  	snatDone bool
   145  
   146  	// dnatDone indicates if the packet's destination has been manipulated as per
   147  	// iptables NAT table.
   148  	dnatDone bool
   149  
   150  	// PktType indicates the SockAddrLink.PacketType of the packet as defined in
   151  	// https://www.man7.org/linux/man-pages/man7/packet.7.html.
   152  	PktType tcpip.PacketType
   153  
   154  	// NICID is the ID of the last interface the network packet was handled at.
   155  	NICID tcpip.NICID
   156  
   157  	// RXChecksumValidated indicates that checksum verification may be
   158  	// safely skipped.
   159  	RXChecksumValidated bool
   160  
   161  	// NetworkPacketInfo holds an incoming packet's network-layer information.
   162  	NetworkPacketInfo NetworkPacketInfo
   163  
   164  	tuple *tuple
   165  
   166  	// onRelease is a function to be run when the packet buffer is no longer
   167  	// referenced (released back to the pool).
   168  	onRelease func() `state:"nosave"`
   169  }
   170  
   171  // NewPacketBuffer creates a new PacketBuffer with opts.
   172  func NewPacketBuffer(opts PacketBufferOptions) *PacketBuffer {
   173  	pk := pkPool.Get().(*PacketBuffer)
   174  	pk.reset()
   175  	if opts.ReserveHeaderBytes != 0 {
   176  		v := buffer.NewViewSize(opts.ReserveHeaderBytes)
   177  		pk.buf.Append(v)
   178  		pk.reserved = opts.ReserveHeaderBytes
   179  	}
   180  	if opts.Payload.Size() > 0 {
   181  		pk.buf.Merge(&opts.Payload)
   182  	}
   183  	pk.NetworkPacketInfo.IsForwardedPacket = opts.IsForwardedPacket
   184  	pk.onRelease = opts.OnRelease
   185  	pk.InitRefs()
   186  	return pk
   187  }
   188  
   189  // IncRef increments the PacketBuffer's refcount.
   190  func (pk *PacketBuffer) IncRef() *PacketBuffer {
   191  	pk.packetBufferRefs.IncRef()
   192  	return pk
   193  }
   194  
   195  // DecRef decrements the PacketBuffer's refcount. If the refcount is
   196  // decremented to zero, the PacketBuffer is returned to the PacketBuffer
   197  // pool.
   198  func (pk *PacketBuffer) DecRef() {
   199  	pk.packetBufferRefs.DecRef(func() {
   200  		if pk.onRelease != nil {
   201  			pk.onRelease()
   202  		}
   203  
   204  		pk.buf.Release()
   205  		pkPool.Put(pk)
   206  	})
   207  }
   208  
   209  func (pk *PacketBuffer) reset() {
   210  	*pk = PacketBuffer{}
   211  }
   212  
   213  // ReservedHeaderBytes returns the number of bytes initially reserved for
   214  // headers.
   215  func (pk *PacketBuffer) ReservedHeaderBytes() int {
   216  	return pk.reserved
   217  }
   218  
   219  // AvailableHeaderBytes returns the number of bytes currently available for
   220  // headers. This is relevant to PacketHeader.Push method only.
   221  func (pk *PacketBuffer) AvailableHeaderBytes() int {
   222  	return pk.reserved - pk.pushed
   223  }
   224  
   225  // VirtioNetHeader returns the handle to virtio-layer header.
   226  func (pk *PacketBuffer) VirtioNetHeader() PacketHeader {
   227  	return PacketHeader{
   228  		pk:  pk,
   229  		typ: virtioNetHeader,
   230  	}
   231  }
   232  
   233  // LinkHeader returns the handle to link-layer header.
   234  func (pk *PacketBuffer) LinkHeader() PacketHeader {
   235  	return PacketHeader{
   236  		pk:  pk,
   237  		typ: linkHeader,
   238  	}
   239  }
   240  
   241  // NetworkHeader returns the handle to network-layer header.
   242  func (pk *PacketBuffer) NetworkHeader() PacketHeader {
   243  	return PacketHeader{
   244  		pk:  pk,
   245  		typ: networkHeader,
   246  	}
   247  }
   248  
   249  // TransportHeader returns the handle to transport-layer header.
   250  func (pk *PacketBuffer) TransportHeader() PacketHeader {
   251  	return PacketHeader{
   252  		pk:  pk,
   253  		typ: transportHeader,
   254  	}
   255  }
   256  
   257  // HeaderSize returns the total size of all headers in bytes.
   258  func (pk *PacketBuffer) HeaderSize() int {
   259  	return pk.pushed + pk.consumed
   260  }
   261  
   262  // Size returns the size of packet in bytes.
   263  func (pk *PacketBuffer) Size() int {
   264  	return int(pk.buf.Size()) - pk.headerOffset()
   265  }
   266  
   267  // MemSize returns the estimation size of the pk in memory, including backing
   268  // buffer data.
   269  func (pk *PacketBuffer) MemSize() int {
   270  	return int(pk.buf.Size()) + PacketBufferStructSize
   271  }
   272  
   273  // Data returns the handle to data portion of pk.
   274  func (pk *PacketBuffer) Data() PacketData {
   275  	return PacketData{pk: pk}
   276  }
   277  
   278  // AsSlices returns the underlying storage of the whole packet.
   279  //
   280  // Note that AsSlices can allocate a lot. In hot paths it may be preferable to
   281  // iterate over a PacketBuffer's data via AsViewList.
   282  func (pk *PacketBuffer) AsSlices() [][]byte {
   283  	vl := pk.buf.AsViewList()
   284  	views := make([][]byte, 0, vl.Len())
   285  	offset := pk.headerOffset()
   286  	pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v *buffer.View) {
   287  		views = append(views, v.AsSlice())
   288  	})
   289  	return views
   290  }
   291  
   292  // AsViewList returns the list of Views backing the PacketBuffer along with the
   293  // header offset into them. Users may not save or modify the ViewList returned.
   294  func (pk *PacketBuffer) AsViewList() (buffer.ViewList, int) {
   295  	return pk.buf.AsViewList(), pk.headerOffset()
   296  }
   297  
   298  // ToBuffer returns a caller-owned copy of the underlying storage of the whole
   299  // packet.
   300  func (pk *PacketBuffer) ToBuffer() buffer.Buffer {
   301  	b := pk.buf.Clone()
   302  	b.TrimFront(int64(pk.headerOffset()))
   303  	return b
   304  }
   305  
   306  // ToView returns a caller-owned copy of the underlying storage of the whole
   307  // packet as a view.
   308  func (pk *PacketBuffer) ToView() *buffer.View {
   309  	p := buffer.NewView(int(pk.buf.Size()))
   310  	offset := pk.headerOffset()
   311  	pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v *buffer.View) {
   312  		p.Write(v.AsSlice())
   313  	})
   314  	return p
   315  }
   316  
   317  func (pk *PacketBuffer) headerOffset() int {
   318  	return pk.reserved - pk.pushed
   319  }
   320  
   321  func (pk *PacketBuffer) headerOffsetOf(typ headerType) int {
   322  	return pk.reserved + pk.headers[typ].offset
   323  }
   324  
   325  func (pk *PacketBuffer) dataOffset() int {
   326  	return pk.reserved + pk.consumed
   327  }
   328  
   329  func (pk *PacketBuffer) push(typ headerType, size int) []byte {
   330  	h := &pk.headers[typ]
   331  	if h.length > 0 {
   332  		panic(fmt.Sprintf("push(%s, %d) called after previous push", typ, size))
   333  	}
   334  	if pk.pushed+size > pk.reserved {
   335  		panic(fmt.Sprintf("push(%s, %d) overflows; pushed=%d reserved=%d", typ, size, pk.pushed, pk.reserved))
   336  	}
   337  	pk.pushed += size
   338  	h.offset = -pk.pushed
   339  	h.length = size
   340  	view := pk.headerView(typ)
   341  	return view.AsSlice()
   342  }
   343  
   344  func (pk *PacketBuffer) consume(typ headerType, size int) (v []byte, consumed bool) {
   345  	h := &pk.headers[typ]
   346  	if h.length > 0 {
   347  		panic(fmt.Sprintf("consume must not be called twice: type %s", typ))
   348  	}
   349  	if pk.reserved+pk.consumed+size > int(pk.buf.Size()) {
   350  		return nil, false
   351  	}
   352  	h.offset = pk.consumed
   353  	h.length = size
   354  	pk.consumed += size
   355  	view := pk.headerView(typ)
   356  	return view.AsSlice(), true
   357  }
   358  
   359  func (pk *PacketBuffer) headerView(typ headerType) buffer.View {
   360  	h := &pk.headers[typ]
   361  	if h.length == 0 {
   362  		return buffer.View{}
   363  	}
   364  	v, ok := pk.buf.PullUp(pk.headerOffsetOf(typ), h.length)
   365  	if !ok {
   366  		panic("PullUp failed")
   367  	}
   368  	return v
   369  }
   370  
   371  // Clone makes a semi-deep copy of pk. The underlying packet payload is
   372  // shared. Hence, no modifications is done to underlying packet payload.
   373  func (pk *PacketBuffer) Clone() *PacketBuffer {
   374  	newPk := pkPool.Get().(*PacketBuffer)
   375  	newPk.reset()
   376  	newPk.buf = pk.buf.Clone()
   377  	newPk.reserved = pk.reserved
   378  	newPk.pushed = pk.pushed
   379  	newPk.consumed = pk.consumed
   380  	newPk.headers = pk.headers
   381  	newPk.Hash = pk.Hash
   382  	newPk.Owner = pk.Owner
   383  	newPk.GSOOptions = pk.GSOOptions
   384  	newPk.NetworkProtocolNumber = pk.NetworkProtocolNumber
   385  	newPk.dnatDone = pk.dnatDone
   386  	newPk.snatDone = pk.snatDone
   387  	newPk.TransportProtocolNumber = pk.TransportProtocolNumber
   388  	newPk.PktType = pk.PktType
   389  	newPk.NICID = pk.NICID
   390  	newPk.RXChecksumValidated = pk.RXChecksumValidated
   391  	newPk.NetworkPacketInfo = pk.NetworkPacketInfo
   392  	newPk.tuple = pk.tuple
   393  	newPk.InitRefs()
   394  	return newPk
   395  }
   396  
   397  // ReserveHeaderBytes prepends reserved space for headers at the front
   398  // of the underlying buf. Can only be called once per packet.
   399  func (pk *PacketBuffer) ReserveHeaderBytes(reserved int) {
   400  	if pk.reserved != 0 {
   401  		panic(fmt.Sprintf("ReserveHeaderBytes(...) called on packet with reserved=%d, want reserved=0", pk.reserved))
   402  	}
   403  	pk.reserved = reserved
   404  	pk.buf.Prepend(buffer.NewViewSize(reserved))
   405  }
   406  
   407  // Network returns the network header as a header.Network.
   408  //
   409  // Network should only be called when NetworkHeader has been set.
   410  func (pk *PacketBuffer) Network() header.Network {
   411  	switch netProto := pk.NetworkProtocolNumber; netProto {
   412  	case header.IPv4ProtocolNumber:
   413  		return header.IPv4(pk.NetworkHeader().Slice())
   414  	case header.IPv6ProtocolNumber:
   415  		return header.IPv6(pk.NetworkHeader().Slice())
   416  	default:
   417  		panic(fmt.Sprintf("unknown network protocol number %d", netProto))
   418  	}
   419  }
   420  
   421  // CloneToInbound makes a semi-deep copy of the packet buffer (similar to
   422  // Clone) to be used as an inbound packet.
   423  //
   424  // See PacketBuffer.Data for details about how a packet buffer holds an inbound
   425  // packet.
   426  func (pk *PacketBuffer) CloneToInbound() *PacketBuffer {
   427  	newPk := pkPool.Get().(*PacketBuffer)
   428  	newPk.reset()
   429  	newPk.buf = pk.buf.Clone()
   430  	newPk.InitRefs()
   431  	// Treat unfilled header portion as reserved.
   432  	newPk.reserved = pk.AvailableHeaderBytes()
   433  	newPk.tuple = pk.tuple
   434  	return newPk
   435  }
   436  
   437  // DeepCopyForForwarding creates a deep copy of the packet buffer for
   438  // forwarding.
   439  //
   440  // The returned packet buffer will have the network and transport headers
   441  // set if the original packet buffer did.
   442  func (pk *PacketBuffer) DeepCopyForForwarding(reservedHeaderBytes int) *PacketBuffer {
   443  	payload := BufferSince(pk.NetworkHeader())
   444  	defer payload.Release()
   445  	newPk := NewPacketBuffer(PacketBufferOptions{
   446  		ReserveHeaderBytes: reservedHeaderBytes,
   447  		Payload:            payload.DeepClone(),
   448  		IsForwardedPacket:  true,
   449  	})
   450  
   451  	{
   452  		consumeBytes := len(pk.NetworkHeader().Slice())
   453  		if _, consumed := newPk.NetworkHeader().Consume(consumeBytes); !consumed {
   454  			panic(fmt.Sprintf("expected to consume network header %d bytes from new packet", consumeBytes))
   455  		}
   456  		newPk.NetworkProtocolNumber = pk.NetworkProtocolNumber
   457  	}
   458  
   459  	{
   460  		consumeBytes := len(pk.TransportHeader().Slice())
   461  		if _, consumed := newPk.TransportHeader().Consume(consumeBytes); !consumed {
   462  			panic(fmt.Sprintf("expected to consume transport header %d bytes from new packet", consumeBytes))
   463  		}
   464  		newPk.TransportProtocolNumber = pk.TransportProtocolNumber
   465  	}
   466  
   467  	newPk.tuple = pk.tuple
   468  
   469  	return newPk
   470  }
   471  
   472  // headerInfo stores metadata about a header in a packet.
   473  //
   474  // +stateify savable
   475  type headerInfo struct {
   476  	// offset is the offset of the header in pk.buf relative to
   477  	// pk.buf[pk.reserved]. See the PacketBuffer struct for details.
   478  	offset int
   479  
   480  	// length is the length of this header.
   481  	length int
   482  }
   483  
   484  // PacketHeader is a handle object to a header in the underlying packet.
   485  type PacketHeader struct {
   486  	pk  *PacketBuffer
   487  	typ headerType
   488  }
   489  
   490  // View returns an caller-owned copy of the underlying storage of h as a
   491  // *buffer.View.
   492  func (h PacketHeader) View() *buffer.View {
   493  	view := h.pk.headerView(h.typ)
   494  	if view.Size() == 0 {
   495  		return nil
   496  	}
   497  	return view.Clone()
   498  }
   499  
   500  // Slice returns the underlying storage of h as a []byte. The returned slice
   501  // should not be modified if the underlying packet could be shared, cloned, or
   502  // borrowed.
   503  func (h PacketHeader) Slice() []byte {
   504  	view := h.pk.headerView(h.typ)
   505  	return view.AsSlice()
   506  }
   507  
   508  // Push pushes size bytes in the front of its residing packet, and returns the
   509  // backing storage. Callers may only call one of Push or Consume once on each
   510  // header in the lifetime of the underlying packet.
   511  func (h PacketHeader) Push(size int) []byte {
   512  	return h.pk.push(h.typ, size)
   513  }
   514  
   515  // Consume moves the first size bytes of the unparsed data portion in the packet
   516  // to h, and returns the backing storage. In the case of data is shorter than
   517  // size, consumed will be false, and the state of h will not be affected.
   518  // Callers may only call one of Push or Consume once on each header in the
   519  // lifetime of the underlying packet.
   520  func (h PacketHeader) Consume(size int) (v []byte, consumed bool) {
   521  	return h.pk.consume(h.typ, size)
   522  }
   523  
   524  // PacketData represents the data portion of a PacketBuffer.
   525  //
   526  // +stateify savable
   527  type PacketData struct {
   528  	pk *PacketBuffer
   529  }
   530  
   531  // PullUp returns a contiguous slice of size bytes from the beginning of d.
   532  // Callers should not keep the view for later use. Callers can write to the
   533  // returned slice if they have singular ownership over the underlying
   534  // Buffer.
   535  func (d PacketData) PullUp(size int) (b []byte, ok bool) {
   536  	view, ok := d.pk.buf.PullUp(d.pk.dataOffset(), size)
   537  	return view.AsSlice(), ok
   538  }
   539  
   540  // Consume is the same as PullUp except that is additionally consumes the
   541  // returned bytes. Subsequent PullUp or Consume will not return these bytes.
   542  func (d PacketData) Consume(size int) ([]byte, bool) {
   543  	v, ok := d.PullUp(size)
   544  	if ok {
   545  		d.pk.consumed += size
   546  	}
   547  	return v, ok
   548  }
   549  
   550  // ReadTo reads bytes from d to dst. It also removes these bytes from d
   551  // unless peek is true.
   552  func (d PacketData) ReadTo(dst io.Writer, peek bool) (int, error) {
   553  	var (
   554  		err  error
   555  		done int
   556  	)
   557  	offset := d.pk.dataOffset()
   558  	d.pk.buf.SubApply(offset, int(d.pk.buf.Size())-offset, func(v *buffer.View) {
   559  		if err != nil {
   560  			return
   561  		}
   562  		var n int
   563  		n, err = dst.Write(v.AsSlice())
   564  		done += n
   565  		if err != nil {
   566  			return
   567  		}
   568  		if n != v.Size() {
   569  			panic(fmt.Sprintf("io.Writer.Write succeeded with incomplete write: %d != %d", n, v.Size()))
   570  		}
   571  	})
   572  	if !peek {
   573  		d.pk.buf.TrimFront(int64(done))
   574  	}
   575  	return done, err
   576  }
   577  
   578  // CapLength reduces d to at most length bytes.
   579  func (d PacketData) CapLength(length int) {
   580  	if length < 0 {
   581  		panic("length < 0")
   582  	}
   583  	d.pk.buf.Truncate(int64(length + d.pk.dataOffset()))
   584  }
   585  
   586  // ToBuffer returns the underlying storage of d in a buffer.Buffer.
   587  func (d PacketData) ToBuffer() buffer.Buffer {
   588  	buf := d.pk.buf.Clone()
   589  	offset := d.pk.dataOffset()
   590  	buf.TrimFront(int64(offset))
   591  	return buf
   592  }
   593  
   594  // AppendView appends v into d, taking the ownership of v.
   595  func (d PacketData) AppendView(v *buffer.View) {
   596  	d.pk.buf.Append(v)
   597  }
   598  
   599  // MergeBuffer merges b into d and clears b.
   600  func (d PacketData) MergeBuffer(b *buffer.Buffer) {
   601  	d.pk.buf.Merge(b)
   602  }
   603  
   604  // MergeFragment appends the data portion of frag to dst. It modifies
   605  // frag and frag should not be used again.
   606  func MergeFragment(dst, frag *PacketBuffer) {
   607  	frag.buf.TrimFront(int64(frag.dataOffset()))
   608  	dst.buf.Merge(&frag.buf)
   609  }
   610  
   611  // ReadFrom moves at most count bytes from the beginning of src to the end
   612  // of d and returns the number of bytes moved.
   613  func (d PacketData) ReadFrom(src *buffer.Buffer, count int) int {
   614  	toRead := int64(count)
   615  	if toRead > src.Size() {
   616  		toRead = src.Size()
   617  	}
   618  	clone := src.Clone()
   619  	clone.Truncate(toRead)
   620  	d.pk.buf.Merge(&clone)
   621  	src.TrimFront(toRead)
   622  	return int(toRead)
   623  }
   624  
   625  // ReadFromPacketData moves count bytes from the beginning of oth to the end of
   626  // d.
   627  func (d PacketData) ReadFromPacketData(oth PacketData, count int) {
   628  	buf := oth.ToBuffer()
   629  	buf.Truncate(int64(count))
   630  	d.MergeBuffer(&buf)
   631  	oth.TrimFront(count)
   632  	buf.Release()
   633  }
   634  
   635  // Merge clears headers in oth and merges its data with d.
   636  func (d PacketData) Merge(oth PacketData) {
   637  	oth.pk.buf.TrimFront(int64(oth.pk.dataOffset()))
   638  	d.pk.buf.Merge(&oth.pk.buf)
   639  }
   640  
   641  // TrimFront removes up to count bytes from the front of d's payload.
   642  func (d PacketData) TrimFront(count int) {
   643  	if count > d.Size() {
   644  		count = d.Size()
   645  	}
   646  	buf := d.pk.Data().ToBuffer()
   647  	buf.TrimFront(int64(count))
   648  	d.pk.buf.Truncate(int64(d.pk.dataOffset()))
   649  	d.pk.buf.Merge(&buf)
   650  }
   651  
   652  // Size returns the number of bytes in the data payload of the packet.
   653  func (d PacketData) Size() int {
   654  	return int(d.pk.buf.Size()) - d.pk.dataOffset()
   655  }
   656  
   657  // AsRange returns a Range representing the current data payload of the packet.
   658  func (d PacketData) AsRange() Range {
   659  	return Range{
   660  		pk:     d.pk,
   661  		offset: d.pk.dataOffset(),
   662  		length: d.Size(),
   663  	}
   664  }
   665  
   666  // Checksum returns a checksum over the data payload of the packet.
   667  func (d PacketData) Checksum() uint16 {
   668  	return d.pk.buf.Checksum(d.pk.dataOffset())
   669  }
   670  
   671  // ChecksumAtOffset returns a checksum over the data payload of the packet
   672  // starting from offset.
   673  func (d PacketData) ChecksumAtOffset(offset int) uint16 {
   674  	return d.pk.buf.Checksum(offset)
   675  }
   676  
   677  // Range represents a contiguous subportion of a PacketBuffer.
   678  type Range struct {
   679  	pk     *PacketBuffer
   680  	offset int
   681  	length int
   682  }
   683  
   684  // Size returns the number of bytes in r.
   685  func (r Range) Size() int {
   686  	return r.length
   687  }
   688  
   689  // SubRange returns a new Range starting at off bytes of r. It returns an empty
   690  // range if off is out-of-bounds.
   691  func (r Range) SubRange(off int) Range {
   692  	if off > r.length {
   693  		return Range{pk: r.pk}
   694  	}
   695  	return Range{
   696  		pk:     r.pk,
   697  		offset: r.offset + off,
   698  		length: r.length - off,
   699  	}
   700  }
   701  
   702  // Capped returns a new Range with the same starting point of r and length
   703  // capped at max.
   704  func (r Range) Capped(max int) Range {
   705  	if r.length <= max {
   706  		return r
   707  	}
   708  	return Range{
   709  		pk:     r.pk,
   710  		offset: r.offset,
   711  		length: max,
   712  	}
   713  }
   714  
   715  // ToSlice returns a caller-owned copy of data in r.
   716  func (r Range) ToSlice() []byte {
   717  	if r.length == 0 {
   718  		return nil
   719  	}
   720  	all := make([]byte, 0, r.length)
   721  	r.iterate(func(v *buffer.View) {
   722  		all = append(all, v.AsSlice()...)
   723  	})
   724  	return all
   725  }
   726  
   727  // ToView returns a caller-owned copy of data in r.
   728  func (r Range) ToView() *buffer.View {
   729  	if r.length == 0 {
   730  		return nil
   731  	}
   732  	newV := buffer.NewView(r.length)
   733  	r.iterate(func(v *buffer.View) {
   734  		newV.Write(v.AsSlice())
   735  	})
   736  	return newV
   737  }
   738  
   739  // iterate calls fn for each piece in r. fn is always called with a non-empty
   740  // slice.
   741  func (r Range) iterate(fn func(*buffer.View)) {
   742  	r.pk.buf.SubApply(r.offset, r.length, fn)
   743  }
   744  
   745  // PayloadSince returns a caller-owned view containing the payload starting from
   746  // and including a particular header.
   747  func PayloadSince(h PacketHeader) *buffer.View {
   748  	offset := h.pk.headerOffset()
   749  	for i := headerType(0); i < h.typ; i++ {
   750  		offset += h.pk.headers[i].length
   751  	}
   752  	return Range{
   753  		pk:     h.pk,
   754  		offset: offset,
   755  		length: int(h.pk.buf.Size()) - offset,
   756  	}.ToView()
   757  }
   758  
   759  // BufferSince returns a caller-owned view containing the packet payload
   760  // starting from and including a particular header.
   761  func BufferSince(h PacketHeader) buffer.Buffer {
   762  	offset := h.pk.headerOffset()
   763  	for i := headerType(0); i < h.typ; i++ {
   764  		offset += h.pk.headers[i].length
   765  	}
   766  	clone := h.pk.buf.Clone()
   767  	clone.TrimFront(int64(offset))
   768  	return clone
   769  }