summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/transport/tcp
diff options
context:
space:
mode:
authorIan Gudger <igudger@google.com>2018-11-15 13:16:05 -0800
committerShentubot <shentubot@google.com>2018-11-15 13:17:06 -0800
commit9d8e49d9505e0b2659be01ec49cdad1948134188 (patch)
treeca5f0989f488b77932b355d30039ef024ac19d66 /pkg/tcpip/transport/tcp
parentbc41e4761b6adfb4ef31401c438bd6a34f76ce87 (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.go10
-rw-r--r--pkg/tcpip/transport/tcp/tcp_test.go70
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