github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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  	"github.com/metacubex/gvisor/pkg/buffer"
    21  	"github.com/metacubex/gvisor/pkg/sync"
    22  	"github.com/metacubex/gvisor/pkg/tcpip"
    23  	"github.com/metacubex/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  // IsNil returns whether the pointer is logically nil.
   473  func (pk *PacketBuffer) IsNil() bool {
   474  	return pk == nil
   475  }
   476  
   477  // headerInfo stores metadata about a header in a packet.
   478  //
   479  // +stateify savable
   480  type headerInfo struct {
   481  	// offset is the offset of the header in pk.buf relative to
   482  	// pk.buf[pk.reserved]. See the PacketBuffer struct for details.
   483  	offset int
   484  
   485  	// length is the length of this header.
   486  	length int
   487  }
   488  
   489  // PacketHeader is a handle object to a header in the underlying packet.
   490  type PacketHeader struct {
   491  	pk  *PacketBuffer
   492  	typ headerType
   493  }
   494  
   495  // View returns an caller-owned copy of the underlying storage of h as a
   496  // *buffer.View.
   497  func (h PacketHeader) View() *buffer.View {
   498  	view := h.pk.headerView(h.typ)
   499  	if view.Size() == 0 {
   500  		return nil
   501  	}
   502  	return view.Clone()
   503  }
   504  
   505  // Slice returns the underlying storage of h as a []byte. The returned slice
   506  // should not be modified if the underlying packet could be shared, cloned, or
   507  // borrowed.
   508  func (h PacketHeader) Slice() []byte {
   509  	view := h.pk.headerView(h.typ)
   510  	return view.AsSlice()
   511  }
   512  
   513  // Push pushes size bytes in the front of its residing packet, and returns the
   514  // backing storage. Callers may only call one of Push or Consume once on each
   515  // header in the lifetime of the underlying packet.
   516  func (h PacketHeader) Push(size int) []byte {
   517  	return h.pk.push(h.typ, size)
   518  }
   519  
   520  // Consume moves the first size bytes of the unparsed data portion in the packet
   521  // to h, and returns the backing storage. In the case of data is shorter than
   522  // size, consumed will be false, and the state of h will not be affected.
   523  // Callers may only call one of Push or Consume once on each header in the
   524  // lifetime of the underlying packet.
   525  func (h PacketHeader) Consume(size int) (v []byte, consumed bool) {
   526  	return h.pk.consume(h.typ, size)
   527  }
   528  
   529  // PacketData represents the data portion of a PacketBuffer.
   530  //
   531  // +stateify savable
   532  type PacketData struct {
   533  	pk *PacketBuffer
   534  }
   535  
   536  // PullUp returns a contiguous slice of size bytes from the beginning of d.
   537  // Callers should not keep the view for later use. Callers can write to the
   538  // returned slice if they have singular ownership over the underlying
   539  // Buffer.
   540  func (d PacketData) PullUp(size int) (b []byte, ok bool) {
   541  	view, ok := d.pk.buf.PullUp(d.pk.dataOffset(), size)
   542  	return view.AsSlice(), ok
   543  }
   544  
   545  // Consume is the same as PullUp except that is additionally consumes the
   546  // returned bytes. Subsequent PullUp or Consume will not return these bytes.
   547  func (d PacketData) Consume(size int) ([]byte, bool) {
   548  	v, ok := d.PullUp(size)
   549  	if ok {
   550  		d.pk.consumed += size
   551  	}
   552  	return v, ok
   553  }
   554  
   555  // ReadTo reads bytes from d to dst. It also removes these bytes from d
   556  // unless peek is true.
   557  func (d PacketData) ReadTo(dst io.Writer, peek bool) (int, error) {
   558  	var (
   559  		err  error
   560  		done int
   561  	)
   562  	offset := d.pk.dataOffset()
   563  	d.pk.buf.SubApply(offset, int(d.pk.buf.Size())-offset, func(v *buffer.View) {
   564  		if err != nil {
   565  			return
   566  		}
   567  		var n int
   568  		n, err = dst.Write(v.AsSlice())
   569  		done += n
   570  		if err != nil {
   571  			return
   572  		}
   573  		if n != v.Size() {
   574  			panic(fmt.Sprintf("io.Writer.Write succeeded with incomplete write: %d != %d", n, v.Size()))
   575  		}
   576  	})
   577  	if !peek {
   578  		d.pk.buf.TrimFront(int64(done))
   579  	}
   580  	return done, err
   581  }
   582  
   583  // CapLength reduces d to at most length bytes.
   584  func (d PacketData) CapLength(length int) {
   585  	if length < 0 {
   586  		panic("length < 0")
   587  	}
   588  	d.pk.buf.Truncate(int64(length + d.pk.dataOffset()))
   589  }
   590  
   591  // ToBuffer returns the underlying storage of d in a buffer.Buffer.
   592  func (d PacketData) ToBuffer() buffer.Buffer {
   593  	buf := d.pk.buf.Clone()
   594  	offset := d.pk.dataOffset()
   595  	buf.TrimFront(int64(offset))
   596  	return buf
   597  }
   598  
   599  // AppendView appends v into d, taking the ownership of v.
   600  func (d PacketData) AppendView(v *buffer.View) {
   601  	d.pk.buf.Append(v)
   602  }
   603  
   604  // MergeBuffer merges b into d and clears b.
   605  func (d PacketData) MergeBuffer(b *buffer.Buffer) {
   606  	d.pk.buf.Merge(b)
   607  }
   608  
   609  // MergeFragment appends the data portion of frag to dst. It modifies
   610  // frag and frag should not be used again.
   611  func MergeFragment(dst, frag *PacketBuffer) {
   612  	frag.buf.TrimFront(int64(frag.dataOffset()))
   613  	dst.buf.Merge(&frag.buf)
   614  }
   615  
   616  // ReadFrom moves at most count bytes from the beginning of src to the end
   617  // of d and returns the number of bytes moved.
   618  func (d PacketData) ReadFrom(src *buffer.Buffer, count int) int {
   619  	toRead := int64(count)
   620  	if toRead > src.Size() {
   621  		toRead = src.Size()
   622  	}
   623  	clone := src.Clone()
   624  	clone.Truncate(toRead)
   625  	d.pk.buf.Merge(&clone)
   626  	src.TrimFront(toRead)
   627  	return int(toRead)
   628  }
   629  
   630  // ReadFromPacketData moves count bytes from the beginning of oth to the end of
   631  // d.
   632  func (d PacketData) ReadFromPacketData(oth PacketData, count int) {
   633  	buf := oth.ToBuffer()
   634  	buf.Truncate(int64(count))
   635  	d.MergeBuffer(&buf)
   636  	oth.TrimFront(count)
   637  	buf.Release()
   638  }
   639  
   640  // Merge clears headers in oth and merges its data with d.
   641  func (d PacketData) Merge(oth PacketData) {
   642  	oth.pk.buf.TrimFront(int64(oth.pk.dataOffset()))
   643  	d.pk.buf.Merge(&oth.pk.buf)
   644  }
   645  
   646  // TrimFront removes up to count bytes from the front of d's payload.
   647  func (d PacketData) TrimFront(count int) {
   648  	if count > d.Size() {
   649  		count = d.Size()
   650  	}
   651  	buf := d.pk.Data().ToBuffer()
   652  	buf.TrimFront(int64(count))
   653  	d.pk.buf.Truncate(int64(d.pk.dataOffset()))
   654  	d.pk.buf.Merge(&buf)
   655  }
   656  
   657  // Size returns the number of bytes in the data payload of the packet.
   658  func (d PacketData) Size() int {
   659  	return int(d.pk.buf.Size()) - d.pk.dataOffset()
   660  }
   661  
   662  // AsRange returns a Range representing the current data payload of the packet.
   663  func (d PacketData) AsRange() Range {
   664  	return Range{
   665  		pk:     d.pk,
   666  		offset: d.pk.dataOffset(),
   667  		length: d.Size(),
   668  	}
   669  }
   670  
   671  // Checksum returns a checksum over the data payload of the packet.
   672  func (d PacketData) Checksum() uint16 {
   673  	return d.pk.buf.Checksum(d.pk.dataOffset())
   674  }
   675  
   676  // ChecksumAtOffset returns a checksum over the data payload of the packet
   677  // starting from offset.
   678  func (d PacketData) ChecksumAtOffset(offset int) uint16 {
   679  	return d.pk.buf.Checksum(offset)
   680  }
   681  
   682  // Range represents a contiguous subportion of a PacketBuffer.
   683  type Range struct {
   684  	pk     *PacketBuffer
   685  	offset int
   686  	length int
   687  }
   688  
   689  // Size returns the number of bytes in r.
   690  func (r Range) Size() int {
   691  	return r.length
   692  }
   693  
   694  // SubRange returns a new Range starting at off bytes of r. It returns an empty
   695  // range if off is out-of-bounds.
   696  func (r Range) SubRange(off int) Range {
   697  	if off > r.length {
   698  		return Range{pk: r.pk}
   699  	}
   700  	return Range{
   701  		pk:     r.pk,
   702  		offset: r.offset + off,
   703  		length: r.length - off,
   704  	}
   705  }
   706  
   707  // Capped returns a new Range with the same starting point of r and length
   708  // capped at max.
   709  func (r Range) Capped(max int) Range {
   710  	if r.length <= max {
   711  		return r
   712  	}
   713  	return Range{
   714  		pk:     r.pk,
   715  		offset: r.offset,
   716  		length: max,
   717  	}
   718  }
   719  
   720  // ToSlice returns a caller-owned copy of data in r.
   721  func (r Range) ToSlice() []byte {
   722  	if r.length == 0 {
   723  		return nil
   724  	}
   725  	all := make([]byte, 0, r.length)
   726  	r.iterate(func(v *buffer.View) {
   727  		all = append(all, v.AsSlice()...)
   728  	})
   729  	return all
   730  }
   731  
   732  // ToView returns a caller-owned copy of data in r.
   733  func (r Range) ToView() *buffer.View {
   734  	if r.length == 0 {
   735  		return nil
   736  	}
   737  	newV := buffer.NewView(r.length)
   738  	r.iterate(func(v *buffer.View) {
   739  		newV.Write(v.AsSlice())
   740  	})
   741  	return newV
   742  }
   743  
   744  // iterate calls fn for each piece in r. fn is always called with a non-empty
   745  // slice.
   746  func (r Range) iterate(fn func(*buffer.View)) {
   747  	r.pk.buf.SubApply(r.offset, r.length, fn)
   748  }
   749  
   750  // PayloadSince returns a caller-owned view containing the payload starting from
   751  // and including a particular header.
   752  func PayloadSince(h PacketHeader) *buffer.View {
   753  	offset := h.pk.headerOffset()
   754  	for i := headerType(0); i < h.typ; i++ {
   755  		offset += h.pk.headers[i].length
   756  	}
   757  	return Range{
   758  		pk:     h.pk,
   759  		offset: offset,
   760  		length: int(h.pk.buf.Size()) - offset,
   761  	}.ToView()
   762  }
   763  
   764  // BufferSince returns a caller-owned view containing the packet payload
   765  // starting from and including a particular header.
   766  func BufferSince(h PacketHeader) buffer.Buffer {
   767  	offset := h.pk.headerOffset()
   768  	for i := headerType(0); i < h.typ; i++ {
   769  		offset += h.pk.headers[i].length
   770  	}
   771  	clone := h.pk.buf.Clone()
   772  	clone.TrimFront(int64(offset))
   773  	return clone
   774  }