diff options
author | gVisor bot <gvisor-bot@google.com> | 2020-08-18 23:02:35 +0000 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-08-18 23:02:35 +0000 |
commit | c24a221d82975154bd7d39adeeb86c1aa8506885 (patch) | |
tree | ea2f8fa74c25e3d15b5bf93bffb39c6cb6e9e3ab | |
parent | 7f6b3895cca4922601b67d3ebdf1a13683328c0b (diff) | |
parent | 4184a7d5f189cfac4a7c9d7a1f0197d074e74e9b (diff) |
Merge release-20200810.0-53-g4184a7d5f (automated)
-rw-r--r-- | pkg/abi/linux/linux_abi_autogen_unsafe.go | 28 | ||||
-rw-r--r-- | pkg/sentry/fsimpl/tmpfs/inode_refs.go | 2 | ||||
-rw-r--r-- | pkg/sentry/platform/ring0/defs_impl_arm64.go | 2 | ||||
-rw-r--r-- | pkg/sentry/socket/unix/socket_refs.go | 2 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/connect.go | 11 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/endpoint.go | 4 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/segment.go | 23 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/snd.go | 41 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/tcp_rack_segment_list.go | 178 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/tcp_segment_list.go | 47 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/tcp_state_autogen.go | 178 |
11 files changed, 386 insertions, 130 deletions
diff --git a/pkg/abi/linux/linux_abi_autogen_unsafe.go b/pkg/abi/linux/linux_abi_autogen_unsafe.go index 4b5c51e7b..f11703282 100644 --- a/pkg/abi/linux/linux_abi_autogen_unsafe.go +++ b/pkg/abi/linux/linux_abi_autogen_unsafe.go @@ -152,7 +152,7 @@ func (s *Statx) UnmarshalBytes(src []byte) { // Packed implements marshal.Marshallable.Packed. //go:nosplit func (s *Statx) Packed() bool { - return s.Atime.Packed() && s.Btime.Packed() && s.Ctime.Packed() && s.Mtime.Packed() + return s.Ctime.Packed() && s.Mtime.Packed() && s.Atime.Packed() && s.Btime.Packed() } // MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe. @@ -167,7 +167,7 @@ func (s *Statx) MarshalUnsafe(dst []byte) { // UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe. func (s *Statx) UnmarshalUnsafe(src []byte) { - if s.Atime.Packed() && s.Btime.Packed() && s.Ctime.Packed() && s.Mtime.Packed() { + if s.Ctime.Packed() && s.Mtime.Packed() && s.Atime.Packed() && s.Btime.Packed() { safecopy.CopyOut(unsafe.Pointer(s), src) } else { // Type Statx doesn't have a packed layout in memory, fallback to UnmarshalBytes. @@ -208,7 +208,7 @@ func (s *Statx) CopyOut(task marshal.Task, addr usermem.Addr) (int, error) { // CopyIn implements marshal.Marshallable.CopyIn. //go:nosplit func (s *Statx) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) { - if !s.Mtime.Packed() && s.Atime.Packed() && s.Btime.Packed() && s.Ctime.Packed() { + if !s.Ctime.Packed() && s.Mtime.Packed() && s.Atime.Packed() && s.Btime.Packed() { // Type Statx doesn't have a packed layout in memory, fall back to UnmarshalBytes. buf := task.CopyScratchBuffer(s.SizeBytes()) // escapes: okay. length, err := task.CopyInBytes(addr, buf) // escapes: okay. @@ -683,7 +683,7 @@ func (f *FUSEHeaderIn) CopyOut(task marshal.Task, addr usermem.Addr) (int, error // CopyIn implements marshal.Marshallable.CopyIn. //go:nosplit func (f *FUSEHeaderIn) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) { - if !f.Unique.Packed() && f.Opcode.Packed() { + if !f.Opcode.Packed() && f.Unique.Packed() { // Type FUSEHeaderIn doesn't have a packed layout in memory, fall back to UnmarshalBytes. buf := task.CopyScratchBuffer(f.SizeBytes()) // escapes: okay. length, err := task.CopyInBytes(addr, buf) // escapes: okay. @@ -2035,7 +2035,7 @@ func (i *IPTEntry) MarshalUnsafe(dst []byte) { // UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe. func (i *IPTEntry) UnmarshalUnsafe(src []byte) { - if i.IP.Packed() && i.Counters.Packed() { + if i.Counters.Packed() && i.IP.Packed() { safecopy.CopyOut(unsafe.Pointer(i), src) } else { // Type IPTEntry doesn't have a packed layout in memory, fallback to UnmarshalBytes. @@ -2208,7 +2208,7 @@ func (i *IPTIP) UnmarshalBytes(src []byte) { // Packed implements marshal.Marshallable.Packed. //go:nosplit func (i *IPTIP) Packed() bool { - return i.Dst.Packed() && i.SrcMask.Packed() && i.DstMask.Packed() && i.Src.Packed() + return i.DstMask.Packed() && i.Src.Packed() && i.Dst.Packed() && i.SrcMask.Packed() } // MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe. @@ -2234,7 +2234,7 @@ func (i *IPTIP) UnmarshalUnsafe(src []byte) { // CopyOutN implements marshal.Marshallable.CopyOutN. //go:nosplit func (i *IPTIP) CopyOutN(task marshal.Task, addr usermem.Addr, limit int) (int, error) { - if !i.Src.Packed() && i.Dst.Packed() && i.SrcMask.Packed() && i.DstMask.Packed() { + if !i.SrcMask.Packed() && i.DstMask.Packed() && i.Src.Packed() && i.Dst.Packed() { // Type IPTIP doesn't have a packed layout in memory, fall back to MarshalBytes. buf := task.CopyScratchBuffer(i.SizeBytes()) // escapes: okay. i.MarshalBytes(buf) // escapes: fallback. @@ -2264,7 +2264,7 @@ func (i *IPTIP) CopyOut(task marshal.Task, addr usermem.Addr) (int, error) { // CopyIn implements marshal.Marshallable.CopyIn. //go:nosplit func (i *IPTIP) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) { - if !i.Src.Packed() && i.Dst.Packed() && i.SrcMask.Packed() && i.DstMask.Packed() { + if !i.SrcMask.Packed() && i.DstMask.Packed() && i.Src.Packed() && i.Dst.Packed() { // Type IPTIP doesn't have a packed layout in memory, fall back to UnmarshalBytes. buf := task.CopyScratchBuffer(i.SizeBytes()) // escapes: okay. length, err := task.CopyInBytes(addr, buf) // escapes: okay. @@ -2290,7 +2290,7 @@ func (i *IPTIP) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) { // WriteTo implements io.WriterTo.WriteTo. func (i *IPTIP) WriteTo(w io.Writer) (int64, error) { - if !i.DstMask.Packed() && i.Src.Packed() && i.Dst.Packed() && i.SrcMask.Packed() { + if !i.Src.Packed() && i.Dst.Packed() && i.SrcMask.Packed() && i.DstMask.Packed() { // Type IPTIP doesn't have a packed layout in memory, fall back to MarshalBytes. buf := make([]byte, i.SizeBytes()) i.MarshalBytes(buf) @@ -3025,7 +3025,7 @@ func (i *IP6TEntry) UnmarshalUnsafe(src []byte) { // CopyOutN implements marshal.Marshallable.CopyOutN. //go:nosplit func (i *IP6TEntry) CopyOutN(task marshal.Task, addr usermem.Addr, limit int) (int, error) { - if !i.IPv6.Packed() && i.Counters.Packed() { + if !i.Counters.Packed() && i.IPv6.Packed() { // Type IP6TEntry doesn't have a packed layout in memory, fall back to MarshalBytes. buf := task.CopyScratchBuffer(i.SizeBytes()) // escapes: okay. i.MarshalBytes(buf) // escapes: fallback. @@ -3201,7 +3201,7 @@ func (i *IP6TIP) Packed() bool { // MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe. func (i *IP6TIP) MarshalUnsafe(dst []byte) { - if i.Src.Packed() && i.Dst.Packed() && i.SrcMask.Packed() && i.DstMask.Packed() { + if i.DstMask.Packed() && i.Src.Packed() && i.Dst.Packed() && i.SrcMask.Packed() { safecopy.CopyIn(dst, unsafe.Pointer(i)) } else { // Type IP6TIP doesn't have a packed layout in memory, fallback to MarshalBytes. @@ -3211,7 +3211,7 @@ func (i *IP6TIP) MarshalUnsafe(dst []byte) { // UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe. func (i *IP6TIP) UnmarshalUnsafe(src []byte) { - if i.Src.Packed() && i.Dst.Packed() && i.SrcMask.Packed() && i.DstMask.Packed() { + if i.SrcMask.Packed() && i.DstMask.Packed() && i.Src.Packed() && i.Dst.Packed() { safecopy.CopyOut(unsafe.Pointer(i), src) } else { // Type IP6TIP doesn't have a packed layout in memory, fallback to UnmarshalBytes. @@ -3252,7 +3252,7 @@ func (i *IP6TIP) CopyOut(task marshal.Task, addr usermem.Addr) (int, error) { // CopyIn implements marshal.Marshallable.CopyIn. //go:nosplit func (i *IP6TIP) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) { - if !i.Src.Packed() && i.Dst.Packed() && i.SrcMask.Packed() && i.DstMask.Packed() { + if !i.SrcMask.Packed() && i.DstMask.Packed() && i.Src.Packed() && i.Dst.Packed() { // Type IP6TIP doesn't have a packed layout in memory, fall back to UnmarshalBytes. buf := task.CopyScratchBuffer(i.SizeBytes()) // escapes: okay. length, err := task.CopyInBytes(addr, buf) // escapes: okay. @@ -3278,7 +3278,7 @@ func (i *IP6TIP) CopyIn(task marshal.Task, addr usermem.Addr) (int, error) { // WriteTo implements io.WriterTo.WriteTo. func (i *IP6TIP) WriteTo(w io.Writer) (int64, error) { - if !i.Src.Packed() && i.Dst.Packed() && i.SrcMask.Packed() && i.DstMask.Packed() { + if !i.SrcMask.Packed() && i.DstMask.Packed() && i.Src.Packed() && i.Dst.Packed() { // Type IP6TIP doesn't have a packed layout in memory, fall back to MarshalBytes. buf := make([]byte, i.SizeBytes()) i.MarshalBytes(buf) diff --git a/pkg/sentry/fsimpl/tmpfs/inode_refs.go b/pkg/sentry/fsimpl/tmpfs/inode_refs.go index 3245ede1f..8b7ff185f 100644 --- a/pkg/sentry/fsimpl/tmpfs/inode_refs.go +++ b/pkg/sentry/fsimpl/tmpfs/inode_refs.go @@ -1,11 +1,11 @@ package tmpfs import ( + "runtime" "sync/atomic" "gvisor.dev/gvisor/pkg/log" refs_vfs1 "gvisor.dev/gvisor/pkg/refs" - "runtime" ) // ownerType is used to customize logging. Note that we use a pointer to T so diff --git a/pkg/sentry/platform/ring0/defs_impl_arm64.go b/pkg/sentry/platform/ring0/defs_impl_arm64.go index 424b66f76..8ebfbfdb6 100644 --- a/pkg/sentry/platform/ring0/defs_impl_arm64.go +++ b/pkg/sentry/platform/ring0/defs_impl_arm64.go @@ -1,10 +1,10 @@ package ring0 import ( - "gvisor.dev/gvisor/pkg/sentry/arch" "gvisor.dev/gvisor/pkg/sentry/platform/ring0/pagetables" "fmt" + "gvisor.dev/gvisor/pkg/sentry/arch" "gvisor.dev/gvisor/pkg/usermem" "io" "reflect" diff --git a/pkg/sentry/socket/unix/socket_refs.go b/pkg/sentry/socket/unix/socket_refs.go index 6ed7b1151..4c6ec186b 100644 --- a/pkg/sentry/socket/unix/socket_refs.go +++ b/pkg/sentry/socket/unix/socket_refs.go @@ -1,11 +1,11 @@ package unix import ( + "runtime" "sync/atomic" "gvisor.dev/gvisor/pkg/log" refs_vfs1 "gvisor.dev/gvisor/pkg/refs" - "runtime" ) // ownerType is used to customize logging. Note that we use a pointer to T so diff --git a/pkg/tcpip/transport/tcp/connect.go b/pkg/tcpip/transport/tcp/connect.go index 290172ac9..87980c0a1 100644 --- a/pkg/tcpip/transport/tcp/connect.go +++ b/pkg/tcpip/transport/tcp/connect.go @@ -924,7 +924,18 @@ func (e *endpoint) handleWrite() *tcpip.Error { first := e.sndQueue.Front() if first != nil { + lastSeg := e.snd.writeList.Back() e.snd.writeList.PushBackList(&e.sndQueue) + if lastSeg == nil { + lastSeg = e.snd.writeList.Front() + } else { + lastSeg = lastSeg.segEntry.Next() + } + // Add new segments to rcList, as rcList and writeList should + // be consistent. + for seg := lastSeg; seg != nil; seg = seg.segEntry.Next() { + e.snd.rcList.PushBack(seg) + } e.sndBufInQueue = 0 } diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index 1ccedebcc..21a4b6e2f 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -1428,7 +1428,7 @@ func (e *endpoint) Peek(vec [][]byte) (int64, tcpip.ControlMessages, *tcpip.Erro vec = append([][]byte(nil), vec...) var num int64 - for s := e.rcvList.Front(); s != nil; s = s.Next() { + for s := e.rcvList.Front(); s != nil; s = s.segEntry.Next() { views := s.data.Views() for i := s.viewToDeliver; i < len(views); i++ { @@ -2249,7 +2249,7 @@ func (e *endpoint) connect(addr tcpip.FullAddress, handshake bool, run bool) *tc if !handshake { e.segmentQueue.mu.Lock() for _, l := range []segmentList{e.segmentQueue.list, e.sndQueue, e.snd.writeList} { - for s := l.Front(); s != nil; s = s.Next() { + for s := l.Front(); s != nil; s = s.segEntry.Next() { s.id = e.ID s.route = r.Clone() e.sndWaker.Assert() diff --git a/pkg/tcpip/transport/tcp/segment.go b/pkg/tcpip/transport/tcp/segment.go index 94307d31a..a20755f78 100644 --- a/pkg/tcpip/transport/tcp/segment.go +++ b/pkg/tcpip/transport/tcp/segment.go @@ -30,12 +30,13 @@ import ( // // +stateify savable type segment struct { - segmentEntry - refCnt int32 - id stack.TransportEndpointID `state:"manual"` - route stack.Route `state:"manual"` - data buffer.VectorisedView `state:".(buffer.VectorisedView)"` - hdr header.TCP + segEntry segmentEntry + rackSegEntry rackSegmentEntry + refCnt int32 + id stack.TransportEndpointID `state:"manual"` + route stack.Route `state:"manual"` + data buffer.VectorisedView `state:".(buffer.VectorisedView)"` + hdr header.TCP // views is used as buffer for data when its length is large // enough to store a VectorisedView. views [8]buffer.View `state:"nosave"` @@ -61,6 +62,16 @@ type segment struct { xmitCount uint32 } +// segmentMapper is the ElementMapper for the writeList. +type segmentMapper struct{} + +func (segmentMapper) linkerFor(seg *segment) *segmentEntry { return &seg.segEntry } + +// rackSegmentMapper is the ElementMapper for the rcList. +type rackSegmentMapper struct{} + +func (rackSegmentMapper) linkerFor(seg *segment) *rackSegmentEntry { return &seg.rackSegEntry } + func newSegment(r *stack.Route, id stack.TransportEndpointID, pkt *stack.PacketBuffer) *segment { s := &segment{ refCnt: 1, diff --git a/pkg/tcpip/transport/tcp/snd.go b/pkg/tcpip/transport/tcp/snd.go index c55589c45..31151f23d 100644 --- a/pkg/tcpip/transport/tcp/snd.go +++ b/pkg/tcpip/transport/tcp/snd.go @@ -154,6 +154,7 @@ type sender struct { closed bool writeNext *segment writeList segmentList + rcList rackSegmentList resendTimer timer `state:"nosave"` resendWaker sleep.Waker `state:"nosave"` @@ -367,7 +368,7 @@ func (s *sender) updateMaxPayloadSize(mtu, count int) { // Rewind writeNext to the first segment exceeding the MTU. Do nothing // if it is already before such a packet. - for seg := s.writeList.Front(); seg != nil; seg = seg.Next() { + for seg := s.writeList.Front(); seg != nil; seg = seg.segEntry.Next() { if seg == s.writeNext { // We got to writeNext before we could find a segment // exceeding the MTU. @@ -622,6 +623,7 @@ func (s *sender) splitSeg(seg *segment, size int) { nSeg.data.TrimFront(size) nSeg.sequenceNumber.UpdateForward(seqnum.Size(size)) s.writeList.InsertAfter(seg, nSeg) + s.rcList.InsertAfter(seg, nSeg) // The segment being split does not carry PUSH flag because it is // followed by the newly split segment. @@ -653,7 +655,7 @@ func (s *sender) NextSeg(nextSegHint *segment) (nextSeg, hint *segment, rescueRt var s3 *segment var s4 *segment // Step 1. - for seg := nextSegHint; seg != nil; seg = seg.Next() { + for seg := nextSegHint; seg != nil; seg = seg.segEntry.Next() { // Stop iteration if we hit a segment that has never been // transmitted (i.e. either it has no assigned sequence number // or if it does have one, it's >= the next sequence number @@ -683,7 +685,7 @@ func (s *sender) NextSeg(nextSegHint *segment) (nextSeg, hint *segment, rescueRt // NextSeg(): // (1.c) IsLost(S2) returns true. if s.ep.scoreboard.IsLost(segSeq) { - return seg, seg.Next(), false + return seg, seg.segEntry.Next(), false } // NextSeg(): @@ -697,7 +699,7 @@ func (s *sender) NextSeg(nextSegHint *segment) (nextSeg, hint *segment, rescueRt // SHOULD be returned. if s3 == nil { s3 = seg - hint = seg.Next() + hint = seg.segEntry.Next() } } // NextSeg(): @@ -731,7 +733,7 @@ func (s *sender) NextSeg(nextSegHint *segment) (nextSeg, hint *segment, rescueRt // range of one segment of up to SMSS octets of // previously unsent data starting with sequence number // HighData+1 MUST be returned." - for seg := s.writeNext; seg != nil; seg = seg.Next() { + for seg := s.writeNext; seg != nil; seg = seg.segEntry.Next() { if s.isAssignedSequenceNumber(seg) && seg.sequenceNumber.LessThan(s.sndNxt) { continue } @@ -773,15 +775,16 @@ func (s *sender) maybeSendSegment(seg *segment, limit int, end seqnum.Value) (se // triggering bugs in poorly written DNS // implementations. var nextTooBig bool - for seg.Next() != nil && seg.Next().data.Size() != 0 { - if seg.data.Size()+seg.Next().data.Size() > available { + for seg.segEntry.Next() != nil && seg.segEntry.Next().data.Size() != 0 { + if seg.data.Size()+seg.segEntry.Next().data.Size() > available { nextTooBig = true break } - seg.data.Append(seg.Next().data) + seg.data.Append(seg.segEntry.Next().data) // Consume the segment that we just merged in. - s.writeList.Remove(seg.Next()) + s.writeList.Remove(seg.segEntry.Next()) + s.rcList.Remove(seg.rackSegEntry.Next()) } if !nextTooBig && seg.data.Size() < available { // Segment is not full. @@ -948,7 +951,7 @@ func (s *sender) handleSACKRecovery(limit int, end seqnum.Value) (dataSent bool) } dataSent = true s.outstanding++ - s.writeNext = nextSeg.Next() + s.writeNext = nextSeg.segEntry.Next() continue } @@ -961,6 +964,7 @@ func (s *sender) handleSACKRecovery(limit int, end seqnum.Value) (dataSent bool) // transmitted in (C.1)." s.outstanding++ dataSent = true + s.sendSegment(nextSeg) segEnd := nextSeg.sequenceNumber.Add(nextSeg.logicalLen()) @@ -1035,7 +1039,7 @@ func (s *sender) sendData() { if s.fr.active && s.ep.sackPermitted { dataSent = s.handleSACKRecovery(s.maxPayloadSize, end) } else { - for seg := s.writeNext; seg != nil && s.outstanding < s.sndCwnd; seg = seg.Next() { + for seg := s.writeNext; seg != nil && s.outstanding < s.sndCwnd; seg = seg.segEntry.Next() { cwndLimit := (s.sndCwnd - s.outstanding) * s.maxPayloadSize if cwndLimit < limit { limit = cwndLimit @@ -1043,7 +1047,7 @@ func (s *sender) sendData() { if s.isAssignedSequenceNumber(seg) && s.ep.sackPermitted && s.ep.scoreboard.IsSACKED(seg.sackBlock()) { // Move writeNext along so that we don't try and scan data that // has already been SACKED. - s.writeNext = seg.Next() + s.writeNext = seg.segEntry.Next() continue } if sent := s.maybeSendSegment(seg, limit, end); !sent { @@ -1051,7 +1055,7 @@ func (s *sender) sendData() { } dataSent = true s.outstanding += s.pCount(seg) - s.writeNext = seg.Next() + s.writeNext = seg.segEntry.Next() } } @@ -1182,7 +1186,7 @@ func (s *sender) SetPipe() { } pipe := 0 smss := seqnum.Size(s.ep.scoreboard.SMSS()) - for s1 := s.writeList.Front(); s1 != nil && s1.data.Size() != 0 && s.isAssignedSequenceNumber(s1); s1 = s1.Next() { + for s1 := s.writeList.Front(); s1 != nil && s1.data.Size() != 0 && s.isAssignedSequenceNumber(s1); s1 = s1.segEntry.Next() { // With GSO each segment can be much larger than SMSS. So check the segment // in SMSS sized ranges. segEnd := s1.sequenceNumber.Add(seqnum.Size(s1.data.Size())) @@ -1384,7 +1388,7 @@ func (s *sender) handleRcvdSegment(rcvdSeg *segment) { } if s.writeNext == seg { - s.writeNext = seg.Next() + s.writeNext = seg.segEntry.Next() } // Update the RACK fields if SACK is enabled. @@ -1393,6 +1397,7 @@ func (s *sender) handleRcvdSegment(rcvdSeg *segment) { } s.writeList.Remove(seg) + s.rcList.Remove(seg) // if SACK is enabled then Only reduce outstanding if // the segment was not previously SACKED as these have @@ -1460,6 +1465,12 @@ func (s *sender) sendSegment(seg *segment) *tcpip.Error { if s.sndCwnd < s.sndSsthresh { s.ep.stack.Stats().TCP.SlowStartRetransmits.Increment() } + + // Move the segment which has to be retransmitted to the end of the list, as + // RACK requires the segments in the order of their transmission times. + // See: https://tools.ietf.org/html/draft-ietf-tcpm-rack-09#section-6.2 + // Step 5 + s.rcList.PushBack(seg) } seg.xmitTime = time.Now() seg.xmitCount++ diff --git a/pkg/tcpip/transport/tcp/tcp_rack_segment_list.go b/pkg/tcpip/transport/tcp/tcp_rack_segment_list.go new file mode 100644 index 000000000..ccdaab4df --- /dev/null +++ b/pkg/tcpip/transport/tcp/tcp_rack_segment_list.go @@ -0,0 +1,178 @@ +package tcp + +// List is an intrusive list. Entries can be added to or removed from the list +// in O(1) time and with no additional memory allocations. +// +// The zero value for List is an empty list ready to use. +// +// To iterate over a list (where l is a List): +// for e := l.Front(); e != nil; e = e.Next() { +// // do something with e. +// } +// +// +stateify savable +type rackSegmentList struct { + head *segment + tail *segment +} + +// Reset resets list l to the empty state. +func (l *rackSegmentList) Reset() { + l.head = nil + l.tail = nil +} + +// Empty returns true iff the list is empty. +func (l *rackSegmentList) Empty() bool { + return l.head == nil +} + +// Front returns the first element of list l or nil. +func (l *rackSegmentList) Front() *segment { + return l.head +} + +// Back returns the last element of list l or nil. +func (l *rackSegmentList) Back() *segment { + return l.tail +} + +// Len returns the number of elements in the list. +// +// NOTE: This is an O(n) operation. +func (l *rackSegmentList) Len() (count int) { + for e := l.Front(); e != nil; e = (rackSegmentMapper{}.linkerFor(e)).Next() { + count++ + } + return count +} + +// PushFront inserts the element e at the front of list l. +func (l *rackSegmentList) PushFront(e *segment) { + linker := rackSegmentMapper{}.linkerFor(e) + linker.SetNext(l.head) + linker.SetPrev(nil) + if l.head != nil { + rackSegmentMapper{}.linkerFor(l.head).SetPrev(e) + } else { + l.tail = e + } + + l.head = e +} + +// PushBack inserts the element e at the back of list l. +func (l *rackSegmentList) PushBack(e *segment) { + linker := rackSegmentMapper{}.linkerFor(e) + linker.SetNext(nil) + linker.SetPrev(l.tail) + if l.tail != nil { + rackSegmentMapper{}.linkerFor(l.tail).SetNext(e) + } else { + l.head = e + } + + l.tail = e +} + +// PushBackList inserts list m at the end of list l, emptying m. +func (l *rackSegmentList) PushBackList(m *rackSegmentList) { + if l.head == nil { + l.head = m.head + l.tail = m.tail + } else if m.head != nil { + rackSegmentMapper{}.linkerFor(l.tail).SetNext(m.head) + rackSegmentMapper{}.linkerFor(m.head).SetPrev(l.tail) + + l.tail = m.tail + } + m.head = nil + m.tail = nil +} + +// InsertAfter inserts e after b. +func (l *rackSegmentList) InsertAfter(b, e *segment) { + bLinker := rackSegmentMapper{}.linkerFor(b) + eLinker := rackSegmentMapper{}.linkerFor(e) + + a := bLinker.Next() + + eLinker.SetNext(a) + eLinker.SetPrev(b) + bLinker.SetNext(e) + + if a != nil { + rackSegmentMapper{}.linkerFor(a).SetPrev(e) + } else { + l.tail = e + } +} + +// InsertBefore inserts e before a. +func (l *rackSegmentList) InsertBefore(a, e *segment) { + aLinker := rackSegmentMapper{}.linkerFor(a) + eLinker := rackSegmentMapper{}.linkerFor(e) + + b := aLinker.Prev() + eLinker.SetNext(a) + eLinker.SetPrev(b) + aLinker.SetPrev(e) + + if b != nil { + rackSegmentMapper{}.linkerFor(b).SetNext(e) + } else { + l.head = e + } +} + +// Remove removes e from l. +func (l *rackSegmentList) Remove(e *segment) { + linker := rackSegmentMapper{}.linkerFor(e) + prev := linker.Prev() + next := linker.Next() + + if prev != nil { + rackSegmentMapper{}.linkerFor(prev).SetNext(next) + } else if l.head == e { + l.head = next + } + + if next != nil { + rackSegmentMapper{}.linkerFor(next).SetPrev(prev) + } else if l.tail == e { + l.tail = prev + } + + linker.SetNext(nil) + linker.SetPrev(nil) +} + +// Entry is a default implementation of Linker. Users can add anonymous fields +// of this type to their structs to make them automatically implement the +// methods needed by List. +// +// +stateify savable +type rackSegmentEntry struct { + next *segment + prev *segment +} + +// Next returns the entry that follows e in the list. +func (e *rackSegmentEntry) Next() *segment { + return e.next +} + +// Prev returns the entry that precedes e in the list. +func (e *rackSegmentEntry) Prev() *segment { + return e.prev +} + +// SetNext assigns 'entry' as the entry that follows e in the list. +func (e *rackSegmentEntry) SetNext(elem *segment) { + e.next = elem +} + +// SetPrev assigns 'entry' as the entry that precedes e in the list. +func (e *rackSegmentEntry) SetPrev(elem *segment) { + e.prev = elem +} diff --git a/pkg/tcpip/transport/tcp/tcp_segment_list.go b/pkg/tcpip/transport/tcp/tcp_segment_list.go index fcd0c7ec1..5c1f7ee41 100644 --- a/pkg/tcpip/transport/tcp/tcp_segment_list.go +++ b/pkg/tcpip/transport/tcp/tcp_segment_list.go @@ -1,20 +1,5 @@ package tcp -// ElementMapper provides an identity mapping by default. -// -// This can be replaced to provide a struct that maps elements to linker -// objects, if they are not the same. An ElementMapper is not typically -// required if: Linker is left as is, Element is left as is, or Linker and -// Element are the same type. -type segmentElementMapper struct{} - -// linkerFor maps an Element to a Linker. -// -// This default implementation should be inlined. -// -//go:nosplit -func (segmentElementMapper) linkerFor(elem *segment) *segment { return elem } - // List is an intrusive list. Entries can be added to or removed from the list // in O(1) time and with no additional memory allocations. // @@ -56,7 +41,7 @@ func (l *segmentList) Back() *segment { // // NOTE: This is an O(n) operation. func (l *segmentList) Len() (count int) { - for e := l.Front(); e != nil; e = (segmentElementMapper{}.linkerFor(e)).Next() { + for e := l.Front(); e != nil; e = (segmentMapper{}.linkerFor(e)).Next() { count++ } return count @@ -64,11 +49,11 @@ func (l *segmentList) Len() (count int) { // PushFront inserts the element e at the front of list l. func (l *segmentList) PushFront(e *segment) { - linker := segmentElementMapper{}.linkerFor(e) + linker := segmentMapper{}.linkerFor(e) linker.SetNext(l.head) linker.SetPrev(nil) if l.head != nil { - segmentElementMapper{}.linkerFor(l.head).SetPrev(e) + segmentMapper{}.linkerFor(l.head).SetPrev(e) } else { l.tail = e } @@ -78,11 +63,11 @@ func (l *segmentList) PushFront(e *segment) { // PushBack inserts the element e at the back of list l. func (l *segmentList) PushBack(e *segment) { - linker := segmentElementMapper{}.linkerFor(e) + linker := segmentMapper{}.linkerFor(e) linker.SetNext(nil) linker.SetPrev(l.tail) if l.tail != nil { - segmentElementMapper{}.linkerFor(l.tail).SetNext(e) + segmentMapper{}.linkerFor(l.tail).SetNext(e) } else { l.head = e } @@ -96,8 +81,8 @@ func (l *segmentList) PushBackList(m *segmentList) { l.head = m.head l.tail = m.tail } else if m.head != nil { - segmentElementMapper{}.linkerFor(l.tail).SetNext(m.head) - segmentElementMapper{}.linkerFor(m.head).SetPrev(l.tail) + segmentMapper{}.linkerFor(l.tail).SetNext(m.head) + segmentMapper{}.linkerFor(m.head).SetPrev(l.tail) l.tail = m.tail } @@ -107,8 +92,8 @@ func (l *segmentList) PushBackList(m *segmentList) { // InsertAfter inserts e after b. func (l *segmentList) InsertAfter(b, e *segment) { - bLinker := segmentElementMapper{}.linkerFor(b) - eLinker := segmentElementMapper{}.linkerFor(e) + bLinker := segmentMapper{}.linkerFor(b) + eLinker := segmentMapper{}.linkerFor(e) a := bLinker.Next() @@ -117,7 +102,7 @@ func (l *segmentList) InsertAfter(b, e *segment) { bLinker.SetNext(e) if a != nil { - segmentElementMapper{}.linkerFor(a).SetPrev(e) + segmentMapper{}.linkerFor(a).SetPrev(e) } else { l.tail = e } @@ -125,8 +110,8 @@ func (l *segmentList) InsertAfter(b, e *segment) { // InsertBefore inserts e before a. func (l *segmentList) InsertBefore(a, e *segment) { - aLinker := segmentElementMapper{}.linkerFor(a) - eLinker := segmentElementMapper{}.linkerFor(e) + aLinker := segmentMapper{}.linkerFor(a) + eLinker := segmentMapper{}.linkerFor(e) b := aLinker.Prev() eLinker.SetNext(a) @@ -134,7 +119,7 @@ func (l *segmentList) InsertBefore(a, e *segment) { aLinker.SetPrev(e) if b != nil { - segmentElementMapper{}.linkerFor(b).SetNext(e) + segmentMapper{}.linkerFor(b).SetNext(e) } else { l.head = e } @@ -142,18 +127,18 @@ func (l *segmentList) InsertBefore(a, e *segment) { // Remove removes e from l. func (l *segmentList) Remove(e *segment) { - linker := segmentElementMapper{}.linkerFor(e) + linker := segmentMapper{}.linkerFor(e) prev := linker.Prev() next := linker.Next() if prev != nil { - segmentElementMapper{}.linkerFor(prev).SetNext(next) + segmentMapper{}.linkerFor(prev).SetNext(next) } else if l.head == e { l.head = next } if next != nil { - segmentElementMapper{}.linkerFor(next).SetPrev(prev) + segmentMapper{}.linkerFor(next).SetPrev(prev) } else if l.tail == e { l.tail = prev } diff --git a/pkg/tcpip/transport/tcp/tcp_state_autogen.go b/pkg/tcpip/transport/tcp/tcp_state_autogen.go index bed45e9a1..09f6c6399 100644 --- a/pkg/tcpip/transport/tcp/tcp_state_autogen.go +++ b/pkg/tcpip/transport/tcp/tcp_state_autogen.go @@ -535,7 +535,8 @@ func (x *segment) StateTypeName() string { func (x *segment) StateFields() []string { return []string{ - "segmentEntry", + "segEntry", + "rackSegEntry", "refCnt", "data", "hdr", @@ -560,48 +561,50 @@ func (x *segment) beforeSave() {} func (x *segment) StateSave(m state.Sink) { x.beforeSave() var data buffer.VectorisedView = x.saveData() - m.SaveValue(2, data) + m.SaveValue(3, data) var options []byte = x.saveOptions() - m.SaveValue(12, options) + m.SaveValue(13, options) var rcvdTime unixTime = x.saveRcvdTime() - m.SaveValue(14, rcvdTime) + m.SaveValue(15, rcvdTime) var xmitTime unixTime = x.saveXmitTime() - m.SaveValue(15, xmitTime) - m.Save(0, &x.segmentEntry) - m.Save(1, &x.refCnt) - m.Save(3, &x.hdr) - m.Save(4, &x.viewToDeliver) - m.Save(5, &x.sequenceNumber) - m.Save(6, &x.ackNumber) - m.Save(7, &x.flags) - m.Save(8, &x.window) - m.Save(9, &x.csum) - m.Save(10, &x.csumValid) - m.Save(11, &x.parsedOptions) - m.Save(13, &x.hasNewSACKInfo) - m.Save(16, &x.xmitCount) + m.SaveValue(16, xmitTime) + m.Save(0, &x.segEntry) + m.Save(1, &x.rackSegEntry) + m.Save(2, &x.refCnt) + m.Save(4, &x.hdr) + m.Save(5, &x.viewToDeliver) + m.Save(6, &x.sequenceNumber) + m.Save(7, &x.ackNumber) + m.Save(8, &x.flags) + m.Save(9, &x.window) + m.Save(10, &x.csum) + m.Save(11, &x.csumValid) + m.Save(12, &x.parsedOptions) + m.Save(14, &x.hasNewSACKInfo) + m.Save(17, &x.xmitCount) } func (x *segment) afterLoad() {} func (x *segment) StateLoad(m state.Source) { - m.Load(0, &x.segmentEntry) - m.Load(1, &x.refCnt) - m.Load(3, &x.hdr) - m.Load(4, &x.viewToDeliver) - m.Load(5, &x.sequenceNumber) - m.Load(6, &x.ackNumber) - m.Load(7, &x.flags) - m.Load(8, &x.window) - m.Load(9, &x.csum) - m.Load(10, &x.csumValid) - m.Load(11, &x.parsedOptions) - m.Load(13, &x.hasNewSACKInfo) - m.Load(16, &x.xmitCount) - m.LoadValue(2, new(buffer.VectorisedView), func(y interface{}) { x.loadData(y.(buffer.VectorisedView)) }) - m.LoadValue(12, new([]byte), func(y interface{}) { x.loadOptions(y.([]byte)) }) - m.LoadValue(14, new(unixTime), func(y interface{}) { x.loadRcvdTime(y.(unixTime)) }) - m.LoadValue(15, new(unixTime), func(y interface{}) { x.loadXmitTime(y.(unixTime)) }) + m.Load(0, &x.segEntry) + m.Load(1, &x.rackSegEntry) + m.Load(2, &x.refCnt) + m.Load(4, &x.hdr) + m.Load(5, &x.viewToDeliver) + m.Load(6, &x.sequenceNumber) + m.Load(7, &x.ackNumber) + m.Load(8, &x.flags) + m.Load(9, &x.window) + m.Load(10, &x.csum) + m.Load(11, &x.csumValid) + m.Load(12, &x.parsedOptions) + m.Load(14, &x.hasNewSACKInfo) + m.Load(17, &x.xmitCount) + m.LoadValue(3, new(buffer.VectorisedView), func(y interface{}) { x.loadData(y.(buffer.VectorisedView)) }) + m.LoadValue(13, new([]byte), func(y interface{}) { x.loadOptions(y.([]byte)) }) + m.LoadValue(15, new(unixTime), func(y interface{}) { x.loadRcvdTime(y.(unixTime)) }) + m.LoadValue(16, new(unixTime), func(y interface{}) { x.loadXmitTime(y.(unixTime)) }) } func (x *segmentQueue) StateTypeName() string { @@ -656,6 +659,7 @@ func (x *sender) StateFields() []string { "closed", "writeNext", "writeList", + "rcList", "rtt", "rto", "minRTO", @@ -695,18 +699,19 @@ func (x *sender) StateSave(m state.Sink) { m.Save(14, &x.closed) m.Save(15, &x.writeNext) m.Save(16, &x.writeList) - m.Save(17, &x.rtt) - m.Save(18, &x.rto) - m.Save(19, &x.minRTO) - m.Save(20, &x.maxRTO) - m.Save(21, &x.maxRetries) - m.Save(22, &x.maxPayloadSize) - m.Save(23, &x.gso) - m.Save(24, &x.sndWndScale) - m.Save(25, &x.maxSentAck) - m.Save(26, &x.state) - m.Save(27, &x.cc) - m.Save(28, &x.rc) + m.Save(17, &x.rcList) + m.Save(18, &x.rtt) + m.Save(19, &x.rto) + m.Save(20, &x.minRTO) + m.Save(21, &x.maxRTO) + m.Save(22, &x.maxRetries) + m.Save(23, &x.maxPayloadSize) + m.Save(24, &x.gso) + m.Save(25, &x.sndWndScale) + m.Save(26, &x.maxSentAck) + m.Save(27, &x.state) + m.Save(28, &x.cc) + m.Save(29, &x.rc) } func (x *sender) StateLoad(m state.Source) { @@ -724,18 +729,19 @@ func (x *sender) StateLoad(m state.Source) { m.Load(14, &x.closed) m.Load(15, &x.writeNext) m.Load(16, &x.writeList) - m.Load(17, &x.rtt) - m.Load(18, &x.rto) - m.Load(19, &x.minRTO) - m.Load(20, &x.maxRTO) - m.Load(21, &x.maxRetries) - m.Load(22, &x.maxPayloadSize) - m.Load(23, &x.gso) - m.Load(24, &x.sndWndScale) - m.Load(25, &x.maxSentAck) - m.Load(26, &x.state) - m.Load(27, &x.cc) - m.Load(28, &x.rc) + m.Load(17, &x.rcList) + m.Load(18, &x.rtt) + m.Load(19, &x.rto) + m.Load(20, &x.minRTO) + m.Load(21, &x.maxRTO) + m.Load(22, &x.maxRetries) + m.Load(23, &x.maxPayloadSize) + m.Load(24, &x.gso) + m.Load(25, &x.sndWndScale) + m.Load(26, &x.maxSentAck) + m.Load(27, &x.state) + m.Load(28, &x.cc) + m.Load(29, &x.rc) m.LoadValue(1, new(unixTime), func(y interface{}) { x.loadLastSendTime(y.(unixTime)) }) m.LoadValue(12, new(unixTime), func(y interface{}) { x.loadRttMeasureTime(y.(unixTime)) }) m.LoadValue(13, new(unixTime), func(y interface{}) { x.loadFirstRetransmittedSegXmitTime(y.(unixTime)) }) @@ -887,6 +893,58 @@ func (x *endpointEntry) StateLoad(m state.Source) { m.Load(1, &x.prev) } +func (x *rackSegmentList) StateTypeName() string { + return "pkg/tcpip/transport/tcp.rackSegmentList" +} + +func (x *rackSegmentList) StateFields() []string { + return []string{ + "head", + "tail", + } +} + +func (x *rackSegmentList) beforeSave() {} + +func (x *rackSegmentList) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.head) + m.Save(1, &x.tail) +} + +func (x *rackSegmentList) afterLoad() {} + +func (x *rackSegmentList) StateLoad(m state.Source) { + m.Load(0, &x.head) + m.Load(1, &x.tail) +} + +func (x *rackSegmentEntry) StateTypeName() string { + return "pkg/tcpip/transport/tcp.rackSegmentEntry" +} + +func (x *rackSegmentEntry) StateFields() []string { + return []string{ + "next", + "prev", + } +} + +func (x *rackSegmentEntry) beforeSave() {} + +func (x *rackSegmentEntry) StateSave(m state.Sink) { + x.beforeSave() + m.Save(0, &x.next) + m.Save(1, &x.prev) +} + +func (x *rackSegmentEntry) afterLoad() {} + +func (x *rackSegmentEntry) StateLoad(m state.Source) { + m.Load(0, &x.next) + m.Load(1, &x.prev) +} + func (x *segmentList) StateTypeName() string { return "pkg/tcpip/transport/tcp.segmentList" } @@ -958,6 +1016,8 @@ func init() { state.Register((*unixTime)(nil)) state.Register((*endpointList)(nil)) state.Register((*endpointEntry)(nil)) + state.Register((*rackSegmentList)(nil)) + state.Register((*rackSegmentEntry)(nil)) state.Register((*segmentList)(nil)) state.Register((*segmentEntry)(nil)) } |