Cleanup temp SLAAC address jobs on DAD conflicts
Previously, when DAD would detect a conflict for a temporary address,
the address would be removed but its timers would not be stopped,
resulting in a panic when the removed address's invalidation timer
fired.
While I'm here, remove the check for unicast-ness on removed address
endpoints since multicast addresses are no longer stored in the same
structure as unicast addresses as of ab40e616341aa46d12ca1264b4036fc75b3.
Test: stack_test.TestMixedSLAACAddrConflictRegen
PiperOrigin-RevId: 359344849
This is a cherry pick of af8abf1.
This cherry pick needed to exclude `dadFailure`
from ipv6.endpoint.removePermanentEndpointInnerLocked as the parent
commits do not include 47454095c0da5bf2534391f21f3e034b8f534c72.
Test: fx test //src/connectivity/network/tests/integration
Bug: 70723
Change-Id: I9d0a2cb6f22265caa40db67e53e7f26e512f4ea1
diff --git a/pkg/tcpip/network/ipv6/ipv6.go b/pkg/tcpip/network/ipv6/ipv6.go
index ae4a8f5..0883956 100644
--- a/pkg/tcpip/network/ipv6/ipv6.go
+++ b/pkg/tcpip/network/ipv6/ipv6.go
@@ -1385,28 +1385,31 @@
// Precondition: e.mu must be write locked.
func (e *endpoint) removePermanentEndpointLocked(addressEndpoint stack.AddressEndpoint, allowSLAACInvalidation bool) *tcpip.Error {
addr := addressEndpoint.AddressWithPrefix()
- unicast := header.IsV6UnicastAddress(addr.Address)
- if unicast {
- e.mu.ndp.stopDuplicateAddressDetection(addr.Address)
- // If we are removing an address generated via SLAAC, cleanup
- // its SLAAC resources and notify the integrator.
- switch addressEndpoint.ConfigType() {
- case stack.AddressConfigSlaac:
- e.mu.ndp.cleanupSLAACAddrResourcesAndNotify(addr, allowSLAACInvalidation)
- case stack.AddressConfigSlaacTemp:
- e.mu.ndp.cleanupTempSLAACAddrResourcesAndNotify(addr, allowSLAACInvalidation)
- }
+ // If we are removing an address generated via SLAAC, cleanup
+ // its SLAAC resources and notify the integrator.
+ switch addressEndpoint.ConfigType() {
+ case stack.AddressConfigSlaac:
+ e.mu.ndp.cleanupSLAACAddrResourcesAndNotify(addr, allowSLAACInvalidation)
+ case stack.AddressConfigSlaacTemp:
+ e.mu.ndp.cleanupTempSLAACAddrResourcesAndNotify(addr)
}
+ return e.removePermanentEndpointInnerLocked(addressEndpoint)
+}
+
+// removePermanentEndpointInnerLocked is like removePermanentEndpointLocked
+// except it does not cleanup SLAAC address state.
+//
+// Precondition: e.mu must be write locked.
+func (e *endpoint) removePermanentEndpointInnerLocked(addressEndpoint stack.AddressEndpoint) *tcpip.Error {
+ addr := addressEndpoint.AddressWithPrefix()
+ e.mu.ndp.stopDuplicateAddressDetection(addr.Address)
+
if err := e.mu.addressableEndpointState.RemovePermanentEndpoint(addressEndpoint); err != nil {
return err
}
- if !unicast {
- return nil
- }
-
snmc := header.SolicitedNodeAddr(addr.Address)
// The endpoint may have already left the multicast group.
if err := e.leaveGroupLocked(snmc); err != nil && err != tcpip.ErrBadLocalAddress {
diff --git a/pkg/tcpip/network/ipv6/ndp.go b/pkg/tcpip/network/ipv6/ndp.go
index 1d8fee5..6a64cc9 100644
--- a/pkg/tcpip/network/ipv6/ndp.go
+++ b/pkg/tcpip/network/ipv6/ndp.go
@@ -1631,9 +1631,11 @@
ndp.cleanupSLAACPrefixResources(prefix, state)
if addressEndpoint := state.stableAddr.addressEndpoint; addressEndpoint != nil {
- // Since we are already invalidating the prefix, do not invalidate the
- // prefix when removing the address.
- if err := ndp.ep.removePermanentEndpointLocked(addressEndpoint, false /* allowSLAACInvalidation */); err != nil {
+ if ndpDisp := ndp.ep.protocol.options.NDPDisp; ndpDisp != nil {
+ ndpDisp.OnAutoGenAddressInvalidated(ndp.ep.nic.ID(), addressEndpoint.AddressWithPrefix())
+ }
+
+ if err := ndp.ep.removePermanentEndpointInnerLocked(addressEndpoint); err != nil {
panic(fmt.Sprintf("ndp: error removing stable SLAAC address %s: %s", addressEndpoint.AddressWithPrefix(), err))
}
}
@@ -1690,28 +1692,19 @@
//
// The IPv6 endpoint that ndp belongs to MUST be locked.
func (ndp *ndpState) invalidateTempSLAACAddr(tempAddrs map[tcpip.Address]tempSLAACAddrState, tempAddr tcpip.Address, tempAddrState tempSLAACAddrState) {
- // Since we are already invalidating the address, do not invalidate the
- // address when removing the address.
- if err := ndp.ep.removePermanentEndpointLocked(tempAddrState.addressEndpoint, false /* allowSLAACInvalidation */); err != nil {
+ ndp.cleanupTempSLAACAddrResourcesAndNotifyInner(tempAddrs, tempAddr, tempAddrState)
+
+ if err := ndp.ep.removePermanentEndpointInnerLocked(tempAddrState.addressEndpoint); err != nil {
panic(fmt.Sprintf("error removing temporary SLAAC address %s: %s", tempAddrState.addressEndpoint.AddressWithPrefix(), err))
}
-
- ndp.cleanupTempSLAACAddrResources(tempAddrs, tempAddr, tempAddrState)
}
// cleanupTempSLAACAddrResourcesAndNotify cleans up an invalidated temporary
-// SLAAC address's resources from ndp.
+// SLAAC address's resources from ndp and notifies the NDP dispatcher that the
+// address was invalidated.
//
// The IPv6 endpoint that ndp belongs to MUST be locked.
-func (ndp *ndpState) cleanupTempSLAACAddrResourcesAndNotify(addr tcpip.AddressWithPrefix, invalidateAddr bool) {
- if ndpDisp := ndp.ep.protocol.options.NDPDisp; ndpDisp != nil {
- ndpDisp.OnAutoGenAddressInvalidated(ndp.ep.nic.ID(), addr)
- }
-
- if !invalidateAddr {
- return
- }
-
+func (ndp *ndpState) cleanupTempSLAACAddrResourcesAndNotify(addr tcpip.AddressWithPrefix) {
prefix := addr.Subnet()
state, ok := ndp.slaacPrefixes[prefix]
if !ok {
@@ -1723,14 +1716,19 @@
panic(fmt.Sprintf("ndp: must have a tempAddr entry to clean up temp addr %s resources", addr))
}
- ndp.cleanupTempSLAACAddrResources(state.tempAddrs, addr.Address, tempAddrState)
+ ndp.cleanupTempSLAACAddrResourcesAndNotifyInner(state.tempAddrs, addr.Address, tempAddrState)
}
-// cleanupTempSLAACAddrResourcesAndNotify cleans up a temporary SLAAC address's
-// jobs and entry.
+// cleanupTempSLAACAddrResourcesAndNotifyInner is like
+// cleanupTempSLAACAddrResourcesAndNotify except it does not lookup the
+// temporary address's state in ndp - it assumes the passed state is valid.
//
// The IPv6 endpoint that ndp belongs to MUST be locked.
-func (ndp *ndpState) cleanupTempSLAACAddrResources(tempAddrs map[tcpip.Address]tempSLAACAddrState, tempAddr tcpip.Address, tempAddrState tempSLAACAddrState) {
+func (ndp *ndpState) cleanupTempSLAACAddrResourcesAndNotifyInner(tempAddrs map[tcpip.Address]tempSLAACAddrState, tempAddr tcpip.Address, tempAddrState tempSLAACAddrState) {
+ if ndpDisp := ndp.ep.protocol.options.NDPDisp; ndpDisp != nil {
+ ndpDisp.OnAutoGenAddressInvalidated(ndp.ep.nic.ID(), tempAddrState.addressEndpoint.AddressWithPrefix())
+ }
+
tempAddrState.addressEndpoint.DecRef()
tempAddrState.addressEndpoint = nil
tempAddrState.deprecationJob.Cancel()