health: track whether we have a functional udp4 bind

Suggested-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
This commit is contained in:
Josh Bleecher Snyder 2021-04-28 10:36:54 -07:00
parent 7dc7078d96
commit fe50ded95c
2 changed files with 19 additions and 1 deletions

View File

@ -37,6 +37,7 @@
ipnState string
ipnWantRunning bool
anyInterfaceUp = true // until told otherwise
udp4Unbound bool
)
// Subsystem is the name of a subsystem whose health can be monitored.
@ -47,7 +48,7 @@
// the system, rather than one particular subsystem.
SysOverall = Subsystem("overall")
// SysRouter is the name the wgengine/router subsystem.
// SysRouter is the name of the wgengine/router subsystem.
SysRouter = Subsystem("router")
// SysDNS is the name of the net/dns subsystem.
@ -214,6 +215,14 @@ func SetAnyInterfaceUp(up bool) {
selfCheckLocked()
}
// SetUDP4Unbound sets whether the udp4 bind failed completely.
func SetUDP4Unbound(unbound bool) {
mu.Lock()
defer mu.Unlock()
udp4Unbound = unbound
selfCheckLocked()
}
func timerSelfCheck() {
mu.Lock()
defer mu.Unlock()
@ -257,6 +266,9 @@ func overallErrorLocked() error {
if d := now.Sub(derpRegionLastFrame[rid]).Round(time.Second); d > tooIdle {
return fmt.Errorf("haven't heard from home DERP region %v in %v", rid, d)
}
if udp4Unbound {
return errors.New("no udp4 bind")
}
// TODO: use
_ = inMapPollSince

View File

@ -2671,6 +2671,9 @@ func (c *Conn) bindSocket(rucPtr **RebindingUDPConn, network string) error {
}
// Success.
ruc.pconn = pconn
if network == "udp4" {
health.SetUDP4Unbound(false)
}
return nil
}
@ -2679,6 +2682,9 @@ func (c *Conn) bindSocket(rucPtr **RebindingUDPConn, network string) error {
// This keeps the receive funcs alive for a future in which
// we get a link change and we can try binding again.
ruc.pconn = newBlockForeverConn()
if network == "udp4" {
health.SetUDP4Unbound(true)
}
return fmt.Errorf("failed to bind any ports (tried %v)", ports)
}