wgengine/magicsock, health, ipn/ipnstate: track DERP-advertised health

And add health check errors to ipnstate.Status (tailscale status --json).

Updates #2746
Updates #2775

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2021-09-01 19:27:22 -07:00
committed by Brad Fitzpatrick
parent 722942dd46
commit 5bacbf3744
4 changed files with 48 additions and 0 deletions

View File

@@ -32,6 +32,7 @@ var (
lastStreamedMapResponse time.Time
derpHomeRegion int
derpRegionConnected = map[int]bool{}
derpRegionHealthProblem = map[int]string{}
derpRegionLastFrame = map[int]time.Time{}
lastMapRequestHeard time.Time // time we got a 200 from control for a MapRequest
ipnState string
@@ -191,6 +192,19 @@ func SetDERPRegionConnectedState(region int, connected bool) {
selfCheckLocked()
}
// SetDERPRegionHealth sets or clears any problem associated with the
// provided DERP region.
func SetDERPRegionHealth(region int, problem string) {
mu.Lock()
defer mu.Unlock()
if problem == "" {
delete(derpRegionHealthProblem, region)
} else {
derpRegionHealthProblem[region] = problem
}
selfCheckLocked()
}
func NoteDERPRegionReceivedFrame(region int) {
mu.Lock()
defer mu.Unlock()
@@ -241,6 +255,16 @@ func selfCheckLocked() {
setLocked(SysOverall, overallErrorLocked())
}
// OverallError returns a summary of the health state.
//
// If there are multiple problems, the error will be of type
// multierror.MultipleErrors.
func OverallError() error {
mu.Lock()
defer mu.Unlock()
return overallErrorLocked()
}
func overallErrorLocked() error {
if !anyInterfaceUp {
return errors.New("network down")
@@ -288,6 +312,9 @@ func overallErrorLocked() error {
}
errs = append(errs, fmt.Errorf("%v: %w", sys, err))
}
for regionID, problem := range derpRegionHealthProblem {
errs = append(errs, fmt.Errorf("derp%d: %v", regionID, problem))
}
sort.Slice(errs, func(i, j int) bool {
// Not super efficient (stringifying these in a sort), but probably max 2 or 3 items.
return errs[i].Error() < errs[j].Error()