Add aggregated NIC stats

This change also includes miscellaneous improvements:
* UnknownProtocolRcvdPackets has been separated into two stats, to
specify at which layer the unknown protocol was found (L3 or L4)
* MalformedRcvdPacket is not aggregated across every endpoint anymore.
Doing it this way did not add useful information, and it was also error-prone
(example: ipv6 forgot to increment this aggregated stat, it only
incremented its own ipv6.MalformedPacketsReceived). It is now only incremented
 the NIC.
* Removed TestStatsString test which was outdated and had no real
utility.

PiperOrigin-RevId: 375057472
This commit is contained in:
Arthur Sfez
2021-05-21 04:27:41 -07:00
committed by gVisor bot
parent 9164154dea
commit 821cec3f1f
16 changed files with 306 additions and 131 deletions
+21 -3
View File
@@ -77,9 +77,27 @@ func mustCreateGauge(name, description string) *tcpip.StatCounter {
// Metrics contains metrics exported by netstack.
var Metrics = tcpip.Stats{
UnknownProtocolRcvdPackets: mustCreateMetric("/netstack/unknown_protocol_received_packets", "Number of packets received that were for an unknown or unsupported protocol."),
MalformedRcvdPackets: mustCreateMetric("/netstack/malformed_received_packets", "Number of packets received that were deemed malformed."),
DroppedPackets: mustCreateMetric("/netstack/dropped_packets", "Number of packets dropped due to full queues."),
DroppedPackets: mustCreateMetric("/netstack/dropped_packets", "Number of packets dropped at the transport layer."),
NICs: tcpip.NICStats{
UnknownL3ProtocolRcvdPackets: mustCreateMetric("/netstack/nic/unknown_l3_protocol_received_packets", "Number of packets received that were for an unknown or unsupported L3 protocol."),
UnknownL4ProtocolRcvdPackets: mustCreateMetric("/netstack/nic/unknown_l4_protocol_received_packets", "Number of packets received that were for an unknown or unsupported L4 protocol."),
MalformedL4RcvdPackets: mustCreateMetric("/netstack/nic/malformed_l4_received_packets", "Number of packets received that failed L4 header parsing."),
Tx: tcpip.NICPacketStats{
Packets: mustCreateMetric("/netstack/nic/tx/packets", "Number of packets transmitted."),
Bytes: mustCreateMetric("/netstack/nic/tx/bytes", "Number of bytes transmitted."),
},
Rx: tcpip.NICPacketStats{
Packets: mustCreateMetric("/netstack/nic/rx/packets", "Number of packets received."),
Bytes: mustCreateMetric("/netstack/nic/rx/bytes", "Number of bytes received."),
},
DisabledRx: tcpip.NICPacketStats{
Packets: mustCreateMetric("/netstack/nic/disabled_rx/packets", "Number of packets received on disabled NICs."),
Bytes: mustCreateMetric("/netstack/nic/disabled_rx/bytes", "Number of bytes received on disabled NICs."),
},
Neighbor: tcpip.NICNeighborStats{
UnreachableEntryLookups: mustCreateMetric("/netstack/nic/neighbor/unreachable_entry_loopups", "Number of lookups performed on a neighbor entry in Unreachable state."),
},
},
ICMP: tcpip.ICMPStats{
V4: tcpip.ICMPv4Stats{
PacketsSent: tcpip.ICMPv4SentPacketStats{
-1
View File
@@ -222,7 +222,6 @@ func (e *endpoint) handleICMP(pkt *stack.PacketBuffer) {
_ = e.protocol.returnError(&icmpReasonParamProblem{
pointer: optProblem.Pointer,
}, pkt)
e.protocol.stack.Stats().MalformedRcvdPackets.Increment()
e.stats.ip.MalformedPacketsReceived.Increment()
}
return
-3
View File
@@ -908,7 +908,6 @@ func (e *endpoint) handleValidatedPacket(h header.IPv4, pkt *stack.PacketBuffer)
case *ip.ErrNoRoute:
stats.ip.Forwarding.Unrouteable.Increment()
case *ip.ErrParameterProblem:
e.protocol.stack.Stats().MalformedRcvdPackets.Increment()
stats.ip.MalformedPacketsReceived.Increment()
case *ip.ErrMessageTooLong:
stats.ip.Forwarding.PacketTooBig.Increment()
@@ -945,7 +944,6 @@ func (e *endpoint) handleValidatedPacket(h header.IPv4, pkt *stack.PacketBuffer)
_ = e.protocol.returnError(&icmpReasonParamProblem{
pointer: optProblem.Pointer,
}, pkt)
e.protocol.stack.Stats().MalformedRcvdPackets.Increment()
e.stats.ip.MalformedPacketsReceived.Increment()
}
return
@@ -1018,7 +1016,6 @@ func (e *endpoint) handleValidatedPacket(h header.IPv4, pkt *stack.PacketBuffer)
_ = e.protocol.returnError(&icmpReasonParamProblem{
pointer: optProblem.Pointer,
}, pkt)
e.protocol.stack.Stats().MalformedRcvdPackets.Increment()
stats.ip.MalformedPacketsReceived.Increment()
}
return
+1
View File
@@ -56,6 +56,7 @@ go_library(
"neighbor_entry_list.go",
"neighborstate_string.go",
"nic.go",
"nic_stats.go",
"nud.go",
"packet_buffer.go",
"packet_buffer_list.go",
+1 -1
View File
@@ -95,7 +95,7 @@ func newTestNeighborResolver(nudDisp NUDDispatcher, config NUDConfigurations, cl
randomGenerator: rng,
},
id: 1,
stats: makeNICStats(),
stats: makeNICStats(tcpip.NICStats{}.FillIn()),
}, linkRes)
return linkRes
}
+1 -1
View File
@@ -361,7 +361,7 @@ func (e *neighborEntry) handlePacketQueuedLocked(localAddr tcpip.Address) {
e.dispatchAddEventLocked()
case Unreachable:
e.dispatchChangeEventLocked()
e.cache.nic.stats.Neighbor.UnreachableEntryLookups.Increment()
e.cache.nic.stats.neighbor.unreachableEntryLookups.Increment()
}
config := e.nudState.Config()
+1 -1
View File
@@ -219,7 +219,7 @@ func entryTestSetup(c NUDConfigurations) (*neighborEntry, *testNUDDispatcher, *e
nudConfigs: c,
randomGenerator: rand.New(rand.NewSource(time.Now().UnixNano())),
},
stats: makeNICStats(),
stats: makeNICStats(tcpip.NICStats{}.FillIn()),
}
netEP := (&testIPv6Protocol{}).NewEndpoint(&nic, nil)
nic.networkEndpoints = map[tcpip.NetworkProtocolNumber]NetworkEndpoint{
+23 -36
View File
@@ -51,7 +51,7 @@ type nic struct {
name string
context NICContext
stats NICStats
stats sharedStats
// The network endpoints themselves may be modified by calling the interface's
// methods, but the map reference and entries must be constant.
@@ -78,26 +78,13 @@ type nic struct {
}
}
// NICStats hold statistics for a NIC.
type NICStats struct {
Tx DirectionStats
Rx DirectionStats
DisabledRx DirectionStats
Neighbor NeighborStats
}
func makeNICStats() NICStats {
var s NICStats
tcpip.InitStatCounters(reflect.ValueOf(&s).Elem())
return s
}
// DirectionStats includes packet and byte counts.
type DirectionStats struct {
Packets *tcpip.StatCounter
Bytes *tcpip.StatCounter
// makeNICStats initializes the NIC statistics and associates them to the global
// NIC statistics.
func makeNICStats(global tcpip.NICStats) sharedStats {
var stats sharedStats
tcpip.InitStatCounters(reflect.ValueOf(&stats.local).Elem())
stats.init(&stats.local, &global)
return stats
}
type packetEndpointList struct {
@@ -150,7 +137,7 @@ func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint, ctx NICC
id: id,
name: name,
context: ctx,
stats: makeNICStats(),
stats: makeNICStats(stack.Stats().NICs),
networkEndpoints: make(map[tcpip.NetworkProtocolNumber]NetworkEndpoint),
linkAddrResolvers: make(map[tcpip.NetworkProtocolNumber]*linkResolver),
duplicateAddressDetectors: make(map[tcpip.NetworkProtocolNumber]DuplicateAddressDetector),
@@ -382,8 +369,8 @@ func (n *nic) writePacket(r RouteInfo, protocol tcpip.NetworkProtocolNumber, pkt
return err
}
n.stats.Tx.Packets.Increment()
n.stats.Tx.Bytes.IncrementBy(uint64(numBytes))
n.stats.tx.packets.Increment()
n.stats.tx.bytes.IncrementBy(uint64(numBytes))
return nil
}
@@ -399,13 +386,13 @@ func (n *nic) writePackets(r RouteInfo, protocol tcpip.NetworkProtocolNumber, pk
}
writtenPackets, err := n.LinkEndpoint.WritePackets(r, pkts, protocol)
n.stats.Tx.Packets.IncrementBy(uint64(writtenPackets))
n.stats.tx.packets.IncrementBy(uint64(writtenPackets))
writtenBytes := 0
for i, pb := 0, pkts.Front(); i < writtenPackets && pb != nil; i, pb = i+1, pb.Next() {
writtenBytes += pb.Size()
}
n.stats.Tx.Bytes.IncrementBy(uint64(writtenBytes))
n.stats.tx.bytes.IncrementBy(uint64(writtenBytes))
return writtenPackets, err
}
@@ -718,18 +705,18 @@ func (n *nic) DeliverNetworkPacket(remote, local tcpip.LinkAddress, protocol tcp
if !enabled {
n.mu.RUnlock()
n.stats.DisabledRx.Packets.Increment()
n.stats.DisabledRx.Bytes.IncrementBy(uint64(pkt.Data().Size()))
n.stats.disabledRx.packets.Increment()
n.stats.disabledRx.bytes.IncrementBy(uint64(pkt.Data().Size()))
return
}
n.stats.Rx.Packets.Increment()
n.stats.Rx.Bytes.IncrementBy(uint64(pkt.Data().Size()))
n.stats.rx.packets.Increment()
n.stats.rx.bytes.IncrementBy(uint64(pkt.Data().Size()))
networkEndpoint, ok := n.networkEndpoints[protocol]
if !ok {
n.mu.RUnlock()
n.stack.stats.UnknownProtocolRcvdPackets.Increment()
n.stats.unknownL3ProtocolRcvdPackets.Increment()
return
}
@@ -786,7 +773,7 @@ func (n *nic) DeliverOutboundPacket(remote, local tcpip.LinkAddress, protocol tc
func (n *nic) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt *PacketBuffer) TransportPacketDisposition {
state, ok := n.stack.transportProtocols[protocol]
if !ok {
n.stack.stats.UnknownProtocolRcvdPackets.Increment()
n.stats.unknownL4ProtocolRcvdPackets.Increment()
return TransportPacketProtocolUnreachable
}
@@ -807,20 +794,20 @@ func (n *nic) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt
// ICMP packets may be longer, but until icmp.Parse is implemented, here
// we parse it using the minimum size.
if _, ok := pkt.TransportHeader().Consume(transProto.MinimumPacketSize()); !ok {
n.stack.stats.MalformedRcvdPackets.Increment()
n.stats.malformedL4RcvdPackets.Increment()
// We consider a malformed transport packet handled because there is
// nothing the caller can do.
return TransportPacketHandled
}
} else if !transProto.Parse(pkt) {
n.stack.stats.MalformedRcvdPackets.Increment()
n.stats.malformedL4RcvdPackets.Increment()
return TransportPacketHandled
}
}
srcPort, dstPort, err := transProto.ParsePorts(pkt.TransportHeader().View())
if err != nil {
n.stack.stats.MalformedRcvdPackets.Increment()
n.stats.malformedL4RcvdPackets.Increment()
return TransportPacketHandled
}
@@ -852,7 +839,7 @@ func (n *nic) DeliverTransportPacket(protocol tcpip.TransportProtocolNumber, pkt
// If it doesn't handle it then we should do so.
switch res := transProto.HandleUnknownDestinationPacket(id, pkt); res {
case UnknownDestinationPacketMalformed:
n.stack.stats.MalformedRcvdPackets.Increment()
n.stats.malformedL4RcvdPackets.Increment()
return TransportPacketHandled
case UnknownDestinationPacketUnhandled:
return TransportPacketDestinationPortUnreachable
+74
View File
@@ -0,0 +1,74 @@
// Copyright 2021 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package stack
import (
"gvisor.dev/gvisor/pkg/tcpip"
)
type sharedStats struct {
local tcpip.NICStats
multiCounterNICStats
}
// LINT.IfChange(multiCounterNICPacketStats)
type multiCounterNICPacketStats struct {
packets tcpip.MultiCounterStat
bytes tcpip.MultiCounterStat
}
func (m *multiCounterNICPacketStats) init(a, b *tcpip.NICPacketStats) {
m.packets.Init(a.Packets, b.Packets)
m.bytes.Init(a.Bytes, b.Bytes)
}
// LINT.ThenChange(../../tcpip.go:NICPacketStats)
// LINT.IfChange(multiCounterNICNeighborStats)
type multiCounterNICNeighborStats struct {
unreachableEntryLookups tcpip.MultiCounterStat
}
func (m *multiCounterNICNeighborStats) init(a, b *tcpip.NICNeighborStats) {
m.unreachableEntryLookups.Init(a.UnreachableEntryLookups, b.UnreachableEntryLookups)
}
// LINT.ThenChange(../../tcpip.go:NICNeighborStats)
// LINT.IfChange(multiCounterNICStats)
type multiCounterNICStats struct {
unknownL3ProtocolRcvdPackets tcpip.MultiCounterStat
unknownL4ProtocolRcvdPackets tcpip.MultiCounterStat
malformedL4RcvdPackets tcpip.MultiCounterStat
tx multiCounterNICPacketStats
rx multiCounterNICPacketStats
disabledRx multiCounterNICPacketStats
neighbor multiCounterNICNeighborStats
}
func (m *multiCounterNICStats) init(a, b *tcpip.NICStats) {
m.unknownL3ProtocolRcvdPackets.Init(a.UnknownL3ProtocolRcvdPackets, b.UnknownL3ProtocolRcvdPackets)
m.unknownL4ProtocolRcvdPackets.Init(a.UnknownL4ProtocolRcvdPackets, b.UnknownL4ProtocolRcvdPackets)
m.malformedL4RcvdPackets.Init(a.MalformedL4RcvdPackets, b.MalformedL4RcvdPackets)
m.tx.init(&a.Tx, &b.Tx)
m.rx.init(&a.Rx, &b.Rx)
m.disabledRx.init(&a.DisabledRx, &b.DisabledRx)
m.neighbor.init(&a.Neighbor, &b.Neighbor)
}
// LINT.ThenChange(../../tcpip.go:NICStats)
+23 -9
View File
@@ -15,11 +15,13 @@
package stack
import (
"reflect"
"testing"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/testutil"
)
var _ AddressableEndpoint = (*testIPv6Endpoint)(nil)
@@ -171,19 +173,19 @@ func TestDisabledRxStatsWhenNICDisabled(t *testing.T) {
// When the NIC is disabled, the only field that matters is the stats field.
// This test is limited to stats counter checks.
nic := nic{
stats: makeNICStats(),
stats: makeNICStats(tcpip.NICStats{}.FillIn()),
}
if got := nic.stats.DisabledRx.Packets.Value(); got != 0 {
if got := nic.stats.local.DisabledRx.Packets.Value(); got != 0 {
t.Errorf("got DisabledRx.Packets = %d, want = 0", got)
}
if got := nic.stats.DisabledRx.Bytes.Value(); got != 0 {
if got := nic.stats.local.DisabledRx.Bytes.Value(); got != 0 {
t.Errorf("got DisabledRx.Bytes = %d, want = 0", got)
}
if got := nic.stats.Rx.Packets.Value(); got != 0 {
if got := nic.stats.local.Rx.Packets.Value(); got != 0 {
t.Errorf("got Rx.Packets = %d, want = 0", got)
}
if got := nic.stats.Rx.Bytes.Value(); got != 0 {
if got := nic.stats.local.Rx.Bytes.Value(); got != 0 {
t.Errorf("got Rx.Bytes = %d, want = 0", got)
}
@@ -195,16 +197,28 @@ func TestDisabledRxStatsWhenNICDisabled(t *testing.T) {
Data: buffer.View([]byte{1, 2, 3, 4}).ToVectorisedView(),
}))
if got := nic.stats.DisabledRx.Packets.Value(); got != 1 {
if got := nic.stats.local.DisabledRx.Packets.Value(); got != 1 {
t.Errorf("got DisabledRx.Packets = %d, want = 1", got)
}
if got := nic.stats.DisabledRx.Bytes.Value(); got != 4 {
if got := nic.stats.local.DisabledRx.Bytes.Value(); got != 4 {
t.Errorf("got DisabledRx.Bytes = %d, want = 4", got)
}
if got := nic.stats.Rx.Packets.Value(); got != 0 {
if got := nic.stats.local.Rx.Packets.Value(); got != 0 {
t.Errorf("got Rx.Packets = %d, want = 0", got)
}
if got := nic.stats.Rx.Bytes.Value(); got != 0 {
if got := nic.stats.local.Rx.Bytes.Value(); got != 0 {
t.Errorf("got Rx.Bytes = %d, want = 0", got)
}
}
func TestMultiCounterStatsInitialization(t *testing.T) {
global := tcpip.NICStats{}.FillIn()
nic := nic{
stats: makeNICStats(global),
}
multi := nic.stats.multiCounterNICStats
local := nic.stats.local
if err := testutil.ValidateMultiCounterStats(reflect.ValueOf(&multi).Elem(), []reflect.Value{reflect.ValueOf(&local).Elem(), reflect.ValueOf(&global).Elem()}); err != nil {
t.Error(err)
}
}
+2 -2
View File
@@ -804,7 +804,7 @@ type NICInfo struct {
// MTU is the maximum transmission unit.
MTU uint32
Stats NICStats
Stats tcpip.NICStats
// NetworkStats holds the stats of each NetworkEndpoint bound to the NIC.
NetworkStats map[tcpip.NetworkProtocolNumber]NetworkEndpointStats
@@ -856,7 +856,7 @@ func (s *Stack) NICInfo() map[tcpip.NICID]NICInfo {
ProtocolAddresses: nic.primaryAddresses(),
Flags: flags,
MTU: nic.LinkEndpoint.MTU(),
Stats: nic.stats,
Stats: nic.stats.local,
NetworkStats: netStats,
Context: nic.context,
ARPHardwareType: nic.LinkEndpoint.ARPHardwareType(),
+74 -33
View File
@@ -2248,46 +2248,87 @@ func TestNICStats(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{fakeNetFactory},
})
ep1 := channel.New(10, defaultMTU, "")
if err := s.CreateNIC(1, ep1); err != nil {
t.Fatal("CreateNIC failed: ", err)
nics := []struct {
addr tcpip.Address
txByteCount int
rxByteCount int
}{
{
addr: "\x01",
txByteCount: 30,
rxByteCount: 10,
},
{
addr: "\x02",
txByteCount: 50,
rxByteCount: 20,
},
}
if err := s.AddAddress(1, fakeNetNumber, "\x01"); err != nil {
t.Fatal("AddAddress failed:", err)
}
// Route all packets for address \x01 to NIC 1.
{
subnet, err := tcpip.NewSubnet("\x01", "\xff")
if err != nil {
t.Fatal(err)
var txBytesTotal, rxBytesTotal, txPacketsTotal, rxPacketsTotal int
for i, nic := range nics {
nicid := tcpip.NICID(i)
ep := channel.New(1, defaultMTU, "")
if err := s.CreateNIC(nicid, ep); err != nil {
t.Fatal("CreateNIC failed: ", err)
}
s.SetRouteTable([]tcpip.Route{{Destination: subnet, Gateway: "\x00", NIC: 1}})
if err := s.AddAddress(nicid, fakeNetNumber, nic.addr); err != nil {
t.Fatal("AddAddress failed:", err)
}
{
subnet, err := tcpip.NewSubnet(nic.addr, "\xff")
if err != nil {
t.Fatal(err)
}
s.SetRouteTable([]tcpip.Route{{Destination: subnet, Gateway: "\x00", NIC: nicid}})
}
nicStats := s.NICInfo()[nicid].Stats
// Inbound packet.
rxBuffer := buffer.NewView(nic.rxByteCount)
ep.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: rxBuffer.ToVectorisedView(),
}))
if got, want := nicStats.Rx.Packets.Value(), uint64(1); got != want {
t.Errorf("got Rx.Packets.Value() = %d, want = %d", got, want)
}
if got, want := nicStats.Rx.Bytes.Value(), uint64(nic.rxByteCount); got != want {
t.Errorf("got Rx.Bytes.Value() = %d, want = %d", got, want)
}
rxPacketsTotal++
rxBytesTotal += nic.rxByteCount
// Outbound packet.
txBuffer := buffer.NewView(nic.txByteCount)
actualTxLength := nic.txByteCount + fakeNetHeaderLen
if err := sendTo(s, nic.addr, txBuffer); err != nil {
t.Fatal("sendTo failed: ", err)
}
want := ep.Drain()
if got := nicStats.Tx.Packets.Value(); got != uint64(want) {
t.Errorf("got Tx.Packets.Value() = %d, ep.Drain() = %d", got, want)
}
if got, want := nicStats.Tx.Bytes.Value(), uint64(actualTxLength); got != want {
t.Errorf("got Tx.Bytes.Value() = %d, want = %d", got, want)
}
txPacketsTotal += want
txBytesTotal += actualTxLength
}
// Send a packet to address 1.
buf := buffer.NewView(30)
ep1.InjectInbound(fakeNetNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: buf.ToVectorisedView(),
}))
if got, want := s.NICInfo()[1].Stats.Rx.Packets.Value(), uint64(1); got != want {
t.Errorf("got Rx.Packets.Value() = %d, want = %d", got, want)
// Now verify that each NIC stats was correctly aggregated at the stack level.
if got, want := s.Stats().NICs.Rx.Packets.Value(), uint64(rxPacketsTotal); got != want {
t.Errorf("got s.Stats().NIC.Rx.Packets.Value() = %d, want = %d", got, want)
}
if got, want := s.NICInfo()[1].Stats.Rx.Bytes.Value(), uint64(len(buf)); got != want {
t.Errorf("got Rx.Bytes.Value() = %d, want = %d", got, want)
if got, want := s.Stats().NICs.Rx.Bytes.Value(), uint64(rxBytesTotal); got != want {
t.Errorf("got s.Stats().Rx.Bytes.Value() = %d, want = %d", got, want)
}
payload := buffer.NewView(10)
// Write a packet out via the address for NIC 1
if err := sendTo(s, "\x01", payload); err != nil {
t.Fatal("sendTo failed: ", err)
if got, want := s.Stats().NICs.Tx.Packets.Value(), uint64(txPacketsTotal); got != want {
t.Errorf("got Tx.Packets.Value() = %d, ep.Drain() = %d", got, want)
}
want := uint64(ep1.Drain())
if got := s.NICInfo()[1].Stats.Tx.Packets.Value(); got != want {
t.Errorf("got Tx.Packets.Value() = %d, ep1.Drain() = %d", got, want)
}
if got, want := s.NICInfo()[1].Stats.Tx.Bytes.Value(), uint64(len(payload)+fakeNetHeaderLen); got != want {
if got, want := s.Stats().NICs.Tx.Bytes.Value(), uint64(txBytesTotal); got != want {
t.Errorf("got Tx.Bytes.Value() = %d, want = %d", got, want)
}
}
+83 -16
View File
@@ -1845,37 +1845,104 @@ type UDPStats struct {
ChecksumErrors *StatCounter
}
// NICNeighborStats holds metrics for the neighbor table.
type NICNeighborStats struct {
// LINT.IfChange(NICNeighborStats)
// UnreachableEntryLookups counts the number of lookups performed on an
// entry in Unreachable state.
UnreachableEntryLookups *StatCounter
// LINT.ThenChange(stack/nic_stats.go:multiCounterNICNeighborStats)
}
// NICPacketStats holds basic packet statistics.
type NICPacketStats struct {
// LINT.IfChange(NICPacketStats)
// Packets is the number of packets counted.
Packets *StatCounter
// Bytes is the number of bytes counted.
Bytes *StatCounter
// LINT.ThenChange(stack/nic_stats.go:multiCounterNICPacketStats)
}
// NICStats holds NIC statistics.
type NICStats struct {
// LINT.IfChange(NICStats)
// UnknownL3ProtocolRcvdPackets is the number of packets received that were
// for an unknown or unsupported network protocol.
UnknownL3ProtocolRcvdPackets *StatCounter
// UnknownL4ProtocolRcvdPackets is the number of packets received that were
// for an unknown or unsupported transport protocol.
UnknownL4ProtocolRcvdPackets *StatCounter
// MalformedL4RcvdPackets is the number of packets received by a NIC that
// could not be delivered to a transport endpoint because the L4 header could
// not be parsed.
MalformedL4RcvdPackets *StatCounter
// Tx contains statistics about transmitted packets.
Tx NICPacketStats
// Rx contains statistics about received packets.
Rx NICPacketStats
// DisabledRx contains statistics about received packets on disabled NICs.
DisabledRx NICPacketStats
// Neighbor contains statistics about neighbor entries.
Neighbor NICNeighborStats
// LINT.ThenChange(stack/nic_stats.go:multiCounterNICStats)
}
// FillIn returns a copy of s with nil fields initialized to new StatCounters.
func (s NICStats) FillIn() NICStats {
InitStatCounters(reflect.ValueOf(&s).Elem())
return s
}
// 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 *StatCounter
// TODO(https://gvisor.dev/issues/5986): Make the DroppedPackets stat less
// ambiguous.
// MalformedRcvdPackets is the number of packets received by the stack
// that were deemed malformed.
MalformedRcvdPackets *StatCounter
// DroppedPackets is the number of packets dropped due to full queues.
// DroppedPackets is the number of packets dropped at the transport layer.
DroppedPackets *StatCounter
// ICMP breaks out ICMP-specific stats (both v4 and v6).
// NICs is an aggregation of every NIC's statistics. These should not be
// incremented using this field, but using the relevant NIC multicounters.
NICs NICStats
// ICMP is an aggregation of every NetworkEndpoint's ICMP statistics (both v4
// and v6). These should not be incremented using this field, but using the
// relevant NetworkEndpoint ICMP multicounters.
ICMP ICMPStats
// IGMP breaks out IGMP-specific stats.
// IGMP is an aggregation of every NetworkEndpoint's IGMP statistics. These
// should not be incremented using this field, but using the relevant
// NetworkEndpoint IGMP multicounters.
IGMP IGMPStats
// IP breaks out IP-specific stats (both v4 and v6).
// IP is an aggregation of every NetworkEndpoint's IP statistics. These should
// not be incremented using this field, but using the relevant NetworkEndpoint
// IP multicounters.
IP IPStats
// ARP breaks out ARP-specific stats.
// ARP is an aggregation of every NetworkEndpoint's ARP statistics. These
// should not be incremented using this field, but using the relevant
// NetworkEndpoint ARP multicounters.
ARP ARPStats
// TCP breaks out TCP-specific stats.
// TCP holds TCP-specific stats.
TCP TCPStats
// UDP breaks out UDP-specific stats.
// UDP holds UDP-specific stats.
UDP UDPStats
}
-21
View File
@@ -19,7 +19,6 @@ import (
"fmt"
"io"
"net"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
@@ -210,26 +209,6 @@ func TestAddressString(t *testing.T) {
}
}
func TestStatsString(t *testing.T) {
got := fmt.Sprintf("%+v", Stats{}.FillIn())
matchers := []string{
// Print root-level stats correctly.
"UnknownProtocolRcvdPackets:0",
// Print protocol-specific stats correctly.
"TCP:{ActiveConnectionOpenings:0",
}
for _, m := range matchers {
if !strings.Contains(got, m) {
t.Errorf("string.Contains(got, %q) = false", m)
}
}
if t.Failed() {
t.Logf(`got = fmt.Sprintf("%%+v", Stats{}.FillIn()) = %q`, got)
}
}
func TestAddressWithPrefixSubnet(t *testing.T) {
tests := []struct {
addr Address
-2
View File
@@ -177,7 +177,6 @@ func (d *dispatcher) queuePacket(stackEP stack.TransportEndpoint, id stack.Trans
s := newIncomingSegment(id, pkt)
if !s.parse(pkt.RXTransportChecksumValidated) {
ep.stack.Stats().MalformedRcvdPackets.Increment()
ep.stack.Stats().TCP.InvalidSegmentsReceived.Increment()
ep.stats.ReceiveErrors.MalformedPacketsReceived.Increment()
s.decRef()
@@ -185,7 +184,6 @@ func (d *dispatcher) queuePacket(stackEP stack.TransportEndpoint, id stack.Trans
}
if !s.csumValid {
ep.stack.Stats().MalformedRcvdPackets.Increment()
ep.stack.Stats().TCP.ChecksumErrors.Increment()
ep.stats.ReceiveErrors.ChecksumErrors.Increment()
s.decRef()
+2 -2
View File
@@ -2115,8 +2115,8 @@ func TestShortHeader(t *testing.T) {
Data: buf.ToVectorisedView(),
}))
if got, want := c.s.Stats().MalformedRcvdPackets.Value(), uint64(1); got != want {
t.Errorf("got c.s.Stats().MalformedRcvdPackets.Value() = %d, want = %d", got, want)
if got, want := c.s.Stats().NICs.MalformedL4RcvdPackets.Value(), uint64(1); got != want {
t.Errorf("got c.s.Stats().NIC.MalformedL4RcvdPackets.Value() = %d, want = %d", got, want)
}
}