Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions localization/strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -1126,6 +1126,14 @@ Attempting web download...</value>
<data name="MessageConfigVirtio9pDisabled" xml:space="preserve">
<value>wsl2.virtio9p is disabled, falling back to 9p with vsock transport.</value>
</data>
<data name="MessageVirtioProxyRequiresVirtio" xml:space="preserve">
<value>VirtioProxy networking is not supported when wsl2.virtio is disabled; falling back to networkingMode {}.</value>
<comment>{Locked="wsl2.virtio"}{Locked="VirtioProxy"}{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageSwiotlbKernelUnsupported" xml:space="preserve">
<value>The running kernel is missing a patch that significantly improves virtio device performance. Update to a more recent WSL kernel to enable this optimization.</value>
<comment>{Locked="virtio"}</comment>
</data>
<data name="MessageInstallationCorrupted" xml:space="preserve">
<value>WSL installation appears to be corrupted (Error code: {}).
Press any key to repair WSL, or CTRL-C to cancel.
Expand Down
4 changes: 2 additions & 2 deletions packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
<package id="Microsoft.WSL.bsdtar" version="0.0.2-2" />
<package id="Microsoft.WSL.Dependencies.amd64fre" version="10.0.27820.1000-250318-1700.rs-base2-hyp" targetFramework="native" />
<package id="Microsoft.WSL.Dependencies.arm64fre" version="10.0.27820.1000-250318-1700.rs-base2-hyp" targetFramework="native" />
<package id="Microsoft.WSL.DeviceHost" version="1.2.23-0" />
<package id="Microsoft.WSL.Kernel" version="6.18.26.1-1" targetFramework="native" />
<package id="Microsoft.WSL.DeviceHost" version="1.2.29-0" />
<package id="Microsoft.WSL.Kernel" version="6.18.26.3-1" targetFramework="native" />
<package id="Microsoft.WSL.LinuxSdk" version="1.20.0" targetFramework="native" />
<package id="Microsoft.WSL.TestData" version="0.4.0" />
<package id="Microsoft.WSL.TestDistro" version="2.7.1-1" />
Expand Down
19 changes: 18 additions & 1 deletion src/linux/init/WSLCInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,23 @@ void HandleMessageImpl(
Transaction.Send<WSLC_GET_DISK::TResponse>(writer.Span());
}

void HandleMessageImpl(
wsl::shared::SocketChannel& Channel,
wsl::shared::Transaction& Transaction,
const WSLC_GET_GUEST_CAPABILITIES& Message,
const gsl::span<gsl::byte>& Buffer)
{
WSLC_GET_GUEST_CAPABILITIES_RESULT response{};
response.Header.MessageType = WSLC_GET_GUEST_CAPABILITIES_RESULT::Type;
response.Header.MessageSize = sizeof(response);

auto pool = UtilReadHvPciSwiotlbPool();
response.HvPciSwiotlbBase = pool.Base;
response.HvPciSwiotlbSize = pool.Size;

Transaction.Send<WSLC_GET_GUEST_CAPABILITIES_RESULT>(response);
}

void HandleMessageImpl(
wsl::shared::SocketChannel& Channel, wsl::shared::Transaction& Transaction, const WSLC_ACCEPT& Message, const gsl::span<gsl::byte>& Buffer)
{
Expand Down Expand Up @@ -836,7 +853,7 @@ void ProcessMessage(wsl::shared::SocketChannel& Channel, wsl::shared::Transactio
{
try
{
HandleMessage<WSLC_GET_DISK, WSLC_MOUNT, WSLC_EXEC, WSLC_FORK, WSLC_CONNECT, WSLC_SIGNAL, WSLC_TTY_RELAY, WSLC_PORT_RELAY, WSLC_UNMOUNT, WSLC_DETACH, WSLC_ACCEPT, WSLC_WATCH_PROCESSES, WSLC_UNIX_CONNECT>(
HandleMessage<WSLC_GET_DISK, WSLC_MOUNT, WSLC_EXEC, WSLC_FORK, WSLC_CONNECT, WSLC_SIGNAL, WSLC_TTY_RELAY, WSLC_PORT_RELAY, WSLC_UNMOUNT, WSLC_DETACH, WSLC_ACCEPT, WSLC_WATCH_PROCESSES, WSLC_UNIX_CONNECT, WSLC_GET_GUEST_CAPABILITIES>(
Channel, Transaction, Type, Buffer);
}
catch (...)
Expand Down
9 changes: 5 additions & 4 deletions src/linux/init/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3391,15 +3391,16 @@ try
wsl::shared::MessageWriter<LX_INIT_GUEST_CAPABILITIES> Message(LxMiniInitMessageGuestCapabilities);
Message.WriteString(Version.release);

//
// SECCOMP_USER_NOTIF_FLAG_CONTINUE is the latest flag that flow steering needs
// but there's no way to test for its presence. The assumption is that if seccomp is available
// and the kernel version is >= 5.10, then SECCOMP_USER_NOTIF_FLAG_CONTINUE is available
//

// and the kernel version is >= 5.10, then SECCOMP_USER_NOTIF_FLAG_CONTINUE is available.
uint32_t SeccompFlag = SECCOMP_RET_USER_NOTIF;
Message->SeccompAvailable = syscall(__NR_seccomp, SECCOMP_GET_ACTION_AVAIL, 0, &SeccompFlag) == 0;

auto pool = UtilReadHvPciSwiotlbPool();
Message->HvPciSwiotlbBase = pool.Base;
Message->HvPciSwiotlbSize = pool.Size;

Channel.SendMessage<LX_INIT_GUEST_CAPABILITIES>(Message.Span());
return 0;
}
Expand Down
16 changes: 16 additions & 0 deletions src/linux/init/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3326,6 +3326,22 @@ std::string UtilReadFileContent(std::string_view path)
return {std::istreambuf_iterator<char>(file), {}};
}

HvPciSwiotlbPool UtilReadHvPciSwiotlbPool()
{
HvPciSwiotlbPool pool{};
try
{
pool.Base = std::stoull(UtilReadFileContent("/sys/bus/vmbus/drivers/hv_pci/swiotlb_base"), nullptr, 0);
pool.Size = std::stoull(UtilReadFileContent("/sys/bus/vmbus/drivers/hv_pci/swiotlb_size"), nullptr, 0);
}
catch (...)
{
pool = {};
}

return pool;
}

uint16_t UtilWinAfToLinuxAf(uint16_t WinAddressFamily)
{
uint16_t LinuxAddressFamily = AF_UNSPEC;
Expand Down
11 changes: 11 additions & 0 deletions src/linux/init/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,17 @@ std::wstring UtilReadFileContentW(std::string_view path);

std::string UtilReadFileContent(std::string_view path);

// Holds the hv_pci swiotlb pool the WSL kernel reserved at boot and published
// under /sys/bus/vmbus/drivers/hv_pci/swiotlb_{base,size}. Both fields are zero
// when running on a kernel that does not publish these files.
struct HvPciSwiotlbPool
{
uint64_t Base = 0;
uint64_t Size = 0;
};

HvPciSwiotlbPool UtilReadHvPciSwiotlbPool();

uint16_t UtilWinAfToLinuxAf(uint16_t AddressFamily);

int WriteToFile(const char* Path, const char* Content, int permissions = 0644);
Expand Down
31 changes: 30 additions & 1 deletion src/shared/inc/lxinitshared.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ typedef enum _LX_MESSAGE_TYPE
LxMessageWSLCWatchProcesses,
LxMessageWSLCProcessExited,
LxMessageWSLCUnixConnect,
LxMessageWSLCGetGuestCapabilities,
LxMessageWSLCGetGuestCapabilitiesResult,
} LX_MESSAGE_TYPE,
*PLX_MESSAGE_TYPE;

Expand Down Expand Up @@ -513,6 +515,8 @@ inline auto ToString(LX_MESSAGE_TYPE messageType)
X(LxMessageWSLCWatchProcesses)
X(LxMessageWSLCProcessExited)
X(LxMessageWSLCUnixConnect)
X(LxMessageWSLCGetGuestCapabilities)
X(LxMessageWSLCGetGuestCapabilitiesResult)

default:
return "<unexpected LX_MESSAGE_TYPE>";
Expand Down Expand Up @@ -1430,9 +1434,11 @@ typedef struct _LX_INIT_GUEST_CAPABILITIES

MESSAGE_HEADER Header;
bool SeccompAvailable;
uint64_t HvPciSwiotlbBase;
uint64_t HvPciSwiotlbSize;
char Buffer[]; // Contains the kernel version string

PRETTY_PRINT(FIELD(Header), FIELD(SeccompAvailable), BUFFER_FIELD(Buffer));
PRETTY_PRINT(FIELD(Header), FIELD(SeccompAvailable), FIELD(HvPciSwiotlbBase), FIELD(HvPciSwiotlbSize), BUFFER_FIELD(Buffer));
} LX_INIT_GUEST_CAPABILITIES, *PLX_INIT_GUEST_CAPABILITIES;

typedef struct _LX_MINI_INIT_WAIT_FOR_PMEM_DEVICE_MESSAGE
Expand Down Expand Up @@ -1836,6 +1842,29 @@ struct WSLC_UNIX_CONNECT
PRETTY_PRINT(FIELD(Header), STRING_FIELD(PathOffset));
};

struct WSLC_GET_GUEST_CAPABILITIES_RESULT
{
static inline auto Type = LxMessageWSLCGetGuestCapabilitiesResult;

MESSAGE_HEADER Header{};
uint64_t HvPciSwiotlbBase{};
uint64_t HvPciSwiotlbSize{};

PRETTY_PRINT(FIELD(Header), FIELD(HvPciSwiotlbBase), FIELD(HvPciSwiotlbSize));
};

struct WSLC_GET_GUEST_CAPABILITIES
{
static inline auto Type = LxMessageWSLCGetGuestCapabilities;
using TResponse = WSLC_GET_GUEST_CAPABILITIES_RESULT;

DECLARE_MESSAGE_CTOR(WSLC_GET_GUEST_CAPABILITIES);

MESSAGE_HEADER Header{};

PRETTY_PRINT(FIELD(Header));
};

typedef struct _LX_MINI_INIT_IMPORT_RESULT
{
static inline auto Type = LxMiniInitMessageImportResult;
Expand Down
5 changes: 4 additions & 1 deletion src/windows/common/GuestDeviceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@ GUID GuestDeviceManager::AddHdvShareWithOptions(
// Options are appended to the name with a semi-colon separator.
// "name;key1=value1;key2=value2"
// The AddSharePath implementation is responsible for separating them out and interpreting them.
// N.B. A ";vm_id=<guid>" option is always appended so the device host can identify the owning VM.
std::wstring nameWithOptions{AccessName};
if (ARGUMENT_PRESENT(Options))
if (ARGUMENT_PRESENT(Options) && Options[0] != L'\0')
{
nameWithOptions += L";";
nameWithOptions += Options;
}

nameWithOptions += std::format(L";vm_id={}", m_machineId);

{
auto revert = wil::impersonate_token(UserToken);

Expand Down
20 changes: 16 additions & 4 deletions src/windows/common/VirtioNetworking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@ static constexpr auto c_eth0DeviceName = L"eth0";
static constexpr auto c_loopbackDeviceName = TEXT(LX_INIT_LOOPBACK_DEVICE_NAME);

VirtioNetworking::VirtioNetworking(
GnsChannel&& gnsChannel, VirtioNetworkingFlags flags, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken) :
GnsChannel&& gnsChannel,
VirtioNetworkingFlags flags,
LPCWSTR dnsOptions,
std::shared_ptr<GuestDeviceManager> guestDeviceManager,
wil::shared_handle userToken,
std::wstring swiotlbConfig) :
m_guestDeviceManager(std::move(guestDeviceManager)),
m_userToken(std::move(userToken)),
m_gnsChannel(std::move(gnsChannel)),
m_flags(flags),
m_dnsOptions(dnsOptions)
m_dnsOptions(dnsOptions),
m_swiotlbOption(std::move(swiotlbConfig))
{
}

Expand Down Expand Up @@ -210,7 +216,13 @@ void VirtioNetworking::RefreshGuestConnection()
if (!m_adapterId.has_value())
{
m_adapterId = m_guestDeviceManager->AddGuestDevice(
VIRTIO_NET_DEVICE_ID, VIRTIO_NET_CLASS_ID, c_eth0DeviceName, nullptr, device_options.c_str(), 0, m_userToken.get());
VIRTIO_NET_DEVICE_ID,
VIRTIO_NET_CLASS_ID,
c_eth0DeviceName,
m_swiotlbOption.c_str(),
device_options.c_str(),
0,
m_userToken.get());
}
else
{
Expand Down Expand Up @@ -244,7 +256,7 @@ void VirtioNetworking::SetupLoopbackDevice()
VIRTIO_NET_DEVICE_ID,
VIRTIO_NET_CLASS_ID,
c_loopbackDeviceName,
nullptr,
m_swiotlbOption.c_str(),
L"client_ip=127.0.0.1;client_mac=00:11:22:33:44:55",
0,
m_userToken.get());
Expand Down
9 changes: 8 additions & 1 deletion src/windows/common/VirtioNetworking.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ DEFINE_ENUM_FLAG_OPERATORS(VirtioNetworkingFlags);
class VirtioNetworking : public INetworkingEngine
{
public:
VirtioNetworking(GnsChannel&& gnsChannel, VirtioNetworkingFlags flags, LPCWSTR dnsOptions, std::shared_ptr<GuestDeviceManager> guestDeviceManager, wil::shared_handle userToken);
VirtioNetworking(
GnsChannel&& gnsChannel,
VirtioNetworkingFlags flags,
LPCWSTR dnsOptions,
std::shared_ptr<GuestDeviceManager> guestDeviceManager,
wil::shared_handle userToken,
std::wstring swiotlbConfig);

~VirtioNetworking();

Expand Down Expand Up @@ -62,6 +68,7 @@ class VirtioNetworking : public INetworkingEngine
std::shared_ptr<networking::NetworkSettings> m_networkSettings;
VirtioNetworkingFlags m_flags = VirtioNetworkingFlags::None;
LPCWSTR m_dnsOptions = nullptr;
std::wstring m_swiotlbOption;
std::optional<GUID> m_localhostAdapterId;
std::optional<GUID> m_adapterId;

Expand Down
51 changes: 34 additions & 17 deletions src/windows/common/WslCoreConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Module Name:

#include "precomp.h"
#include "WslCoreConfig.h"
#include "helpers.hpp"
#include "Localization.h"
#include "WslCoreFirewallSupport.h"
#include "WslCoreNetworkingSupport.h"
Expand Down Expand Up @@ -124,7 +125,8 @@ void wsl::core::Config::ParseConfigFile(_In_opt_ LPCWSTR ConfigFilePath, _In_opt
ConfigKey(ConfigSetting::Experimental::InitialAutoProxyTimeout, InitialAutoProxyTimeout),
ConfigKey(ConfigSetting::Experimental::IgnoredPorts, std::move(parseIgnoredPorts)),
ConfigKey(ConfigSetting::Experimental::HostAddressLoopback, EnableHostAddressLoopback),
ConfigKey(ConfigSetting::Experimental::SetVersionDebug, SetVersionDebug)};
ConfigKey(ConfigSetting::Experimental::SetVersionDebug, SetVersionDebug),
ConfigKey(ConfigSetting::Experimental::Swiotlb, MemoryString(SwiotlbSizeBytes))};

wil::unique_file ConfigFile;
if (ConfigFilePath != nullptr)
Expand Down Expand Up @@ -398,22 +400,6 @@ void wsl::core::Config::Initialize(_In_opt_ HANDLE UserToken)
}
}

