summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip')
-rw-r--r--pkg/tcpip/network/arp/arp.go90
-rw-r--r--pkg/tcpip/network/arp/stats.go70
-rw-r--r--pkg/tcpip/network/ipv4/stats.go2
-rw-r--r--pkg/tcpip/network/ipv6/stats.go2
-rw-r--r--pkg/tcpip/tcpip.go8
5 files changed, 139 insertions, 33 deletions
diff --git a/pkg/tcpip/network/arp/arp.go b/pkg/tcpip/network/arp/arp.go
index 0616b10aa..6bc8c5c02 100644
--- a/pkg/tcpip/network/arp/arp.go
+++ b/pkg/tcpip/network/arp/arp.go
@@ -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)},
+ }
}
diff --git a/pkg/tcpip/network/arp/stats.go b/pkg/tcpip/network/arp/stats.go
new file mode 100644
index 000000000..6d7194c6c
--- /dev/null
+++ b/pkg/tcpip/network/arp/stats.go
@@ -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)
diff --git a/pkg/tcpip/network/ipv4/stats.go b/pkg/tcpip/network/ipv4/stats.go
index 7620728f9..bee72c649 100644
--- a/pkg/tcpip/network/ipv4/stats.go
+++ b/pkg/tcpip/network/ipv4/stats.go
@@ -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 {
diff --git a/pkg/tcpip/network/ipv6/stats.go b/pkg/tcpip/network/ipv6/stats.go
index a2f2f4f78..0839be3cd 100644
--- a/pkg/tcpip/network/ipv6/stats.go
+++ b/pkg/tcpip/network/ipv6/stats.go
@@ -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 {
diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go
index fe01029ad..32e4f02ca 100644
--- a/pkg/tcpip/tcpip.go
+++ b/pkg/tcpip/tcpip.go
@@ -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.