Skip to content

Commit f67e6cf

Browse files
committed
wgengine/magicsock: fix rebind debouncing (tailscale#17282)
On platforms that are causing EPIPE at a high frequency this is resulting in non-working connections, for example when Apple decides to forcefully close UDP sockets due to an unsoliced packet rejection in the firewall. Too frequent rebinds cause a failure to solicit the endpoints triggering the rebinds, that would normally happen via CallMeMaybe. Updates tailscale#14551 Updates tailscale/corp#25648 Signed-off-by: James Tucker <james@tailscale.com>
1 parent 25ea53a commit f67e6cf

File tree

2 files changed

+30
-11
lines changed

2 files changed

+30
-11
lines changed

wgengine/magicsock/magicsock.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,6 +1565,7 @@ func (c *Conn) maybeRebindOnError(err error) {
15651565

15661566
if c.lastErrRebind.Load().Before(time.Now().Add(-5 * time.Second)) {
15671567
c.logf("magicsock: performing rebind due to %q", reason)
1568+
c.lastErrRebind.Store(time.Now())
15681569
c.Rebind()
15691570
go c.ReSTUN(reason)
15701571
} else {

wgengine/magicsock/magicsock_test.go

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"sync/atomic"
2828
"syscall"
2929
"testing"
30+
"testing/synctest"
3031
"time"
3132
"unsafe"
3233

@@ -3116,18 +3117,35 @@ func TestMaybeRebindOnError(t *testing.T) {
31163117
}
31173118

31183119
t.Run("no-frequent-rebind", func(t *testing.T) {
3119-
if runtime.GOOS != "plan9" {
3120-
err := fmt.Errorf("outer err: %w", syscall.EPERM)
3121-
conn := newTestConn(t)
3122-
defer conn.Close()
3123-
conn.lastErrRebind.Store(time.Now().Add(-1 * time.Second))
3124-
before := metricRebindCalls.Value()
3125-
conn.maybeRebindOnError(err)
3126-
after := metricRebindCalls.Value()
3127-
if before != after {
3128-
t.Errorf("should not rebind within 5 seconds of last")
3120+
synctest.Test(t, func(t *testing.T) {
3121+
if runtime.GOOS != "plan9" {
3122+
err := fmt.Errorf("outer err: %w", syscall.EPERM)
3123+
conn := newTestConn(t)
3124+
defer conn.Close()
3125+
lastRebindTime := time.Now().Add(-1 * time.Second)
3126+
conn.lastErrRebind.Store(lastRebindTime)
3127+
before := metricRebindCalls.Value()
3128+
conn.maybeRebindOnError(err)
3129+
after := metricRebindCalls.Value()
3130+
if before != after {
3131+
t.Errorf("should not rebind within 5 seconds of last")
3132+
}
3133+
3134+
// ensure that rebinds are performed and store an updated last
3135+
// rebind time.
3136+
time.Sleep(6 * time.Second)
3137+
3138+
conn.maybeRebindOnError(err)
3139+
newTime := conn.lastErrRebind.Load()
3140+
if newTime == lastRebindTime {
3141+
t.Errorf("expected a rebind to occur")
3142+
}
3143+
if newTime.Sub(lastRebindTime) < 5*time.Second {
3144+
t.Errorf("expected at least 5 seconds between %s and %s", lastRebindTime, newTime)
3145+
}
31293146
}
3130-
}
3147+
3148+
})
31313149
})
31323150
}
31333151

0 commit comments

Comments
 (0)