Resolve and pass gateway MAC address to virtio net device (#14386)
Use ResolveIpNetEntry2 to look up the host gateway's MAC address and pass it as the gateway_mac device option to the virtio net adapter. This allows the guest to see the real gateway MAC instead of the default consomme address. Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
Ben Hillis committed
Mar 9, 2026 at 14:51 UTC
218b71be6717c977f17eb7b70a1747a60661d51f
3 files changed
+46
-21
src/windows/common/VirtioNetworking.cpp
+9
-21
@@ -172,32 +172,20 @@ try
172
// Query current networking information before acquiring the lock.
173
auto networkSettings = GetHostEndpointSettings();
174
175
- // TODO: Determine gateway MAC address
175
std::wstring device_options;
177
- auto client_ip = networkSettings->PreferredIpAddress.AddressString;
178
- if (!client_ip.empty())
179
- {
180
- device_options += L"client_ip=" + client_ip;
181
- }
182
-
183
- if (!networkSettings->MacAddress.empty())
184
- {
185
- if (!device_options.empty())
176
+ auto appendOption = [&device_options](std::wstring_view key, std::wstring_view value) {
177
+ if (!value.empty())
178
{
187
- device_options += L';';
179
+ std::format_to(std::back_inserter(device_options), L"{}{}={}", device_options.empty() ? L"" : L";", key, value);
180
}
189
- device_options += L"client_mac=" + networkSettings->MacAddress;
190
- }
181
+ };
182
+
183
+ appendOption(L"client_ip", networkSettings->PreferredIpAddress.AddressString);
184
+ appendOption(L"client_mac", networkSettings->MacAddress);
185
186
std::wstring default_route = networkSettings->GetBestGatewayAddressString();
193
- if (!default_route.empty())
194
- {
195
- if (!device_options.empty())
196
- {
197
- device_options += L';';
198
- }
199
- device_options += L"gateway_ip=" + default_route;
200
- }
187
+ appendOption(L"gateway_ip", default_route);
188
+ appendOption(L"gateway_mac", networkSettings->GetBestGatewayMacAddress());
189
190
networking::DnsInfo currentDns{};
191
if (WI_IsFlagSet(m_flags, VirtioNetworkingFlags::DnsTunneling))
src/windows/common/WslCoreNetworkEndpointSettings.cpp
+35
@@ -94,3 +94,38 @@ std::shared_ptr<wsl::core::networking::NetworkSettings> wsl::core::networking::G
94
return std::make_shared<NetworkSettings>(
95
bestInterface->NetworkGuid, address, route, macAddress, bestInterface->IfIndex, bestInterface->IfType);
96
}
97
+
98
+std::wstring wsl::core::networking::NetworkSettings::GetBestGatewayMacAddress() const
99
+{
100
+ auto gatewayAddress = GetBestGatewayAddress();
101
+ if (gatewayAddress.si_family != AF_INET)
102
+ {
103
+ return {};
104
+ }
105
+
106
+ MIB_IPNET_ROW2 ipNetRow{};
107
+ ipNetRow.Address = gatewayAddress;
108
+ ipNetRow.InterfaceIndex = InterfaceIndex;
109
+
110
+ const auto result = ResolveIpNetEntry2(&ipNetRow, nullptr);
111
+ if (result != NO_ERROR)
112
+ {
113
+ LOG_HR_MSG(HRESULT_FROM_WIN32(result), "Failed to resolve gateway MAC address");
114
+ return {};
115
+ }
116
+
117
+ if (ipNetRow.PhysicalAddressLength != 6)
118
+ {
119
+ return {};
120
+ }
121
+
122
+ return wsl::shared::string::FormatMacAddress(
123
+ wsl::shared::string::MacAddress{
124
+ ipNetRow.PhysicalAddress[0],
125
+ ipNetRow.PhysicalAddress[1],
126
+ ipNetRow.PhysicalAddress[2],
127
+ ipNetRow.PhysicalAddress[3],
128
+ ipNetRow.PhysicalAddress[4],
129
+ ipNetRow.PhysicalAddress[5]},
130
+ L'-');
131
+}
src/windows/common/WslCoreNetworkEndpointSettings.h
+2
@@ -318,6 +318,8 @@ struct NetworkSettings
318
return {};
319
}
320
321
+ std::wstring GetBestGatewayMacAddress() const;
322
+
323
std::wstring IpAddressesString() const
324
{
325
return std::accumulate(std::begin(IpAddresses), std::end(IpAddresses), std::wstring{}, [](const std::wstring& prev, const auto& addr) {