Compare commits

..
Author SHA1 Message Date
JackDoanandClaude Fable 5.1 e366f9452c smoke: Prove windows honors NlMtu with a 9000 byte ping
Follow-up to #1871. The Get-NetIPInterface check proves the value was written, not that windows fragments to it.

A 9000 byte payload only crosses the tunnel as fragments cut at NlMtu on the way out of the adapter. Left at the adapter default it reaches nebula whole, overflows the udp.MTU (9001) write buffer and is dropped, so the ping never answers. Anything smaller would ride out as one oversized datagram and survive on IP fragmentation of the underlay, which is why a payload that is merely larger than tun.mtu would not catch a regression.

Both families are pinged from the windows side so the v4 NlMtu, which was always right, gets the same guard.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J34ExJUUPKWUvr2g5GMREi
2026-09-08 09:40:55 -05:00
2 changed files with 15 additions and 15 deletions
+14 -8
View File
@@ -228,14 +228,6 @@ try {
Write-Host "OK: $DevName $family NlMtu=$Mtu"
}
# Both are set on the same handle as the v6 NlMtu, so by now they are either applied or never will be.
Wait-Until -TimeoutSec 30 -What "$DevName IPv6 DadTransmits=0 RouterDiscovery=Disabled" -Predicate {
if ($lhProc.HasExited) { throw "lighthouse exited (code $($lhProc.ExitCode)) before the v6 interface was configured" }
$rows = @(Get-NetIPInterface -InterfaceAlias $DevName -AddressFamily IPv6 -ErrorAction SilentlyContinue)
$rows.Count -gt 0 -and -not ($rows | Where-Object { $_.DadTransmits -ne 0 -or "$($_.RouterDiscovery)" -ne 'Disabled' })
}
Write-Host "OK: $DevName IPv6 DadTransmits=0 RouterDiscovery=Disabled"
Wait-Until -TimeoutSec 30 -What "WSL nebula1 with $Ip2" -Predicate {
if ($peerProc.HasExited) { throw "peer exited (code $($peerProc.ExitCode)) before tun was ready" }
$r = wsl -d $Distro -u root -- bash -c "ip -o addr show nebula1 2>/dev/null | grep -q 'inet $Ip2' && echo yes"
@@ -271,6 +263,20 @@ try {
}
Write-Host "OK: WSL peer -> windows lighthouse over v6"
# The NlMtu check above proves the value was written, not that windows honors it. A payload this size only
# crosses the tunnel as fragments cut at NlMtu on the way out of the adapter. Left at the adapter default it
# reaches nebula whole, overflows the udp.MTU (9001) write buffer and is dropped, so the ping never answers.
# Anything smaller would ride out as one oversized datagram and survive on IP fragmentation of the underlay.
$BigPayload = 9000
foreach ($target in @(@{ Family = 'v4'; Ip = $Ip2 }, @{ Family = 'v6'; Ip = $Ip6_2 })) {
Wait-Until -TimeoutSec 30 -What "$($target.Family) ping with a $BigPayload byte payload from windows lighthouse to WSL peer ($($target.Ip))" -Predicate {
if ($peerProc.HasExited) { throw "peer exited (code $($peerProc.ExitCode)) before the large $($target.Family) ping succeeded" }
$null = & ping.exe -n 1 -w 1000 -l $BigPayload $target.Ip
$LASTEXITCODE -eq 0
}
Write-Host "OK: windows lighthouse -> WSL peer, $BigPayload byte $($target.Family) payload"
}
Write-Host ''
Write-Host 'All smoke checks passed.'
}
+1 -7
View File
@@ -218,8 +218,7 @@ func (t *winTun) addRoutes(logErrors bool) error {
return t.setMTU(luid, foundDefault4, carriesV6)
}
// setMTU applies tun.mtu per address family. The default route metric rides along on the v4 handle, DAD and
// router discovery come off with the v6 one.
// setMTU applies tun.mtu per address family. The default route metric rides along on the v4 handle.
func (t *winTun) setMTU(luid winipcfg.LUID, foundDefault4, carriesV6 bool) error {
ipif, err := luid.IPInterface(windows.AF_INET)
if err != nil {
@@ -250,11 +249,6 @@ func (t *winTun) setMTU(luid winipcfg.LUID, foundDefault4, carriesV6 bool) error
}
ipif6.NLMTU = uint32(t.MTU)
// Nothing answers on the far side of this adapter but nebula, which drops the probes. DAD only holds the
// address tentative for a round it can never lose, and solicitations only invite RAs we would drop anyway.
// wireguard-windows turns both off on the same handle.
ipif6.DadTransmits = 0
ipif6.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled
if err := ipif6.Set(); err != nil {
return fmt.Errorf("failed to set ipv6 interface: %w", err)
}