diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 25658a7c..91a47ebd 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -196,7 +196,7 @@ debugConsole=true ### Common Debugging Commands - Debug shell: `wsl --debug-shell` - Collect WSL logs: `powershell diagnostics\collect-wsl-logs.ps1` -- Network logs: `powershell diagnostics\collect-networking-logs.ps1` +- Network logs: `powershell diagnostics\collect-wsl-logs.ps1 -LogProfile networking` ## Critical Timing and Timeout Guidelines diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index af52ff9c..52692428 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,13 +53,18 @@ Install [WPR](https://learn.microsoft.com/windows-hardware/test/wpt/windows-perf To collect WSL networking logs, do the following steps in an administrative powershell prompt: ``` -Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/WSL/master/diagnostics/collect-networking-logs.ps1" -OutFile collect-networking-logs.ps1 +Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/WSL/master/diagnostics/collect-wsl-logs.ps1" -OutFile collect-wsl-logs.ps1 Set-ExecutionPolicy Bypass -Scope Process -Force -.\collect-networking-logs.ps1 +.\collect-wsl-logs.ps1 -LogProfile networking ``` The script will output when log collection starts. Reproduce the problem, then press any key to stop the log collection. The script will output the path of the log file once done. +For additional network creation logs (restarts WSL), use: +``` +.\collect-wsl-logs.ps1 -LogProfile networking -RestartWslReproMode +``` +
@@ -81,9 +86,9 @@ The script will output the path of the log file once done. For specific scenarios, you can use different log profiles: - `.\collect-wsl-logs.ps1 -LogProfile storage` - Enhanced storage tracing -- `.\collect-wsl-logs.ps1 -LogProfile networking` - Networking-focused tracing +- `.\collect-wsl-logs.ps1 -LogProfile networking` - Comprehensive networking tracing (includes packet capture, tcpdump, etc.) +- `.\collect-wsl-logs.ps1 -LogProfile networking -RestartWslReproMode` - Networking tracing with WSL restart for network creation logs - `.\collect-wsl-logs.ps1 -LogProfile hvsocket` - HvSocket-specific tracing -- `.\collect-networking-logs.ps1` - Alternative script for networking tracing ### 10) Reporting a Windows crash (BSOD) diff --git a/diagnostics/collect-networking-logs.ps1 b/diagnostics/collect-networking-logs.ps1 deleted file mode 100644 index 50016281..00000000 --- a/diagnostics/collect-networking-logs.ps1 +++ /dev/null @@ -1,320 +0,0 @@ -#Requires -RunAsAdministrator - -[CmdletBinding()] -Param ( - $RestartWslReproMode = $false - ) - -function Collect-WindowsNetworkState { - - param ( - $ReproStep - ) - - # Collect host networking state relevant for WSL - # Using a try/catch for commands below, as some of them do not exist on all OS versions - - try - { - Get-NetAdapter -includeHidden | select Name,ifIndex,NetLuid,InterfaceGuid,Status,MacAddress,MtuSize,InterfaceType,Hidden,HardwareInterface,ConnectorPresent,MediaType,PhysicalMediaType | Out-File -FilePath "$folder/Get-NetAdapter_$ReproStep.log" -Append - } - catch {} - - try - { - & netsh nlm query all $folder/nlmquery_"$ReproStep".log - } - catch {} - - try - { - Get-NetIPConfiguration -All -Detailed | Out-File -FilePath "$folder/Get-NetIPConfiguration_$ReproStep.log" -Append - } - catch {} - - try - { - Get-NetRoute | Out-File -FilePath "$folder/Get-NetRoute_$ReproStep.log" -Append - } - catch {} - - try - { - Get-NetFirewallHyperVVMCreator | Out-File -FilePath "$folder/Get-NetFirewallHyperVVMCreator_$ReproStep.log" -Append - } - catch {} - - try - { - Get-NetFirewallHyperVVMSetting -PolicyStore ActiveStore | Out-File -FilePath "$folder/Get-NetFirewallHyperVVMSetting_ActiveStore_$ReproStep.log" -Append - } - catch {} - - try - { - Get-NetFirewallHyperVProfile -PolicyStore ActiveStore | Out-File -FilePath "$folder/Get-NetFirewallHyperVProfile_ActiveStore_$ReproStep.log" -Append - } - catch {} - - try - { - Get-NetFirewallHyperVRule -PolicyStore ActiveStore | Out-File -FilePath "$folder/Get-NetFirewallHyperVRule_ActiveStore_$ReproStep.log" -Append - } - catch {} - - try - { - Get-NetFirewallRule -PolicyStore ActiveStore | Out-File -FilePath "$folder/Get-NetFirewallRule_ActiveStore_$ReproStep.log" -Append - } - catch {} - - try - { - Get-NetFirewallProfile -PolicyStore ActiveStore | Out-File -FilePath "$folder/Get-NetFirewallProfile_ActiveStore_$ReproStep.log" -Append - } - catch {} - - try - { - Get-NetFirewallHyperVPort | Out-File -FilePath "$folder/Get-NetFirewallHyperVPort_$ReproStep.log" -Append - } - catch {} - - try - { - & hnsdiag.exe list all 2>&1 > $folder/hnsdiag_list_all_"$ReproStep".log - } - catch {} - - try - { - & hnsdiag.exe list endpoints -df 2>&1 > $folder/hnsdiag_list_endpoints_"$ReproStep".log - } - catch {} - - try - { - foreach ($port in Get-NetFirewallHyperVPort) - { - & vfpctrl.exe /port $port.PortName /get-port-state 2>&1 > "$folder/vfp-port-$($port.PortName)-get-port-state_$ReproStep.log" - & vfpctrl.exe /port $port.PortName /list-rule 2>&1 > "$folder/vfp-port-$($port.PortName)-list-rule_$ReproStep.log" - } - } - catch {} - - try - { - & vfpctrl.exe /list-vmswitch-port 2>&1 > $folder/vfpctrl_list_vmswitch_port_"$ReproStep".log - } - catch {} - - try - { - Get-VMSwitch | select Name,Id,SwitchType | Out-File -FilePath "$folder/Get-VMSwitch_$ReproStep.log" -Append - } - catch {} - - try - { - Get-NetUdpEndpoint | Out-File -FilePath "$folder/Get-NetUdpEndpoint_$ReproStep.log" -Append - } - catch {} -} - -$folder = "WslNetworkingLogs-" + (Get-Date -Format "yyyy-MM-dd_HH-mm-ss") -mkdir -p $folder - -$wprpFile = "$folder/wsl.wprp" -$wprpProfile = "WSL-Networking" -$networkingBashScript = "$folder/networking.sh" - -# Detect the super user first. -# Actually it's not definite that the super user is named "root". Instead, a user with uid=0 is what we are looking for. See #11693. -$superUser = & wsl.exe -- id -nu 0 # user name of the super user. - -# Copy/Download supporting files -if (Test-Path "$PSScriptRoot/wsl.wprp") -{ - Copy-Item "$PSScriptRoot/wsl.wprp" $wprpFile -} -else -{ - Write-Host -ForegroundColor Yellow "wsl.wprp not found in the current directory. Downloading it from GitHub." - Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/WSL/master/diagnostics/wsl.wprp" -OutFile $wprpFile -} - -if (Test-Path "$PSScriptRoot/networking.sh") -{ - Copy-Item "$PSScriptRoot/networking.sh" $networkingBashScript -} -else -{ - Write-Host -ForegroundColor Yellow "networking.sh not found in the current directory. Downloading it from GitHub." - Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/WSL/master/diagnostics/networking.sh" -OutFile $networkingBashScript -} - -# Retrieve WSL version and wslconfig file -get-appxpackage MicrosoftCorporationII.WindowsSubsystemforLinux > $folder/appxpackage.txt - -$wslconfig = "$env:USERPROFILE/.wslconfig" -if (Test-Path $wslconfig) -{ - Copy-Item $wslconfig $folder -} - -# Collect Linux & Windows network state before the repro -& wsl.exe -u $superUser -e $networkingBashScript 2>&1 > $folder/linux_network_configuration_before.log - -Collect-WindowsNetworkState "before_repro" - -if ($RestartWslReproMode) -{ - # The WSL HNS network is created once per boot. Resetting it to collect network creation logs. - # Note: The below HNS command applies only to WSL in NAT mode - Get-HnsNetwork | Where-Object {$_.Name -eq 'WSL' -Or $_.Name -eq 'WSL (Hyper-V firewall)'} | Remove-HnsNetwork - - # Stop WSL. - net.exe stop WslService - if(-not $?) - { - net.exe stop LxssManager - } -} - -# Start logging. -$wprOutputLog = "$folder/wpr.txt" - -wpr.exe -start "$wprpFile!$wprpProfile" -filemode 2>&1 >> $wprOutputLog -if ($LastExitCode -Ne 0) -{ - Write-Host -ForegroundColor Yellow "Log collection failed to start (exit code: $LastExitCode), trying to reset it." - wpr.exe -cancel 2>&1 >> $wprOutputLog - - wpr.exe -start "$wprpFile!$wprpProfile" -filemode 2>&1 >> $wprOutputLog - if ($LastExitCode -Ne 0) - { - Write-Host -ForegroundColor Red "Couldn't start log collection (exitCode: $LastExitCode)" - } -} - -# Start packet capture using pktmon -pktmon start -c --flags 0x1A --file-name "$folder/pktmon.etl" | out-null - -# Start WFP capture -netsh wfp capture start file="$folder/wfpdiag.cab" - -# Start tcpdump. Using a try/catch as tcpdump might not be installed -$tcpdumpProcess = $null -try -{ - $tcpdumpProcess = Start-Process wsl.exe -ArgumentList "-u $superUser tcpdump -n -i any -e -vvv > $folder/tcpdump.log" -PassThru -} -catch {} - -try -{ - Write-Host -NoNewLine -ForegroundColor Green "Log collection is running. Please reproduce the problem and press any key to save the logs." - - $KeysToIgnore = - 16, # Shift (left or right) - 17, # Ctrl (left or right) - 18, # Alt (left or right) - 20, # Caps lock - 91, # Windows key (left) - 92, # Windows key (right) - 93, # Menu key - 144, # Num lock - 145, # Scroll lock - 166, # Back - 167, # Forward - 168, # Refresh - 169, # Stop - 170, # Search - 171, # Favorites - 172, # Start/Home - 173, # Mute - 174, # Volume Down - 175, # Volume Up - 176, # Next Track - 177, # Previous Track - 178, # Stop Media - 179, # Play - 180, # Mail - 181, # Select Media - 182, # Application 1 - 183 # Application 2 - - $Key = $null - while ($Key -Eq $null -Or $Key.VirtualKeyCode -Eq $null -Or $KeysToIgnore -Contains $Key.VirtualKeyCode) - { - if ([console]::KeyAvailable) - { - $Key = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') - } - else - { - Start-Sleep -Seconds 1 - } - } - - Write-Host "`nSaving logs..." -} -finally -{ - try - { - wsl.exe -u $superUser killall tcpdump - if ($tcpdumpProcess -ne $null) - { - Wait-Process -InputObject $tcpdumpProcess -Timeout 10 - } - } - catch {} - - netsh wfp capture stop - pktmon stop | out-null - wpr.exe -stop $folder/logs.etl 2>&1 >> $wprOutputLog -} - -# Collect Linux & Windows network state after the repro -& wsl.exe -u $superUser -e $networkingBashScript 2>&1 > $folder/linux_network_configuration_after.log - -Collect-WindowsNetworkState "after_repro" - -try -{ - # Collect HNS events from past 24 hours - $events = Get-WinEvent -ProviderName Microsoft-Windows-Host-Network-Service | Where-Object { $_.TimeCreated -ge ((Get-Date) - (New-TimeSpan -Day 1)) } - ($events | ForEach-Object { '{0},{1},{2},{3}' -f $_.TimeCreated, $_.Id, $_.LevelDisplayName, $_.Message }) -join [environment]::NewLine | Out-File -FilePath "$folder/hns_events.log" -Append -} -catch {} - -# Collect the old Tcpip6 registry values - as they can break WSL if DisabledComponents is set to 0xff -# see https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/configure-ipv6-in-windows -try -{ - Get-Item HKLM:SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters | Out-File -FilePath "$folder/tcpip6_parameters.log" -Append -} -catch {} - -# Collect the setup and NetSetup log files -$netSetupPath = "$env:WINDIR/logs/netsetup" -if (Test-Path $netSetupPath) -{ - Copy-Item $netSetupPath/* $folder -} - -$setupApiPath = "$env:WINDIR/inf/setupapi.dev.log" -if (Test-Path $setupApiPath) -{ - Copy-Item $setupApiPath $folder -} - -Remove-Item $wprpFile -Remove-Item $networkingBashScript - -$logArchive = "$(Resolve-Path $folder).zip" -Compress-Archive -Path $folder -DestinationPath $logArchive -Remove-Item $folder -Recurse - -Write-Host -ForegroundColor Green "Logs saved in: $logArchive. Please attach that file to the GitHub issue." diff --git a/diagnostics/collect-wsl-logs.ps1 b/diagnostics/collect-wsl-logs.ps1 index 242c2417..139c3ba4 100644 --- a/diagnostics/collect-wsl-logs.ps1 +++ b/diagnostics/collect-wsl-logs.ps1 @@ -3,11 +3,45 @@ [CmdletBinding()] Param ( $LogProfile = $null, - [switch]$Dump = $false + [switch]$Dump = $false, + [switch]$RestartWslReproMode = $false ) Set-StrictMode -Version Latest +function Collect-WindowsNetworkState { + param ( + $Folder, + $ReproStep + ) + + # Collect host networking state relevant for WSL + # Using a try/catch for commands below, as some of them do not exist on all OS versions + + try { Get-NetAdapter -includeHidden | select Name,ifIndex,NetLuid,InterfaceGuid,Status,MacAddress,MtuSize,InterfaceType,Hidden,HardwareInterface,ConnectorPresent,MediaType,PhysicalMediaType | Out-File -FilePath "$Folder/Get-NetAdapter_$ReproStep.log" -Append } catch {} + try { & netsh nlm query all $Folder/nlmquery_"$ReproStep".log } catch {} + try { Get-NetIPConfiguration -All -Detailed | Out-File -FilePath "$Folder/Get-NetIPConfiguration_$ReproStep.log" -Append } catch {} + try { Get-NetRoute | Out-File -FilePath "$Folder/Get-NetRoute_$ReproStep.log" -Append } catch {} + try { Get-NetFirewallHyperVVMCreator | Out-File -FilePath "$Folder/Get-NetFirewallHyperVVMCreator_$ReproStep.log" -Append } catch {} + try { Get-NetFirewallHyperVVMSetting -PolicyStore ActiveStore | Out-File -FilePath "$Folder/Get-NetFirewallHyperVVMSetting_ActiveStore_$ReproStep.log" -Append } catch {} + try { Get-NetFirewallHyperVProfile -PolicyStore ActiveStore | Out-File -FilePath "$Folder/Get-NetFirewallHyperVProfile_ActiveStore_$ReproStep.log" -Append } catch {} + try { Get-NetFirewallHyperVRule -PolicyStore ActiveStore | Out-File -FilePath "$Folder/Get-NetFirewallHyperVRule_ActiveStore_$ReproStep.log" -Append } catch {} + try { Get-NetFirewallRule -PolicyStore ActiveStore | Out-File -FilePath "$Folder/Get-NetFirewallRule_ActiveStore_$ReproStep.log" -Append } catch {} + try { Get-NetFirewallProfile -PolicyStore ActiveStore | Out-File -FilePath "$Folder/Get-NetFirewallProfile_ActiveStore_$ReproStep.log" -Append } catch {} + try { Get-NetFirewallHyperVPort | Out-File -FilePath "$Folder/Get-NetFirewallHyperVPort_$ReproStep.log" -Append } catch {} + try { & hnsdiag.exe list all 2>&1 > $Folder/hnsdiag_list_all_"$ReproStep".log } catch {} + try { & hnsdiag.exe list endpoints -df 2>&1 > $Folder/hnsdiag_list_endpoints_"$ReproStep".log } catch {} + try { + foreach ($port in Get-NetFirewallHyperVPort) { + & vfpctrl.exe /port $port.PortName /get-port-state 2>&1 > "$Folder/vfp-port-$($port.PortName)-get-port-state_$ReproStep.log" + & vfpctrl.exe /port $port.PortName /list-rule 2>&1 > "$Folder/vfp-port-$($port.PortName)-list-rule_$ReproStep.log" + } + } catch {} + try { & vfpctrl.exe /list-vmswitch-port 2>&1 > $Folder/vfpctrl_list_vmswitch_port_"$ReproStep".log } catch {} + try { Get-VMSwitch | select Name,Id,SwitchType | Out-File -FilePath "$Folder/Get-VMSwitch_$ReproStep.log" -Append } catch {} + try { Get-NetUdpEndpoint | Out-File -FilePath "$Folder/Get-NetUdpEndpoint_$ReproStep.log" -Append } catch {} +} + $folder = "WslLogs-" + (Get-Date -Format "yyyy-MM-dd_HH-mm-ss") mkdir -p $folder | Out-Null @@ -52,6 +86,40 @@ else } } +# Networking-specific setup +if ($LogProfile -eq "networking") +{ + # Copy/download networking.sh script + $networkingBashScript = "$folder/networking.sh" + if (Test-Path "$PSScriptRoot/networking.sh") + { + Copy-Item "$PSScriptRoot/networking.sh" $networkingBashScript + } + else + { + Write-Host -ForegroundColor Yellow "networking.sh not found in the current directory. Downloading it from GitHub." + Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/WSL/master/diagnostics/networking.sh" -OutFile $networkingBashScript + } + + # Detect the super user (uid=0, not necessarily named "root" - see #11693) + $superUser = & wsl.exe -- id -nu 0 + + # Collect Linux & Windows network state before the repro + & wsl.exe -u $superUser -e $networkingBashScript 2>&1 > $folder/linux_network_configuration_before.log + Collect-WindowsNetworkState -Folder $folder -ReproStep "before_repro" + + if ($RestartWslReproMode) + { + # The WSL HNS network is created once per boot. Resetting it to collect network creation logs. + # Note: The below HNS command applies only to WSL in NAT mode + Get-HnsNetwork | Where-Object {$_.Name -eq 'WSL' -Or $_.Name -eq 'WSL (Hyper-V firewall)'} | Remove-HnsNetwork + + # Stop WSL + net.exe stop WslService + if(-not $?) { net.exe stop LxssManager } + } +} + reg.exe export HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss $folder/HKCU.txt 2>&1 | Out-Null reg.exe export HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Lxss $folder/HKLM.txt 2>&1 | Out-Null reg.exe export HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\P9NP $folder/P9NP.txt 2>&1 | Out-Null @@ -106,6 +174,24 @@ if ($LastExitCode -Ne 0) } } +# Start networking-specific captures +$tcpdumpProcess = $null +if ($LogProfile -eq "networking") +{ + pktmon start -c --flags 0x1A --file-name "$folder/pktmon.etl" | out-null + netsh wfp capture start file="$folder/wfpdiag.cab" + + # Ensure WSL is running before collecting network state + & wsl.exe -- true 2>&1 | Out-Null + + # Start tcpdump (may not be installed) + try + { + $tcpdumpProcess = Start-Process wsl.exe -ArgumentList "-u $superUser tcpdump -n -i any -e -vvv > $folder/tcpdump.log" -WindowStyle Hidden -PassThru + } + catch {} +} + try { Write-Host -NoNewLine "Log collection is running. Please " @@ -151,9 +237,65 @@ try } finally { + # Stop networking-specific captures + if ($LogProfile -eq "networking") + { + try + { + wsl.exe -u $superUser killall tcpdump + if ($tcpdumpProcess -ne $null) + { + Wait-Process -InputObject $tcpdumpProcess -Timeout 10 + } + } + catch {} + + netsh wfp capture stop + pktmon stop | out-null + } + wpr.exe -stop $folder/logs.etl 2>&1 >> $wprOutputLog } +# Networking-specific post-repro collection +if ($LogProfile -eq "networking") +{ + # Collect Linux & Windows network state after the repro + & wsl.exe -u $superUser -e $networkingBashScript 2>&1 > $folder/linux_network_configuration_after.log + Collect-WindowsNetworkState -Folder $folder -ReproStep "after_repro" + + try + { + # Collect HNS events from past 24 hours + $events = Get-WinEvent -ProviderName Microsoft-Windows-Host-Network-Service | Where-Object { $_.TimeCreated -ge ((Get-Date) - (New-TimeSpan -Day 1)) } + ($events | ForEach-Object { '{0},{1},{2},{3}' -f $_.TimeCreated, $_.Id, $_.LevelDisplayName, $_.Message }) -join [environment]::NewLine | Out-File -FilePath "$folder/hns_events.log" -Append + } + catch {} + + # Collect the old Tcpip6 registry values - as they can break WSL if DisabledComponents is set to 0xff + # see https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/configure-ipv6-in-windows + try + { + Get-Item HKLM:SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters | Out-File -FilePath "$folder/tcpip6_parameters.log" -Append + } + catch {} + + # Collect the setup and NetSetup log files + $netSetupPath = "$env:WINDIR/logs/netsetup" + if (Test-Path $netSetupPath) + { + Copy-Item $netSetupPath/* $folder + } + + $setupApiPath = "$env:WINDIR/inf/setupapi.dev.log" + if (Test-Path $setupApiPath) + { + Copy-Item $setupApiPath $folder + } + + Remove-Item $networkingBashScript +} + if ($Dump) { $Assembly = [PSObject].Assembly.GetType('System.Management.Automation.WindowsErrorReporting') diff --git a/triage/config.yml b/triage/config.yml index ae283c53..6333487b 100644 --- a/triage/config.yml +++ b/triage/config.yml @@ -21,7 +21,7 @@ logs_rules: The script will output the path of the log file once done. - If this is a networking issue, please use [collect-networking-logs.ps1](https://github.com/Microsoft/WSL/blob/master/diagnostics/collect-networking-logs.ps1), following the instructions in [Collect WSL logs for networking issues](https://github.com/microsoft/WSL/blob/master/CONTRIBUTING.md#collect-wsl-logs-for-networking-issues) + If this is a networking issue, please use `.\collect-wsl-logs.ps1 -LogProfile networking` instead, following the instructions in [Collect WSL logs for networking issues](https://github.com/microsoft/WSL/blob/master/CONTRIBUTING.md#collect-wsl-logs-for-networking-issues) Once completed please upload the output files to this GitHub issue.