summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip
diff options
context:
space:
mode:
authorMithun Iyer <iyerm@google.com>2021-06-04 23:37:01 -0700
committergVisor bot <gvisor-bot@google.com>2021-06-04 23:39:44 -0700
commit03f17c7d902945489f44bbd4e0c6e15695098b52 (patch)
treed610ea338a925ee19855e2c588bce59344426090 /pkg/tcpip
parenta2d340739649862a23d86f3e32f1bb3b928697ef (diff)
Honor data and FIN from the ACK completing handshake
If the ACK completing the handshake has FIN or data, requeue the segment for further processing by the newly established endpoint. Otherwise, the segments would have to be retransmitted by the peer to be processed by the established endpoint. Doing this, keeps the behavior in parity with Linux. This also addresses a test flake with TCPNonBlockingConnectClose where the ACK (completing the handshake) and multiple retransmitted FINACKs from the peer could be dropped by the listener, when using syncookies and the accept queue is full. The handshake could eventually get completed with a retransmitted FINACK, without actual processing of FIN. This can cause the poll with POLLRDHUP on the accepted socket to sometimes time out before the next FINACK retransmission. PiperOrigin-RevId: 377651695
Diffstat (limited to 'pkg/tcpip')
-rw-r--r--pkg/tcpip/transport/tcp/accept.go7
-rw-r--r--pkg/tcpip/transport/tcp/connect.go8
2 files changed, 11 insertions, 4 deletions
diff --git a/pkg/tcpip/transport/tcp/accept.go b/pkg/tcpip/transport/tcp/accept.go
index 2b5abd3ee..d807b13b7 100644
--- a/pkg/tcpip/transport/tcp/accept.go
+++ b/pkg/tcpip/transport/tcp/accept.go
@@ -740,6 +740,13 @@ func (e *endpoint) handleListenSegment(ctx *listenContext, s *segment) tcpip.Err
mss: rcvdSynOptions.MSS,
})
+ // Requeue the segment if the ACK completing the handshake has more info
+ // to be procesed by the newly established endpoint.
+ if (s.flags.Contains(header.TCPFlagFin) || s.data.Size() > 0) && n.enqueueSegment(s) {
+ s.incRef()
+ n.newSegmentWaker.Assert()
+ }
+
// Do the delivery in a separate goroutine so
// that we don't block the listen loop in case
// the application is slow to accept or stops
diff --git a/pkg/tcpip/transport/tcp/connect.go b/pkg/tcpip/transport/tcp/connect.go
index 9958547d3..2137ebc25 100644
--- a/pkg/tcpip/transport/tcp/connect.go
+++ b/pkg/tcpip/transport/tcp/connect.go
@@ -406,11 +406,11 @@ func (h *handshake) synRcvdState(s *segment) tcpip.Error {
h.ep.transitionToStateEstablishedLocked(h)
- // If the segment has data then requeue it for the receiver
- // to process it again once main loop is started.
- if s.data.Size() > 0 {
+ // Requeue the segment if the ACK completing the handshake has more info
+ // to be procesed by the newly established endpoint.
+ if (s.flags.Contains(header.TCPFlagFin) || s.data.Size() > 0) && h.ep.enqueueSegment(s) {
s.incRef()
- h.ep.enqueueSegment(s)
+ h.ep.newSegmentWaker.Assert()
}
return nil
}