diff options
author | Ian Gudger <igudger@google.com> | 2018-11-15 13:16:05 -0800 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-11-15 13:17:06 -0800 |
commit | 9d8e49d9505e0b2659be01ec49cdad1948134188 (patch) | |
tree | ca5f0989f488b77932b355d30039ef024ac19d66 /pkg/tcpip/transport/tcp | |
parent | bc41e4761b6adfb4ef31401c438bd6a34f76ce87 (diff) |
Process delayed packets when delay is disabled
Moving the wakeup logic into the disable blocks is an optimization.
PiperOrigin-RevId: 221677028
Change-Id: Ib5a5a6d52cc77b4bbc5dedcad9ee1dbb3da98deb
Diffstat (limited to 'pkg/tcpip/transport/tcp')
-rw-r--r-- | pkg/tcpip/transport/tcp/endpoint.go | 10 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/tcp_test.go | 70 |
2 files changed, 77 insertions, 3 deletions
diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index 96a546aa7..1649dbc97 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -654,21 +654,25 @@ func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error { case tcpip.DelayOption: if v == 0 { atomic.StoreUint32(&e.delay, 0) + + // Handle delayed data. + e.sndWaker.Assert() } else { atomic.StoreUint32(&e.delay, 1) } + return nil case tcpip.CorkOption: if v == 0 { atomic.StoreUint32(&e.cork, 0) + + // Handle the corked data. + e.sndWaker.Assert() } else { atomic.StoreUint32(&e.cork, 1) } - // Handle the corked data. - e.sndWaker.Assert() - return nil case tcpip.ReuseAddressOption: diff --git a/pkg/tcpip/transport/tcp/tcp_test.go b/pkg/tcpip/transport/tcp/tcp_test.go index 8155e4ed8..467d9c156 100644 --- a/pkg/tcpip/transport/tcp/tcp_test.go +++ b/pkg/tcpip/transport/tcp/tcp_test.go @@ -1379,6 +1379,76 @@ func TestDelay(t *testing.T) { } } +func TestUndelay(t *testing.T) { + c := context.New(t, defaultMTU) + defer c.Cleanup() + + c.CreateConnected(789, 30000, nil) + + c.EP.SetSockOpt(tcpip.DelayOption(1)) + + allData := [][]byte{{0}, {1, 2, 3}} + for i, data := range allData { + view := buffer.NewViewFromBytes(data) + if _, _, err := c.EP.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil { + t.Fatalf("Write #%d failed: %v", i+1, err) + } + } + + seq := c.IRS.Add(1) + + // Check that data is received. + first := c.GetPacket() + checker.IPv4(t, first, + checker.PayloadLen(len(allData[0])+header.TCPMinimumSize), + checker.TCP( + checker.DstPort(context.TestPort), + checker.SeqNum(uint32(seq)), + checker.AckNum(790), + checker.TCPFlagsMatch(header.TCPFlagAck, ^uint8(header.TCPFlagPsh)), + ), + ) + + if got, want := first[header.IPv4MinimumSize+header.TCPMinimumSize:], allData[0]; !bytes.Equal(got, want) { + t.Fatalf("got first packet's data = %v, want = %v", got, want) + } + + seq = seq.Add(seqnum.Size(len(allData[0]))) + + // Check that we don't get the second packet yet. + c.CheckNoPacketTimeout("delayed second packet transmitted", 100*time.Millisecond) + + c.EP.SetSockOpt(tcpip.DelayOption(0)) + + // Check that data is received. + second := c.GetPacket() + checker.IPv4(t, second, + checker.PayloadLen(len(allData[1])+header.TCPMinimumSize), + checker.TCP( + checker.DstPort(context.TestPort), + checker.SeqNum(uint32(seq)), + checker.AckNum(790), + checker.TCPFlagsMatch(header.TCPFlagAck, ^uint8(header.TCPFlagPsh)), + ), + ) + + if got, want := second[header.IPv4MinimumSize+header.TCPMinimumSize:], allData[1]; !bytes.Equal(got, want) { + t.Fatalf("got second packet's data = %v, want = %v", got, want) + } + + seq = seq.Add(seqnum.Size(len(allData[1]))) + + // Acknowledge the data. + c.SendPacket(nil, &context.Headers{ + SrcPort: context.TestPort, + DstPort: c.Port, + Flags: header.TCPFlagAck, + SeqNum: 790, + AckNum: seq, + RcvWnd: 30000, + }) +} + func testBrokenUpWrite(t *testing.T, c *context.Context, maxPayload int) { payloadMultiplier := 10 dataLen := payloadMultiplier * maxPayload |