Encapsulate netstack metrics

PiperOrigin-RevId: 209943212
Change-Id: I96dcbc7c2ab2426e510b94a564436505256c5c79
This commit is contained in:
Ian Gudger 2018-08-23 08:54:09 -07:00 committed by Shentubot
parent a78df1d874
commit abe7764928
6 changed files with 67 additions and 39 deletions

View File

@ -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()
}
}

View File

@ -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

View File

@ -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.

View File

@ -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
}

View File

@ -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()
}
}

View File

@ -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)
}