bambouville

WSL MTU 卡住

WSL2 主機是唯一一種工作階段能正常連上、然後就這麼停住,而兩端都沒有錯誤的情境。 問題幾乎不會出在 SSH 或 Tessera —— 而是 WSL2 背後那個虛擬介面卡的 MTU。當 Tessera 在連線期間觀察到這種特徵性的卡住時,會顯示一張琥珀色的 可能是 WSL2 / Tailscale 的 MTU 問題卡片,並連到這裡。

症狀

  • 工作階段連上了,提示字元出現,短指令也能正常執行。
  • 任何會送出大量資料的操作都會凍結:對長檔案執行 cat、寬幅的 ls、tmux 的 完整重繪、檔案面板中的傳輸。
  • 沒有任何東西回報失敗。工作階段就是不動了。重新連線可以成功,然後在同一類 輸出上再次卡住。
  • 同一台主機透過 mosh 的表現比透過 ssh 好。

如果連線根本到不了提示字元,同樣的故障可能正在吞掉 SSH 金鑰交換 —— 那本身 就是一大塊資料。下面的測試依然適用。

為什麼會發生

WSL2 執行在 Hyper-V 虛擬交換器之後,它的 eth0 啟動時 MTU 為 1500。當 Windows 主機實際上是透過更小的路徑連上網路時 —— VPN、PPPoE 或任何通道 —— 超過真實路徑 MTU 的封包就會在中途某處被丟棄。

路徑 MTU 探索本來就是為此而生:無法轉發封包的那一跳會回傳一個 ICMP 需要分片,發送端便會退讓。許多 VPN 和防火牆會丟棄那個 ICMP,於是回覆永遠不會 到來。小封包持續流動,大封包無聲消失 —— 這就是 PMTU 黑洞。看在 SSH 眼裡, 就像一條毫無理由停下來的連線。

確認它

在 WSL 內部,檢查介面自稱的值:

ip link show eth0

接著找出實際上能通過該路徑的大小。下面這些 ping 設定了「不分片」,而負載加上 28 位元組的標頭就是總大小,因此 -s 1472 探測的是 1500 位元組的封包。目標請 選同一路徑另一端的東西 —— 你要連的伺服器,或任何公開位址:

ping -M do -s 1472 -c 1 example.com   # 1500 — usually times out
ping -M do -s 1372 -c 1 example.com   # 1400 — usually gets through

逾時 就是黑洞。(若立刻出現本機錯誤,則表示該大小超過你自己介面的 MTU —— 請調低 -s 再試。)縮小範圍直到找出有回應的最大負載;加上 28,那就是你真實的 路徑 MTU。

Windows 端的等效指令,在 PowerShell 中執行:

ping -f -l 1472 example.com
netsh interface ipv4 show subinterfaces

第二條會列出每個介面卡的 MTU。一個停在 1400 的 VPN 介面卡,旁邊是 1500 的 vEthernet (WSL),這就是你要找的不相符。

在 WSL 中修復

把介面設成你量出來的大小。這會立即生效,並在下次關機時失效:

sudo ip link set dev eth0 mtu 1400

重新連線,再做一次原本會卡住的操作。如果輸出順暢無阻,診斷就確認了。

若要讓它長期生效,請讓 WSL 在開機時套用。在該發行版內的 /etc/wsl.conf 中:

[boot]
command = ip link set dev eth0 mtu 1400

接著從 Windows 執行 wsl --shutdown,然後重新啟動該發行版。[boot] 指令需要 相當新的 WSL —— 可用 wsl --version 檢查。

請使用你的 ping 測試得出的數字,而不是照抄 1400。1400 是一個安全的回退值, 幾乎能通過所有 VPN,但符合你實際路徑的數值能少浪費每個封包的空間。

或者讓 WSL 鏡像主機

在 Windows 11 22H2 以上並搭配 WSL 2.0+ 時,鏡像網路會把主機自己的介面(包含 MTU)交給發行版,於是不相符根本不會發生。在 %UserProfile%\.wslconfig 中:

[wsl2]
networkingMode=mirrored

wsl --shutdown 套用。這改變的遠不止 MTU —— localhost 和區域網路的可達性 都會變得不同 —— 因此如果你唯一的問題只是工作階段卡住,還是優先使用開機指令。

當低 MTU 的那一跳在伺服器那一側

受限的一端不一定是 WSL;從伺服器執行同樣的 ping 測試,就能知道是哪一側被卡住。 如果中間的路由器由你掌控,把 TCP 的 MSS 箝制到探測出的路徑 MTU,就能一次修好 經過它的所有連線:

iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN \
  -j TCPMSS --clamp-mss-to-pmtu

在你還卡著的時候

把主機的傳輸方式改成 mosh 是權宜之計, 而不是修復。mosh 的資料包夠小,能從有問題的 MTU 底下溜過去,而且它是重繪畫面 而非重播位元組串流,所以互動式工作階段能撐下來。檔案面板和 tmux 側通道仍走 SSH,因此大型傳輸仍可能繼續卡住。

如果以上都不符合你看到的狀況,請擷取一份日誌 (設定 → 診斷 → 輸出日誌,見診斷), 並到 GitHub Issues 開立議題。