From 06ed9e329d46268cf12fe07bd3974c5d54ae7e0b Mon Sep 17 00:00:00 2001 From: Ghanan Gowripalan Date: Wed, 16 Oct 2019 22:53:20 -0700 Subject: Do Duplicate Address Detection on permanent IPv6 addresses. This change adds support for Duplicate Address Detection on IPv6 addresses as defined by RFC 4862 section 5.4. Note, this change will not break existing uses of netstack as the default configuration for the stack options is set in such a way that DAD will not be performed. See `stack.Options` and `stack.NDPConfigurations` for more details. Tests: Tests to make sure that the DAD process properly resolves or fails. That is, tests make sure that DAD resolves only if: - No other node is performing DAD for the same address - No other node owns the same address PiperOrigin-RevId: 275189471 --- pkg/tcpip/stack/stack.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'pkg/tcpip/stack/stack.go') diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index f67975525..a199bc1cc 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -399,6 +399,9 @@ type Stack struct { // // TODO(gvisor.dev/issue/940): S/R this field. portSeed uint32 + + // ndpConfigs is the NDP configurations used by interfaces. + ndpConfigs NDPConfigurations } // Options contains optional Stack configuration. @@ -425,6 +428,13 @@ type Options struct { // UnassociatedFactory produces unassociated endpoints raw endpoints. // Raw endpoints are enabled only if this is non-nil. UnassociatedFactory UnassociatedEndpointFactory + + // NDPConfigs is the NDP configurations used by interfaces. + // + // By default, NDPConfigs will have a zero value for its + // DupAddrDetectTransmits field, implying that DAD will not be performed + // before assigning an address to a NIC. + NDPConfigs NDPConfigurations } // TransportEndpointInfo holds useful information about a transport endpoint @@ -458,6 +468,9 @@ func (*TransportEndpointInfo) IsEndpointInfo() {} // New allocates a new networking stack with only the requested networking and // transport protocols configured with default options. // +// Note, NDPConfigurations will be fixed before being used by the Stack. That +// is, if an invalid value was provided, it will be reset to the default value. +// // Protocol options can be changed by calling the // SetNetworkProtocolOption/SetTransportProtocolOption methods provided by the // stack. Please refer to individual protocol implementations as to what options @@ -468,6 +481,9 @@ func New(opts Options) *Stack { clock = &tcpip.StdClock{} } + // Make sure opts.NDPConfigs contains valid values only. + opts.NDPConfigs.validate() + s := &Stack{ transportProtocols: make(map[tcpip.TransportProtocolNumber]*transportProtocolState), networkProtocols: make(map[tcpip.NetworkProtocolNumber]NetworkProtocol), @@ -480,6 +496,7 @@ func New(opts Options) *Stack { handleLocal: opts.HandleLocal, icmpRateLimiter: NewICMPRateLimiter(), portSeed: generateRandUint32(), + ndpConfigs: opts.NDPConfigs, } // Add specified network protocols. @@ -1238,6 +1255,37 @@ func (s *Stack) AllowICMPMessage() bool { return s.icmpRateLimiter.Allow() } +// IsAddrTentative returns true if addr is tentative on the NIC with ID id. +// +// Note that if addr is not associated with a NIC with id ID, then this +// function will return false. It will only return true if the address is +// associated with the NIC AND it is tentative. +func (s *Stack) IsAddrTentative(id tcpip.NICID, addr tcpip.Address) (bool, *tcpip.Error) { + s.mu.RLock() + defer s.mu.RUnlock() + + nic, ok := s.nics[id] + if !ok { + return false, tcpip.ErrUnknownNICID + } + + return nic.isAddrTentative(addr), nil +} + +// DupTentativeAddrDetected attempts to inform the NIC with ID id that a +// tentative addr on it is a duplicate on a link. +func (s *Stack) DupTentativeAddrDetected(id tcpip.NICID, addr tcpip.Address) *tcpip.Error { + s.mu.Lock() + defer s.mu.Unlock() + + nic, ok := s.nics[id] + if !ok { + return tcpip.ErrUnknownNICID + } + + return nic.dupTentativeAddrDetected(addr) +} + // PortSeed returns a 32 bit value that can be used as a seed value for port // picking. // -- cgit v1.2.3