// Load NAT configuration from the registry.
if (NetworkingMode == wsl::core::NetworkingMode::Nat)
{
try
{
const auto machineKey = wsl::windows::common::registry::OpenLxssMachineKey();
NatGateway = wsl::windows::common::registry::ReadString(machineKey.get(), nullptr, c_natGatewayAddress, L"");
NatNetwork = wsl::windows::common::registry::ReadString(machineKey.get(), nullptr, c_natNetwork, L"");

auto runAsUser = wil::impersonate_token(UserToken);
const auto userKey = wsl::windows::common::registry::OpenLxssUserKey();
NatIpAddress = wsl::windows::common::registry::ReadString(userKey.get(), nullptr, c_natIpAddress, L"");
}
CATCH_LOG()
}

// Due to an issue with Global Secure Access Client, do not use DNS tunneling if the service is present.
if (EnableDnsTunneling)
{
Expand Down Expand Up @@ -454,6 +440,13 @@ void wsl::core::Config::Initialize(_In_opt_ HANDLE UserToken)
{
VALIDATE_CONFIG_OPTION(!EnableVirtio, EnableVirtio9p, false);
VALIDATE_CONFIG_OPTION(!EnableVirtio, EnableVirtioFs, false);
VALIDATE_CONFIG_OPTION(!EnableVirtio, SwiotlbSizeBytes, 0);

if (NetworkingMode == NetworkingMode::VirtioProxy)
{
NetworkingMode = (defaultNetworkingMode == NetworkingMode::VirtioProxy) ? NetworkingMode::None : NetworkingMode::Nat;
EMIT_USER_WARNING(wsl::shared::Localization::MessageVirtioProxyRequiresVirtio(ToString(NetworkingMode)));
}
}

if (EnableVirtio9p)
Expand All @@ -462,6 +455,13 @@ void wsl::core::Config::Initialize(_In_opt_ HANDLE UserToken)
EnableVirtio9p = false;
}

