diff options
Diffstat (limited to 'pkg/tcpip/network/arp/arp.go')
-rw-r--r-- | pkg/tcpip/network/arp/arp.go | 77 |
1 files changed, 71 insertions, 6 deletions
diff --git a/pkg/tcpip/network/arp/arp.go b/pkg/tcpip/network/arp/arp.go index 5d7803537..3fcdea119 100644 --- a/pkg/tcpip/network/arp/arp.go +++ b/pkg/tcpip/network/arp/arp.go @@ -22,10 +22,12 @@ import ( "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" "gvisor.dev/gvisor/pkg/tcpip/header/parse" + "gvisor.dev/gvisor/pkg/tcpip/network/internal/ip" "gvisor.dev/gvisor/pkg/tcpip/stack" ) @@ -34,6 +36,7 @@ const ( ProtocolNumber = header.ARPProtocolNumber ) +var _ stack.DuplicateAddressDetector = (*endpoint)(nil) var _ stack.LinkAddressResolver = (*endpoint)(nil) // ARP endpoints need to implement stack.NetworkEndpoint because the stack @@ -52,6 +55,35 @@ type endpoint struct { nic stack.NetworkInterface stats sharedStats + + mu struct { + sync.Mutex + + dad ip.DAD + } +} + +// CheckDuplicateAddress implements stack.DuplicateAddressDetector. +func (e *endpoint) CheckDuplicateAddress(addr tcpip.Address, h stack.DADCompletionHandler) stack.DADCheckAddressDisposition { + e.mu.Lock() + defer e.mu.Unlock() + return e.mu.dad.CheckDuplicateAddressLocked(addr, h) +} + +// SetDADConfigurations implements stack.DuplicateAddressDetector. +func (e *endpoint) SetDADConfigurations(c stack.DADConfigurations) { + e.mu.Lock() + defer e.mu.Unlock() + e.mu.dad.SetConfigsLocked(c) +} + +// DuplicateAddressProtocol implements stack.DuplicateAddressDetector. +func (*endpoint) DuplicateAddressProtocol() tcpip.NetworkProtocolNumber { + return header.IPv4ProtocolNumber +} + +func (e *endpoint) SendDADMessage(addr tcpip.Address) tcpip.Error { + return e.sendARPRequest(header.IPv4Any, addr, header.EthernetBroadcastAddress) } func (e *endpoint) Enable() tcpip.Error { @@ -199,6 +231,10 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) { addr := tcpip.Address(h.ProtocolAddressSender()) linkAddr := tcpip.LinkAddress(h.HardwareAddressSender()) + e.mu.Lock() + e.mu.dad.StopLocked(addr, false /* aborted */) + e.mu.Unlock() + // The solicited, override, and isRouter flags are not available for ARP; // they are only available for IPv6 Neighbor Advertisements. switch err := e.nic.HandleNeighborConfirmation(header.IPv4ProtocolNumber, addr, linkAddr, stack.ReachabilityConfirmationFlags{ @@ -227,9 +263,9 @@ func (e *endpoint) Stats() stack.NetworkEndpointStats { var _ stack.NetworkProtocol = (*protocol)(nil) -// protocol implements stack.NetworkProtocol and stack.LinkAddressResolver. type protocol struct { - stack *stack.Stack + stack *stack.Stack + options Options } func (p *protocol) Number() tcpip.NetworkProtocolNumber { return ProtocolNumber } @@ -246,6 +282,14 @@ func (p *protocol) NewEndpoint(nic stack.NetworkInterface, dispatcher stack.Tran nic: nic, } + e.mu.Lock() + e.mu.dad.Init(&e.mu, p.options.DADConfigs, ip.DADOptions{ + Clock: p.stack.Clock(), + Protocol: e, + NICID: nic.ID(), + }) + e.mu.Unlock() + tcpip.InitStatCounters(reflect.ValueOf(&e.stats.localStats).Elem()) stackStats := p.stack.Stats() @@ -286,8 +330,12 @@ func (e *endpoint) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remot return &tcpip.ErrBadLocalAddress{} } + return e.sendARPRequest(localAddr, targetAddr, remoteLinkAddr) +} + +func (e *endpoint) sendARPRequest(localAddr, targetAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress) tcpip.Error { pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ - ReserveHeaderBytes: int(e.nic.MaxHeaderLength()) + header.ARPSize, + ReserveHeaderBytes: int(e.MaxHeaderLength()), }) h := header.ARP(pkt.NetworkHeader().Push(header.ARPSize)) pkt.NetworkProtocolNumber = ProtocolNumber @@ -302,6 +350,8 @@ func (e *endpoint) 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)) } + + stats := e.stats.arp if err := e.nic.WritePacketToRemote(remoteLinkAddr, nil /* gso */, ProtocolNumber, pkt); err != nil { stats.outgoingRequestsDropped.Increment() return err @@ -342,9 +392,24 @@ func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNu return 0, false, parse.ARP(pkt) } +// Options holds options to configure a protocol. +type Options struct { + // DADConfigs is the default DAD configurations used by ARP endpoints. + DADConfigs stack.DADConfigurations +} + +// NewProtocolWithOptions returns an ARP network protocol factory that +// will return an ARP network protocol with the provided options. +func NewProtocolWithOptions(opts Options) stack.NetworkProtocolFactory { + return func(s *stack.Stack) stack.NetworkProtocol { + return &protocol{ + stack: s, + options: opts, + } + } +} + // NewProtocol returns an ARP network protocol. func NewProtocol(s *stack.Stack) stack.NetworkProtocol { - return &protocol{ - stack: s, - } + return NewProtocolWithOptions(Options{})(s) } |