diff options
author | Arthur Sfez <asfez@google.com> | 2021-01-19 15:05:17 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-01-19 15:07:39 -0800 |
commit | be17b94446b2f96c2a3d531fe20271537c77c8aa (patch) | |
tree | 1274841ecbb71f37195676354908deea9bf0d24c /pkg/tcpip/stack | |
parent | 833ba3590b422d453012e5b2ec2e780211d9caf9 (diff) |
Per NIC NetworkEndpoint statistics
To facilitate the debugging of multi-homed setup, track Network
protocols statistics for each endpoint. Note that the original
stack-wide stats still exist.
A new type of statistic counter is introduced, which track two
versions of a stat at the same time. This lets a network endpoint
increment both the local stat and the stack-wide stat at the same
time.
Fixes #4605
PiperOrigin-RevId: 352663276
Diffstat (limited to 'pkg/tcpip/stack')
-rw-r--r-- | pkg/tcpip/stack/forwarding_test.go | 32 | ||||
-rw-r--r-- | pkg/tcpip/stack/nic_test.go | 19 | ||||
-rw-r--r-- | pkg/tcpip/stack/pending_packets.go | 15 | ||||
-rw-r--r-- | pkg/tcpip/stack/registration.go | 20 | ||||
-rw-r--r-- | pkg/tcpip/stack/stack.go | 10 | ||||
-rw-r--r-- | pkg/tcpip/stack/stack_test.go | 22 |
6 files changed, 95 insertions, 23 deletions
diff --git a/pkg/tcpip/stack/forwarding_test.go b/pkg/tcpip/stack/forwarding_test.go index 4908848e9..9f2fd8181 100644 --- a/pkg/tcpip/stack/forwarding_test.go +++ b/pkg/tcpip/stack/forwarding_test.go @@ -41,6 +41,8 @@ const ( protocolNumberOffset = 2 ) +var _ NetworkEndpoint = (*fwdTestNetworkEndpoint)(nil) + // fwdTestNetworkEndpoint is a network-layer protocol endpoint. // Headers of this protocol are fwdTestNetHeaderLen bytes, but we currently only // use the first three: destination address, source address, and transport @@ -53,8 +55,6 @@ type fwdTestNetworkEndpoint struct { dispatcher TransportDispatcher } -var _ NetworkEndpoint = (*fwdTestNetworkEndpoint)(nil) - func (*fwdTestNetworkEndpoint) Enable() *tcpip.Error { return nil } @@ -104,7 +104,7 @@ func (f *fwdTestNetworkEndpoint) MaxHeaderLength() uint16 { return f.nic.MaxHeaderLength() + fwdTestNetHeaderLen } -func (f *fwdTestNetworkEndpoint) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, dstAddr tcpip.Address) uint16 { +func (*fwdTestNetworkEndpoint) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, dstAddr tcpip.Address) uint16 { return 0 } @@ -124,7 +124,7 @@ func (f *fwdTestNetworkEndpoint) WritePacket(r *Route, gso *GSO, params NetworkH } // WritePackets implements LinkEndpoint.WritePackets. -func (f *fwdTestNetworkEndpoint) WritePackets(r *Route, gso *GSO, pkts PacketBufferList, params NetworkHeaderParams) (int, *tcpip.Error) { +func (*fwdTestNetworkEndpoint) WritePackets(r *Route, gso *GSO, pkts PacketBufferList, params NetworkHeaderParams) (int, *tcpip.Error) { panic("not implemented") } @@ -141,6 +141,21 @@ func (f *fwdTestNetworkEndpoint) Close() { f.AddressableEndpointState.Cleanup() } +// Stats implements stack.NetworkEndpoint. +func (*fwdTestNetworkEndpoint) Stats() NetworkEndpointStats { + return &fwdTestNetworkEndpointStats{} +} + +var _ NetworkEndpointStats = (*fwdTestNetworkEndpointStats)(nil) + +type fwdTestNetworkEndpointStats struct{} + +// IsNetworkEndpointStats implements stack.NetworkEndpointStats. +func (*fwdTestNetworkEndpointStats) IsNetworkEndpointStats() {} + +var _ LinkAddressResolver = (*fwdTestNetworkProtocol)(nil) +var _ NetworkProtocol = (*fwdTestNetworkProtocol)(nil) + // fwdTestNetworkProtocol is a network-layer protocol that implements Address // resolution. type fwdTestNetworkProtocol struct { @@ -158,18 +173,15 @@ type fwdTestNetworkProtocol struct { } } -var _ NetworkProtocol = (*fwdTestNetworkProtocol)(nil) -var _ LinkAddressResolver = (*fwdTestNetworkProtocol)(nil) - -func (f *fwdTestNetworkProtocol) Number() tcpip.NetworkProtocolNumber { +func (*fwdTestNetworkProtocol) Number() tcpip.NetworkProtocolNumber { return fwdTestNetNumber } -func (f *fwdTestNetworkProtocol) MinimumPacketSize() int { +func (*fwdTestNetworkProtocol) MinimumPacketSize() int { return fwdTestNetHeaderLen } -func (f *fwdTestNetworkProtocol) DefaultPrefixLen() int { +func (*fwdTestNetworkProtocol) DefaultPrefixLen() int { return fwdTestNetDefaultPrefixLen } diff --git a/pkg/tcpip/stack/nic_test.go b/pkg/tcpip/stack/nic_test.go index 5b5c58afb..be5df7b01 100644 --- a/pkg/tcpip/stack/nic_test.go +++ b/pkg/tcpip/stack/nic_test.go @@ -99,11 +99,20 @@ func (e *testIPv6Endpoint) InvalidateDefaultRouter(rtr tcpip.Address) { e.invalidatedRtr = rtr } -var _ NetworkProtocol = (*testIPv6Protocol)(nil) +// Stats implements NetworkEndpoint. +func (*testIPv6Endpoint) Stats() NetworkEndpointStats { + return &testIPv6EndpointStats{} +} + +var _ NetworkEndpointStats = (*testIPv6EndpointStats)(nil) + +type testIPv6EndpointStats struct{} + +// IsNetworkEndpointStats implements stack.NetworkEndpointStats. +func (*testIPv6EndpointStats) IsNetworkEndpointStats() {} + +var _ LinkAddressResolver = (*testIPv6Protocol)(nil) -// An IPv6 NetworkProtocol that supports the bare minimum to make a stack -// believe it supports IPv6. -// // We use this instead of ipv6.protocol because the ipv6 package depends on // the stack package which this test lives in, causing a cyclic dependency. type testIPv6Protocol struct{} @@ -160,8 +169,6 @@ func (*testIPv6Protocol) Parse(*PacketBuffer) (tcpip.TransportProtocolNumber, bo return 0, false, false } -var _ LinkAddressResolver = (*testIPv6Protocol)(nil) - // LinkAddressProtocol implements LinkAddressResolver. func (*testIPv6Protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber { return header.IPv6ProtocolNumber diff --git a/pkg/tcpip/stack/pending_packets.go b/pkg/tcpip/stack/pending_packets.go index 41529ffd5..81d8ff6e8 100644 --- a/pkg/tcpip/stack/pending_packets.go +++ b/pkg/tcpip/stack/pending_packets.go @@ -54,6 +54,15 @@ func (f *packetsPendingLinkResolution) init() { f.packets = make(map[<-chan struct{}][]pendingPacket) } +func incrementOutgoingPacketErrors(r *Route, proto tcpip.NetworkProtocolNumber) { + r.Stats().IP.OutgoingPacketErrors.Increment() + + // ok may be false if the endpoint's stats do not collect IP-related data. + if ipEndpointStats, ok := r.outgoingNIC.getNetworkEndpoint(proto).Stats().(IPNetworkEndpointStats); ok { + ipEndpointStats.IPStats().OutgoingPacketErrors.Increment() + } +} + func (f *packetsPendingLinkResolution) enqueue(ch <-chan struct{}, r *Route, proto tcpip.NetworkProtocolNumber, pkt *PacketBuffer) { f.Lock() defer f.Unlock() @@ -63,7 +72,9 @@ func (f *packetsPendingLinkResolution) enqueue(ch <-chan struct{}, r *Route, pro p := packets[0] packets[0] = pendingPacket{} packets = packets[1:] - p.route.Stats().IP.OutgoingPacketErrors.Increment() + + incrementOutgoingPacketErrors(r, proto) + p.route.Release() } @@ -102,7 +113,7 @@ func (f *packetsPendingLinkResolution) enqueue(ch <-chan struct{}, r *Route, pro for _, p := range packets { if cancelled || p.route.IsResolutionRequired() { - p.route.Stats().IP.OutgoingPacketErrors.Increment() + incrementOutgoingPacketErrors(r, proto) if linkResolvableEP, ok := p.route.outgoingNIC.getNetworkEndpoint(p.route.NetProto).(LinkResolvableNetworkEndpoint); ok { linkResolvableEP.HandleLinkResolutionFailure(pkt) diff --git a/pkg/tcpip/stack/registration.go b/pkg/tcpip/stack/registration.go index a73bc7007..34c122728 100644 --- a/pkg/tcpip/stack/registration.go +++ b/pkg/tcpip/stack/registration.go @@ -597,6 +597,26 @@ type NetworkEndpoint interface { // NetworkProtocolNumber returns the tcpip.NetworkProtocolNumber for // this endpoint. NetworkProtocolNumber() tcpip.NetworkProtocolNumber + + // Stats returns a reference to the network endpoint stats. + Stats() NetworkEndpointStats +} + +// NetworkEndpointStats is the interface implemented by each network endpoint +// stats struct. +type NetworkEndpointStats interface { + // IsNetworkEndpointStats is an empty method to implement the + // NetworkEndpointStats marker interface. + IsNetworkEndpointStats() +} + +// IPNetworkEndpointStats is a NetworkEndpointStats that tracks IP-related +// statistics. +type IPNetworkEndpointStats interface { + NetworkEndpointStats + + // IPStats returns the IP statistics of a network endpoint. + IPStats() *tcpip.IPStats } // ForwardingNetworkProtocol is a NetworkProtocol that may forward packets. diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index c0aec61a6..b4878669c 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -1050,6 +1050,9 @@ type NICInfo struct { Stats NICStats + // NetworkStats holds the stats of each NetworkEndpoint bound to the NIC. + NetworkStats map[tcpip.NetworkProtocolNumber]NetworkEndpointStats + // Context is user-supplied data optionally supplied in CreateNICWithOptions. // See type NICOptions for more details. Context NICContext @@ -1081,6 +1084,12 @@ func (s *Stack) NICInfo() map[tcpip.NICID]NICInfo { Promiscuous: nic.Promiscuous(), Loopback: nic.IsLoopback(), } + + netStats := make(map[tcpip.NetworkProtocolNumber]NetworkEndpointStats) + for proto, netEP := range nic.networkEndpoints { + netStats[proto] = netEP.Stats() + } + nics[id] = NICInfo{ Name: nic.name, LinkAddress: nic.LinkEndpoint.LinkAddress(), @@ -1088,6 +1097,7 @@ func (s *Stack) NICInfo() map[tcpip.NICID]NICInfo { Flags: flags, MTU: nic.LinkEndpoint.MTU(), Stats: nic.stats, + NetworkStats: netStats, Context: nic.context, ARPHardwareType: nic.LinkEndpoint.ARPHardwareType(), } diff --git a/pkg/tcpip/stack/stack_test.go b/pkg/tcpip/stack/stack_test.go index 7e935ddff..b9ef455e5 100644 --- a/pkg/tcpip/stack/stack_test.go +++ b/pkg/tcpip/stack/stack_test.go @@ -145,7 +145,7 @@ func (f *fakeNetworkEndpoint) MaxHeaderLength() uint16 { return f.nic.MaxHeaderLength() + fakeNetHeaderLen } -func (f *fakeNetworkEndpoint) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, dstAddr tcpip.Address) uint16 { +func (*fakeNetworkEndpoint) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, dstAddr tcpip.Address) uint16 { return 0 } @@ -176,7 +176,7 @@ func (f *fakeNetworkEndpoint) WritePacket(r *stack.Route, gso *stack.GSO, params } // WritePackets implements stack.LinkEndpoint.WritePackets. -func (f *fakeNetworkEndpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.PacketBufferList, params stack.NetworkHeaderParams) (int, *tcpip.Error) { +func (*fakeNetworkEndpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.PacketBufferList, params stack.NetworkHeaderParams) (int, *tcpip.Error) { panic("not implemented") } @@ -188,6 +188,18 @@ func (f *fakeNetworkEndpoint) Close() { f.AddressableEndpointState.Cleanup() } +// Stats implements NetworkEndpoint. +func (*fakeNetworkEndpoint) Stats() stack.NetworkEndpointStats { + return &fakeNetworkEndpointStats{} +} + +var _ stack.NetworkEndpointStats = (*fakeNetworkEndpointStats)(nil) + +type fakeNetworkEndpointStats struct{} + +// IsNetworkEndpointStats implements stack.NetworkEndpointStats. +func (*fakeNetworkEndpointStats) IsNetworkEndpointStats() {} + // fakeNetworkProtocol is a network-layer protocol descriptor. It aggregates the // number of packets sent and received via endpoints of this protocol. The index // where packets are added is given by the packet's destination address MOD 10. @@ -202,15 +214,15 @@ type fakeNetworkProtocol struct { } } -func (f *fakeNetworkProtocol) Number() tcpip.NetworkProtocolNumber { +func (*fakeNetworkProtocol) Number() tcpip.NetworkProtocolNumber { return fakeNetNumber } -func (f *fakeNetworkProtocol) MinimumPacketSize() int { +func (*fakeNetworkProtocol) MinimumPacketSize() int { return fakeNetHeaderLen } -func (f *fakeNetworkProtocol) DefaultPrefixLen() int { +func (*fakeNetworkProtocol) DefaultPrefixLen() int { return fakeDefaultPrefixLen } |