From 518535de9b0e27cb13ac22b1bf8e6d2a8104d8a4 Mon Sep 17 00:00:00 2001 From: Tony Gong Date: Fri, 4 Feb 2022 10:26:35 -0800 Subject: [PATCH] Expose address deprecation on Stack Add a method for setting an address to be deprecated/preferred to AddressableEndpoint, so that addresses added from outside the stack can be deprecated/renewed respectively, e.g. by a DHCPv6 client. PiperOrigin-RevId: 426435598 --- pkg/tcpip/network/ipv4/ipv4.go | 7 +++++ pkg/tcpip/network/ipv6/ipv6.go | 7 +++++ pkg/tcpip/stack/addressable_endpoint_state.go | 13 ++++++++ pkg/tcpip/stack/nic.go | 18 +++++++++++ pkg/tcpip/stack/registration.go | 6 ++++ pkg/tcpip/stack/stack.go | 12 +++++++ pkg/tcpip/stack/stack_test.go | 31 ++++++++++++++++++- 7 files changed, 93 insertions(+), 1 deletion(-) diff --git a/pkg/tcpip/network/ipv4/ipv4.go b/pkg/tcpip/network/ipv4/ipv4.go index c393aaa38..d2a41a9d4 100644 --- a/pkg/tcpip/network/ipv4/ipv4.go +++ b/pkg/tcpip/network/ipv4/ipv4.go @@ -1053,6 +1053,13 @@ func (e *endpoint) RemovePermanentAddress(addr tcpip.Address) tcpip.Error { return e.addressableEndpointState.RemovePermanentAddress(addr) } +// SetDeprecated implements stack.AddressableEndpoint. +func (e *endpoint) SetDeprecated(addr tcpip.Address, deprecated bool) tcpip.Error { + e.mu.RLock() + defer e.mu.RUnlock() + return e.addressableEndpointState.SetDeprecated(addr, deprecated) +} + // MainAddress implements stack.AddressableEndpoint. func (e *endpoint) MainAddress() tcpip.AddressWithPrefix { e.mu.RLock() diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go index adc4ac50b..98d167bdb 100644 --- a/pkg/tcpip/network/ipv6/ipv6.go +++ b/pkg/tcpip/network/ipv6/ipv6.go @@ -1681,6 +1681,13 @@ func (e *endpoint) getAddressRLocked(localAddr tcpip.Address) stack.AddressEndpo return e.mu.addressableEndpointState.GetAddress(localAddr) } +// SetDeprecated implements stack.AddressableEndpoint. +func (e *endpoint) SetDeprecated(addr tcpip.Address, deprecated bool) tcpip.Error { + e.mu.RLock() + defer e.mu.RUnlock() + return e.mu.addressableEndpointState.SetDeprecated(addr, deprecated) +} + // MainAddress implements stack.AddressableEndpoint. func (e *endpoint) MainAddress() tcpip.AddressWithPrefix { e.mu.RLock() diff --git a/pkg/tcpip/stack/addressable_endpoint_state.go b/pkg/tcpip/stack/addressable_endpoint_state.go index 197acce0f..4f3ac1640 100644 --- a/pkg/tcpip/stack/addressable_endpoint_state.go +++ b/pkg/tcpip/stack/addressable_endpoint_state.go @@ -374,6 +374,19 @@ func (a *AddressableEndpointState) decAddressRefLocked(addrState *addressState) a.releaseAddressStateLocked(addrState) } +// SetDeprecated implements stack.AddressableEndpoint. +func (a *AddressableEndpointState) SetDeprecated(addr tcpip.Address, deprecated bool) tcpip.Error { + a.mu.Lock() + defer a.mu.Unlock() + + addrState, ok := a.mu.endpoints[addr] + if !ok { + return &tcpip.ErrBadLocalAddress{} + } + addrState.SetDeprecated(deprecated) + return nil +} + // MainAddress implements AddressableEndpoint. func (a *AddressableEndpointState) MainAddress() tcpip.AddressWithPrefix { a.mu.RLock() diff --git a/pkg/tcpip/stack/nic.go b/pkg/tcpip/stack/nic.go index b754d1c23..ef5282dfe 100644 --- a/pkg/tcpip/stack/nic.go +++ b/pkg/tcpip/stack/nic.go @@ -591,6 +591,24 @@ func (n *nic) removeAddress(addr tcpip.Address) tcpip.Error { return &tcpip.ErrBadLocalAddress{} } +func (n *nic) setAddressDeprecated(addr tcpip.Address, deprecated bool) tcpip.Error { + for _, ep := range n.networkEndpoints { + ep, ok := ep.(AddressableEndpoint) + if !ok { + continue + } + + switch err := ep.SetDeprecated(addr, deprecated); err.(type) { + case *tcpip.ErrBadLocalAddress: + continue + default: + return err + } + } + + return &tcpip.ErrBadLocalAddress{} +} + func (n *nic) getLinkAddress(addr, localAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, onResolve func(LinkResolutionResult)) tcpip.Error { linkRes, ok := n.linkAddrResolvers[protocol] if !ok { diff --git a/pkg/tcpip/stack/registration.go b/pkg/tcpip/stack/registration.go index 541bb736e..8a18b9948 100644 --- a/pkg/tcpip/stack/registration.go +++ b/pkg/tcpip/stack/registration.go @@ -491,6 +491,12 @@ type AddressableEndpoint interface { // permanent address. RemovePermanentAddress(addr tcpip.Address) tcpip.Error + // SetDeprecated sets whether the address should be deprecated or not. + // + // Returns *tcpip.ErrBadLocalAddress if the endpoint does not have the passed + // address. + SetDeprecated(addr tcpip.Address, deprecated bool) tcpip.Error + // MainAddress returns the endpoint's primary permanent address. MainAddress() tcpip.AddressWithPrefix diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index 2a05d29b3..581101d9a 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -943,6 +943,18 @@ func (s *Stack) RemoveAddress(id tcpip.NICID, addr tcpip.Address) tcpip.Error { return &tcpip.ErrUnknownNICID{} } +// SetAddressDeprecated sets an address to be deprecated or preferred. +func (s *Stack) SetAddressDeprecated(id tcpip.NICID, addr tcpip.Address, deprecated bool) tcpip.Error { + s.mu.RLock() + defer s.mu.RUnlock() + + if nic, ok := s.nics[id]; ok { + return nic.setAddressDeprecated(addr, deprecated) + } + + return &tcpip.ErrUnknownNICID{} +} + // AllAddresses returns a map of NICIDs to their protocol addresses (primary // and non-primary). func (s *Stack) AllAddresses() map[tcpip.NICID][]tcpip.ProtocolAddress { diff --git a/pkg/tcpip/stack/stack_test.go b/pkg/tcpip/stack/stack_test.go index d8e64dc71..c129386b3 100644 --- a/pkg/tcpip/stack/stack_test.go +++ b/pkg/tcpip/stack/stack_test.go @@ -2980,7 +2980,7 @@ func TestIPv6SourceAddressSelectionScopeAndSameAddress(t *testing.T) { properties stack.AddressProperties } - // Rule 3 is not tested here, and is instead tested by NDP's AutoGenAddr test. + // Rule 3 is also tested by NDP's AutoGenAddr test. tests := []struct { name string slaacPrefixForTempAddrBeforeNICAddrAdd tcpip.AddressWithPrefix @@ -3101,6 +3101,35 @@ func TestIPv6SourceAddressSelectionScopeAndSameAddress(t *testing.T) { expectedLocalAddr: linkLocalAddr1, }, + // Test Rule 3 of RFC 6724 section 5 (avoid deprecated addresses). + { + name: "Deprecated least preferred (last address)", + nicAddrs: []addressWithProperties{ + {addr: globalAddr1}, + { + addr: globalAddr2, + properties: stack.AddressProperties{ + Deprecated: true, + }, + }, + }, + remoteAddr: globalAddr3, + expectedLocalAddr: globalAddr1, + }, + { + name: "Deprecated least preferred (first address)", + nicAddrs: []addressWithProperties{ + { + addr: globalAddr2, + properties: stack.AddressProperties{ + Deprecated: true, + }, + }, + {addr: globalAddr1}, + }, + remoteAddr: globalAddr3, + expectedLocalAddr: globalAddr1, + }, // Test Rule 6 of 6724 section 5 (prefer matching label). { name: "Unique Local most preferred (last address)",