Preserve unreachable state and ping failures across node merges

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Ian Gulliver
2026-02-04 12:45:09 -08:00
parent c328e737d0
commit 41f3602696
2 changed files with 23 additions and 22 deletions

View File

@@ -388,9 +388,6 @@ func (n *Nodes) mergeNodes(keep, merge *Node) {
return
}
keepWasUnreachable := keep.Unreachable
mergeWasUnreachable := merge.Unreachable
for name := range merge.Names {
if keep.Names == nil {
keep.Names = NameSet{}
@@ -428,28 +425,20 @@ func (n *Nodes) mergeNodes(keep, merge *Node) {
n.mergeMulticast(keep, merge)
n.mergeDante(keep, merge)
if merge.cancelFunc != nil {
merge.cancelFunc()
if merge.InConfig {
keep.InConfig = true
}
hasIPs := false
for _, iface := range keep.Interfaces {
if len(iface.IPs) > 0 {
hasIPs = true
break
}
if merge.Unreachable {
keep.Unreachable = true
}
if hasIPs && (keepWasUnreachable || mergeWasUnreachable) {
keep.Unreachable = false
if n.t != nil && n.t.errors != nil {
n.t.errors.RemoveUnreachable(keep)
}
if keepWasUnreachable {
log.Printf("[merge] %s is now reachable (merged with node that has IPs)", keep.DisplayName())
}
if mergeWasUnreachable {
log.Printf("[merge] %s is now reachable (merged into %s)", merge.DisplayName(), keep.DisplayName())
}
if n.t != nil && n.t.ping != nil {
n.t.ping.TransferFailures(merge.ID, keep.ID)
}
if merge.cancelFunc != nil {
merge.cancelFunc()
}
n.removeNode(merge)

12
ping.go
View File

@@ -138,6 +138,18 @@ func (pm *PingManager) Ping(ipStr string, timeout time.Duration) bool {
}
}
func (pm *PingManager) TransferFailures(fromID, toID string) {
pm.mu.Lock()
defer pm.mu.Unlock()
fromFailures := pm.failures[fromID]
toFailures := pm.failures[toID]
if fromFailures > toFailures {
pm.failures[toID] = fromFailures
}
delete(pm.failures, fromID)
}
func (t *Tendrils) pingNode(node *Node) {
t.nodes.mu.RLock()
if node.Avoid {