Add stats for ARP

Fixes #4963

Startblock:
  has LGTM from sbalana
  and then
  add reviewer ghanan
PiperOrigin-RevId: 351886320
This commit is contained in:
Arthur Sfez
2021-01-14 15:16:24 -08:00
committed by gVisor bot
parent dbe4176565
commit 833516c139
4 changed files with 334 additions and 42 deletions
+15
View File
@@ -186,6 +186,21 @@ var Metrics = tcpip.Stats{
IPTablesInputDropped: mustCreateMetric("/netstack/ip/iptables/input_dropped", "Total number of IP packets dropped in the Input chain."),
IPTablesOutputDropped: mustCreateMetric("/netstack/ip/iptables/output_dropped", "Total number of IP packets dropped in the Output chain."),
},
ARP: tcpip.ARPStats{
PacketsReceived: mustCreateMetric("/netstack/arp/packets_received", "Number of ARP packets received from the link layer."),
DisabledPacketsReceived: mustCreateMetric("/netstack/arp/disabled_packets_received", "Number of ARP packets received from the link layer when the ARP layer is disabled."),
MalformedPacketsReceived: mustCreateMetric("/netstack/arp/malformed_packets_received", "Number of ARP packets which failed ARP header validation checks."),
RequestsReceived: mustCreateMetric("/netstack/arp/requests_received", "Number of ARP requests received."),
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."),
OutgoingRepliesDropped: mustCreateMetric("/netstack/arp/outgoing_replies_dropped", "Number of ARP replies which failed to write to a link-layer endpoint."),
OutgoingRepliesSent: mustCreateMetric("/netstack/arp/outgoing_replies_sent", "Number of ARP replies sent."),
},
TCP: tcpip.TCPStats{
ActiveConnectionOpenings: mustCreateMetric("/netstack/tcp/active_connection_openings", "Number of connections opened successfully via Connect."),
PassiveConnectionOpenings: mustCreateMetric("/netstack/tcp/passive_connection_openings", "Number of connections opened successfully via Listen."),
+25 -2
View File
@@ -119,21 +119,28 @@ func (*endpoint) WriteHeaderIncludedPacket(*stack.Route, *stack.PacketBuffer) *t
}
func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
stats := e.protocol.stack.Stats().ARP
stats.PacketsReceived.Increment()
if !e.isEnabled() {
stats.DisabledPacketsReceived.Increment()
return
}
h := header.ARP(pkt.NetworkHeader().View())
if !h.IsValid() {
stats.MalformedPacketsReceived.Increment()
return
}
switch h.Op() {
case header.ARPRequest:
stats.RequestsReceived.Increment()
localAddr := tcpip.Address(h.ProtocolAddressTarget())
if e.nud == nil {
if e.linkAddrCache.CheckLocalAddress(e.nic.ID(), header.IPv4ProtocolNumber, localAddr) == 0 {
stats.RequestsReceivedUnknownTargetAddress.Increment()
return // we have no useful answer, ignore the request
}
@@ -142,6 +149,7 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
e.linkAddrCache.AddLinkAddress(e.nic.ID(), addr, linkAddr)
} else {
if e.protocol.stack.CheckLocalAddress(e.nic.ID(), header.IPv4ProtocolNumber, localAddr) == 0 {
stats.RequestsReceivedUnknownTargetAddress.Increment()
return // we have no useful answer, ignore the request
}
@@ -177,9 +185,14 @@ 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.
_ = e.nic.WritePacketToRemote(tcpip.LinkAddress(origSender), nil /* gso */, ProtocolNumber, respPkt)
if err := e.nic.WritePacketToRemote(tcpip.LinkAddress(origSender), nil /* gso */, ProtocolNumber, respPkt); err != nil {
stats.OutgoingRepliesDropped.Increment()
} else {
stats.OutgoingRepliesSent.Increment()
}
case header.ARPReply:
stats.RepliesReceived.Increment()
addr := tcpip.Address(h.ProtocolAddressSender())
linkAddr := tcpip.LinkAddress(h.HardwareAddressSender())
@@ -233,6 +246,8 @@ 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
if len(remoteLinkAddr) == 0 {
remoteLinkAddr = header.EthernetBroadcastAddress
}
@@ -241,15 +256,18 @@ func (p *protocol) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remot
if len(localAddr) == 0 {
addr, err := p.stack.GetMainNICAddress(nicID, header.IPv4ProtocolNumber)
if err != nil {
stats.OutgoingRequestInterfaceHasNoLocalAddressErrors.Increment()
return err
}
if len(addr.Address) == 0 {
stats.OutgoingRequestNetworkUnreachableErrors.Increment()
return tcpip.ErrNetworkUnreachable
}
localAddr = addr.Address
} else if p.stack.CheckLocalAddress(nicID, header.IPv4ProtocolNumber, localAddr) == 0 {
stats.OutgoingRequestBadLocalAddressErrors.Increment()
return tcpip.ErrBadLocalAddress
}
@@ -269,7 +287,12 @@ func (p *protocol) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remot
if n := copy(h.ProtocolAddressTarget(), targetAddr); n != header.IPv4AddressSize {
panic(fmt.Sprintf("copied %d bytes, expected %d bytes", n, header.IPv4AddressSize))
}
return nic.WritePacketToRemote(remoteLinkAddr, nil /* gso */, ProtocolNumber, pkt)
if err := nic.WritePacketToRemote(remoteLinkAddr, nil /* gso */, ProtocolNumber, pkt); err != nil {
stats.OutgoingRequestsDropped.Increment()
return err
}
stats.OutgoingRequestsSent.Increment()
return nil
}
// ResolveStaticAddress implements stack.LinkAddressResolver.ResolveStaticAddress.
+238 -40
View File
@@ -240,6 +240,10 @@ func TestDirectRequest(t *testing.T) {
for i, address := range []tcpip.Address{stackAddr, remoteAddr} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
expectedPacketsReceived := c.s.Stats().ARP.PacketsReceived.Value() + 1
expectedRequestsReceived := c.s.Stats().ARP.RequestsReceived.Value() + 1
expectedRepliesSent := c.s.Stats().ARP.OutgoingRepliesSent.Value() + 1
inject(address)
pi, _ := c.linkEP.ReadContext(context.Background())
if pi.Proto != arp.ProtocolNumber {
@@ -249,6 +253,9 @@ func TestDirectRequest(t *testing.T) {
if !rep.IsValid() {
t.Fatalf("invalid ARP response: len = %d; response = %x", len(rep), rep)
}
if got := rep.Op(); got != header.ARPReply {
t.Fatalf("got Op = %d, want = %d", got, header.ARPReply)
}
if got, want := tcpip.LinkAddress(rep.HardwareAddressSender()), stackLinkAddr; got != want {
t.Errorf("got HardwareAddressSender = %s, want = %s", got, want)
}
@@ -261,6 +268,16 @@ func TestDirectRequest(t *testing.T) {
if got, want := tcpip.Address(rep.ProtocolAddressTarget()), tcpip.Address(h.ProtocolAddressSender()); got != want {
t.Errorf("got ProtocolAddressTarget = %s, want = %s", got, want)
}
if got := c.s.Stats().ARP.PacketsReceived.Value(); got != expectedPacketsReceived {
t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = %d", got, expectedPacketsReceived)
}
if got := c.s.Stats().ARP.RequestsReceived.Value(); got != expectedRequestsReceived {
t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = %d", got, expectedRequestsReceived)
}
if got := c.s.Stats().ARP.OutgoingRepliesSent.Value(); got != expectedRepliesSent {
t.Errorf("got c.s.Stats().ARP.OutgoingRepliesSent.Value() = %d, want = %d", got, expectedRepliesSent)
}
})
}
@@ -273,6 +290,84 @@ func TestDirectRequest(t *testing.T) {
if pkt, ok := c.linkEP.ReadContext(ctx); ok {
t.Errorf("stackAddrBad: unexpected packet sent, Proto=%v", pkt.Proto)
}
if got := c.s.Stats().ARP.RequestsReceivedUnknownTargetAddress.Value(); got != 1 {
t.Errorf("got c.s.Stats().ARP.RequestsReceivedUnKnownTargetAddress.Value() = %d, want = 1", got)
}
}
func TestMalformedPacket(t *testing.T) {
c := newTestContext(t, false)
defer c.cleanup()
v := make(buffer.View, header.ARPSize)
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: v.ToVectorisedView(),
})
c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
if got := c.s.Stats().ARP.PacketsReceived.Value(); got != 1 {
t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
}
if got := c.s.Stats().ARP.MalformedPacketsReceived.Value(); got != 1 {
t.Errorf("got c.s.Stats().ARP.MalformedPacketsReceived.Value() = %d, want = 1", got)
}
}
func TestDisabledEndpoint(t *testing.T) {
c := newTestContext(t, false)
defer c.cleanup()
ep, err := c.s.GetNetworkEndpoint(nicID, header.ARPProtocolNumber)
if err != nil {
t.Fatalf("GetNetworkEndpoint(%d, header.ARPProtocolNumber) failed: %s", nicID, err)
}
ep.Disable()
v := make(buffer.View, header.ARPSize)
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: v.ToVectorisedView(),
})
c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
if got := c.s.Stats().ARP.PacketsReceived.Value(); got != 1 {
t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
}
if got := c.s.Stats().ARP.DisabledPacketsReceived.Value(); got != 1 {
t.Errorf("got c.s.Stats().ARP.DisabledPacketsReceived.Value() = %d, want = 1", got)
}
}
func TestDirectReply(t *testing.T) {
c := newTestContext(t, false)
defer c.cleanup()
const senderMAC = "\x01\x02\x03\x04\x05\x06"
const senderIPv4 = "\x0a\x00\x00\x02"
v := make(buffer.View, header.ARPSize)
h := header.ARP(v)
h.SetIPv4OverEthernet()
h.SetOp(header.ARPReply)
copy(h.HardwareAddressSender(), senderMAC)
copy(h.ProtocolAddressSender(), senderIPv4)
copy(h.HardwareAddressTarget(), stackLinkAddr)
copy(h.ProtocolAddressTarget(), stackAddr)
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Data: v.ToVectorisedView(),
})
c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
if got := c.s.Stats().ARP.PacketsReceived.Value(); got != 1 {
t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
}
if got := c.s.Stats().ARP.RepliesReceived.Value(); got != 1 {
t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
}
}
func TestDirectRequestWithNeighborCache(t *testing.T) {
@@ -311,6 +406,11 @@ func TestDirectRequestWithNeighborCache(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
packetsRecv := c.s.Stats().ARP.PacketsReceived.Value()
requestsRecv := c.s.Stats().ARP.RequestsReceived.Value()
requestsRecvUnknownAddr := c.s.Stats().ARP.RequestsReceivedUnknownTargetAddress.Value()
outgoingReplies := c.s.Stats().ARP.OutgoingRepliesSent.Value()
// Inject an incoming ARP request.
v := make(buffer.View, header.ARPSize)
h := header.ARP(v)
@@ -323,6 +423,13 @@ func TestDirectRequestWithNeighborCache(t *testing.T) {
Data: v.ToVectorisedView(),
}))
if got, want := c.s.Stats().ARP.PacketsReceived.Value(), packetsRecv+1; got != want {
t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = %d", got, want)
}
if got, want := c.s.Stats().ARP.RequestsReceived.Value(), requestsRecv+1; got != want {
t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = %d", got, want)
}
if !test.isValid {
// No packets should be sent after receiving an invalid ARP request.
// There is no need to perform a blocking read here, since packets are
@@ -330,9 +437,20 @@ func TestDirectRequestWithNeighborCache(t *testing.T) {
if pkt, ok := c.linkEP.Read(); ok {
t.Errorf("unexpected packet sent with network protocol number %d", pkt.Proto)
}
if got, want := c.s.Stats().ARP.RequestsReceivedUnknownTargetAddress.Value(), requestsRecvUnknownAddr+1; got != want {
t.Errorf("got c.s.Stats().ARP.RequestsReceivedUnknownTargetAddress.Value() = %d, want = %d", got, want)
}
if got, want := c.s.Stats().ARP.OutgoingRepliesSent.Value(), outgoingReplies; got != want {
t.Errorf("got c.s.Stats().ARP.OutgoingRepliesSent.Value() = %d, want = %d", got, want)
}
return
}
if got, want := c.s.Stats().ARP.OutgoingRepliesSent.Value(), outgoingReplies+1; got != want {
t.Errorf("got c.s.Stats().ARP.OutgoingRepliesSent.Value() = %d, want = %d", got, want)
}
// Verify an ARP response was sent.
pi, ok := c.linkEP.Read()
if !ok {
@@ -418,6 +536,8 @@ type testInterface struct {
stack.LinkEndpoint
nicID tcpip.NICID
writeErr *tcpip.Error
}
func (t *testInterface) ID() tcpip.NICID {
@@ -441,6 +561,10 @@ func (*testInterface) Promiscuous() bool {
}
func (t *testInterface) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, gso *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) *tcpip.Error {
if t.writeErr != nil {
return t.writeErr
}
var r stack.Route
r.NetProto = protocol
r.ResolveWith(remoteLinkAddr)
@@ -458,61 +582,99 @@ func TestLinkAddressRequest(t *testing.T) {
localAddr tcpip.Address
remoteLinkAddr tcpip.LinkAddress
expectedErr *tcpip.Error
expectedLocalAddr tcpip.Address
expectedRemoteLinkAddr tcpip.LinkAddress
linkErr *tcpip.Error
expectedErr *tcpip.Error
expectedLocalAddr tcpip.Address
expectedRemoteLinkAddr tcpip.LinkAddress
expectedRequestsSent uint64
expectedRequestBadLocalAddressErrors uint64
expectedRequestNetworkUnreachableErrors uint64
expectedRequestDroppedErrors uint64
}{
{
name: "Unicast",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: remoteLinkAddr,
name: "Unicast",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: remoteLinkAddr,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 0,
},
{
name: "Multicast",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: "",
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: header.EthernetBroadcastAddress,
name: "Multicast",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: "",
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: header.EthernetBroadcastAddress,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 0,
},
{
name: "Unicast with unspecified source",
nicAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: remoteLinkAddr,
name: "Unicast with unspecified source",
nicAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: remoteLinkAddr,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 0,
},
{
name: "Multicast with unspecified source",
nicAddr: stackAddr,
remoteLinkAddr: "",
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: header.EthernetBroadcastAddress,
name: "Multicast with unspecified source",
nicAddr: stackAddr,
remoteLinkAddr: "",
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: header.EthernetBroadcastAddress,
expectedRequestsSent: 1,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 0,
},
{
name: "Unicast with unassigned address",
localAddr: testAddr,
remoteLinkAddr: remoteLinkAddr,
expectedErr: tcpip.ErrBadLocalAddress,
name: "Unicast with unassigned address",
localAddr: testAddr,
remoteLinkAddr: remoteLinkAddr,
expectedErr: tcpip.ErrBadLocalAddress,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 1,
expectedRequestNetworkUnreachableErrors: 0,
},
{
name: "Multicast with unassigned address",
localAddr: testAddr,
remoteLinkAddr: "",
expectedErr: tcpip.ErrBadLocalAddress,
name: "Multicast with unassigned address",
localAddr: testAddr,
remoteLinkAddr: "",
expectedErr: tcpip.ErrBadLocalAddress,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 1,
expectedRequestNetworkUnreachableErrors: 0,
},
{
name: "Unicast with no local address available",
remoteLinkAddr: remoteLinkAddr,
expectedErr: tcpip.ErrNetworkUnreachable,
name: "Unicast with no local address available",
remoteLinkAddr: remoteLinkAddr,
expectedErr: tcpip.ErrNetworkUnreachable,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 1,
},
{
name: "Multicast with no local address available",
remoteLinkAddr: "",
expectedErr: tcpip.ErrNetworkUnreachable,
name: "Multicast with no local address available",
remoteLinkAddr: "",
expectedErr: tcpip.ErrNetworkUnreachable,
expectedRequestsSent: 0,
expectedRequestBadLocalAddressErrors: 0,
expectedRequestNetworkUnreachableErrors: 1,
},
{
name: "Link error",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
linkErr: tcpip.ErrInvalidEndpointState,
expectedErr: tcpip.ErrInvalidEndpointState,
expectedRequestDroppedErrors: 1,
},
}
@@ -543,10 +705,24 @@ func TestLinkAddressRequest(t *testing.T) {
// can mock a link address request and observe the packets sent to the
// link endpoint even though the stack uses the real NIC to validate the
// local address.
if err := linkRes.LinkAddressRequest(remoteAddr, test.localAddr, test.remoteLinkAddr, &testInterface{LinkEndpoint: linkEP, nicID: nicID}); err != test.expectedErr {
iface := testInterface{LinkEndpoint: linkEP, nicID: nicID, writeErr: test.linkErr}
if err := linkRes.LinkAddressRequest(remoteAddr, test.localAddr, test.remoteLinkAddr, &iface); err != test.expectedErr {
t.Fatalf("got p.LinkAddressRequest(%s, %s, %s, _) = %s, want = %s", remoteAddr, test.localAddr, test.remoteLinkAddr, err, test.expectedErr)
}
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.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)
}
if test.expectedErr != nil {
return
}
@@ -561,6 +737,9 @@ func TestLinkAddressRequest(t *testing.T) {
}
rep := header.ARP(stack.PayloadSince(pkt.Pkt.NetworkHeader()))
if got := rep.Op(); got != header.ARPRequest {
t.Errorf("got Op = %d, want = %d", got, header.ARPRequest)
}
if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != stackLinkAddr {
t.Errorf("got HardwareAddressSender = %s, want = %s", got, stackLinkAddr)
}
@@ -576,3 +755,22 @@ func TestLinkAddressRequest(t *testing.T) {
})
}
}
func TestLinkAddressRequestWithoutNIC(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol},
})
p := s.NetworkProtocolInstance(arp.ProtocolNumber)
linkRes, ok := p.(stack.LinkAddressResolver)
if !ok {
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)
}
}
+56
View File
@@ -1591,6 +1591,59 @@ type IPStats struct {
OptionUnknownReceived *StatCounter
}
// ARPStats collects ARP-specific stats.
type ARPStats struct {
// PacketsReceived is the number of ARP packets received from the link layer.
PacketsReceived *StatCounter
// DisabledPacketsReceived is the number of ARP packets received from the link
// layer when the ARP layer is disabled.
DisabledPacketsReceived *StatCounter
// MalformedPacketsReceived is the number of ARP packets that were dropped due
// to being malformed.
MalformedPacketsReceived *StatCounter
// RequestsReceived is the number of ARP requests received.
RequestsReceived *StatCounter
// RequestsReceivedUnknownTargetAddress is the number of ARP requests that
// were targeted to an interface different from the one it was received on.
RequestsReceivedUnknownTargetAddress *StatCounter
// OutgoingRequestInterfaceHasNoLocalAddressErrors is the number of failures
// to send an ARP request because the interface has no network address
// assigned to it.
OutgoingRequestInterfaceHasNoLocalAddressErrors *StatCounter
// OutgoingRequestBadLocalAddressErrors is the number of failures to send an
// 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
// OutgoingRequestSent is the number of ARP requests successfully written to a
// link-layer endpoint.
OutgoingRequestsSent *StatCounter
// RepliesReceived is the number of ARP replies received.
RepliesReceived *StatCounter
// OutgoingRepliesDropped is the number of ARP replies which failed to write
// to a link-layer endpoint.
OutgoingRepliesDropped *StatCounter
// OutgoingRepliesSent is the number of ARP replies successfully written to a
// link-layer endpoint.
OutgoingRepliesSent *StatCounter
}
// TCPStats collects TCP-specific stats.
type TCPStats struct {
// ActiveConnectionOpenings is the number of connections opened
@@ -1743,6 +1796,9 @@ type Stats struct {
// IP breaks out IP-specific stats (both v4 and v6).
IP IPStats
// ARP breaks out ARP-specific stats.
ARP ARPStats
// TCP breaks out TCP-specific stats.
TCP TCPStats