policy: add NodeNeedsPeerRecompute predicate
Reports whether a node's online/offline transition forces peers to recompute their netmap. True for subnet routers, relay targets (tailscale.com/cap/relay), and via targets; false otherwise. The relay-target IP set and via-target tag set are precompiled from the grants in updateLocked, alongside the existing filter, so the per-node check is a cheap set lookup. Keyed on the node itself, so an ordinary node in a tailnet that uses relay or via for other nodes is still classified as not needing a recompute. Updates #3293
This commit is contained in:
parent
171fd7a3c5
commit
bceac495f9
4 changed files with 253 additions and 0 deletions
|
|
@ -594,6 +594,58 @@ func hasPerNodeGrants(grants []compiledGrant) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// collectRelayTargetIPs returns the set of IPs that are destinations of a
|
||||
// tailscale.com/cap/relay grant. A node whose IP is in this set is a relay
|
||||
// target: when it goes offline, peers holding a PeerRelay allocation through
|
||||
// it must recompute their netmap to drop the now-dead allocation. The relay
|
||||
// cap is carried on each grant's [tailcfg.CapGrant] with Dsts set to the
|
||||
// resolved relay destinations (see [Policy.compileOtherDests]); the reversed
|
||||
// companion rule carries [tailcfg.PeerCapabilityRelayTarget] instead and is
|
||||
// intentionally skipped.
|
||||
func collectRelayTargetIPs(grants []compiledGrant) (*netipx.IPSet, error) {
|
||||
var b netipx.IPSetBuilder
|
||||
|
||||
for i := range grants {
|
||||
for _, rule := range grants[i].rules {
|
||||
for _, cg := range rule.CapGrant {
|
||||
if _, ok := cg.CapMap[tailcfg.PeerCapabilityRelay]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, dst := range cg.Dsts {
|
||||
b.AddPrefix(dst)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return b.IPSet()
|
||||
}
|
||||
|
||||
// collectViaTargetTags returns the set of tags used as via targets across all
|
||||
// grants. A node carrying any of these tags is a via target: peers steering
|
||||
// traffic through it must recompute when it goes offline. Returns nil when no
|
||||
// via grants exist.
|
||||
func collectViaTargetTags(grants []compiledGrant) map[Tag]struct{} {
|
||||
var tags map[Tag]struct{}
|
||||
|
||||
for i := range grants {
|
||||
if grants[i].via == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, t := range grants[i].via.viaTags {
|
||||
if tags == nil {
|
||||
tags = make(map[Tag]struct{})
|
||||
}
|
||||
|
||||
tags[t] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return tags
|
||||
}
|
||||
|
||||
// globalFilterRules extracts global filter rules from [compiledGrant]s.
|
||||
// Via grants produce no global rules (they are per-node only); regular
|
||||
// grants contribute their full pre-compiled ruleset; self grants
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue