Add openvmm as vmm backend option for wslc vms#40629
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces an optional OpenVMM-backed virtual machine implementation for WSLC sessions, including the plumbing needed to orchestrate VM lifecycle and networking via ttrpc/protobuf, plus Windows-side socket I/O adjustments to support AF_UNIX-based vsock bridging.
Changes:
- Add an OpenVMM-based
IWSLCVirtualMachineimplementation and a minimal ttrpc client/envelope codec for vmservice RPCs. - Add a new Consomme networking mode and a new mini_init message to configure guest networking for that backend.
- Extend socket handling to support non-overlapped (blocking) I/O paths required by Windows AF_UNIX sockets, and wire service/session code to use a backend-agnostic “connect/accept vsock port” VM API.
Reviewed changes
Copilot reviewed 30 out of 30 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| src/windows/wslcsession/WSLCVirtualMachine.h | Expose underlying VM interface pointer; adjust crash dump collection signature. |
| src/windows/wslcsession/WSLCVirtualMachine.cpp | Route vsock/crashdump connections through VM backend; add Consomme guest network setup; AF_UNIX crashdump relay path. |
| src/windows/wslcsession/WSLCSession.cpp | Adjust Docker client wiring and add mount-format-retry behavior for pre-attached disks. |
| src/windows/wslcsession/DockerHTTPClient.h | Detect socket family for Boost.Asio stream protocol assignment (HV socket vs AF_UNIX). |
| src/windows/wslcsession/DockerHTTPClient.cpp | Use VM backend to connect to per-request vsock ports. |
| src/windows/wslc/CMakeLists.txt | Add OpenVMM protobuf generation hook for wslc library when enabled. |
| src/windows/service/inc/wslc.idl | Add Consomme networking mode; extend VM interface with vsock/crashdump connection methods. |
| src/windows/service/exe/WSLCSessionManager.cpp | Choose VM backend (OpenVMM vs HCS) based on user setting; adjust settings for OpenVMM constraints. |
| src/windows/service/exe/TtrpcEnvelopeCodec.h | Define ttrpc header/envelope codec interface. |
| src/windows/service/exe/TtrpcEnvelopeCodec.cpp | Implement ttrpc request encoding and response decoding. |
| src/windows/service/exe/TtrpcClient.h | Define minimal ttrpc client + VM configuration helpers. |
| src/windows/service/exe/TtrpcClient.cpp | Implement AF_UNIX ttrpc transport, request/response handling, and vmservice RPC wrappers. |
| src/windows/service/exe/OpenVmmVirtualMachine.h | Define OpenVMM-backed IWSLCVirtualMachine implementation. |
| src/windows/service/exe/OpenVmmVirtualMachine.cpp | Implement OpenVMM process launch, vsock bridge listeners, ttrpc orchestration, and disk management. |
| src/windows/service/exe/HcsVirtualMachine.h | Extend HCS backend declaration to implement new vsock/crashdump methods. |
| src/windows/service/exe/HcsVirtualMachine.cpp | Implement new vsock/crashdump methods; create crashdump listen socket. |
| src/windows/service/exe/CMakeLists.txt | Conditionally include OpenVMM sources, proto generation, and compile defs. |
| src/windows/common/WSLCUserSettings.h | Add user setting key for enabling OpenVMM backend. |
| src/windows/common/WSLCUserSettings.cpp | Update default settings template and validator for OpenVMM option. |
| src/windows/common/ConsommeNetworking.h | Add Consomme networking engine and associated constants. |
| src/windows/common/ConsommeNetworking.cpp | Implement Consomme networking engine stubs and initial config fill. |
| src/windows/common/CMakeLists.txt | Add ConsommeNetworking sources; add ATL include-dir discovery logic. |
| src/shared/inc/SocketChannel.h | Add AF_UNIX detection and blocking send/receive paths for non-overlapped sockets on Windows. |
| src/shared/inc/lxinitshared.h | Add WSLC_CONFIGURE_NETWORKING message type and payload. |
| src/linux/init/WSLCInit.cpp | Handle WSLC_CONFIGURE_NETWORKING by configuring guest network + resolv.conf; register handler. |
| packages.config | Bump Microsoft.WSL.DeviceHost nuget version to include OpenVMM + proto. |
| msipackage/package.wix.in | Add openvmm.exe to MSI payload. |
| msipackage/CMakeLists.txt | Add OpenVMM-related DeviceHost binaries to packaging dependencies when enabled. |
| CMakeLists.txt | Add INCLUDE_OPENVMM option; conditionally fetch/build protobuf; add proto generation helper function. |
| cgmanifest.json | Add protobuf component metadata for CG compliance. |
| wil::unique_socket socket; | ||
| THROW_IF_FAILED(m_vm->ConnectToVsockPort(port, reinterpret_cast<HANDLE*>(&socket))); | ||
|
|
| ConnectedSocket socket; | ||
| socket.Socket = wsl::windows::common::hvsocket::Connect(m_vmId, response.Result, m_vmTerminatingEvent.get(), m_initChannelTimeout); | ||
| THROW_IF_FAILED(m_vm->ConnectToVsockPort(response.Result, reinterpret_cast<HANDLE*>(&socket.Socket))); | ||
|
|
| wil::unique_socket socket; | ||
| HRESULT hr = m_vm->AcceptCrashDumpConnection(reinterpret_cast<HANDLE*>(&socket)); | ||
| if (hr == E_ABORT) | ||
| { | ||
| // VM is exiting. | ||
| break; | ||
| } | ||
| THROW_IF_FAILED(hr); | ||
|
|
| constexpr size_t bufferSize = 65536; | ||
| std::vector<char> buf(bufferSize); | ||
| for (;;) | ||
| { | ||
| int bytesRead = ::recv(channel.Socket(), buf.data(), static_cast<int>(buf.size()), 0); | ||
| if (bytesRead <= 0) | ||
| { | ||
| break; | ||
| } | ||
|
|
||
| DWORD bytesWritten{}; | ||
| THROW_IF_WIN32_BOOL_FALSE(WriteFile(file.get(), buf.data(), static_cast<DWORD>(bytesRead), &bytesWritten, nullptr)); | ||
| } |
| // Connect the new socket via the VM interface. | ||
| wil::unique_socket connSocket; | ||
| THROW_IF_FAILED(m_vm->ConnectToVsockPort(response.Port, reinterpret_cast<HANDLE*>(&connSocket))); | ||
| wsl::shared::SocketChannel newChannel{ |
| HRESULT RemoveShare([in] REFGUID ShareId); | ||
|
|
||
| // Returns an event that is signaled when the VM exits (graceful or forced). | ||
| HRESULT GetTerminationEvent([out, system_handle(sh_event)] HANDLE* Event); | ||
|
|
||
| // Connects to a vsock port in the VM. Returns a socket handle. | ||
| // For HCS VMs, this uses hvsocket (supports overlapped I/O). | ||
| // For OpenVMM VMs, this uses the hybrid_vsock Unix domain socket bridge. | ||
| // AF_UNIX sockets do not support overlapped I/O | ||
| HRESULT ConnectToVsockPort([in] ULONG Port, [out, system_handle(sh_socket)] HANDLE* Socket); | ||
|
|
||
| // Accepts a crash dump connection from the VM. Blocks until a crash dump | ||
| // connection arrives or the VM exits. Returns E_ABORT if the VM exits | ||
| // before a connection is received. | ||
| // For HCS VMs, this uses an HV socket listener on the crash dump port. | ||
| // For OpenVMM VMs, this uses the hybrid_vsock Unix domain socket bridge. | ||
| HRESULT AcceptCrashDumpConnection([out, system_handle(sh_socket)] HANDLE* Socket); |
| HRESULT HcsVirtualMachine::ConnectToVsockPort(_In_ ULONG Port, _Out_ HANDLE* Socket) | ||
| try | ||
| { | ||
| auto socket = wsl::windows::common::hvsocket::Connect(m_vmId, Port); | ||
| *Socket = reinterpret_cast<HANDLE>(socket.release()); | ||
| return S_OK; | ||
| } | ||
| CATCH_RETURN() |
| // OpenVMM provides networking via its built-in consomme backend. | ||
| // Use ConsommeNetworking mode so the session process skips GNS but | ||
| // still configures the networking engine and port relay. |
| // Try to reap the child. If WSLC_WATCH_PROCESSES already reaped it, we | ||
| // get ECHILD which is fine — the pipe close confirms the child exited. | ||
| int status = -1; | ||
| if (TEMP_FAILURE_RETRY(waitpid(childPid, &status, 0)) < 0) | ||
| { | ||
| if (errno == ECHILD) | ||
| { | ||
| // Child was already reaped by the WatchProcesses handler. | ||
| // The pipe confirmed it exited, so treat as success. | ||
| status = 0; | ||
| } | ||
| else |
| // Set socket timeouts to prevent blocking forever if OpenVMM hangs. | ||
| setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<const char*>(&c_socketTimeoutMs), sizeof(c_socketTimeoutMs)); | ||
| setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<const char*>(&c_socketTimeoutMs), sizeof(c_socketTimeoutMs)); |
| endforeach() | ||
|
|
||
| if (INCLUDE_OPENVMM) | ||
| set(WSL_DEVICE_HOST_BINARIES wsldevicehost.dll;openvmm.exe) |
There was a problem hiding this comment.
wsldevicehost.dll should be included all the time.
There was a problem hiding this comment.
maybe that's an existing issue?
| Transaction.SendResultMessage(result < 0 ? errno : 0); | ||
| } | ||
|
|
||
| void HandleMessageImpl( |
There was a problem hiding this comment.
I think we probably want to use the existing GNS implementation to do network configuration. it should support all of this stuff.
| set_target_properties(common PROPERTIES FOLDER windows) | ||
| target_include_directories(common PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/../service/mc/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}) | ||
|
|
||
| # ATL headers (atlsafe.h) are needed by precomp.h but not automatically included |
|
|
||
| // Disable features not yet supported by the OpenVMM backend. | ||
| WI_ClearFlag(m_featureFlags, WslcFeatureFlagsGPU); | ||
| WI_ClearFlag(m_featureFlags, WslcFeatureFlagsVirtioFs); |
There was a problem hiding this comment.
what does openvmm use for host shares if not virtiofs?
This PR adds OpenVMM as a possible VMM backing WSLC VMs.
This feature is gated on both a compile time gate and a WSLC feature flag. Non-exhaustive list of changes made to implement this:
WSLC_CONFIGURE_NETWORKINGmessage that allows us to configure networking within the VM using OpenVMM's consomme networking stack.OpenVmmVirtualMachineclass that implements theIWSLCVirtualMachineallowing users to switch between traditional HCS VMs and OpenVMM VMs.SocketChannelclass to support non-overlapped I/O which is not supported when using AF_UNIX sockets. This is required to bridge the connection between themini_initprocess from the guest to thewslcservice.