inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/tcpip/transport/tcp/segment.go (about)

     1  // Copyright 2018 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  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tcp
    16  
    17  import (
    18  	"fmt"
    19  	"sync/atomic"
    20  
    21  	"inet.af/netstack/tcpip"
    22  	"inet.af/netstack/tcpip/buffer"
    23  	"inet.af/netstack/tcpip/header"
    24  	"inet.af/netstack/tcpip/seqnum"
    25  	"inet.af/netstack/tcpip/stack"
    26  )
    27  
    28  // queueFlags are used to indicate which queue of an endpoint a particular segment
    29  // belongs to. This is used to track memory accounting correctly.
    30  type queueFlags uint8
    31  
    32  const (
    33  	recvQ queueFlags = 1 << iota
    34  	sendQ
    35  )
    36  
    37  // segment represents a TCP segment. It holds the payload and parsed TCP segment
    38  // information, and can be added to intrusive lists.
    39  // segment is mostly immutable, the only field allowed to change is data.
    40  //
    41  // +stateify savable
    42  type segment struct {
    43  	segmentEntry
    44  	refCnt int32
    45  	ep     *endpoint
    46  	qFlags queueFlags
    47  	id     stack.TransportEndpointID `state:"manual"`
    48  
    49  	// TODO(gvisor.dev/issue/4417): Hold a stack.PacketBuffer instead of
    50  	// individual members for link/network packet info.
    51  	srcAddr  tcpip.Address
    52  	dstAddr  tcpip.Address
    53  	netProto tcpip.NetworkProtocolNumber
    54  	nicID    tcpip.NICID
    55  
    56  	data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
    57  
    58  	hdr header.TCP
    59  	// views is used as buffer for data when its length is large
    60  	// enough to store a VectorisedView.
    61  	views          [8]buffer.View `state:"nosave"`
    62  	sequenceNumber seqnum.Value
    63  	ackNumber      seqnum.Value
    64  	flags          header.TCPFlags
    65  	window         seqnum.Size
    66  	// csum is only populated for received segments.
    67  	csum uint16
    68  	// csumValid is true if the csum in the received segment is valid.
    69  	csumValid bool
    70  
    71  	// parsedOptions stores the parsed values from the options in the segment.
    72  	parsedOptions  header.TCPOptions
    73  	options        []byte `state:".([]byte)"`
    74  	hasNewSACKInfo bool
    75  	rcvdTime       tcpip.MonotonicTime
    76  	// xmitTime is the last transmit time of this segment.
    77  	xmitTime  tcpip.MonotonicTime
    78  	xmitCount uint32
    79  
    80  	// acked indicates if the segment has already been SACKed.
    81  	acked bool
    82  
    83  	// dataMemSize is the memory used by data initially.
    84  	dataMemSize int
    85  
    86  	// lost indicates if the segment is marked as lost by RACK.
    87  	lost bool
    88  }
    89  
    90  func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt *stack.PacketBuffer) *segment {
    91  	netHdr := pkt.Network()
    92  	s := &segment{
    93  		refCnt:   1,
    94  		id:       id,
    95  		srcAddr:  netHdr.SourceAddress(),
    96  		dstAddr:  netHdr.DestinationAddress(),
    97  		netProto: pkt.NetworkProtocolNumber,
    98  		nicID:    pkt.NICID,
    99  	}
   100  	s.data = pkt.Data().ExtractVV().Clone(s.views[:])
   101  	s.hdr = header.TCP(pkt.TransportHeader().View())
   102  	s.rcvdTime = clock.NowMonotonic()
   103  	s.dataMemSize = s.data.Size()
   104  	return s
   105  }
   106  
   107  func newOutgoingSegment(id stack.TransportEndpointID, clock tcpip.Clock, v buffer.View) *segment {
   108  	s := &segment{
   109  		refCnt: 1,
   110  		id:     id,
   111  	}
   112  	s.rcvdTime = clock.NowMonotonic()
   113  	if len(v) != 0 {
   114  		s.views[0] = v
   115  		s.data = buffer.NewVectorisedView(len(v), s.views[:1])
   116  	}
   117  	s.dataMemSize = s.data.Size()
   118  	return s
   119  }
   120  
   121  func (s *segment) clone() *segment {
   122  	t := &segment{
   123  		refCnt:         1,
   124  		id:             s.id,
   125  		sequenceNumber: s.sequenceNumber,
   126  		ackNumber:      s.ackNumber,
   127  		flags:          s.flags,
   128  		window:         s.window,
   129  		netProto:       s.netProto,
   130  		nicID:          s.nicID,
   131  		rcvdTime:       s.rcvdTime,
   132  		xmitTime:       s.xmitTime,
   133  		xmitCount:      s.xmitCount,
   134  		ep:             s.ep,
   135  		qFlags:         s.qFlags,
   136  		dataMemSize:    s.dataMemSize,
   137  	}
   138  	t.data = s.data.Clone(t.views[:])
   139  	return t
   140  }
   141  
   142  // merge merges data in oth and clears oth.
   143  func (s *segment) merge(oth *segment) {
   144  	s.data.Append(oth.data)
   145  	s.dataMemSize = s.data.Size()
   146  
   147  	oth.data = buffer.VectorisedView{}
   148  	oth.dataMemSize = oth.data.Size()
   149  }
   150  
   151  // setOwner sets the owning endpoint for this segment. Its required
   152  // to be called to ensure memory accounting for receive/send buffer
   153  // queues is done properly.
   154  func (s *segment) setOwner(ep *endpoint, qFlags queueFlags) {
   155  	switch qFlags {
   156  	case recvQ:
   157  		ep.updateReceiveMemUsed(s.segMemSize())
   158  	case sendQ:
   159  		// no memory account for sendQ yet.
   160  	default:
   161  		panic(fmt.Sprintf("unexpected queue flag %b", qFlags))
   162  	}
   163  	s.ep = ep
   164  	s.qFlags = qFlags
   165  }
   166  
   167  func (s *segment) decRef() {
   168  	if atomic.AddInt32(&s.refCnt, -1) == 0 {
   169  		if s.ep != nil {
   170  			switch s.qFlags {
   171  			case recvQ:
   172  				s.ep.updateReceiveMemUsed(-s.segMemSize())
   173  			case sendQ:
   174  				// no memory accounting for sendQ yet.
   175  			default:
   176  				panic(fmt.Sprintf("unexpected queue flag %b set for segment", s.qFlags))
   177  			}
   178  		}
   179  	}
   180  }
   181  
   182  func (s *segment) incRef() {
   183  	atomic.AddInt32(&s.refCnt, 1)
   184  }
   185  
   186  // logicalLen is the segment length in the sequence number space. It's defined
   187  // as the data length plus one for each of the SYN and FIN bits set.
   188  func (s *segment) logicalLen() seqnum.Size {
   189  	l := seqnum.Size(s.data.Size())
   190  	if s.flags.Contains(header.TCPFlagSyn) {
   191  		l++
   192  	}
   193  	if s.flags.Contains(header.TCPFlagFin) {
   194  		l++
   195  	}
   196  	return l
   197  }
   198  
   199  // payloadSize is the size of s.data.
   200  func (s *segment) payloadSize() int {
   201  	return s.data.Size()
   202  }
   203  
   204  // segMemSize is the amount of memory used to hold the segment data and
   205  // the associated metadata.
   206  func (s *segment) segMemSize() int {
   207  	return SegSize + s.dataMemSize
   208  }
   209  
   210  // parse populates the sequence & ack numbers, flags, and window fields of the
   211  // segment from the TCP header stored in the data. It then updates the view to
   212  // skip the header.
   213  //
   214  // Returns boolean indicating if the parsing was successful.
   215  //
   216  // If checksum verification may not be skipped, parse also verifies the
   217  // TCP checksum and stores the checksum and result of checksum verification in
   218  // the csum and csumValid fields of the segment.
   219  func (s *segment) parse(skipChecksumValidation bool) bool {
   220  	// h is the header followed by the payload. We check that the offset to
   221  	// the data respects the following constraints:
   222  	// 1. That it's at least the minimum header size; if we don't do this
   223  	//    then part of the header would be delivered to user.
   224  	// 2. That the header fits within the buffer; if we don't do this, we
   225  	//    would panic when we tried to access data beyond the buffer.
   226  	//
   227  	// N.B. The segment has already been validated as having at least the
   228  	//      minimum TCP size before reaching here, so it's safe to read the
   229  	//      fields.
   230  	offset := int(s.hdr.DataOffset())
   231  	if offset < header.TCPMinimumSize || offset > len(s.hdr) {
   232  		return false
   233  	}
   234  
   235  	s.options = s.hdr[header.TCPMinimumSize:]
   236  	s.parsedOptions = header.ParseTCPOptions(s.options)
   237  	if skipChecksumValidation {
   238  		s.csumValid = true
   239  	} else {
   240  		s.csum = s.hdr.Checksum()
   241  		payloadChecksum := header.ChecksumVV(s.data, 0)
   242  		payloadLength := uint16(s.data.Size())
   243  		s.csumValid = s.hdr.IsChecksumValid(s.srcAddr, s.dstAddr, payloadChecksum, payloadLength)
   244  	}
   245  	s.sequenceNumber = seqnum.Value(s.hdr.SequenceNumber())
   246  	s.ackNumber = seqnum.Value(s.hdr.AckNumber())
   247  	s.flags = s.hdr.Flags()
   248  	s.window = seqnum.Size(s.hdr.WindowSize())
   249  	return true
   250  }
   251  
   252  // sackBlock returns a header.SACKBlock that represents this segment.
   253  func (s *segment) sackBlock() header.SACKBlock {
   254  	return header.SACKBlock{Start: s.sequenceNumber, End: s.sequenceNumber.Add(s.logicalLen())}
   255  }