mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-22 04:48:39 +00:00
wgengine/magicsock: don't run the DERP cleanup so often
To save CPU and wakeups, don't run the DERP cleanup timer regularly unless there is a non-home DERP connection open. Also eliminates the goroutine, moving to a time.AfterFunc. Updates #1034 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
ab9cccb292
commit
187e22a756
@ -173,6 +173,15 @@ type Conn struct {
|
|||||||
started bool // Start was called
|
started bool // Start was called
|
||||||
closed bool // Close was called
|
closed bool // Close was called
|
||||||
|
|
||||||
|
// derpCleanupTimer is the timer that fires to occasionally clean
|
||||||
|
// up idle DERP connections. It's only used when there is a non-home
|
||||||
|
// DERP connection in use.
|
||||||
|
derpCleanupTimer *time.Timer
|
||||||
|
|
||||||
|
// derpCleanupTimerArmed is whether derpCleanupTimer is
|
||||||
|
// scheduled to fire within derpCleanStaleInterval.
|
||||||
|
derpCleanupTimerArmed bool
|
||||||
|
|
||||||
// endpointsUpdateActive indicates that updateEndpoints is
|
// endpointsUpdateActive indicates that updateEndpoints is
|
||||||
// currently running. It's used to deduplicate concurrent endpoint
|
// currently running. It's used to deduplicate concurrent endpoint
|
||||||
// update requests.
|
// update requests.
|
||||||
@ -488,7 +497,6 @@ func (c *Conn) Start() {
|
|||||||
if !version.IsMobile() {
|
if !version.IsMobile() {
|
||||||
go c.periodicReSTUN()
|
go c.periodicReSTUN()
|
||||||
}
|
}
|
||||||
go c.periodicDerpCleanup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignoreSTUNPackets sets a STUN packet processing func that does nothing.
|
// ignoreSTUNPackets sets a STUN packet processing func that does nothing.
|
||||||
@ -1219,6 +1227,7 @@ func (c *Conn) derpWriteChanOfAddr(addr netaddr.IPPort, peer key.Public) chan<-
|
|||||||
c.activeDerp[regionID] = ad
|
c.activeDerp[regionID] = ad
|
||||||
c.logActiveDerpLocked()
|
c.logActiveDerpLocked()
|
||||||
c.setPeerLastDerpLocked(peer, regionID, regionID)
|
c.setPeerLastDerpLocked(peer, regionID, regionID)
|
||||||
|
c.scheduleCleanStaleDerpLocked()
|
||||||
|
|
||||||
// Build a startGate for the derp reader+writer
|
// Build a startGate for the derp reader+writer
|
||||||
// goroutines, so they don't start running until any
|
// goroutines, so they don't start running until any
|
||||||
@ -2199,9 +2208,14 @@ func (c *Conn) foreachActiveDerpSortedLocked(fn func(regionID int, ad activeDerp
|
|||||||
func (c *Conn) cleanStaleDerp() {
|
func (c *Conn) cleanStaleDerp() {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
const inactivityTime = 60 * time.Second
|
if c.closed {
|
||||||
tooOld := time.Now().Add(-inactivityTime)
|
return
|
||||||
|
}
|
||||||
|
c.derpCleanupTimerArmed = false
|
||||||
|
|
||||||
|
tooOld := time.Now().Add(-derpInactiveCleanupTime)
|
||||||
dirty := false
|
dirty := false
|
||||||
|
someNonHomeOpen := false
|
||||||
for i, ad := range c.activeDerp {
|
for i, ad := range c.activeDerp {
|
||||||
if i == c.myDerp {
|
if i == c.myDerp {
|
||||||
continue
|
continue
|
||||||
@ -2209,11 +2223,31 @@ func (c *Conn) cleanStaleDerp() {
|
|||||||
if ad.lastWrite.Before(tooOld) {
|
if ad.lastWrite.Before(tooOld) {
|
||||||
c.closeDerpLocked(i, "idle")
|
c.closeDerpLocked(i, "idle")
|
||||||
dirty = true
|
dirty = true
|
||||||
|
} else {
|
||||||
|
someNonHomeOpen = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if dirty {
|
if dirty {
|
||||||
c.logActiveDerpLocked()
|
c.logActiveDerpLocked()
|
||||||
}
|
}
|
||||||
|
if someNonHomeOpen {
|
||||||
|
c.scheduleCleanStaleDerpLocked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Conn) scheduleCleanStaleDerpLocked() {
|
||||||
|
if c.derpCleanupTimerArmed {
|
||||||
|
// Already going to fire soon. Let the existing one
|
||||||
|
// fire lest it get infinitely delayed by repeated
|
||||||
|
// calls to scheduleCleanStaleDerpLocked.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.derpCleanupTimerArmed = true
|
||||||
|
if c.derpCleanupTimer != nil {
|
||||||
|
c.derpCleanupTimer.Reset(derpCleanStaleInterval)
|
||||||
|
} else {
|
||||||
|
c.derpCleanupTimer = time.AfterFunc(derpCleanStaleInterval, c.cleanStaleDerp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DERPs reports the number of active DERP connections.
|
// DERPs reports the number of active DERP connections.
|
||||||
@ -2236,6 +2270,9 @@ func (c *Conn) Close() error {
|
|||||||
if c.closed {
|
if c.closed {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if c.derpCleanupTimerArmed {
|
||||||
|
c.derpCleanupTimer.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
for _, ep := range c.endpointOfDisco {
|
for _, ep := range c.endpointOfDisco {
|
||||||
ep.stopAndReset()
|
ep.stopAndReset()
|
||||||
@ -2351,19 +2388,6 @@ func (c *Conn) periodicReSTUN() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) periodicDerpCleanup() {
|
|
||||||
ticker := time.NewTicker(15 * time.Second) // arbitrary
|
|
||||||
defer ticker.Stop()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-c.donec:
|
|
||||||
return
|
|
||||||
case <-ticker.C:
|
|
||||||
c.cleanStaleDerp()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReSTUN triggers an address discovery.
|
// ReSTUN triggers an address discovery.
|
||||||
// The provided why string is for debug logging only.
|
// The provided why string is for debug logging only.
|
||||||
func (c *Conn) ReSTUN(why string) {
|
func (c *Conn) ReSTUN(why string) {
|
||||||
@ -2856,6 +2880,14 @@ const (
|
|||||||
// goodEnoughLatency is the latency at or under which we don't
|
// goodEnoughLatency is the latency at or under which we don't
|
||||||
// try to upgrade to a better path.
|
// try to upgrade to a better path.
|
||||||
goodEnoughLatency = 5 * time.Millisecond
|
goodEnoughLatency = 5 * time.Millisecond
|
||||||
|
|
||||||
|
// derpInactiveCleanupTime is how long a non-home DERP connection
|
||||||
|
// needs to be idle (last written to) before we close it.
|
||||||
|
derpInactiveCleanupTime = 60 * time.Second
|
||||||
|
|
||||||
|
// derpCleanStaleInterval is how often cleanStaleDerp runs when there
|
||||||
|
// are potentially-stale DERP connections to close.
|
||||||
|
derpCleanStaleInterval = 15 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// endpointState is some state and history for a specific endpoint of
|
// endpointState is some state and history for a specific endpoint of
|
||||||
|
Loading…
x
Reference in New Issue
Block a user