2019-04-29 21:25:05 +00:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-07-09 21:03:03 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2018-04-27 17:37:02 +00:00
|
|
|
|
|
|
|
package tcp
|
|
|
|
|
|
|
|
import (
|
2020-09-24 14:13:23 +00:00
|
|
|
"fmt"
|
2018-04-27 17:37:02 +00:00
|
|
|
|
2020-11-05 23:49:51 +00:00
|
|
|
"gvisor.dev/gvisor/pkg/tcpip"
|
2019-06-13 23:49:09 +00:00
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/header"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/seqnum"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
2018-04-27 17:37:02 +00:00
|
|
|
)
|
|
|
|
|
2020-09-24 14:13:23 +00:00
|
|
|
// queueFlags are used to indicate which queue of an endpoint a particular segment
|
|
|
|
// belongs to. This is used to track memory accounting correctly.
|
|
|
|
type queueFlags uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
recvQ queueFlags = 1 << iota
|
|
|
|
sendQ
|
|
|
|
)
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// segment represents a TCP segment. It holds the payload and parsed TCP segment
|
|
|
|
// information, and can be added to intrusive lists.
|
2021-01-07 22:14:58 +00:00
|
|
|
// segment is mostly immutable, the only field allowed to change is data.
|
2018-08-02 17:41:44 +00:00
|
|
|
//
|
|
|
|
// +stateify savable
|
2018-04-27 17:37:02 +00:00
|
|
|
type segment struct {
|
2020-08-25 03:39:26 +00:00
|
|
|
segmentEntry
|
2022-03-24 23:53:40 +00:00
|
|
|
segmentRefs
|
|
|
|
|
2020-09-24 14:13:23 +00:00
|
|
|
ep *endpoint
|
|
|
|
qFlags queueFlags
|
2020-08-25 03:39:26 +00:00
|
|
|
id stack.TransportEndpointID `state:"manual"`
|
2020-11-05 23:49:51 +00:00
|
|
|
|
|
|
|
// TODO(gvisor.dev/issue/4417): Hold a stack.PacketBuffer instead of
|
|
|
|
// individual members for link/network packet info.
|
2021-01-14 00:02:26 +00:00
|
|
|
srcAddr tcpip.Address
|
|
|
|
dstAddr tcpip.Address
|
|
|
|
netProto tcpip.NetworkProtocolNumber
|
|
|
|
nicID tcpip.NICID
|
2020-11-05 23:49:51 +00:00
|
|
|
|
|
|
|
data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
|
|
|
|
|
|
|
|
hdr header.TCP
|
2018-04-27 17:37:02 +00:00
|
|
|
// views is used as buffer for data when its length is large
|
|
|
|
// enough to store a VectorisedView.
|
2021-01-07 22:14:58 +00:00
|
|
|
views [8]buffer.View `state:"nosave"`
|
2018-04-27 17:37:02 +00:00
|
|
|
sequenceNumber seqnum.Value
|
|
|
|
ackNumber seqnum.Value
|
2021-03-10 01:58:02 +00:00
|
|
|
flags header.TCPFlags
|
2018-04-27 17:37:02 +00:00
|
|
|
window seqnum.Size
|
2019-04-09 18:22:28 +00:00
|
|
|
// csum is only populated for received segments.
|
|
|
|
csum uint16
|
|
|
|
// csumValid is true if the csum in the received segment is valid.
|
|
|
|
csumValid bool
|
2018-04-27 17:37:02 +00:00
|
|
|
|
|
|
|
// parsedOptions stores the parsed values from the options in the segment.
|
2019-02-25 23:18:55 +00:00
|
|
|
parsedOptions header.TCPOptions
|
|
|
|
options []byte `state:".([]byte)"`
|
|
|
|
hasNewSACKInfo bool
|
2021-05-26 13:47:52 +00:00
|
|
|
rcvdTime tcpip.MonotonicTime
|
2020-03-18 23:25:20 +00:00
|
|
|
// xmitTime is the last transmit time of this segment.
|
2021-05-26 13:47:52 +00:00
|
|
|
xmitTime tcpip.MonotonicTime
|
2020-03-18 23:25:20 +00:00
|
|
|
xmitCount uint32
|
2020-10-10 00:45:23 +00:00
|
|
|
|
|
|
|
// acked indicates if the segment has already been SACKed.
|
|
|
|
acked bool
|
2021-01-07 22:14:58 +00:00
|
|
|
|
|
|
|
// dataMemSize is the memory used by data initially.
|
|
|
|
dataMemSize int
|
2021-02-08 20:08:11 +00:00
|
|
|
|
|
|
|
// lost indicates if the segment is marked as lost by RACK.
|
|
|
|
lost bool
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
2021-05-26 13:47:52 +00:00
|
|
|
func newIncomingSegment(id stack.TransportEndpointID, clock tcpip.Clock, pkt *stack.PacketBuffer) *segment {
|
2020-11-05 23:49:51 +00:00
|
|
|
netHdr := pkt.Network()
|
2018-04-27 17:37:02 +00:00
|
|
|
s := &segment{
|
2021-01-14 00:02:26 +00:00
|
|
|
id: id,
|
|
|
|
srcAddr: netHdr.SourceAddress(),
|
|
|
|
dstAddr: netHdr.DestinationAddress(),
|
|
|
|
netProto: pkt.NetworkProtocolNumber,
|
|
|
|
nicID: pkt.NICID,
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
2022-03-24 23:53:40 +00:00
|
|
|
s.InitRefs()
|
2021-03-04 00:03:04 +00:00
|
|
|
s.data = pkt.Data().ExtractVV().Clone(s.views[:])
|
2020-08-13 20:07:03 +00:00
|
|
|
s.hdr = header.TCP(pkt.TransportHeader().View())
|
2021-05-26 13:47:52 +00:00
|
|
|
s.rcvdTime = clock.NowMonotonic()
|
2021-01-07 22:14:58 +00:00
|
|
|
s.dataMemSize = s.data.Size()
|
2018-04-27 17:37:02 +00:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2021-05-26 13:47:52 +00:00
|
|
|
func newOutgoingSegment(id stack.TransportEndpointID, clock tcpip.Clock, v buffer.View) *segment {
|
2018-04-27 17:37:02 +00:00
|
|
|
s := &segment{
|
2022-03-24 23:53:40 +00:00
|
|
|
id: id,
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
2022-03-24 23:53:40 +00:00
|
|
|
s.InitRefs()
|
2021-05-26 13:47:52 +00:00
|
|
|
s.rcvdTime = clock.NowMonotonic()
|
2020-04-04 01:34:48 +00:00
|
|
|
if len(v) != 0 {
|
|
|
|
s.views[0] = v
|
|
|
|
s.data = buffer.NewVectorisedView(len(v), s.views[:1])
|
|
|
|
}
|
2021-01-07 22:14:58 +00:00
|
|
|
s.dataMemSize = s.data.Size()
|
2018-04-27 17:37:02 +00:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *segment) clone() *segment {
|
|
|
|
t := &segment{
|
|
|
|
id: s.id,
|
|
|
|
sequenceNumber: s.sequenceNumber,
|
|
|
|
ackNumber: s.ackNumber,
|
|
|
|
flags: s.flags,
|
|
|
|
window: s.window,
|
2020-11-05 23:49:51 +00:00
|
|
|
netProto: s.netProto,
|
|
|
|
nicID: s.nicID,
|
2019-02-25 23:18:55 +00:00
|
|
|
rcvdTime: s.rcvdTime,
|
2020-05-07 17:24:47 +00:00
|
|
|
xmitTime: s.xmitTime,
|
|
|
|
xmitCount: s.xmitCount,
|
2020-09-24 14:13:23 +00:00
|
|
|
ep: s.ep,
|
|
|
|
qFlags: s.qFlags,
|
2021-01-07 22:14:58 +00:00
|
|
|
dataMemSize: s.dataMemSize,
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
2022-03-24 23:53:40 +00:00
|
|
|
t.InitRefs()
|
2018-04-27 17:37:02 +00:00
|
|
|
t.data = s.data.Clone(t.views[:])
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
2021-05-12 21:09:52 +00:00
|
|
|
// merge merges data in oth and clears oth.
|
|
|
|
func (s *segment) merge(oth *segment) {
|
|
|
|
s.data.Append(oth.data)
|
|
|
|
s.dataMemSize = s.data.Size()
|
|
|
|
|
|
|
|
oth.data = buffer.VectorisedView{}
|
|
|
|
oth.dataMemSize = oth.data.Size()
|
|
|
|
}
|
|
|
|
|
2020-09-24 14:13:23 +00:00
|
|
|
// setOwner sets the owning endpoint for this segment. Its required
|
|
|
|
// to be called to ensure memory accounting for receive/send buffer
|
|
|
|
// queues is done properly.
|
|
|
|
func (s *segment) setOwner(ep *endpoint, qFlags queueFlags) {
|
|
|
|
switch qFlags {
|
|
|
|
case recvQ:
|
|
|
|
ep.updateReceiveMemUsed(s.segMemSize())
|
|
|
|
case sendQ:
|
|
|
|
// no memory account for sendQ yet.
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("unexpected queue flag %b", qFlags))
|
|
|
|
}
|
|
|
|
s.ep = ep
|
|
|
|
s.qFlags = qFlags
|
|
|
|
}
|
|
|
|
|
2022-03-24 23:53:40 +00:00
|
|
|
func (s *segment) DecRef() {
|
|
|
|
s.segmentRefs.DecRef(func() {
|
2020-09-24 14:13:23 +00:00
|
|
|
if s.ep != nil {
|
|
|
|
switch s.qFlags {
|
|
|
|
case recvQ:
|
|
|
|
s.ep.updateReceiveMemUsed(-s.segMemSize())
|
|
|
|
case sendQ:
|
|
|
|
// no memory accounting for sendQ yet.
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("unexpected queue flag %b set for segment", s.qFlags))
|
|
|
|
}
|
|
|
|
}
|
2022-03-24 23:53:40 +00:00
|
|
|
})
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// logicalLen is the segment length in the sequence number space. It's defined
|
|
|
|
// as the data length plus one for each of the SYN and FIN bits set.
|
|
|
|
func (s *segment) logicalLen() seqnum.Size {
|
|
|
|
l := seqnum.Size(s.data.Size())
|
2021-05-26 19:16:36 +00:00
|
|
|
if s.flags.Contains(header.TCPFlagSyn) {
|
2018-04-27 17:37:02 +00:00
|
|
|
l++
|
|
|
|
}
|
2021-05-26 19:16:36 +00:00
|
|
|
if s.flags.Contains(header.TCPFlagFin) {
|
2018-04-27 17:37:02 +00:00
|
|
|
l++
|
|
|
|
}
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
2020-09-24 14:13:23 +00:00
|
|
|
// payloadSize is the size of s.data.
|
|
|
|
func (s *segment) payloadSize() int {
|
|
|
|
return s.data.Size()
|
|
|
|
}
|
|
|
|
|
2020-07-27 22:12:36 +00:00
|
|
|
// segMemSize is the amount of memory used to hold the segment data and
|
|
|
|
// the associated metadata.
|
|
|
|
func (s *segment) segMemSize() int {
|
2021-01-07 22:14:58 +00:00
|
|
|
return SegSize + s.dataMemSize
|
2020-07-27 22:12:36 +00:00
|
|
|
}
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// parse populates the sequence & ack numbers, flags, and window fields of the
|
|
|
|
// segment from the TCP header stored in the data. It then updates the view to
|
2019-04-09 18:22:28 +00:00
|
|
|
// skip the header.
|
|
|
|
//
|
|
|
|
// Returns boolean indicating if the parsing was successful.
|
|
|
|
//
|
2020-11-05 23:49:51 +00:00
|
|
|
// If checksum verification may not be skipped, parse also verifies the
|
2019-04-09 18:22:28 +00:00
|
|
|
// TCP checksum and stores the checksum and result of checksum verification in
|
|
|
|
// the csum and csumValid fields of the segment.
|
2020-11-05 23:49:51 +00:00
|
|
|
func (s *segment) parse(skipChecksumValidation bool) bool {
|
2018-04-27 17:37:02 +00:00
|
|
|
// h is the header followed by the payload. We check that the offset to
|
|
|
|
// the data respects the following constraints:
|
|
|
|
// 1. That it's at least the minimum header size; if we don't do this
|
|
|
|
// then part of the header would be delivered to user.
|
|
|
|
// 2. That the header fits within the buffer; if we don't do this, we
|
|
|
|
// would panic when we tried to access data beyond the buffer.
|
|
|
|
//
|
|
|
|
// N.B. The segment has already been validated as having at least the
|
|
|
|
// minimum TCP size before reaching here, so it's safe to read the
|
|
|
|
// fields.
|
2020-06-07 20:37:25 +00:00
|
|
|
offset := int(s.hdr.DataOffset())
|
|
|
|
if offset < header.TCPMinimumSize || offset > len(s.hdr) {
|
2018-04-27 17:37:02 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-05-22 12:47:06 +00:00
|
|
|
s.options = s.hdr[header.TCPMinimumSize:]
|
2018-04-27 17:37:02 +00:00
|
|
|
s.parsedOptions = header.ParseTCPOptions(s.options)
|
2020-11-05 23:49:51 +00:00
|
|
|
if skipChecksumValidation {
|
2019-04-09 18:22:28 +00:00
|
|
|
s.csumValid = true
|
2021-04-20 07:26:54 +00:00
|
|
|
} else {
|
2020-06-07 20:37:25 +00:00
|
|
|
s.csum = s.hdr.Checksum()
|
2021-04-20 07:26:54 +00:00
|
|
|
payloadChecksum := header.ChecksumVV(s.data, 0)
|
|
|
|
payloadLength := uint16(s.data.Size())
|
|
|
|
s.csumValid = s.hdr.IsChecksumValid(s.srcAddr, s.dstAddr, payloadChecksum, payloadLength)
|
2019-04-09 18:22:28 +00:00
|
|
|
}
|
2020-06-07 20:37:25 +00:00
|
|
|
s.sequenceNumber = seqnum.Value(s.hdr.SequenceNumber())
|
|
|
|
s.ackNumber = seqnum.Value(s.hdr.AckNumber())
|
|
|
|
s.flags = s.hdr.Flags()
|
|
|
|
s.window = seqnum.Size(s.hdr.WindowSize())
|
2018-04-27 17:37:02 +00:00
|
|
|
return true
|
|
|
|
}
|
2019-05-03 17:49:58 +00:00
|
|
|
|
|
|
|
// sackBlock returns a header.SACKBlock that represents this segment.
|
|
|
|
func (s *segment) sackBlock() header.SACKBlock {
|
2021-05-22 12:47:06 +00:00
|
|
|
return header.SACKBlock{Start: s.sequenceNumber, End: s.sequenceNumber.Add(s.logicalLen())}
|
2019-05-03 17:49:58 +00:00
|
|
|
}
|