From 2f9ebca6bb07f9c41273fcc509ee2486dc2a26e1 Mon Sep 17 00:00:00 2001 From: Daman Mulye Date: Tue, 6 Oct 2026 13:31:31 -0700 Subject: [PATCH] networking --- .../technical-documentation/boot-process.md | 4 +- src/windows/common/CMakeLists.txt | 2 + src/windows/common/OpenVmmNatNetworking.cpp | 50 +++++++++++++++++++ src/windows/common/OpenVmmNatNetworking.h | 30 +++++++++++ src/windows/service/exe/WslCoreVm.cpp | 32 ++++++++++-- .../OpenVmmVirtualMachineBackendTests.cpp | 26 +++++++++- 6 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 src/windows/common/OpenVmmNatNetworking.cpp create mode 100644 src/windows/common/OpenVmmNatNetworking.h diff --git a/doc/docs/technical-documentation/boot-process.md b/doc/docs/technical-documentation/boot-process.md index fdd91dff..2dc47650 100644 --- a/doc/docs/technical-documentation/boot-process.md +++ b/doc/docs/technical-documentation/boot-process.md @@ -63,7 +63,7 @@ By default, the WSL2 virtual machine is created via the [Host Compute System (HC gpuSupport=false guiApplications=false hostFileSystemAccess=false -networkingMode=none +networkingMode=nat [experimental] openVmm=true @@ -74,7 +74,7 @@ OpenVMM currently does not support: - ARM64 or UEFI boot - GPU assignment or WSLg shared memory - Persistent-memory or physical-disk devices -- Mirrored or bridged networking +- Mirrored or bridged networking, custom NAT addressing, Hyper-V firewall, DNS tunneling, or IPv6 - Nested virtualization, performance counters, or advanced memory controls - Plan 9 file sharing or per-user virtio-fs options diff --git a/src/windows/common/CMakeLists.txt b/src/windows/common/CMakeLists.txt index 45250d2e..22255c49 100644 --- a/src/windows/common/CMakeLists.txt +++ b/src/windows/common/CMakeLists.txt @@ -28,6 +28,7 @@ set(SOURCES LxssServerPort.cpp MountSpecParsing.cpp NatNetworking.cpp + OpenVmmNatNetworking.cpp notifications.cpp Redirector.cpp registry.cpp @@ -118,6 +119,7 @@ set(HEADERS LxssServerPort.h MountSpecParsing.h NatNetworking.h + OpenVmmNatNetworking.h notifications.h precomp.h Redirector.h diff --git a/src/windows/common/OpenVmmNatNetworking.cpp b/src/windows/common/OpenVmmNatNetworking.cpp new file mode 100644 index 00000000..ac024256 --- /dev/null +++ b/src/windows/common/OpenVmmNatNetworking.cpp @@ -0,0 +1,50 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. + +#include "precomp.h" +#include "OpenVmmNatNetworking.h" + +using wsl::core::OpenVmmNatNetworking; + +VmNetworkAdapterRequest wsl::core::CreateOpenVmmNatNetworkAdapterRequest() +{ + VmUserModeNatNetwork network; + constexpr std::array clientMac{0x00, 0x00, 0x00, 0x00, 0x01, 0x00}; + std::copy(clientMac.begin(), clientMac.end(), std::begin(network.Configuration.clientMac.bytes)); + return {L"eth0", std::move(network)}; +} + +OpenVmmNatNetworking::OpenVmmNatNetworking(GnsChannel&& GnsChannel, bool EnableLocalhostRelay, int DhcpTimeout) : + m_gnsChannel(std::move(GnsChannel)), m_enableLocalhostRelay(EnableLocalhostRelay), m_dhcpTimeout(DhcpTimeout) +{ +} + +OpenVmmNatNetworking::~OpenVmmNatNetworking() +{ + m_gnsChannel.Stop(); +} + +void OpenVmmNatNetworking::Initialize() +{ +} + +void OpenVmmNatNetworking::TraceLoggingRundown() noexcept +{ + WSL_LOG( + "OpenVmmNatNetworking::TraceLoggingRundown", + TraceLoggingValue(m_enableLocalhostRelay, "localhostRelay"), + TraceLoggingValue(m_dhcpTimeout, "dhcpTimeout")); +} + +void OpenVmmNatNetworking::FillInitialConfiguration(LX_MINI_INIT_NETWORKING_CONFIGURATION& Message) +{ + Message.NetworkingMode = LxMiniInitNetworkingModeNat; + Message.DisableIpv6 = true; + Message.EnableDhcpClient = true; + Message.DhcpTimeout = static_cast(std::round(m_dhcpTimeout / 1000.0)); + Message.PortTrackerType = m_enableLocalhostRelay ? LxMiniInitPortTrackerTypeRelay : LxMiniInitPortTrackerTypeNone; +} + +void OpenVmmNatNetworking::StartPortTracker(wil::unique_socket&&) +{ + THROW_HR(E_NOTIMPL); +} diff --git a/src/windows/common/OpenVmmNatNetworking.h b/src/windows/common/OpenVmmNatNetworking.h new file mode 100644 index 00000000..46aca9f0 --- /dev/null +++ b/src/windows/common/OpenVmmNatNetworking.h @@ -0,0 +1,30 @@ +// Copyright (C) Microsoft Corporation. All rights reserved. + +#pragma once + +#include "GnsChannel.h" +#include "INetworkingEngine.h" +#include "IVirtualMachineBackend.h" + +namespace wsl::core { + +VmNetworkAdapterRequest CreateOpenVmmNatNetworkAdapterRequest(); + +class OpenVmmNatNetworking : public INetworkingEngine +{ +public: + OpenVmmNatNetworking(GnsChannel&& GnsChannel, bool EnableLocalhostRelay, int DhcpTimeout); + ~OpenVmmNatNetworking() override; + + void Initialize() override; + void TraceLoggingRundown() noexcept override; + void FillInitialConfiguration(LX_MINI_INIT_NETWORKING_CONFIGURATION& Message) override; + void StartPortTracker(wil::unique_socket&& Socket) override; + +private: + GnsChannel m_gnsChannel; + bool m_enableLocalhostRelay; + int m_dhcpTimeout; +}; + +} // namespace wsl::core diff --git a/src/windows/service/exe/WslCoreVm.cpp b/src/windows/service/exe/WslCoreVm.cpp index 0454f02b..7f1d7b80 100644 --- a/src/windows/service/exe/WslCoreVm.cpp +++ b/src/windows/service/exe/WslCoreVm.cpp @@ -21,6 +21,7 @@ Abstract: #include "disk.hpp" #include "WslCoreInstance.h" #include "NatNetworking.h" +#include "OpenVmmNatNetworking.h" #include "BridgedNetworking.h" #include "MirroredNetworking.h" #include "WslCoreFirewallSupport.h" @@ -569,8 +570,9 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken message->MemoryReclaimMode = static_cast(m_vmConfig.MemoryReclaim); message->EnableDebugShell = m_vmConfig.EnableDebugShell; message->EnableSafeMode = m_vmConfig.EnableSafeMode; - // Consomme forwards DNS via the host proxy, so the dedicated DNS hvsocket is only used by NAT and Mirrored modes. - message->EnableDnsTunneling = m_vmConfig.EnableDnsTunneling && m_vmConfig.NetworkingMode != NetworkingMode::Consomme; + // User-mode NAT forwards DNS via the host proxy, so the dedicated DNS hvsocket is only used by HCS NAT and Mirrored modes. + message->EnableDnsTunneling = m_vmConfig.EnableDnsTunneling && m_vmConfig.NetworkingMode != NetworkingMode::Consomme && + backendKind != BackendKind::OpenVmm; message->DefaultKernel = m_defaultKernel; message->IsolateDistroCgroup = m_vmConfig.IsolateDistroCgroup; message->KernelModulesDeviceId = m_kernelModulesDeviceId; @@ -600,7 +602,7 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken // For NAT networking, ensure the network can be created. If creating the network fails, fall back to // Consomme networking mode. wsl::windows::common::hcs::unique_hcn_network natNetwork; - if (m_vmConfig.NetworkingMode == NetworkingMode::Nat) + if (backendKind == BackendKind::Hcs && m_vmConfig.NetworkingMode == NetworkingMode::Nat) { { SlowOperationWatcher slowOperation{"CreateNatNetwork"}; @@ -617,6 +619,22 @@ void WslCoreVm::Initialize(const GUID& VmId, const wil::shared_handle& UserToken // Create and initialize the networking engine. const auto result = wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&] { + if (backendKind == BackendKind::OpenVmm) + { + if (m_vmConfig.NetworkingMode == NetworkingMode::Nat) + { + m_networkingEngine = std::make_unique( + std::move(gnsChannel), m_vmConfig.EnableLocalhostRelay, m_vmConfig.DhcpTimeout); + m_networkingEngine->Initialize(); + } + else + { + WI_ASSERT(m_vmConfig.NetworkingMode == NetworkingMode::None); + } + + return; + } + // N.B. The existing networking engines still manage HCS resources directly. Keep this // concrete escape hatch localized here until they are moved onto IVirtualMachineBackend. auto& hcsBackend = static_cast(*m_backend); @@ -1363,7 +1381,9 @@ void WslCoreVm::ValidateBackendConfiguration(BackendKind Backend) const THROW_HR_IF_MSG( notSupported, m_vmConfig.EnableHostFileSystemAccess, "OpenVMM host filesystem access is not integrated with WslCoreVm"); THROW_HR_IF_MSG( - notSupported, m_vmConfig.NetworkingMode != NetworkingMode::None, "OpenVMM networking is not integrated with WslCoreVm"); + notSupported, + m_vmConfig.NetworkingMode != NetworkingMode::None && m_vmConfig.NetworkingMode != NetworkingMode::Nat, + "OpenVMM only supports NAT or disabled networking"); } VmCreateRequest WslCoreVm::GenerateBackendRequest(const GUID& VmId, BackendKind Backend) @@ -1550,6 +1570,10 @@ VmCreateRequest WslCoreVm::GenerateBackendRequest(const GUID& VmId, BackendKind { addBootDisk(L"kernel-modules", m_vmConfig.KernelModulesPath, m_privateKernelModules); } + if (Backend == BackendKind::OpenVmm && m_vmConfig.NetworkingMode == NetworkingMode::Nat) + { + request.NetworkAdapters.emplace_back(wsl::core::CreateOpenVmmNatNetworkAdapterRequest()); + } return request; } diff --git a/test/windows/OpenVmmVirtualMachineBackendTests.cpp b/test/windows/OpenVmmVirtualMachineBackendTests.cpp index 8609e3ae..6972e437 100644 --- a/test/windows/OpenVmmVirtualMachineBackendTests.cpp +++ b/test/windows/OpenVmmVirtualMachineBackendTests.cpp @@ -2,6 +2,7 @@ #include "precomp.h" #include "Common.h" +#include "OpenVmmNatNetworking.h" #include "OpenVmmVirtualMachineBackend.h" #include "VirtualMachineBackendTestHelpers.h" @@ -110,10 +111,31 @@ class OpenVmmVirtualMachineBackendTests VERIFY_ARE_EQUAL(c_notSupported, DescribeResult(request)); *feature = VmFeatureRequest::Disabled; } + request.Memory.HostingProcessNameSuffix = L"WSL"; VERIFY_ARE_EQUAL(c_notSupported, DescribeResult(request)); } + TEST_METHOD(OpenVmmNatUsesCreationTimeAdapterAndGuestDhcp) + { + const auto request = wsl::core::CreateOpenVmmNatNetworkAdapterRequest(); + VERIFY_ARE_EQUAL(L"eth0", request.Tag); + const auto& network = std::get(request.Configuration); + constexpr wsl::shared::string::MacAddress expectedMac{0x00, 0x00, 0x00, 0x00, 0x01, 0x00}; + VERIFY_IS_TRUE(network.ClientMacAddress() == expectedMac); + + auto [client, server] = MakeSocketPair(); + wsl::core::OpenVmmNatNetworking networking(wsl::core::GnsChannel(std::move(server)), true, 5000); + LX_MINI_INIT_NETWORKING_CONFIGURATION configuration{}; + networking.FillInitialConfiguration(configuration); + + VERIFY_ARE_EQUAL(LxMiniInitNetworkingModeNat, configuration.NetworkingMode); + VERIFY_IS_TRUE(configuration.DisableIpv6); + VERIFY_IS_TRUE(configuration.EnableDhcpClient); + VERIFY_ARE_EQUAL(5, configuration.DhcpTimeout); + VERIFY_ARE_EQUAL(LxMiniInitPortTrackerTypeRelay, configuration.PortTrackerType); + } + TEST_METHOD(AllowsGuestAndSavedStateCrashCapture) { SKIP_TEST_ARM64(); @@ -243,10 +265,10 @@ class OpenVmmVirtualMachineBackendTests TEST_METHOD(GuestShutdownTerminatesProcess) { SKIP_TEST_ARM64(); - auto backend = OpenVmmVirtualMachineBackend::Create(CreateRunnableRequest()); - auto terminationEvent = backend->GetTerminationEvent(); wil::unique_event callbackEvent{wil::EventOptions::ManualReset}; GUID callbackVmId{}; + auto backend = OpenVmmVirtualMachineBackend::Create(CreateRunnableRequest()); + auto terminationEvent = backend->GetTerminationEvent(); backend->RegisterTerminationCallback([&](GUID VmId) { callbackVmId = VmId; callbackEvent.SetEvent();