// Compute a default swiotlb config only when a virtio device that requires bounce buffers is present.
// N.B. Must run after policy overrides so networking/fs modes reflect final values.
if (SwiotlbSizeBytes == 0 && (EnableVirtioFs || EnableVirtio9p || (NetworkingMode == NetworkingMode::VirtioProxy)))
{
SwiotlbSizeBytes = wsl::windows::common::helpers::ComputeDefaultSwiotlbConfig(MemorySizeBytes);
}

if (NetworkingMode != NetworkingMode::Nat && NetworkingMode != NetworkingMode::Mirrored && NetworkingMode != NetworkingMode::VirtioProxy)
{
VALIDATE_CONFIG_OPTION(
Expand All @@ -481,6 +481,23 @@ void wsl::core::Config::Initialize(_In_opt_ HANDLE UserToken)
VALIDATE_CONFIG_OPTION((NetworkingMode != NetworkingMode::Mirrored), IgnoredPorts, std::set<uint16_t>{});
VALIDATE_CONFIG_OPTION((NetworkingMode != NetworkingMode::Mirrored), EnableHostAddressLoopback, false);
}

// Load NAT configuration from the registry.
// N.B. This must be done after all networking mode adjustments (e.g. VirtioProxy -> NAT fallback).
if (NetworkingMode == wsl::core::NetworkingMode::Nat)
{
try
{
const auto machineKey = wsl::windows::common::registry::OpenLxssMachineKey();
NatGateway = wsl::windows::common::registry::ReadString(machineKey.get(), nullptr, c_natGatewayAddress, L"");
NatNetwork = wsl::windows::common::registry::ReadString(machineKey.get(), nullptr, c_natNetwork, L"");

auto runAsUser = wil::impersonate_token(UserToken);
const auto userKey = wsl::windows::common::registry::OpenLxssUserKey();
NatIpAddress = wsl::windows::common::registry::ReadString(userKey.get(), nullptr, c_natIpAddress, L"");
}
CATCH_LOG()
}
}

GUID wsl::core::Config::NatNetworkId() const noexcept
Expand Down
12 changes: 7 additions & 5 deletions src/windows/common/WslCoreConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ Module Name:
T_VALUE(c, EnableHostAddressLoopback), T_VALUE(c, EnableHostFileSystemAccess), T_VALUE(c, EnableIpv6), \
T_VALUE(c, EnableLocalhostRelay), T_VALUE(c, EnableNestedVirtualization), T_VALUE(c, EnableSafeMode), \
T_VALUE(c, EnableSparseVhd), T_VALUE(c, EnableVirtio), T_VALUE(c, EnableVirtio9p), T_VALUE(c, EnableVirtioFs), \
T_ENUM(c, FirewallConfigPresence), T_VALUE(c, KernelBootTimeout), T_SET(c, KernelCommandLine), \
T_VALUE(c, KernelDebugPort), T_SET(c, KernelModulesPath), T_STRING(c, KernelModulesList), T_SET(c, KernelPath), \
T_VALUE(c, LoadDefaultKernelModules), T_PRESENT(c, LoadKernelModulesPresence), T_VALUE(c, MaximumMemorySizeBytes), \
T_VALUE(c, MaximumProcessorCount), T_ENUM(c, MemoryReclaim), T_VALUE(c, MemorySizeBytes), T_VALUE(c, MountDeviceTimeout), \
T_ENUM(c, NetworkingMode), T_VALUE(c, ProcessorCount), T_SET(c, SwapFilePath), T_VALUE(c, SwapSizeBytes), \
T_ENUM(c, FirewallConfigPresence), T_VALUE(c, KernelBootTimeout), T_SET(c, KernelCommandLine), T_VALUE(c, KernelDebugPort), \
T_STRING(c, KernelModulesList), T_SET(c, KernelModulesPath), T_SET(c, KernelPath), T_VALUE(c, LoadDefaultKernelModules), \
T_PRESENT(c, LoadKernelModulesPresence), T_VALUE(c, MaximumMemorySizeBytes), T_VALUE(c, MaximumProcessorCount), \
T_ENUM(c, MemoryReclaim), T_VALUE(c, MemorySizeBytes), T_VALUE(c, MountDeviceTimeout), T_ENUM(c, NetworkingMode), \
T_VALUE(c, ProcessorCount), T_SET(c, SwapFilePath), T_VALUE(c, SwapSizeBytes), T_VALUE(c, SwiotlbSizeBytes), \
T_SET(c, SystemDistroPath), T_VALUE(c, VhdSizeBytes), T_VALUE(c, VmIdleTimeout), T_SET(c, VmSwitch)

namespace wsl::core {
Expand Down Expand Up @@ -289,6 +289,7 @@ namespace ConfigSetting {
static constexpr auto IgnoredPorts = "experimental.ignoredPorts";
static constexpr auto HostAddressLoopback = "experimental.hostAddressLoopback";
static constexpr auto SetVersionDebug = "experimental.setVersionDebug";
static constexpr auto Swiotlb = "experimental.swiotlb";

} // namespace Experimental
} // namespace ConfigSetting
Expand Down Expand Up @@ -375,6 +376,7 @@ struct Config
bool EnableHostAddressLoopback = false;
std::filesystem::path CrashDumpFolder;
int MaxCrashDumpCount = 10;
UINT64 SwiotlbSizeBytes = 0;

// Temporary config value to help root cause the truncated archive errors in SetVersion()
bool SetVersionDebug = false;
Expand Down
Loading