Add TCP resets sent to stack.Stats.
Change-Id: I40d5b2cac3de9eaaa79d85d871d97b0c9f8089e2
diff --git a/tcpip/tcpip.go b/tcpip/tcpip.go
index e419999..cde2a55 100644
--- a/tcpip/tcpip.go
+++ b/tcpip/tcpip.go
@@ -428,13 +428,14 @@
// InvalidSegmentsReceived is the number of TCP segments received that
// the transport layer could not parse.
InvalidSegmentsReceived uint64
-
// SegmentsSent is the number of TCP segments sent from the transport
// layer. Excludes shutdown, reset, and syn segments, because those
// segments are sent via stack.Route, which writes directly to the network
// endpoint (bypassing the transport endpoint and its associated Stats
// struct completely).
SegmentsSent uint64
+ // ResetsSent is the number of TCP resets sent.
+ ResetsSent uint64
}
}
diff --git a/tcpip/transport/tcp/connect.go b/tcpip/transport/tcp/connect.go
index b4d0d8e..9582576 100644
--- a/tcpip/transport/tcp/connect.go
+++ b/tcpip/transport/tcp/connect.go
@@ -489,6 +489,10 @@
// sendRaw sends a TCP segment to the endpoint's peer.
func (e *endpoint) sendRaw(data buffer.View, flags byte, seq, ack seqnum.Value, rcvWnd seqnum.Size) *tcpip.Error {
atomic.AddUint64(&e.stack.MutableStats().TCP.SegmentsSent, 1)
+
+ if (flags & flagRst) != 0 {
+ atomic.AddUint64(&e.stack.MutableStats().TCP.ResetsSent, 1)
+ }
if e.sendTSOk {
// Embed the timestamp if timestamp has been enabled.
//
diff --git a/tcpip/transport/tcp/tcp_test.go b/tcpip/transport/tcp/tcp_test.go
index 2ce3b49..95de8bc 100644
--- a/tcpip/transport/tcp/tcp_test.go
+++ b/tcpip/transport/tcp/tcp_test.go
@@ -158,6 +158,58 @@
}
}
+func TestTCPResetsSentIncrement(t *testing.T) {
+ c := context.New(t, defaultMTU)
+ defer c.Cleanup()
+ stats := c.Stack().MutableStats()
+ wq := &waiter.Queue{}
+ ep, err := c.Stack().NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, wq)
+ if err != nil {
+ t.Fatalf("NewEndpoint failed: %v", err)
+ }
+ expected := stats.TCP.SegmentsSent + 1
+
+ if err := ep.Bind(tcpip.FullAddress{Port: context.StackPort}, nil); err != nil {
+ t.Fatalf("Bind failed: %v", err)
+ }
+
+ if err := ep.Listen(10); err != nil {
+ t.Fatalf("Listen failed: %v", err)
+ }
+
+ // Send a SYN request.
+ iss := seqnum.Value(789)
+ c.SendPacket(nil, &context.Headers{
+ SrcPort: context.TestPort,
+ DstPort: context.StackPort,
+ Flags: header.TCPFlagSyn,
+ SeqNum: iss,
+ })
+
+ // Receive the SYN-ACK reply.
+ b := c.GetPacket()
+ tcp := header.TCP(header.IPv4(b).Payload())
+ c.IRS = seqnum.Value(tcp.SequenceNumber())
+
+ ackHeaders := &context.Headers{
+ SrcPort: context.TestPort,
+ DstPort: context.StackPort,
+ Flags: header.TCPFlagAck,
+ SeqNum: iss + 1,
+ // If the AckNum is not the increment of the last sequence number, a RST
+ // segment is sent back in response.
+ AckNum: c.IRS + 2,
+ }
+
+ // Send ACK.
+ c.SendPacket(nil, ackHeaders)
+
+ c.GetPacket()
+ if actual := stats.TCP.ResetsSent; actual != expected {
+ t.Fatalf("Expected SegmentsSent to be %d, got %d", expected, actual)
+ }
+}
+
func TestActiveHandshake(t *testing.T) {
c := context.New(t, defaultMTU)
defer c.Cleanup()