diff options
-rw-r--r-- | pkg/tcpip/stack/nic.go | 14 | ||||
-rw-r--r-- | pkg/tcpip/stack/stack.go | 26 | ||||
-rw-r--r-- | pkg/tcpip/tcpip.go | 48 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/connect.go | 5 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/endpoint.go | 4 | ||||
-rw-r--r-- | pkg/tcpip/transport/tcp/tcp_timestamp_test.go | 9 |
6 files changed, 67 insertions, 39 deletions
diff --git a/pkg/tcpip/stack/nic.go b/pkg/tcpip/stack/nic.go index 592006a32..284732874 100644 --- a/pkg/tcpip/stack/nic.go +++ b/pkg/tcpip/stack/nic.go @@ -282,12 +282,12 @@ func (n *NIC) RemoveAddress(addr tcpip.Address) *tcpip.Error { func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv *buffer.VectorisedView) { netProto, ok := n.stack.networkProtocols[protocol] if !ok { - atomic.AddUint64(&n.stack.stats.UnknownProtocolRcvdPackets, 1) + n.stack.stats.UnknownProtocolRcvdPackets.Increment() return } if len(vv.First()) < netProto.MinimumPacketSize() { - atomic.AddUint64(&n.stack.stats.MalformedRcvdPackets, 1) + n.stack.stats.MalformedRcvdPackets.Increment() return } @@ -330,7 +330,7 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr tcpip.Lin } if ref == nil { - atomic.AddUint64(&n.stack.stats.UnknownNetworkEndpointRcvdPackets, 1) + n.stack.stats.UnknownNetworkEndpointRcvdPackets.Increment() return } @@ -345,19 +345,19 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remoteLinkAddr tcpip.Lin func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolNumber, vv *buffer.VectorisedView) { state, ok := n.stack.transportProtocols[protocol] if !ok { - atomic.AddUint64(&n.stack.stats.UnknownProtocolRcvdPackets, 1) + n.stack.stats.UnknownProtocolRcvdPackets.Increment() return } transProto := state.proto if len(vv.First()) < transProto.MinimumPacketSize() { - atomic.AddUint64(&n.stack.stats.MalformedRcvdPackets, 1) + n.stack.stats.MalformedRcvdPackets.Increment() return } srcPort, dstPort, err := transProto.ParsePorts(vv.First()) if err != nil { - atomic.AddUint64(&n.stack.stats.MalformedRcvdPackets, 1) + n.stack.stats.MalformedRcvdPackets.Increment() return } @@ -379,7 +379,7 @@ func (n *NIC) DeliverTransportPacket(r *Route, protocol tcpip.TransportProtocolN // We could not find an appropriate destination for this packet, so // deliver it to the global handler. if !transProto.HandleUnknownDestinationPacket(r, id, vv) { - atomic.AddUint64(&n.stack.stats.MalformedRcvdPackets, 1) + n.stack.stats.MalformedRcvdPackets.Increment() } } diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index e09c7efda..cc5427cf9 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -26,7 +26,6 @@ package stack import ( "sync" - "sync/atomic" "time" "gvisor.googlesource.com/gvisor/pkg/sleep" @@ -308,6 +307,9 @@ type Options struct { // // If no Clock is specified, the clock source will be time.Now. Clock tcpip.Clock + + // Stats are optional statistic counters. + Stats tcpip.Stats } // New allocates a new networking stack with only the requested networking and @@ -331,6 +333,7 @@ func New(network []string, transport []string, opts Options) *Stack { linkAddrCache: newLinkAddrCache(ageLimit, resolutionTimeout, resolutionAttempts), PortManager: ports.NewPortManager(), clock: clock, + stats: opts.Stats.FillIn(), } // Add specified network protocols. @@ -437,27 +440,12 @@ func (s *Stack) NowNanoseconds() int64 { return s.clock.NowNanoseconds() } -// Stats returns a snapshot of the current stats. -// -// NOTE: The underlying stats are updated using atomic instructions as a result -// the snapshot returned does not represent the value of all the stats at any -// single given point of time. -// TODO: Make stats available in sentry for debugging/diag. -func (s *Stack) Stats() tcpip.Stats { - return tcpip.Stats{ - UnknownProtocolRcvdPackets: atomic.LoadUint64(&s.stats.UnknownProtocolRcvdPackets), - UnknownNetworkEndpointRcvdPackets: atomic.LoadUint64(&s.stats.UnknownNetworkEndpointRcvdPackets), - MalformedRcvdPackets: atomic.LoadUint64(&s.stats.MalformedRcvdPackets), - DroppedPackets: atomic.LoadUint64(&s.stats.DroppedPackets), - } -} - -// MutableStats returns a mutable copy of the current stats. +// Stats returns a mutable copy of the current stats. // // This is not generally exported via the public interface, but is available // internally. -func (s *Stack) MutableStats() *tcpip.Stats { - return &s.stats +func (s *Stack) Stats() tcpip.Stats { + return s.stats } // SetRouteTable assigns the route table to be used by this stack. It diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go index bea73def9..e323aea8c 100644 --- a/pkg/tcpip/tcpip.go +++ b/pkg/tcpip/tcpip.go @@ -34,6 +34,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "time" "gvisor.googlesource.com/gvisor/pkg/tcpip/buffer" @@ -465,23 +466,62 @@ type TransportProtocolNumber uint32 // NetworkProtocolNumber is the number of a network protocol. type NetworkProtocolNumber uint32 +// A StatCounter keeps track of a statistic. +type StatCounter struct { + count uint64 +} + +// Increment adds one to the counter. +func (s *StatCounter) Increment() { + atomic.AddUint64(&s.count, 1) +} + +// Value returns the current value of the counter. +func (s *StatCounter) Value() uint64 { + return atomic.LoadUint64(&s.count) +} + +// IncrementBy increments the counter by v. +func (s *StatCounter) IncrementBy(v uint64) { + atomic.AddUint64(&s.count, v) +} + // Stats holds statistics about the networking stack. +// +// All fields are optional. type Stats struct { // UnknownProtocolRcvdPackets is the number of packets received by the // stack that were for an unknown or unsupported protocol. - UnknownProtocolRcvdPackets uint64 + UnknownProtocolRcvdPackets *StatCounter // UnknownNetworkEndpointRcvdPackets is the number of packets received // by the stack that were for a supported network protocol, but whose // destination address didn't having a matching endpoint. - UnknownNetworkEndpointRcvdPackets uint64 + UnknownNetworkEndpointRcvdPackets *StatCounter // MalformedRcvPackets is the number of packets received by the stack // that were deemed malformed. - MalformedRcvdPackets uint64 + MalformedRcvdPackets *StatCounter // DroppedPackets is the number of packets dropped due to full queues. - DroppedPackets uint64 + DroppedPackets *StatCounter +} + +// FillIn returns a copy of s with nil fields initialized to new StatCounters. +func (s Stats) FillIn() Stats { + if s.UnknownProtocolRcvdPackets == nil { + s.UnknownProtocolRcvdPackets = &StatCounter{} + } + if s.UnknownNetworkEndpointRcvdPackets == nil { + s.UnknownNetworkEndpointRcvdPackets = &StatCounter{} + } + if s.MalformedRcvdPackets == nil { + s.MalformedRcvdPackets = &StatCounter{} + } + if s.DroppedPackets == nil { + s.DroppedPackets = &StatCounter{} + } + return s } // String implements the fmt.Stringer interface. diff --git a/pkg/tcpip/transport/tcp/connect.go b/pkg/tcpip/transport/tcp/connect.go index b90d3fe48..58d7942f3 100644 --- a/pkg/tcpip/transport/tcp/connect.go +++ b/pkg/tcpip/transport/tcp/connect.go @@ -16,7 +16,6 @@ package tcp import ( "sync" - "sync/atomic" "time" "gvisor.googlesource.com/gvisor/pkg/rand" @@ -292,7 +291,7 @@ func (h *handshake) synRcvdState(s *segment) *tcpip.Error { // not carry a timestamp option then the segment must be dropped // as per https://tools.ietf.org/html/rfc7323#section-3.2. if h.ep.sendTSOk && !s.parsedOptions.TS { - atomic.AddUint64(&h.ep.stack.MutableStats().DroppedPackets, 1) + h.ep.stack.Stats().DroppedPackets.Increment() return nil } @@ -793,7 +792,7 @@ func (e *endpoint) handleSegments() *tcpip.Error { // must be dropped as per // https://tools.ietf.org/html/rfc7323#section-3.2. if e.sendTSOk && !s.parsedOptions.TS { - atomic.AddUint64(&e.stack.MutableStats().DroppedPackets, 1) + e.stack.Stats().DroppedPackets.Increment() s.decRef() continue } diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index 3fcbf6502..bdcba39c6 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -1225,7 +1225,7 @@ func (e *endpoint) GetRemoteAddress() (tcpip.FullAddress, *tcpip.Error) { func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv *buffer.VectorisedView) { s := newSegment(r, id, vv) if !s.parse() { - atomic.AddUint64(&e.stack.MutableStats().MalformedRcvdPackets, 1) + e.stack.Stats().MalformedRcvdPackets.Increment() s.decRef() return } @@ -1235,7 +1235,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv e.newSegmentWaker.Assert() } else { // The queue is full, so we drop the segment. - atomic.AddUint64(&e.stack.MutableStats().DroppedPackets, 1) + e.stack.Stats().DroppedPackets.Increment() s.decRef() } } diff --git a/pkg/tcpip/transport/tcp/tcp_timestamp_test.go b/pkg/tcpip/transport/tcp/tcp_timestamp_test.go index 4f6f1da18..a529d9e72 100644 --- a/pkg/tcpip/transport/tcp/tcp_timestamp_test.go +++ b/pkg/tcpip/transport/tcp/tcp_timestamp_test.go @@ -268,7 +268,8 @@ func TestSegmentDropWhenTimestampMissing(t *testing.T) { defer c.WQ.EventUnregister(&we) stk := c.Stack() - droppedPackets := stk.Stats().DroppedPackets + droppedPacketsStat := stk.Stats().DroppedPackets + droppedPackets := droppedPacketsStat.Value() data := []byte{1, 2, 3} // Save the sequence number as we will reset it later down // in the test. @@ -283,11 +284,11 @@ func TestSegmentDropWhenTimestampMissing(t *testing.T) { } // Assert that DroppedPackets was incremented by 1. - if got, want := stk.Stats().DroppedPackets, droppedPackets+1; got != want { + if got, want := droppedPacketsStat.Value(), droppedPackets+1; got != want { t.Fatalf("incorrect number of dropped packets, got: %v, want: %v", got, want) } - droppedPackets = stk.Stats().DroppedPackets + droppedPackets = droppedPacketsStat.Value() // Reset the sequence number so that the other endpoint accepts // this segment and does not treat it like an out of order delivery. rep.NextSeqNum = savedSeqNum @@ -301,7 +302,7 @@ func TestSegmentDropWhenTimestampMissing(t *testing.T) { } // Assert that DroppedPackets was not incremented by 1. - if got, want := stk.Stats().DroppedPackets, droppedPackets; got != want { + if got, want := droppedPacketsStat.Value(), droppedPackets; got != want { t.Fatalf("incorrect number of dropped packets, got: %v, want: %v", got, want) } |