packet_buffer.go raw

   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.EgressRoute = pk.EgressRoute
 385  	newPk.NetworkProtocolNumber = pk.NetworkProtocolNumber
 386  	newPk.dnatDone = pk.dnatDone
 387  	newPk.snatDone = pk.snatDone
 388  	newPk.TransportProtocolNumber = pk.TransportProtocolNumber
 389  	newPk.PktType = pk.PktType
 390  	newPk.NICID = pk.NICID
 391  	newPk.RXChecksumValidated = pk.RXChecksumValidated
 392  	newPk.NetworkPacketInfo = pk.NetworkPacketInfo
 393  	newPk.tuple = pk.tuple
 394  	newPk.InitRefs()
 395  	return newPk
 396  }
 397  
 398  // ReserveHeaderBytes prepends reserved space for headers at the front
 399  // of the underlying buf. Can only be called once per packet.
 400  func (pk *PacketBuffer) ReserveHeaderBytes(reserved int) {
 401  	if pk.reserved != 0 {
 402  		panic(fmt.Sprintf("ReserveHeaderBytes(...) called on packet with reserved=%d, want reserved=0", pk.reserved))
 403  	}
 404  	pk.reserved = reserved
 405  	pk.buf.Prepend(buffer.NewViewSize(reserved))
 406  }
 407  
 408  // Network returns the network header as a header.Network.
 409  //
 410  // Network should only be called when NetworkHeader has been set.
 411  func (pk *PacketBuffer) Network() header.Network {
 412  	switch netProto := pk.NetworkProtocolNumber; netProto {
 413  	case header.IPv4ProtocolNumber:
 414  		return header.IPv4(pk.NetworkHeader().Slice())
 415  	case header.IPv6ProtocolNumber:
 416  		return header.IPv6(pk.NetworkHeader().Slice())
 417  	default:
 418  		panic(fmt.Sprintf("unknown network protocol number %d", netProto))
 419  	}
 420  }
 421  
 422  // CloneToInbound makes a semi-deep copy of the packet buffer (similar to
 423  // Clone) to be used as an inbound packet.
 424  //
 425  // See PacketBuffer.Data for details about how a packet buffer holds an inbound
 426  // packet.
 427  func (pk *PacketBuffer) CloneToInbound() *PacketBuffer {
 428  	newPk := pkPool.Get().(*PacketBuffer)
 429  	newPk.reset()
 430  	newPk.buf = pk.buf.Clone()
 431  	newPk.InitRefs()
 432  	// Treat unfilled header portion as reserved.
 433  	newPk.reserved = pk.AvailableHeaderBytes()
 434  	newPk.tuple = pk.tuple
 435  	return newPk
 436  }
 437  
 438  // DeepCopyForForwarding creates a deep copy of the packet buffer for
 439  // forwarding.
 440  //
 441  // The returned packet buffer will have the network and transport headers
 442  // set if the original packet buffer did.
 443  func (pk *PacketBuffer) DeepCopyForForwarding(reservedHeaderBytes int) *PacketBuffer {
 444  	payload := BufferSince(pk.NetworkHeader())
 445  	defer payload.Release()
 446  	newPk := NewPacketBuffer(PacketBufferOptions{
 447  		ReserveHeaderBytes: reservedHeaderBytes,
 448  		Payload:            payload.DeepClone(),
 449  		IsForwardedPacket:  true,
 450  	})
 451  
 452  	{
 453  		consumeBytes := len(pk.NetworkHeader().Slice())
 454  		if _, consumed := newPk.NetworkHeader().Consume(consumeBytes); !consumed {
 455  			panic(fmt.Sprintf("expected to consume network header %d bytes from new packet", consumeBytes))
 456  		}
 457  		newPk.NetworkProtocolNumber = pk.NetworkProtocolNumber
 458  	}
 459  
 460  	{
 461  		consumeBytes := len(pk.TransportHeader().Slice())
 462  		if _, consumed := newPk.TransportHeader().Consume(consumeBytes); !consumed {
 463  			panic(fmt.Sprintf("expected to consume transport header %d bytes from new packet", consumeBytes))
 464  		}
 465  		newPk.TransportProtocolNumber = pk.TransportProtocolNumber
 466  	}
 467  
 468  	newPk.tuple = pk.tuple
 469  
 470  	return newPk
 471  }
 472  
 473  // headerInfo stores metadata about a header in a packet.
 474  //
 475  // +stateify savable
 476  type headerInfo struct {
 477  	// offset is the offset of the header in pk.buf relative to
 478  	// pk.buf[pk.reserved]. See the PacketBuffer struct for details.
 479  	offset int
 480  
 481  	// length is the length of this header.
 482  	length int
 483  }
 484  
 485  // PacketHeader is a handle object to a header in the underlying packet.
 486  type PacketHeader struct {
 487  	pk  *PacketBuffer
 488  	typ headerType
 489  }
 490  
 491  // View returns an caller-owned copy of the underlying storage of h as a
 492  // *buffer.View.
 493  func (h PacketHeader) View() *buffer.View {
 494  	view := h.pk.headerView(h.typ)
 495  	if view.Size() == 0 {
 496  		return nil
 497  	}
 498  	return view.Clone()
 499  }
 500  
 501  // Slice returns the underlying storage of h as a []byte. The returned slice
 502  // should not be modified if the underlying packet could be shared, cloned, or
 503  // borrowed.
 504  func (h PacketHeader) Slice() []byte {
 505  	view := h.pk.headerView(h.typ)
 506  	return view.AsSlice()
 507  }
 508  
 509  // Push pushes size bytes in the front of its residing packet, and returns the
 510  // backing storage. Callers may only call one of Push or Consume once on each
 511  // header in the lifetime of the underlying packet.
 512  func (h PacketHeader) Push(size int) []byte {
 513  	return h.pk.push(h.typ, size)
 514  }
 515  
 516  // Consume moves the first size bytes of the unparsed data portion in the packet
 517  // to h, and returns the backing storage. In the case of data is shorter than
 518  // size, consumed will be false, and the state of h will not be affected.
 519  // Callers may only call one of Push or Consume once on each header in the
 520  // lifetime of the underlying packet.
 521  func (h PacketHeader) Consume(size int) (v []byte, consumed bool) {
 522  	return h.pk.consume(h.typ, size)
 523  }
 524  
 525  // PacketData represents the data portion of a PacketBuffer.
 526  //
 527  // +stateify savable
 528  type PacketData struct {
 529  	pk *PacketBuffer
 530  }
 531  
 532  // PullUp returns a contiguous slice of size bytes from the beginning of d.
 533  // Callers should not keep the view for later use. Callers can write to the
 534  // returned slice if they have singular ownership over the underlying
 535  // Buffer.
 536  func (d PacketData) PullUp(size int) (b []byte, ok bool) {
 537  	view, ok := d.pk.buf.PullUp(d.pk.dataOffset(), size)
 538  	return view.AsSlice(), ok
 539  }
 540  
 541  // Consume is the same as PullUp except that is additionally consumes the
 542  // returned bytes. Subsequent PullUp or Consume will not return these bytes.
 543  func (d PacketData) Consume(size int) ([]byte, bool) {
 544  	v, ok := d.PullUp(size)
 545  	if ok {
 546  		d.pk.consumed += size
 547  	}
 548  	return v, ok
 549  }
 550  
 551  // ReadTo reads bytes from d to dst. It also removes these bytes from d
 552  // unless peek is true.
 553  func (d PacketData) ReadTo(dst io.Writer, peek bool) (int, error) {
 554  	var (
 555  		err  error
 556  		done int
 557  	)
 558  	offset := d.pk.dataOffset()
 559  	d.pk.buf.SubApply(offset, int(d.pk.buf.Size())-offset, func(v *buffer.View) {
 560  		if err != nil {
 561  			return
 562  		}
 563  		var n int
 564  		n, err = dst.Write(v.AsSlice())
 565  		done += n
 566  		if err != nil {
 567  			return
 568  		}
 569  		if n != v.Size() {
 570  			panic(fmt.Sprintf("io.Writer.Write succeeded with incomplete write: %d != %d", n, v.Size()))
 571  		}
 572  	})
 573  	if !peek {
 574  		d.pk.buf.TrimFront(int64(done))
 575  	}
 576  	return done, err
 577  }
 578  
 579  // CapLength reduces d to at most length bytes.
 580  func (d PacketData) CapLength(length int) {
 581  	if length < 0 {
 582  		panic("length < 0")
 583  	}
 584  	d.pk.buf.Truncate(int64(length + d.pk.dataOffset()))
 585  }
 586  
 587  // ToBuffer returns the underlying storage of d in a buffer.Buffer.
 588  func (d PacketData) ToBuffer() buffer.Buffer {
 589  	buf := d.pk.buf.Clone()
 590  	offset := d.pk.dataOffset()
 591  	buf.TrimFront(int64(offset))
 592  	return buf
 593  }
 594  
 595  // AppendView appends v into d, taking the ownership of v.
 596  func (d PacketData) AppendView(v *buffer.View) {
 597  	d.pk.buf.Append(v)
 598  }
 599  
 600  // MergeBuffer merges b into d and clears b.
 601  func (d PacketData) MergeBuffer(b *buffer.Buffer) {
 602  	d.pk.buf.Merge(b)
 603  }
 604  
 605  // MergeFragment appends the data portion of frag to dst. It modifies
 606  // frag and frag should not be used again.
 607  func MergeFragment(dst, frag *PacketBuffer) {
 608  	frag.buf.TrimFront(int64(frag.dataOffset()))
 609  	dst.buf.Merge(&frag.buf)
 610  }
 611  
 612  // ReadFrom moves at most count bytes from the beginning of src to the end
 613  // of d and returns the number of bytes moved.
 614  func (d PacketData) ReadFrom(src *buffer.Buffer, count int) int {
 615  	toRead := int64(count)
 616  	if toRead > src.Size() {
 617  		toRead = src.Size()
 618  	}
 619  	clone := src.Clone()
 620  	clone.Truncate(toRead)
 621  	d.pk.buf.Merge(&clone)
 622  	src.TrimFront(toRead)
 623  	return int(toRead)
 624  }
 625  
 626  // ReadFromPacketData moves count bytes from the beginning of oth to the end of
 627  // d.
 628  func (d PacketData) ReadFromPacketData(oth PacketData, count int) {
 629  	buf := oth.ToBuffer()
 630  	buf.Truncate(int64(count))
 631  	d.MergeBuffer(&buf)
 632  	oth.TrimFront(count)
 633  	buf.Release()
 634  }
 635  
 636  // Merge clears headers in oth and merges its data with d.
 637  func (d PacketData) Merge(oth PacketData) {
 638  	oth.pk.buf.TrimFront(int64(oth.pk.dataOffset()))
 639  	d.pk.buf.Merge(&oth.pk.buf)
 640  }
 641  
 642  // TrimFront removes up to count bytes from the front of d's payload.
 643  func (d PacketData) TrimFront(count int) {
 644  	if count > d.Size() {
 645  		count = d.Size()
 646  	}
 647  	buf := d.pk.Data().ToBuffer()
 648  	buf.TrimFront(int64(count))
 649  	d.pk.buf.Truncate(int64(d.pk.dataOffset()))
 650  	d.pk.buf.Merge(&buf)
 651  }
 652  
 653  // Size returns the number of bytes in the data payload of the packet.
 654  func (d PacketData) Size() int {
 655  	return int(d.pk.buf.Size()) - d.pk.dataOffset()
 656  }
 657  
 658  // AsRange returns a Range representing the current data payload of the packet.
 659  func (d PacketData) AsRange() Range {
 660  	return Range{
 661  		pk:     d.pk,
 662  		offset: d.pk.dataOffset(),
 663  		length: d.Size(),
 664  	}
 665  }
 666  
 667  // Checksum returns a checksum over the data payload of the packet.
 668  func (d PacketData) Checksum() uint16 {
 669  	return d.pk.buf.Checksum(d.pk.dataOffset())
 670  }
 671  
 672  // ChecksumAtOffset returns a checksum over the data payload of the packet
 673  // starting from offset.
 674  func (d PacketData) ChecksumAtOffset(offset int) uint16 {
 675  	return d.pk.buf.Checksum(offset)
 676  }
 677  
 678  // Range represents a contiguous subportion of a PacketBuffer.
 679  type Range struct {
 680  	pk     *PacketBuffer
 681  	offset int
 682  	length int
 683  }
 684  
 685  // Size returns the number of bytes in r.
 686  func (r Range) Size() int {
 687  	return r.length
 688  }
 689  
 690  // SubRange returns a new Range starting at off bytes of r. It returns an empty
 691  // range if off is out-of-bounds.
 692  func (r Range) SubRange(off int) Range {
 693  	if off > r.length {
 694  		return Range{pk: r.pk}
 695  	}
 696  	return Range{
 697  		pk:     r.pk,
 698  		offset: r.offset + off,
 699  		length: r.length - off,
 700  	}
 701  }
 702  
 703  // Capped returns a new Range with the same starting point of r and length
 704  // capped at max.
 705  func (r Range) Capped(max int) Range {
 706  	if r.length <= max {
 707  		return r
 708  	}
 709  	return Range{
 710  		pk:     r.pk,
 711  		offset: r.offset,
 712  		length: max,
 713  	}
 714  }
 715  
 716  // ToSlice returns a caller-owned copy of data in r.
 717  func (r Range) ToSlice() []byte {
 718  	if r.length == 0 {
 719  		return nil
 720  	}
 721  	all := make([]byte, 0, r.length)
 722  	r.iterate(func(v *buffer.View) {
 723  		all = append(all, v.AsSlice()...)
 724  	})
 725  	return all
 726  }
 727  
 728  // ToView returns a caller-owned copy of data in r.
 729  func (r Range) ToView() *buffer.View {
 730  	if r.length == 0 {
 731  		return nil
 732  	}
 733  	newV := buffer.NewView(r.length)
 734  	r.iterate(func(v *buffer.View) {
 735  		newV.Write(v.AsSlice())
 736  	})
 737  	return newV
 738  }
 739  
 740  // iterate calls fn for each piece in r. fn is always called with a non-empty
 741  // slice.
 742  func (r Range) iterate(fn func(*buffer.View)) {
 743  	r.pk.buf.SubApply(r.offset, r.length, fn)
 744  }
 745  
 746  // PayloadSince returns a caller-owned view containing the payload starting from
 747  // and including a particular header.
 748  func PayloadSince(h PacketHeader) *buffer.View {
 749  	offset := h.pk.headerOffset()
 750  	for i := headerType(0); i < h.typ; i++ {
 751  		offset += h.pk.headers[i].length
 752  	}
 753  	return Range{
 754  		pk:     h.pk,
 755  		offset: offset,
 756  		length: int(h.pk.buf.Size()) - offset,
 757  	}.ToView()
 758  }
 759  
 760  // BufferSince returns a caller-owned view containing the packet payload
 761  // starting from and including a particular header.
 762  func BufferSince(h PacketHeader) buffer.Buffer {
 763  	offset := h.pk.headerOffset()
 764  	for i := headerType(0); i < h.typ; i++ {
 765  		offset += h.pk.headers[i].length
 766  	}
 767  	clone := h.pk.buf.Clone()
 768  	clone.TrimFront(int64(offset))
 769  	return clone
 770  }
 771