ipn/ipnlocal: do not process old status messages received out of order
When `setWgengineStatus` is invoked concurrently from multiple goroutines, it is possible that the call invoked with a newer status is processed before a call with an older status. e.g. a status that has endpoints might be followed by a status without endpoints. This causes unnecessary work in the engine and can result in packet loss. This patch adds an `AsOf time.Time` field to the status to specifiy when the status was calculated, which later allows `setWgengineStatus` to ignore any status messages it receives that are older than the one it has already processed. Updates tailscale/corp#2579 Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
@@ -140,6 +140,7 @@ type LocalBackend struct {
|
||||
peerAPIListeners []*peerAPIListener
|
||||
loginFlags controlclient.LoginFlags
|
||||
incomingFiles map[*incomingFile]bool
|
||||
lastStatusTime time.Time // status.AsOf value of the last processed status update
|
||||
// directFileRoot, if non-empty, means to write received files
|
||||
// directly to this directory, without staging them in an
|
||||
// intermediate buffered directory for "pick-up" later. If
|
||||
@@ -706,6 +707,13 @@ func (b *LocalBackend) setWgengineStatus(s *wgengine.Status, err error) {
|
||||
}
|
||||
|
||||
b.mu.Lock()
|
||||
if s.AsOf.Before(b.lastStatusTime) {
|
||||
// Don't process a status update that is older than the one we have
|
||||
// already processed. (corp#2579)
|
||||
b.mu.Unlock()
|
||||
return
|
||||
}
|
||||
b.lastStatusTime = s.AsOf
|
||||
es := b.parseWgStatusLocked(s)
|
||||
cc := b.cc
|
||||
b.engineStatus = es
|
||||
|
||||
Reference in New Issue
Block a user