Add per endpoint ARP statistics

The ARP stat NetworkUnreachable was removed, and was replaced by
InterfaceHasNoLocalAddress. No stats are recorded when dealing with an
missing endpoint (ErrNotConnected) (because if there is no endpoint,
there is no valid per-endpoint stats).

PiperOrigin-RevId: 353759462
This commit is contained in:
Arthur Sfez
2021-01-25 16:52:05 -08:00
committed by gVisor bot
parent b4665aef87
commit 39db3b9355
12 changed files with 389 additions and 164 deletions
-1
View File
@@ -193,7 +193,6 @@ var Metrics = tcpip.Stats{
RequestsReceivedUnknownTargetAddress: mustCreateMetric("/netstack/arp/requests_received_unknown_addr", "Number of ARP requests received with an unknown target address."),
OutgoingRequestInterfaceHasNoLocalAddressErrors: mustCreateMetric("/netstack/arp/outgoing_requests_iface_has_no_addr", "Number of failed attempts to send an ARP request with an interface that has no network address."),
OutgoingRequestBadLocalAddressErrors: mustCreateMetric("/netstack/arp/outgoing_requests_invalid_local_addr", "Number of failed attempts to send an ARP request with a provided local address that is invalid."),
OutgoingRequestNetworkUnreachableErrors: mustCreateMetric("/netstack/arp/outgoing_requests_network_unreachable", "Number of failed attempts to send an ARP request with a network unreachable error."),
OutgoingRequestsDropped: mustCreateMetric("/netstack/arp/outgoing_requests_dropped", "Number of ARP requests which failed to write to a link-layer endpoint."),
OutgoingRequestsSent: mustCreateMetric("/netstack/arp/outgoing_requests_sent", "Number of ARP requests sent."),
RepliesReceived: mustCreateMetric("/netstack/arp/replies_received", "Number of ARP replies received."),
+17 -1
View File
@@ -4,9 +4,13 @@ package(licenses = ["notice"])
go_library(
name = "arp",
srcs = ["arp.go"],
srcs = [
"arp.go",
"stats.go",
],
visibility = ["//visibility:public"],
deps = [
"//pkg/sync",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/header",
@@ -33,3 +37,15 @@ go_test(
"@com_github_google_go_cmp//cmp/cmpopts:go_default_library",
],
)
go_test(
name = "stats_test",
size = "small",
srcs = ["stats_test.go"],
library = ":arp",
deps = [
"//pkg/tcpip",
"//pkg/tcpip/network/testutil",
"//pkg/tcpip/stack",
],
)
+63 -27
View File
@@ -19,8 +19,10 @@ package arp
import (
"fmt"
"reflect"
"sync/atomic"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
@@ -50,6 +52,7 @@ type endpoint struct {
nic stack.NetworkInterface
linkAddrCache stack.LinkAddressCache
nud stack.NUDHandler
stats sharedStats
}
func (e *endpoint) Enable() *tcpip.Error {
@@ -98,7 +101,9 @@ func (e *endpoint) MaxHeaderLength() uint16 {
return e.nic.MaxHeaderLength() + header.ARPSize
}
func (*endpoint) Close() {}
func (e *endpoint) Close() {
e.protocol.forgetEndpoint(e.nic.ID())
}
func (*endpoint) WritePacket(*stack.Route, *stack.GSO, stack.NetworkHeaderParams, *stack.PacketBuffer) *tcpip.Error {
return tcpip.ErrNotSupported
@@ -119,27 +124,27 @@ func (*endpoint) WriteHeaderIncludedPacket(*stack.Route, *stack.PacketBuffer) *t
}
func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
stats := e.protocol.stack.Stats().ARP
stats.PacketsReceived.Increment()
stats := e.stats.arp
stats.packetsReceived.Increment()
if !e.isEnabled() {
stats.DisabledPacketsReceived.Increment()
stats.disabledPacketsReceived.Increment()
return
}
h := header.ARP(pkt.NetworkHeader().View())
if !h.IsValid() {
stats.MalformedPacketsReceived.Increment()
stats.malformedPacketsReceived.Increment()
return
}
switch h.Op() {
case header.ARPRequest:
stats.RequestsReceived.Increment()
stats.requestsReceived.Increment()
localAddr := tcpip.Address(h.ProtocolAddressTarget())
if e.protocol.stack.CheckLocalAddress(e.nic.ID(), header.IPv4ProtocolNumber, localAddr) == 0 {
stats.RequestsReceivedUnknownTargetAddress.Increment()
stats.requestsReceivedUnknownTargetAddress.Increment()
return // we have no useful answer, ignore the request
}
@@ -180,13 +185,13 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
// Send the packet to the (new) target hardware address on the same
// hardware on which the request was received.
if err := e.nic.WritePacketToRemote(tcpip.LinkAddress(origSender), nil /* gso */, ProtocolNumber, respPkt); err != nil {
stats.OutgoingRepliesDropped.Increment()
stats.outgoingRepliesDropped.Increment()
} else {
stats.OutgoingRepliesSent.Increment()
stats.outgoingRepliesSent.Increment()
}
case header.ARPReply:
stats.RepliesReceived.Increment()
stats.repliesReceived.Increment()
addr := tcpip.Address(h.ProtocolAddressSender())
linkAddr := tcpip.LinkAddress(h.HardwareAddressSender())
@@ -212,21 +217,23 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
// Stats implements stack.NetworkEndpoint.
func (e *endpoint) Stats() stack.NetworkEndpointStats {
// TODO(gvisor.dev/issues/4963): Record statistics for ARP.
return &Stats{}
return &e.stats.localStats
}
var _ stack.NetworkEndpointStats = (*Stats)(nil)
// Stats holds ARP statistics.
type Stats struct{}
// IsNetworkEndpointStats implements stack.NetworkEndpointStats.
func (*Stats) IsNetworkEndpointStats() {}
var _ stack.NetworkProtocol = (*protocol)(nil)
var _ stack.LinkAddressResolver = (*protocol)(nil)
// protocol implements stack.NetworkProtocol and stack.LinkAddressResolver.
type protocol struct {
stack *stack.Stack
mu struct {
sync.RWMutex
// eps is keyed by NICID to allow protocol methods to retrieve the correct
// endpoint depending on the NIC.
eps map[tcpip.NICID]*endpoint
}
}
func (p *protocol) Number() tcpip.NetworkProtocolNumber { return ProtocolNumber }
@@ -244,9 +251,25 @@ func (p *protocol) NewEndpoint(nic stack.NetworkInterface, linkAddrCache stack.L
linkAddrCache: linkAddrCache,
nud: nud,
}
tcpip.InitStatCounters(reflect.ValueOf(&e.stats.localStats).Elem())
stackStats := p.stack.Stats()
e.stats.arp.init(&e.stats.localStats.ARP, &stackStats.ARP)
p.mu.Lock()
p.mu.eps[nic.ID()] = e
p.mu.Unlock()
return e
}
func (p *protocol) forgetEndpoint(nicID tcpip.NICID) {
p.mu.Lock()
defer p.mu.Unlock()
delete(p.mu.eps, nicID)
}
// LinkAddressProtocol implements stack.LinkAddressResolver.LinkAddressProtocol.
func (*protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
return header.IPv4ProtocolNumber
@@ -254,28 +277,35 @@ func (*protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
// LinkAddressRequest implements stack.LinkAddressResolver.LinkAddressRequest.
func (p *protocol) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, nic stack.NetworkInterface) *tcpip.Error {
stats := p.stack.Stats().ARP
nicID := nic.ID()
p.mu.Lock()
netEP, ok := p.mu.eps[nicID]
p.mu.Unlock()
if !ok {
return tcpip.ErrNotConnected
}
stats := netEP.stats.arp
if len(remoteLinkAddr) == 0 {
remoteLinkAddr = header.EthernetBroadcastAddress
}
nicID := nic.ID()
if len(localAddr) == 0 {
addr, ok := p.stack.GetMainNICAddress(nicID, header.IPv4ProtocolNumber)
if !ok {
stats.OutgoingRequestInterfaceHasNoLocalAddressErrors.Increment()
return tcpip.ErrUnknownNICID
}
if len(addr.Address) == 0 {
stats.OutgoingRequestNetworkUnreachableErrors.Increment()
stats.outgoingRequestInterfaceHasNoLocalAddressErrors.Increment()
return tcpip.ErrNetworkUnreachable
}
localAddr = addr.Address
} else if p.stack.CheckLocalAddress(nicID, header.IPv4ProtocolNumber, localAddr) == 0 {
stats.OutgoingRequestBadLocalAddressErrors.Increment()
stats.outgoingRequestBadLocalAddressErrors.Increment()
return tcpip.ErrBadLocalAddress
}
@@ -296,10 +326,10 @@ func (p *protocol) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remot
panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.IPv4AddressSize))
}
if err := nic.WritePacketToRemote(remoteLinkAddr, nil /* gso */, ProtocolNumber, pkt); err != nil {
stats.OutgoingRequestsDropped.Increment()
stats.outgoingRequestsDropped.Increment()
return err
}
stats.OutgoingRequestsSent.Increment()
stats.outgoingRequestsSent.Increment()
return nil
}
@@ -337,5 +367,11 @@ func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNu
// NewProtocol returns an ARP network protocol.
func NewProtocol(s *stack.Stack) stack.NetworkProtocol {
return &protocol{stack: s}
return &protocol{
stack: s,
mu: struct {
sync.RWMutex
eps map[tcpip.NICID]*endpoint
}{eps: make(map[tcpip.NICID]*endpoint)},
}
}
+103 -89
View File
@@ -585,104 +585,122 @@ func TestLinkAddressRequest(t *testing.T) {
testAddr := tcpip.Address([]byte{1, 2, 3, 4})
tests := []struct {
name string
nicAddr tcpip.Address
localAddr tcpip.Address
remoteLinkAddr tcpip.LinkAddress
linkErr *tcpip.Error
expectedErr *tcpip.Error
expectedLocalAddr tcpip.Address
expectedRemoteLinkAddr tcpip.LinkAddress
expectedRequestsSent uint64
expectedRequestBadLocalAddressErrors uint64
expectedRequestNetworkUnreachableErrors uint64
expectedRequestDroppedErrors uint64
name string
nicAddr tcpip.Address
localAddr tcpip.Address
remoteLinkAddr tcpip.LinkAddress
linkErr *tcpip.Error
expectedErr *tcpip.Error
expectedLocalAddr tcpip.Address
expectedRemoteLinkAddr tcpip.LinkAddress
expectedRequestsSent uint64
expectedRequestBadLocalAddressErrors uint64
expectedRequestInterfaceHasNoLocalAddressErrors uint64
expectedRequestDroppedErrors uint64
}{
{
name: "Unicast",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: remoteLinkAddr,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 0,
name: "Unicast",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: remoteLinkAddr,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestInterfaceHasNoLocalAddressErrors: 0,
expectedRequestDroppedErrors: 0,
},
{
name: "Multicast",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: "",
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: header.EthernetBroadcastAddress,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 0,
name: "Multicast",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: "",
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: header.EthernetBroadcastAddress,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestInterfaceHasNoLocalAddressErrors: 0,
expectedRequestDroppedErrors: 0,
},
{
name: "Unicast with unspecified source",
nicAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: remoteLinkAddr,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 0,
name: "Unicast with unspecified source",
nicAddr: stackAddr,
localAddr: "",
remoteLinkAddr: remoteLinkAddr,
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: remoteLinkAddr,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestInterfaceHasNoLocalAddressErrors: 0,
expectedRequestDroppedErrors: 0,
},
{
name: "Multicast with unspecified source",
nicAddr: stackAddr,
remoteLinkAddr: "",
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: header.EthernetBroadcastAddress,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 0,
name: "Multicast with unspecified source",
nicAddr: stackAddr,
localAddr: "",
remoteLinkAddr: "",
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: header.EthernetBroadcastAddress,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestInterfaceHasNoLocalAddressErrors: 0,
expectedRequestDroppedErrors: 0,
},
{
name: "Unicast with unassigned address",
localAddr: testAddr,
remoteLinkAddr: remoteLinkAddr,
expectedErr: tcpip.ErrBadLocalAddress,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 1,
expectedRequestNetworkUnreachableErrors: 0,
name: "Unicast with unassigned address",
nicAddr: stackAddr,
localAddr: testAddr,
remoteLinkAddr: remoteLinkAddr,
expectedErr: tcpip.ErrBadLocalAddress,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 1,
expectedRequestInterfaceHasNoLocalAddressErrors: 0,
expectedRequestDroppedErrors: 0,
},
{
name: "Multicast with unassigned address",
localAddr: testAddr,
remoteLinkAddr: "",
expectedErr: tcpip.ErrBadLocalAddress,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 1,
expectedRequestNetworkUnreachableErrors: 0,
name: "Multicast with unassigned address",
nicAddr: stackAddr,
localAddr: testAddr,
remoteLinkAddr: "",
expectedErr: tcpip.ErrBadLocalAddress,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 1,
expectedRequestInterfaceHasNoLocalAddressErrors: 0,
expectedRequestDroppedErrors: 0,
},
{
name: "Unicast with no local address available",
remoteLinkAddr: remoteLinkAddr,
expectedErr: tcpip.ErrNetworkUnreachable,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 1,
name: "Unicast with no local address available",
nicAddr: "",
localAddr: "",
remoteLinkAddr: remoteLinkAddr,
expectedErr: tcpip.ErrNetworkUnreachable,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestInterfaceHasNoLocalAddressErrors: 1,
expectedRequestDroppedErrors: 0,
},
{
name: "Multicast with no local address available",
remoteLinkAddr: "",
expectedErr: tcpip.ErrNetworkUnreachable,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 1,
name: "Multicast with no local address available",
nicAddr: "",
localAddr: "",
remoteLinkAddr: "",
expectedErr: tcpip.ErrNetworkUnreachable,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestInterfaceHasNoLocalAddressErrors: 1,
expectedRequestDroppedErrors: 0,
},
{
name: "Link error",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
linkErr: tcpip.ErrInvalidEndpointState,
expectedErr: tcpip.ErrInvalidEndpointState,
expectedRequestDroppedErrors: 1,
name: "Link error",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
linkErr: tcpip.ErrInvalidEndpointState,
expectedErr: tcpip.ErrInvalidEndpointState,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestInterfaceHasNoLocalAddressErrors: 0,
expectedRequestDroppedErrors: 1,
},
}
@@ -721,12 +739,12 @@ func TestLinkAddressRequest(t *testing.T) {
if got := s.Stats().ARP.OutgoingRequestsSent.Value(); got != test.expectedRequestsSent {
t.Errorf("got s.Stats().ARP.OutgoingRequestsSent.Value() = %d, want = %d", got, test.expectedRequestsSent)
}
if got := s.Stats().ARP.OutgoingRequestInterfaceHasNoLocalAddressErrors.Value(); got != test.expectedRequestInterfaceHasNoLocalAddressErrors {
t.Errorf("got s.Stats().ARP.OutgoingRequestInterfaceHasNoLocalAddressErrors.Value() = %d, want = %d", got, test.expectedRequestInterfaceHasNoLocalAddressErrors)
}
if got := s.Stats().ARP.OutgoingRequestBadLocalAddressErrors.Value(); got != test.expectedRequestBadLocalAddressErrors {
t.Errorf("got s.Stats().ARP.OutgoingRequestBadLocalAddressErrors.Value() = %d, want = %d", got, test.expectedRequestBadLocalAddressErrors)
}
if got := s.Stats().ARP.OutgoingRequestNetworkUnreachableErrors.Value(); got != test.expectedRequestNetworkUnreachableErrors {
t.Errorf("got s.Stats().ARP.OutgoingRequestNetworkUnreachableErrors.Value() = %d, want = %d", got, test.expectedRequestNetworkUnreachableErrors)
}
if got := s.Stats().ARP.OutgoingRequestsDropped.Value(); got != test.expectedRequestDroppedErrors {
t.Errorf("got s.Stats().ARP.OutgoingRequestsDropped.Value() = %d, want = %d", got, test.expectedRequestDroppedErrors)
}
@@ -774,11 +792,7 @@ func TestLinkAddressRequestWithoutNIC(t *testing.T) {
t.Fatal("expected ARP protocol to implement stack.LinkAddressResolver")
}
if err := linkRes.LinkAddressRequest(remoteAddr, "", remoteLinkAddr, &testInterface{nicID: nicID}); err != tcpip.ErrUnknownNICID {
t.Fatalf("got p.LinkAddressRequest(%s, %s, %s, _) = %s, want = %s", remoteAddr, "", remoteLinkAddr, err, tcpip.ErrUnknownNICID)
}
if got := s.Stats().ARP.OutgoingRequestInterfaceHasNoLocalAddressErrors.Value(); got != 1 {
t.Errorf("got s.Stats().ARP.OutgoingRequestInterfaceHasNoLocalAddressErrors.Value() = %d, want = 1", got)
if err := linkRes.LinkAddressRequest(remoteAddr, "", remoteLinkAddr, &testInterface{nicID: nicID}); err != tcpip.ErrNotConnected {
t.Fatalf("got p.LinkAddressRequest(%s, %s, %s, _) = %s, want = %s", remoteAddr, "", remoteLinkAddr, err, tcpip.ErrNotConnected)
}
}
+70
View File
@@ -0,0 +1,70 @@
// 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 arp
import (
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
var _ stack.NetworkEndpointStats = (*Stats)(nil)
// Stats holds statistics related to ARP.
type Stats struct {
// ARP holds ARP statistics.
ARP tcpip.ARPStats
}
// IsNetworkEndpointStats implements stack.NetworkEndpointStats.
func (*Stats) IsNetworkEndpointStats() {}
type sharedStats struct {
localStats Stats
arp multiCounterARPStats
}
// LINT.IfChange(multiCounterARPStats)
type multiCounterARPStats struct {
packetsReceived tcpip.MultiCounterStat
disabledPacketsReceived tcpip.MultiCounterStat
malformedPacketsReceived tcpip.MultiCounterStat
requestsReceived tcpip.MultiCounterStat
requestsReceivedUnknownTargetAddress tcpip.MultiCounterStat
outgoingRequestInterfaceHasNoLocalAddressErrors tcpip.MultiCounterStat
outgoingRequestBadLocalAddressErrors tcpip.MultiCounterStat
outgoingRequestsDropped tcpip.MultiCounterStat
outgoingRequestsSent tcpip.MultiCounterStat
repliesReceived tcpip.MultiCounterStat
outgoingRepliesDropped tcpip.MultiCounterStat
outgoingRepliesSent tcpip.MultiCounterStat
}
func (m *multiCounterARPStats) init(a, b *tcpip.ARPStats) {
m.packetsReceived.Init(a.PacketsReceived, b.PacketsReceived)
m.disabledPacketsReceived.Init(a.DisabledPacketsReceived, b.DisabledPacketsReceived)
m.malformedPacketsReceived.Init(a.MalformedPacketsReceived, b.MalformedPacketsReceived)
m.requestsReceived.Init(a.RequestsReceived, b.RequestsReceived)
m.requestsReceivedUnknownTargetAddress.Init(a.RequestsReceivedUnknownTargetAddress, b.RequestsReceivedUnknownTargetAddress)
m.outgoingRequestInterfaceHasNoLocalAddressErrors.Init(a.OutgoingRequestInterfaceHasNoLocalAddressErrors, b.OutgoingRequestInterfaceHasNoLocalAddressErrors)
m.outgoingRequestBadLocalAddressErrors.Init(a.OutgoingRequestBadLocalAddressErrors, b.OutgoingRequestBadLocalAddressErrors)
m.outgoingRequestsDropped.Init(a.OutgoingRequestsDropped, b.OutgoingRequestsDropped)
m.outgoingRequestsSent.Init(a.OutgoingRequestsSent, b.OutgoingRequestsSent)
m.repliesReceived.Init(a.RepliesReceived, b.RepliesReceived)
m.outgoingRepliesDropped.Init(a.OutgoingRepliesDropped, b.OutgoingRepliesDropped)
m.outgoingRepliesSent.Init(a.OutgoingRepliesSent, b.OutgoingRepliesSent)
}
// LINT.ThenChange(../../tcpip.go:ARPStats)
+93
View File
@@ -0,0 +1,93 @@
// 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 arp
import (
"reflect"
"testing"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/network/testutil"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
var _ stack.NetworkInterface = (*testInterface)(nil)
type testInterface struct {
stack.NetworkInterface
nicID tcpip.NICID
}
func (t *testInterface) ID() tcpip.NICID {
return t.nicID
}
func knownNICIDs(proto *protocol) []tcpip.NICID {
var nicIDs []tcpip.NICID
for k := range proto.mu.eps {
nicIDs = append(nicIDs, k)
}
return nicIDs
}
func TestClearEndpointFromProtocolOnClose(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
})
proto := s.NetworkProtocolInstance(ProtocolNumber).(*protocol)
nic := testInterface{nicID: 1}
ep := proto.NewEndpoint(&nic, nil, nil, nil).(*endpoint)
var nicIDs []tcpip.NICID
proto.mu.Lock()
foundEP, hasEndpointBeforeClose := proto.mu.eps[nic.ID()]
nicIDs = knownNICIDs(proto)
proto.mu.Unlock()
if !hasEndpointBeforeClose {
t.Fatalf("expected to find the nic id %d in the protocol's endpoint map (%v)", nic.ID(), nicIDs)
}
if foundEP != ep {
t.Fatalf("found an incorrect endpoint mapped to nic id %d", nic.ID())
}
ep.Close()
proto.mu.Lock()
_, hasEndpointAfterClose := proto.mu.eps[nic.ID()]
nicIDs = knownNICIDs(proto)
proto.mu.Unlock()
if hasEndpointAfterClose {
t.Fatalf("unexpectedly found an endpoint mapped to the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs)
}
}
func TestMultiCounterStatsInitialization(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{NewProtocol},
})
proto := s.NetworkProtocolInstance(ProtocolNumber).(*protocol)
var nic testInterface
ep := proto.NewEndpoint(&nic, nil, nil, nil).(*endpoint)
// At this point, the Stack's stats and the NetworkEndpoint's stats are
// expected to be bound by a MultiCounterStat.
refStack := s.Stats()
refEP := ep.stats.localStats
if err := testutil.ValidateMultiCounterStats(reflect.ValueOf(&ep.stats.arp).Elem(), []reflect.Value{reflect.ValueOf(&refEP.ARP).Elem(), reflect.ValueOf(&refStack.ARP).Elem()}); err != nil {
t.Error(err)
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ type Stats struct {
}
// IsNetworkEndpointStats implements stack.NetworkEndpointStats.
func (s *Stats) IsNetworkEndpointStats() {}
func (*Stats) IsNetworkEndpointStats() {}
// IPStats implements stack.IPNetworkEndointStats
func (s *Stats) IPStats() *tcpip.IPStats {
+18 -20
View File
@@ -34,7 +34,7 @@ func (t *testInterface) ID() tcpip.NICID {
return t.nicID
}
func getKnownNICIDs(proto *protocol) []tcpip.NICID {
func knownNICIDs(proto *protocol) []tcpip.NICID {
var nicIDs []tcpip.NICID
for k := range proto.mu.eps {
@@ -51,30 +51,28 @@ func TestClearEndpointFromProtocolOnClose(t *testing.T) {
proto := s.NetworkProtocolInstance(ProtocolNumber).(*protocol)
nic := testInterface{nicID: 1}
ep := proto.NewEndpoint(&nic, nil, nil, nil).(*endpoint)
{
proto.mu.Lock()
foundEP, hasEP := proto.mu.eps[nic.ID()]
nicIDs := getKnownNICIDs(proto)
proto.mu.Unlock()
var nicIDs []tcpip.NICID
if !hasEP {
t.Fatalf("expected to find the nic id %d in the protocol's endpoint map (%v)", nic.ID(), nicIDs)
}
if foundEP != ep {
t.Fatalf("expected protocol to map endpoint %p to nic id %d, but endpoint %p was found instead", ep, nic.ID(), foundEP)
}
proto.mu.Lock()
foundEP, hasEndpointBeforeClose := proto.mu.eps[nic.ID()]
nicIDs = knownNICIDs(proto)
proto.mu.Unlock()
if !hasEndpointBeforeClose {
t.Fatalf("expected to find the nic id %d in the protocol's endpoint map (%v)", nic.ID(), nicIDs)
}
if foundEP != ep {
t.Fatalf("found an incorrect endpoint mapped to nic id %d", nic.ID())
}
ep.Close()
{
proto.mu.Lock()
_, hasEP := proto.mu.eps[nic.ID()]
nicIDs := getKnownNICIDs(proto)
proto.mu.Unlock()
if hasEP {
t.Fatalf("unexpectedly found an endpoint mapped to the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs)
}
proto.mu.Lock()
_, hasEP := proto.mu.eps[nic.ID()]
nicIDs = knownNICIDs(proto)
proto.mu.Unlock()
if hasEP {
t.Fatalf("unexpectedly found an endpoint mapped to the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs)
}
}
+18 -20
View File
@@ -2581,7 +2581,7 @@ func (lm *limitedMatcher) Match(stack.Hook, *stack.PacketBuffer, string, string)
return false, false
}
func getKnownNICIDs(proto *protocol) []tcpip.NICID {
func knownNICIDs(proto *protocol) []tcpip.NICID {
var nicIDs []tcpip.NICID
for k := range proto.mu.eps {
@@ -2598,29 +2598,27 @@ func TestClearEndpointFromProtocolOnClose(t *testing.T) {
proto := s.NetworkProtocolInstance(ProtocolNumber).(*protocol)
var nic testInterface
ep := proto.NewEndpoint(&nic, nil, nil, nil).(*endpoint)
{
proto.mu.Lock()
foundEP, hasEP := proto.mu.eps[nic.ID()]
nicIDs := getKnownNICIDs(proto)
proto.mu.Unlock()
if !hasEP {
t.Fatalf("expected to find the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs)
}
if foundEP != ep {
t.Fatalf("expected protocol to map endpoint %p to nic id %d, but endpoint %p was found instead", ep, nic.ID(), foundEP)
}
var nicIDs []tcpip.NICID
proto.mu.Lock()
foundEP, hasEndpointBeforeClose := proto.mu.eps[nic.ID()]
nicIDs = knownNICIDs(proto)
proto.mu.Unlock()
if !hasEndpointBeforeClose {
t.Fatalf("expected to find the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs)
}
if foundEP != ep {
t.Fatalf("found an incorrect endpoint mapped to nic id %d", nic.ID())
}
ep.Close()
{
proto.mu.Lock()
_, hasEP := proto.mu.eps[nic.ID()]
nicIDs := getKnownNICIDs(proto)
proto.mu.Unlock()
if hasEP {
t.Fatalf("unexpectedly found an endpoint mapped to the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs)
}
proto.mu.Lock()
_, hasEndpointAfterClose := proto.mu.eps[nic.ID()]
nicIDs = knownNICIDs(proto)
proto.mu.Unlock()
if hasEndpointAfterClose {
t.Fatalf("unexpectedly found an endpoint mapped to the nic id %d in the protocol's known nic ids (%v)", nic.ID(), nicIDs)
}
}
+1 -1
View File
@@ -32,7 +32,7 @@ type Stats struct {
}
// IsNetworkEndpointStats implements stack.NetworkEndpointStats.
func (s *Stats) IsNetworkEndpointStats() {}
func (*Stats) IsNetworkEndpointStats() {}
// IPStats implements stack.IPNetworkEndointStats
func (s *Stats) IPStats() *tcpip.IPStats {
+1
View File
@@ -9,6 +9,7 @@ go_library(
"testutil_unsafe.go",
],
visibility = [
"//pkg/tcpip/network/arp:__pkg__",
"//pkg/tcpip/network/fragmentation:__pkg__",
"//pkg/tcpip/network/ipv4:__pkg__",
"//pkg/tcpip/network/ipv6:__pkg__",
+4 -4
View File
@@ -1667,6 +1667,8 @@ type IPStats struct {
// ARPStats collects ARP-specific stats.
type ARPStats struct {
// LINT.IfChange(ARPStats)
// PacketsReceived is the number of ARP packets received from the link layer.
PacketsReceived *StatCounter
@@ -1694,10 +1696,6 @@ type ARPStats struct {
// ARP request with a bad local address.
OutgoingRequestBadLocalAddressErrors *StatCounter
// OutgoingRequestNetworkUnreachableErrors is the number of failures to send
// an ARP request with a network unreachable error.
OutgoingRequestNetworkUnreachableErrors *StatCounter
// OutgoingRequestsDropped is the number of ARP requests which failed to write
// to a link-layer endpoint.
OutgoingRequestsDropped *StatCounter
@@ -1716,6 +1714,8 @@ type ARPStats struct {
// OutgoingRepliesSent is the number of ARP replies successfully written to a
// link-layer endpoint.
OutgoingRepliesSent *StatCounter
// LINT.ThenChange(network/arp/stats.go:multiCounterARPStats)
}
// TCPStats collects TCP-specific stats.