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 }