mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-28 05:58:20 +00:00
updates tailscale/corp#33891 Addresses several older the TODO's in netmon. This removes the Major flag precomputes the ChangeDelta state, rather than making consumers of ChangeDeltas sort that out themselves. We're also seeing a lot of ChangeDelta's being flagged as "Major" when they are not interesting, triggering rebinds in wgengine that are not needed. This cleans that up and adds a host of additional tests. The dependencies are cleaned, notably removing dependency on netmon itself for calculating what is interesting, and what is not. This includes letting individual platforms set a bespoke global "IsInterestingInterface" function. This is only used on Darwin. RebindRequired now roughly follows how "Major" was historically calculated but includes some additional checks for various uninteresting events such as changes in interface addresses that shouldn't trigger a rebind. This significantly reduces thrashing (by roughly half on Darwin clients which switching between nics). The individual values that we roll into RebindRequired are also exposed so that components consuming netmap.ChangeDelta can ask more targeted questions. Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
83 lines
2.0 KiB
Go
83 lines
2.0 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
//go:build !windows && !darwin
|
|
|
|
package netmon
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"os"
|
|
"runtime"
|
|
"sync"
|
|
"time"
|
|
|
|
"tailscale.com/types/logger"
|
|
)
|
|
|
|
func newPollingMon(logf logger.Logf, m *Monitor) (osMon, error) {
|
|
return &pollingMon{
|
|
logf: logf,
|
|
m: m,
|
|
stop: make(chan struct{}),
|
|
}, nil
|
|
}
|
|
|
|
// pollingMon is a bad but portable implementation of the link monitor
|
|
// that works by polling the interface state every 10 seconds, in lieu
|
|
// of anything to subscribe to.
|
|
type pollingMon struct {
|
|
logf logger.Logf
|
|
m *Monitor
|
|
|
|
closeOnce sync.Once
|
|
stop chan struct{}
|
|
}
|
|
|
|
func (pm *pollingMon) Close() error {
|
|
pm.closeOnce.Do(func() {
|
|
close(pm.stop)
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (pm *pollingMon) isCloudRun() bool {
|
|
// https: //cloud.google.com/run/docs/reference/container-contract#env-vars
|
|
if os.Getenv("K_REVISION") == "" || os.Getenv("K_CONFIGURATION") == "" ||
|
|
os.Getenv("K_SERVICE") == "" || os.Getenv("PORT") == "" {
|
|
return false
|
|
}
|
|
vers, err := os.ReadFile("/proc/version")
|
|
if err != nil {
|
|
pm.logf("Failed to read /proc/version: %v", err)
|
|
return false
|
|
}
|
|
return string(bytes.TrimSpace(vers)) == "Linux version 4.4.0 #1 SMP Sun Jan 10 15:06:54 PST 2016"
|
|
}
|
|
|
|
func (pm *pollingMon) Receive() (message, error) {
|
|
d := 10 * time.Second
|
|
if runtime.GOOS == "android" {
|
|
// We'll have Android notify the link monitor to wake up earlier,
|
|
// so this can go very slowly there, to save battery.
|
|
// https://github.com/tailscale/tailscale/issues/1427
|
|
d = 10 * time.Minute
|
|
} else if pm.isCloudRun() {
|
|
// Cloud Run routes never change at runtime. the containers are killed within
|
|
// 15 minutes by default, set the interval long enough to be effectively infinite.
|
|
pm.logf("monitor polling: Cloud Run detected, reduce polling interval to 24h")
|
|
d = 24 * time.Hour
|
|
}
|
|
timer := time.NewTimer(d)
|
|
defer timer.Stop()
|
|
for {
|
|
select {
|
|
case <-timer.C:
|
|
return unspecifiedMessage{}, nil
|
|
case <-pm.stop:
|
|
return nil, errors.New("stopped")
|
|
}
|
|
}
|
|
}
|