summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/tcpip/stack/nic.go14
-rw-r--r--pkg/tcpip/stack/stack.go26
-rw-r--r--pkg/tcpip/tcpip.go48
-rw-r--r--pkg/tcpip/transport/tcp/connect.go5
-rw-r--r--pkg/tcpip/transport/tcp/endpoint.go4
-rw-r--r--pkg/tcpip/transport/tcp/tcp_timestamp_test.go9
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)
}