From 7b73c9628da452bc7f000ee96349cd18517892eb Mon Sep 17 00:00:00 2001 From: James Tucker Date: Thu, 2 Mar 2023 21:04:01 -0800 Subject: [PATCH] version/distro,wgengine/router: raise WSL eth0 MTU when too low WSL has started to set the eth0 default route interface default to 1280 MTU, which is too low to carry 1280 byte packets from tailscale0 once wrapped in WireGuard. The change down to 1280 is very likely smaller than necessary for almost all users. We can not easily determine the ideal MTU, but if all the preconditions match, we raise the MTU to 1360, which is just enough for Tailscale traffic to work. Updates #4833 Updates #7346 Signed-off-by: James Tucker --- version/distro/distro.go | 10 ++++++++ wgengine/router/router_linux.go | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/version/distro/distro.go b/version/distro/distro.go index 970b8c1ae..0724265a4 100644 --- a/version/distro/distro.go +++ b/version/distro/distro.go @@ -32,6 +32,7 @@ const ( ) var distro lazy.SyncValue[Distro] +var isWSL lazy.SyncValue[bool] // Get returns the current distro, or the empty string if unknown. func Get() Distro { @@ -47,6 +48,15 @@ func Get() Distro { }) } +// IsWSL reports whether we're running in the Windows Subsystem for Linux. +func IsWSL() bool { + return runtime.GOOS == "linux" && isWSL.Get(func() bool { + // We could look for $WSL_INTEROP instead, however that may be missing if + // the user has started to use systemd in WSL2. + return have("/proc/sys/fs/binfmt_misc/WSLInterop") || have("/mnt/wsl") + }) +} + func have(file string) bool { _, err := os.Stat(file) return err == nil diff --git a/wgengine/router/router_linux.go b/wgengine/router/router_linux.go index 4afdaf7fb..1fd733fa0 100644 --- a/wgengine/router/router_linux.go +++ b/wgengine/router/router_linux.go @@ -7,6 +7,7 @@ import ( "bytes" "errors" "fmt" + "net" "net/netip" "os" "os/exec" @@ -224,6 +225,8 @@ func newUserspaceRouterAdvanced(logf logger.Logf, tunname string, linkMon *monit r.logf("mwan3 on openWRT detected, switching policy base priority to 1300") } + r.fixupWSLMTU() + return r, nil } @@ -891,6 +894,45 @@ func (r *linuxRouter) downInterface() error { return netlink.LinkSetDown(link) } +// fixupWSLMTU sets the MTU on the eth0 interface to 1360 bytes if running under +// WSL, eth0 is the default route, and has the MTU 1280 bytes. +func (r *linuxRouter) fixupWSLMTU() { + if !distro.IsWSL() { + return + } + + if r.useIPCommand() { + r.logf("fixupWSLMTU: not implemented by ip command") + return + } + + link, err := netlink.LinkByName("eth0") + if err != nil { + r.logf("warning: fixupWSLMTU: could not open eth0: %v", err) + return + } + + routes, err := netlink.RouteGet(net.IPv4(8, 8, 8, 8)) + if err != nil || len(routes) == 0 { + if err == nil { + err = fmt.Errorf("none found") + } + r.logf("fixupWSLMTU: could not get default route: %v", err) + return + } + + if routes[0].LinkIndex != link.Attrs().Index { + r.logf("fixupWSLMTU: default route is not via eth0") + return + } + + if link.Attrs().MTU == 1280 { + if err := netlink.LinkSetMTU(link, 1360); err != nil { + r.logf("warning: fixupWSLMTU: could not raise eth0 MTU: %v", err) + } + } +} + // addrFamily is an address family: IPv4 or IPv6. type addrFamily byte