cleanup: VirtioNetworking refactoring (#13760)
* cleanup: update VirtioNetworking class to not rely on the WslCoreConfig struct * cleanup: simplify VirtioNetworking construction * remove old constructor and other cleanup * more minor cleanup * string cleanup in HandleVirtioModifyOpenPorts --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Ben Hillis committed
Nov 21, 2025 at 16:50 UTC
d9c69a50abdd158ad0257c96d0451dcd8adc8962
4 files changed
+96
-94
src/windows/service/exe/VirtioNetworking.cpp
+18
-29
@@ -12,34 +12,23 @@ using wsl::core::VirtioNetworking;
12
13
static constexpr auto c_loopbackDeviceName = TEXT(LX_INIT_LOOPBACK_DEVICE_NAME);
14
15
-VirtioNetworking::VirtioNetworking(GnsChannel&& gnsChannel, const Config& config) :
16
- m_gnsChannel(std::move(gnsChannel)), m_config(config)
15
+VirtioNetworking::VirtioNetworking(
16
+ GnsChannel&& gnsChannel,
17
+ bool enableLocalhostRelay,
18
+ AddGuestDeviceCallback addGuestDeviceCallback,
19
+ ModifyOpenPortsCallback modifyOpenPortsCallback,
20
+ GuestInterfaceStateChangeCallback guestInterfaceStateChangeCallback) :
21
+ m_addGuestDeviceCallback(std::move(addGuestDeviceCallback)),
22
+ m_gnsChannel(std::move(gnsChannel)),
23
+ m_modifyOpenPortsCallback(std::move(modifyOpenPortsCallback)),
24
+ m_guestInterfaceStateChangeCallback(std::move(guestInterfaceStateChangeCallback)),
25
+ m_enableLocalhostRelay(enableLocalhostRelay)
26
{
27
}
28
20
-VirtioNetworking& VirtioNetworking::OnAddGuestDevice(const AddGuestDeviceRoutine& addGuestDeviceRoutine)
21
-{
22
- m_addGuestDeviceRoutine = addGuestDeviceRoutine;
23
- return *this;
24
-}
25
-
26
-VirtioNetworking& VirtioNetworking::OnModifyOpenPorts(const ModifyOpenPortsCallback& modifyOpenPortsCallback)
27
-{
28
- m_modifyOpenPortsCallback = modifyOpenPortsCallback;
29
- return *this;
30
-}
31
-
32
-VirtioNetworking& VirtioNetworking::OnGuestInterfaceStateChanged(const GuestInterfaceStateChangeCallback& guestInterfaceStateChangedCallback)
33
-{
34
- m_guestInterfaceStateChangeCallback = guestInterfaceStateChangedCallback;
35
- return *this;
36
-}
37
-
29
void VirtioNetworking::Initialize()
30
try
31
{
41
- THROW_HR_IF(E_NOT_SET, !m_addGuestDeviceRoutine || !m_modifyOpenPortsCallback || !m_guestInterfaceStateChangeCallback);
42
-
32
m_networkSettings = GetHostEndpointSettings();
33
34
// TODO: Determine gateway MAC address
@@ -84,7 +73,7 @@ try
73
}
74
75
// Add virtio net adapter to guest
87
- m_adapterId = (*m_addGuestDeviceRoutine)(c_virtioNetworkClsid, c_virtioNetworkDeviceId, L"eth0", device_options.str().c_str());
76
+ m_adapterId = m_addGuestDeviceCallback(c_virtioNetworkClsid, c_virtioNetworkDeviceId, L"eth0", device_options.str().c_str());
77
78
auto lock = m_lock.lock_exclusive();
79
@@ -121,7 +110,7 @@ try
110
UpdateDns(std::move(dnsSettings));
111
}
112
124
- if (m_config.EnableLocalhostRelay)
113
+ if (m_enableLocalhostRelay)
114
{
115
SetupLoopbackDevice();
116
}
@@ -132,7 +121,7 @@ CATCH_LOG()
121
122
void VirtioNetworking::SetupLoopbackDevice()
123
{
135
- m_localhostAdapterId = (*m_addGuestDeviceRoutine)(
124
+ m_localhostAdapterId = m_addGuestDeviceCallback(
125
c_virtioNetworkClsid, c_virtioNetworkDeviceId, c_loopbackDeviceName, L"client_ip=127.0.0.1;client_mac=00:11:22:33:44:55");
126
127
hns::HNSEndpoint endpointProperties;
@@ -162,7 +151,7 @@ void VirtioNetworking::StartPortTracker(wil::unique_socket&& socket)
151
m_gnsPortTrackerChannel.emplace(
152
std::move(socket),
153
[&](const SOCKADDR_INET& addr, int protocol, bool allocate) { return HandlePortNotification(addr, protocol, allocate); },
165
- [&](_In_ const std::string& interfaceName, _In_ bool up) { (*m_guestInterfaceStateChangeCallback)(interfaceName, up); });
154
+ [&](_In_ const std::string& interfaceName, _In_ bool up) { m_guestInterfaceStateChangeCallback(interfaceName, up); });
155
}
156
157
HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int protocol, bool allocate) const noexcept
@@ -181,7 +170,7 @@ HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int
170
}
171
}
172
184
- if (m_config.EnableLocalhostRelay && (unspecified || loopback))
173
+ if (m_enableLocalhostRelay && (unspecified || loopback))
174
{
175
SOCKADDR_INET localAddr = addr;
176
if (!loopback)
@@ -196,12 +185,12 @@ HRESULT VirtioNetworking::HandlePortNotification(const SOCKADDR_INET& addr, int
185
localAddr.Ipv6.sin6_port = addr.Ipv6.sin6_port;
186
}
187
}
199
- result = (*m_modifyOpenPortsCallback)(c_virtioNetworkClsid, c_loopbackDeviceName, localAddr, protocol, allocate);
188
+ result = m_modifyOpenPortsCallback(c_virtioNetworkClsid, c_loopbackDeviceName, localAddr, protocol, allocate);
189
LOG_HR_IF_MSG(E_FAIL, result != S_OK, "Failure adding localhost relay port %d", localAddr.Ipv4.sin_port);
190
}
191
if (!loopback)
192
{
204
- const int localResult = (*m_modifyOpenPortsCallback)(c_virtioNetworkClsid, L"eth0", addr, protocol, allocate);
193
+ const int localResult = m_modifyOpenPortsCallback(c_virtioNetworkClsid, L"eth0", addr, protocol, allocate);
194
LOG_HR_IF_MSG(E_FAIL, localResult != S_OK, "Failure adding relay port %d", addr.Ipv4.sin_port);
195
if (result == 0)
196
{
src/windows/service/exe/VirtioNetworking.h
+11
-10
@@ -9,20 +9,21 @@
9
10
namespace wsl::core {
11
12
-using AddGuestDeviceRoutine = std::function<GUID(const GUID& clsid, const GUID& deviceId, PCWSTR tag, PCWSTR options)>;
12
+using AddGuestDeviceCallback = std::function<GUID(const GUID& clsid, const GUID& deviceId, PCWSTR tag, PCWSTR options)>;
13
using ModifyOpenPortsCallback = std::function<int(const GUID& clsid, PCWSTR tag, const SOCKADDR_INET& addr, int protocol, bool isOpen)>;
14
using GuestInterfaceStateChangeCallback = std::function<void(const std::string& name, bool isUp)>;
15
16
class VirtioNetworking : public INetworkingEngine
17
{
18
public:
19
- VirtioNetworking(GnsChannel&& gnsChannel, const Config& config);
19
+ VirtioNetworking(
20
+ GnsChannel&& gnsChannel,
21
+ bool enableLocalhostRelay,
22
+ AddGuestDeviceCallback addGuestDeviceCallback,
23
+ ModifyOpenPortsCallback modifyOpenPortsCallback,
24
+ GuestInterfaceStateChangeCallback guestInterfaceStateChangeCallback);
25
~VirtioNetworking() = default;
26
22
- VirtioNetworking& OnAddGuestDevice(const AddGuestDeviceRoutine& addGuestDeviceRoutine);
23
- VirtioNetworking& OnModifyOpenPorts(const ModifyOpenPortsCallback& modifyOpenPortsCallback);
24
- VirtioNetworking& OnGuestInterfaceStateChanged(const GuestInterfaceStateChangeCallback& guestInterfaceStateChangedCallback);
25
-
27
// Note: This class cannot be moved because m_networkNotifyHandle captures a 'this' pointer.
28
VirtioNetworking(const VirtioNetworking&) = delete;
29
VirtioNetworking(VirtioNetworking&&) = delete;
@@ -49,17 +50,17 @@ private:
50
51
mutable wil::srwlock m_lock;
52
52
- std::optional<AddGuestDeviceRoutine> m_addGuestDeviceRoutine;
53
+ AddGuestDeviceCallback m_addGuestDeviceCallback;
54
GnsChannel m_gnsChannel;
55
std::optional<GnsPortTrackerChannel> m_gnsPortTrackerChannel;
56
std::shared_ptr<networking::NetworkSettings> m_networkSettings;
56
- const Config& m_config;
57
+ bool m_enableLocalhostRelay;
58
GUID m_localhostAdapterId;
59
GUID m_adapterId;
60
std::optional<NL_NETWORK_CONNECTIVITY_LEVEL_HINT> m_connectivityLevel;
61
std::optional<NL_NETWORK_CONNECTIVITY_COST_HINT> m_connectivityCost;
61
- std::optional<ModifyOpenPortsCallback> m_modifyOpenPortsCallback;
62
- std::optional<GuestInterfaceStateChangeCallback> m_guestInterfaceStateChangeCallback;
62
+ ModifyOpenPortsCallback m_modifyOpenPortsCallback;
63
+ GuestInterfaceStateChangeCallback m_guestInterfaceStateChangeCallback;
64
65
std::optional<ULONGLONG> m_interfaceLuid;
66
ULONG m_networkMtu = 0;
src/windows/service/exe/WslCoreVm.cpp
+63
-55
@@ -607,55 +607,16 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken
607
}
608
else if (m_vmConfig.NetworkingMode == NetworkingMode::VirtioProxy)
609
{
610
- auto virtioNetworkingEngine = std::make_unique<wsl::core::VirtioNetworking>(std::move(gnsChannel), m_vmConfig);
611
- virtioNetworkingEngine->OnAddGuestDevice([&](const GUID& Clsid, const GUID& DeviceId, PCWSTR Tag, PCWSTR Options) {
612
- auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
613
- return AddHdvShareWithOptions(DeviceId, Clsid, Tag, {}, Options, 0, m_userToken.get());
614
- });
615
-
616
- virtioNetworkingEngine->OnModifyOpenPorts([&](const GUID& Clsid, PCWSTR Tag, const SOCKADDR_INET& addr, int protocol, bool isOpen) {
617
- if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
618
- {
619
- LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Unsupported bind protocol %d", protocol);
620
- return 0;
621
- }
622
- else if (addr.si_family == AF_INET6)
623
- {
624
- // The virtio net adapter does not yet support IPv6 packets, so any traffic would arrive via
625
- // IPv4. If the caller wants IPv4 they will also likely listen on an IPv4 address, which will
626
- // be handled as a separate callback to this same code.
627
- return 0;
628
- }
629
-
630
- auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
631
- const auto server = m_deviceHostSupport->GetRemoteFileSystem(Clsid, c_defaultTag);
632
- if (server)
633
- {
634
- std::wstring portString(L"tag=");
635
- portString += Tag;
636
- portString += L";port_number=";
637
- portString += std::to_wstring(addr.Ipv4.sin_port);
638
- if (protocol == IPPROTO_UDP)
639
- {
640
- portString += L";udp";
641
- }
642
- if (!isOpen)
643
- {
644
- portString += L";allocate=false";
645
- }
646
- else
647
- {
648
- std::wstring addrStr(L"000.000.000.000\0");
649
- RtlIpv4AddressToStringW(&addr.Ipv4.sin_addr, addrStr.data());
650
- portString += L";listen_addr=";
651
- portString += addrStr;
652
- }
653
- LOG_IF_FAILED(server->AddShare(portString.c_str(), nullptr, 0));
654
- }
655
- return 0;
656
- });
657
- virtioNetworkingEngine->OnGuestInterfaceStateChanged([&](const std::string& name, bool isUp) {});
658
- m_networkingEngine.reset(virtioNetworkingEngine.release());
610
+ m_networkingEngine = std::make_unique<wsl::core::VirtioNetworking>(
611
+ std::move(gnsChannel),
612
+ m_vmConfig.EnableLocalhostRelay,
613
+ [this](const GUID& Clsid, const GUID& DeviceId, PCWSTR Tag, PCWSTR Options) {
614
+ return HandleVirtioAddGuestDevice(Clsid, DeviceId, Tag, Options);
615
+ },
616
+ [this](const GUID& Clsid, PCWSTR Tag, const SOCKADDR_INET& Addr, int Protocol, bool IsOpen) {
617
+ return HandleVirtioModifyOpenPorts(Clsid, Tag, Addr, Protocol, IsOpen);
618
+ },
619
+ [](const std::string&, bool) {});
620
}
621
else if (m_vmConfig.NetworkingMode == NetworkingMode::Bridged)
622
{
@@ -2037,6 +1998,59 @@ bool WslCoreVm::IsDnsTunnelingSupported() const
1998
return SUCCEEDED_LOG(wsl::core::networking::DnsResolver::LoadDnsResolverMethods());
1999
}
2000
2001
+bool WslCoreVm::IsVhdAttached(_In_ PCWSTR VhdPath)
2002
+{
2003
+ auto lock = m_lock.lock_exclusive();
2004
+ return m_attachedDisks.contains({DiskType::VHD, VhdPath});
2005
+}
2006
+
2007
+GUID WslCoreVm::HandleVirtioAddGuestDevice(_In_ const GUID& Clsid, _In_ const GUID& DeviceId, _In_ PCWSTR Tag, _In_ PCWSTR Options)
2008
+{
2009
+ auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
2010
+ return AddHdvShareWithOptions(DeviceId, Clsid, Tag, {}, Options, 0, m_userToken.get());
2011
+}
2012
+
2013
+int WslCoreVm::HandleVirtioModifyOpenPorts(_In_ const GUID& Clsid, _In_ PCWSTR Tag, _In_ const SOCKADDR_INET& Addr, _In_ int Protocol, _In_ bool IsOpen)
2014
+{
2015
+ if (Protocol != IPPROTO_TCP && Protocol != IPPROTO_UDP)
2016
+ {
2017
+ LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), "Unsupported bind protocol %d", Protocol);
2018
+ return 0;
2019
+ }
2020
+ else if (Addr.si_family == AF_INET6)
2021
+ {
2022
+ // The virtio net adapter does not yet support IPv6 packets, so any traffic would arrive via
2023
+ // IPv4. If the caller wants IPv4 they will also likely listen on an IPv4 address, which will
2024
+ // be handled as a separate callback to this same code.
2025
+ return 0;
2026
+ }
2027
+
2028
+ auto guestDeviceLock = m_guestDeviceLock.lock_exclusive();
2029
+ const auto server = m_deviceHostSupport->GetRemoteFileSystem(Clsid, c_defaultTag);
2030
+ if (server)
2031
+ {
2032
+ std::wstring portString = std::format(L"tag={};port_number={}", Tag, Addr.Ipv4.sin_port);
2033
+ if (Protocol == IPPROTO_UDP)
2034
+ {
2035
+ portString += L";udp";
2036
+ }
2037
+
2038
+ if (!IsOpen)
2039
+ {
2040
+ portString += L";allocate=false";
2041
+ }
2042
+ else
2043
+ {
2044
+ wchar_t addrStr[16]; // "000.000.000.000" + null terminator
2045
+ RtlIpv4AddressToStringW(&Addr.Ipv4.sin_addr, addrStr);
2046
+ portString += std::format(L";listen_addr={}", addrStr);
2047
+ }
2048
+
2049
+ LOG_IF_FAILED(server->AddShare(portString.c_str(), nullptr, 0));
2050
+ }
2051
+ return 0;
2052
+}
2053
+
2054
WslCoreVm::DiskMountResult WslCoreVm::MountDisk(
2055
_In_ PCWSTR Disk, _In_ DiskType MountDiskType, _In_ ULONG PartitionIndex, _In_opt_ PCWSTR Name, _In_opt_ PCWSTR Type, _In_opt_ PCWSTR Options)
2056
{
@@ -2846,12 +2860,6 @@ LX_INIT_DRVFS_MOUNT WslCoreVm::s_InitializeDrvFs(_Inout_ WslCoreVm* VmContext, _
2860
}
2861
}
2862
2849
-bool WslCoreVm::IsVhdAttached(_In_ PCWSTR VhdPath)
2850
-{
2851
- auto lock = m_lock.lock_exclusive();
2852
- return m_attachedDisks.contains({DiskType::VHD, VhdPath});
2853
-}
2854
-
2863
void CALLBACK WslCoreVm::s_OnExit(_In_ HCS_EVENT* Event, _In_opt_ void* Context)
2864
try
2865
{
src/windows/service/exe/WslCoreVm.h
+4
@@ -107,6 +107,10 @@ public:
107
108
bool IsVhdAttached(_In_ PCWSTR VhdPath);
109
110
+ GUID HandleVirtioAddGuestDevice(_In_ const GUID& Clsid, _In_ const GUID& DeviceId, _In_ PCWSTR Tag, _In_ PCWSTR Options);
111
+
112
+ int HandleVirtioModifyOpenPorts(_In_ const GUID& Clsid, _In_ PCWSTR Tag, _In_ const SOCKADDR_INET& Addr, _In_ int Protocol, _In_ bool IsOpen);
113
+
114
DiskMountResult MountDisk(
115
_In_ PCWSTR Disk, _In_ DiskType MountDiskType, _In_ ULONG PartitionIndex, _In_opt_ PCWSTR Name, _In_opt_ PCWSTR Type, _In_opt_ PCWSTR Options);
116