Allowing Windows Subsystem for Linux to communicate with Hyper-V VMs

ยท

4 min read

Howdy! ๐Ÿ‘‹ Hope everyone's weekend is swell!

I was experimenting with Windows Subsystem for Linux and Hyper-V. I noticed that almost immediately that my Hyper-V Server 2019 virtual machine was unable to communicate with my Ubuntu 20.04 WSL system on the same host:

$ โฏ ping 172.25.0.196                       
PING 172.25.0.196 (172.25.0.196) 56(84) bytes of data.
-no data, timeout-

I do see that I can ping via PowerShell (same command). What's up here?๐Ÿค” Well, we have a Hyper-V VM on the same computer as the WSL system, so firewall shouldn't be a problem.

Let's investigate traffic forwarding.

Whatever network interface WSL is using might not be forwarding the traffic. We can test this with a traceroute:

Windows:

PS C:\WINDOWS\system32> tracert 172.25.0.196
Tracing route to OUR-HYPERV-HOST.mshome.net [172.25.0.196]
over a maximum of 30 hops:

  1    <1 ms    <1 ms    <1 ms  OUR-HYPERV-HOST.mshome.net [172.25.0.196]

WSL (needs traceroute installed via apt, if running Ubuntu):

$ โฏ traceroute 172.25.0.196                                                                                         
traceroute to 172.25.0.196 (172.25.0.196), 30 hops max, 60 byte packets
# this never finishes ๐Ÿ˜„

I know WSL has its own network. I verified this by running the following inside WSL:

$ โฏ cat /etc/resolv.conf
----
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.24.32.1

Which will display contents of the DNS resolver file telling you that WSL manages this.

Even in Hyper-V, there is a WSL virtual switch (running the below on the host system running Hyper-V)

PS C:\WINDOWS\system32> Get-VMSwitch

Name           SwitchType NetAdapterInterfaceDescription
----           ---------- ------------------------------
Default Switch Internal
WSL            Internal <--- interesting, huh ๐Ÿ˜ƒ

Experimenting further, I grabbed all interfaces on my host system running Hyper-V. An interface called vEthernet (WSL) appears:

PS C:\WINDOWS\system32> Get-NetIPInterface

ifIndex InterfaceAlias                  AddressFamily NlMtu(Bytes) InterfaceMetric Dhcp     ConnectionState PolicyStore
------- --------------                  ------------- ------------ --------------- ----     --------------- -----------
52      vEthernet (WSL)                 IPv6                  1500            5000 Enabled  Connected       ActiveStore

I then explored this WSL Interface and see the options I had available to me via the Get-Member cmdlet:

PS C:\WINDOWS\system32> Get-NetIPInterface | `
where {$_.InterfaceAlias -eq 'vEthernet (WSL)' -or `
$_.InterfaceAlias -eq 'vEthernet (Default Switch)'}| `
Get-Member
...
Forwarding      ScriptProperty System.Object Forwarding `
{get=[Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetIPInterface.Forwarding]`
($this.PSBase.CimInstanceProperties['Forwarding'].Value);set=p...
...

There's an interesting scriptProperty for Forwarading.

One can logically assume this may enable Forwarding for us! Let's explore the Set-NetIPInterface PowerShell cmdlet and we will see that Forwarding is an argument we can set:

PS C:\WINDOWS\system32> help Set-NetIPInterface | `
Select-String -CaseSensitive:$false 'forwarding'

[-PolicyStore <string>] [-IncludeAllCompartments] `
**[-Forwarding {Disabled | Enabled}]** [-ClampMss {Disabled | Enabled}]`
 [-Advertising {Disabled | Enabled}] [-NlMtuBytes <uint32>] `
[-InterfaceMetric <uint32>]

We know this has a value of Disabled or Enabled.

Let's give this a shot! We see that it seems like forwarding is not enabled and this may be the cause of our issue. Let's enable forwarding:

PS C:\WINDOWS\system32> Get-NetIPInterface | `
where {$_.InterfaceAlias -eq 'vEthernet (WSL)'} | `
Set-NetIPInterface -Forwarding Enabled -Verbose

VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 52 -AddressFamily IPv4 -Store Active"
VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 52 -AddressFamily IPv6 -Store Active"
VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 52 -AddressFamily IPv6 -Store Persistent"
VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 52 -AddressFamily IPv4 -Store Persistent"

Okay we verify forwarding is now enabled:

PS C:\WINDOWS\system32> Get-NetIPInterface | where {$_.InterfaceAlias -eq 'vEthernet (WSL)'} | Select-Object ifIndex,InterfaceAlias,ConnectionState,Forwarding
PS C:\WINDOWS\system32> Get-NetIPInterface | where {$_.InterfaceAlias -eq 'vEthernet (WSL)'} | Select-Object ifIndex,InterfaceAlias,ConnectionState,Forwarding

ifIndex InterfaceAlias  ConnectionState Forwarding
------- --------------  --------------- ----------
     52 vEthernet (WSL)       Connected    Enabled

Let's try to ping and run a traceroute, from WSL:

$  โฏ traceroute 172.25.0.196                                                                                    
traceroute to 172.25.0.196 (172.25.0.196), 30 hops max, 60 byte packets
 1  OUR-HYPER-V-HOST (172.24.32.1)  0.270 ms  0.263 ms  0.260 ms

Okay so we can traceroute now. But we cannot ping:

~ โฏ ping 172.25.0.196                       
PING 172.25.0.196 (172.25.0.196) 56(84) bytes of data.
-timeout, no data-

Let's try and enable this on both WSL and the Default interface for the host:

PS C:\WINDOWS\system32> Get-NetIPInterface | where {$_.InterfaceAlias -eq 'vEthernet (WSL)' -or $_.InterfaceAlias -eq 'vEthernet (Default Switch)'} | Set-NetIPInterface -Forwarding Enabled -Verbose

VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 52 -AddressFamily IPv6 -Store Active"
VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 45 -AddressFamily IPv6 -Store Active"
VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 52 -AddressFamily IPv4 -Store Active"
VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 45 -AddressFamily IPv4 -Store Active"
VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 45 -AddressFamily IPv6 -Store Persistent"
VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 52 -AddressFamily IPv6 -Store Persistent"
VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 52 -AddressFamily IPv4 -Store Persistent"
VERBOSE: Performing operation "Set" on Target "NetIPInterface -InterfaceIndex 45 -AddressFamily IPv4 -Store Persistent"

Success! ๐ŸŽ‰ We have pings and traceroute works:

$ โฏ ping 172.25.0.196                                                             
PING 172.25.0.196 (172.25.0.196) 56(84) bytes of data.
64 bytes from 172.25.0.196: icmp_seq=277 ttl=127 time=0.389 ms
^C
--- 172.25.0.196 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.356/0.356/0.356/0.000 ms

$ โฏ traceroute 172.25.0.196                                                       
traceroute to 172.25.0.196 (172.25.0.196), 30 hops max, 60 byte packets
 1  HOST (172.24.32.1)  0.288 ms  0.269 ms  0.265 ms

Hope this helps someone. ๐Ÿ˜ƒ