mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add TCP stats for connection close and keep-alive timeouts.
Fix bugs in updates to TCP CurrentEstablished stat. Fixes #1277 PiperOrigin-RevId: 284292459
This commit is contained in:
@@ -151,6 +151,8 @@ var Metrics = tcpip.Stats{
|
||||
PassiveConnectionOpenings: mustCreateMetric("/netstack/tcp/passive_connection_openings", "Number of connections opened successfully via Listen."),
|
||||
CurrentEstablished: mustCreateMetric("/netstack/tcp/current_established", "Number of connections in either ESTABLISHED or CLOSE-WAIT state now."),
|
||||
EstablishedResets: mustCreateMetric("/netstack/tcp/established_resets", "Number of times TCP connections have made a direct transition to the CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state"),
|
||||
EstablishedClosed: mustCreateMetric("/netstack/tcp/established_closed", "number of times established TCP connections made a transition to CLOSED state."),
|
||||
EstablishedTimedout: mustCreateMetric("/netstack/tcp/established_timedout", "Number of times an established connection was reset because of keep-alive time out."),
|
||||
ListenOverflowSynDrop: mustCreateMetric("/netstack/tcp/listen_overflow_syn_drop", "Number of times the listen queue overflowed and a SYN was dropped."),
|
||||
ListenOverflowAckDrop: mustCreateMetric("/netstack/tcp/listen_overflow_ack_drop", "Number of times the listen queue overflowed and the final ACK in the handshake was dropped."),
|
||||
ListenOverflowSynCookieSent: mustCreateMetric("/netstack/tcp/listen_overflow_syn_cookie_sent", "Number of times a SYN cookie was sent."),
|
||||
|
||||
@@ -924,6 +924,14 @@ type TCPStats struct {
|
||||
// ESTABLISHED state or the CLOSE-WAIT state.
|
||||
EstablishedResets *StatCounter
|
||||
|
||||
// EstablishedClosed is the number of times established TCP connections
|
||||
// made a transition to CLOSED state.
|
||||
EstablishedClosed *StatCounter
|
||||
|
||||
// EstablishedTimedout is the number of times an established connection
|
||||
// was reset because of keep-alive time out.
|
||||
EstablishedTimedout *StatCounter
|
||||
|
||||
// ListenOverflowSynDrop is the number of times the listen queue overflowed
|
||||
// and a SYN was dropped.
|
||||
ListenOverflowSynDrop *StatCounter
|
||||
|
||||
@@ -924,6 +924,7 @@ func (e *endpoint) transitionToStateCloseLocked() {
|
||||
}
|
||||
e.cleanupLocked()
|
||||
e.state = StateClose
|
||||
e.stack.Stats().TCP.EstablishedClosed.Increment()
|
||||
}
|
||||
|
||||
// tryDeliverSegmentFromClosedEndpoint attempts to deliver the parsed
|
||||
@@ -1094,6 +1095,7 @@ func (e *endpoint) keepaliveTimerExpired() *tcpip.Error {
|
||||
|
||||
if e.keepalive.unacked >= e.keepalive.count {
|
||||
e.keepalive.Unlock()
|
||||
e.stack.Stats().TCP.EstablishedTimedout.Increment()
|
||||
return tcpip.ErrTimeout
|
||||
}
|
||||
|
||||
@@ -1179,8 +1181,6 @@ func (e *endpoint) protocolMainLoop(handshake bool) *tcpip.Error {
|
||||
e.lastErrorMu.Unlock()
|
||||
|
||||
e.mu.Lock()
|
||||
e.stack.Stats().TCP.EstablishedResets.Increment()
|
||||
e.stack.Stats().TCP.CurrentEstablished.Decrement()
|
||||
e.state = StateError
|
||||
e.HardError = err
|
||||
|
||||
@@ -1389,7 +1389,6 @@ func (e *endpoint) protocolMainLoop(handshake bool) *tcpip.Error {
|
||||
// Mark endpoint as closed.
|
||||
e.mu.Lock()
|
||||
if e.state != StateError {
|
||||
e.stack.Stats().TCP.EstablishedResets.Increment()
|
||||
e.stack.Stats().TCP.CurrentEstablished.Decrement()
|
||||
e.transitionToStateCloseLocked()
|
||||
}
|
||||
|
||||
@@ -674,7 +674,6 @@ func (s *sender) maybeSendSegment(seg *segment, limit int, end seqnum.Value) (se
|
||||
default:
|
||||
s.ep.state = StateFinWait1
|
||||
}
|
||||
s.ep.stack.Stats().TCP.CurrentEstablished.Decrement()
|
||||
s.ep.mu.Unlock()
|
||||
} else {
|
||||
// We're sending a non-FIN segment.
|
||||
|
||||
@@ -75,6 +75,20 @@ func TestGiveUpConnect(t *testing.T) {
|
||||
if err := ep.GetSockOpt(tcpip.ErrorOption{}); err != tcpip.ErrAborted {
|
||||
t.Fatalf("got ep.GetSockOpt(tcpip.ErrorOption{}) = %v, want = %v", err, tcpip.ErrAborted)
|
||||
}
|
||||
|
||||
// Call Connect again to retreive the handshake failure status
|
||||
// and stats updates.
|
||||
if err := ep.Connect(tcpip.FullAddress{Addr: context.TestAddr, Port: context.TestPort}); err != tcpip.ErrAborted {
|
||||
t.Fatalf("got ep.Connect(...) = %v, want = %v", err, tcpip.ErrAborted)
|
||||
}
|
||||
|
||||
if got := c.Stack().Stats().TCP.FailedConnectionAttempts.Value(); got != 1 {
|
||||
t.Errorf("got stats.TCP.FailedConnectionAttempts.Value() = %v, want = 1", got)
|
||||
}
|
||||
|
||||
if got := c.Stack().Stats().TCP.CurrentEstablished.Value(); got != 0 {
|
||||
t.Errorf("got stats.TCP.CurrentEstablished.Value() = %v, want = 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectIncrementActiveConnection(t *testing.T) {
|
||||
@@ -548,6 +562,14 @@ func TestClosingWithEnqueuedSegments(t *testing.T) {
|
||||
t.Errorf("Unexpected endpoint state: want %v, got %v", want, got)
|
||||
}
|
||||
|
||||
if got := c.Stack().Stats().TCP.EstablishedClosed.Value(); got != 1 {
|
||||
t.Errorf("got c.Stack().Stats().TCP.EstablishedClosed = %v, want = 1", got)
|
||||
}
|
||||
|
||||
if got := c.Stack().Stats().TCP.CurrentEstablished.Value(); got != 0 {
|
||||
t.Errorf("got stats.TCP.CurrentEstablished.Value() = %v, want = 0", got)
|
||||
}
|
||||
|
||||
// Check if the endpoint was moved to CLOSED and netstack a reset in
|
||||
// response to the ACK packet that we sent after last-ACK.
|
||||
checker.IPv4(t, c.GetPacket(),
|
||||
@@ -2694,6 +2716,13 @@ loop:
|
||||
if tcp.EndpointState(c.EP.State()) != tcp.StateError {
|
||||
t.Fatalf("got EP state is not StateError")
|
||||
}
|
||||
|
||||
if got := c.Stack().Stats().TCP.EstablishedResets.Value(); got != 1 {
|
||||
t.Errorf("got stats.TCP.EstablishedResets.Value() = %v, want = 1", got)
|
||||
}
|
||||
if got := c.Stack().Stats().TCP.CurrentEstablished.Value(); got != 0 {
|
||||
t.Errorf("got stats.TCP.CurrentEstablished.Value() = %v, want = 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendOnResetConnection(t *testing.T) {
|
||||
@@ -4363,9 +4392,17 @@ func TestKeepalive(t *testing.T) {
|
||||
),
|
||||
)
|
||||
|
||||
if got := c.Stack().Stats().TCP.EstablishedTimedout.Value(); got != 1 {
|
||||
t.Errorf("got c.Stack().Stats().TCP.EstablishedTimedout.Value() = %v, want = 1", got)
|
||||
}
|
||||
|
||||
if _, _, err := c.EP.Read(nil); err != tcpip.ErrTimeout {
|
||||
t.Fatalf("got c.EP.Read(nil) = %v, want = %v", err, tcpip.ErrTimeout)
|
||||
}
|
||||
|
||||
if got := c.Stack().Stats().TCP.CurrentEstablished.Value(); got != 0 {
|
||||
t.Errorf("got stats.TCP.CurrentEstablished.Value() = %v, want = 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func executeHandshake(t *testing.T, c *context.Context, srcPort uint16, synCookieInUse bool) (irs, iss seqnum.Value) {
|
||||
@@ -5992,6 +6029,8 @@ func TestTCPTimeWaitDuplicateFINExtendsTimeWait(t *testing.T) {
|
||||
t.Fatalf("c.stack.SetTransportProtocolOption(tcp, tcpip.TCPLingerTimeoutOption(%d) failed: %s", tcpTimeWaitTimeout, err)
|
||||
}
|
||||
|
||||
want := c.Stack().Stats().TCP.EstablishedClosed.Value() + 1
|
||||
|
||||
wq := &waiter.Queue{}
|
||||
ep, err := c.Stack().NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, wq)
|
||||
if err != nil {
|
||||
@@ -6120,6 +6159,13 @@ func TestTCPTimeWaitDuplicateFINExtendsTimeWait(t *testing.T) {
|
||||
checker.SeqNum(uint32(ackHeaders.AckNum)),
|
||||
checker.AckNum(uint32(ackHeaders.SeqNum)),
|
||||
checker.TCPFlags(header.TCPFlagRst|header.TCPFlagAck)))
|
||||
|
||||
if got := c.Stack().Stats().TCP.EstablishedClosed.Value(); got != want {
|
||||
t.Errorf("got c.Stack().Stats().TCP.EstablishedClosed = %v, want = %v", got, want)
|
||||
}
|
||||
if got := c.Stack().Stats().TCP.CurrentEstablished.Value(); got != 0 {
|
||||
t.Errorf("got stats.TCP.CurrentEstablished.Value() = %v, want = 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTCPCloseWithData(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user