master
h 318 lines 13.4 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 WslMirroredNetworking.h
8
9 Abstract:
10
11 This file contains WSL mirrored networking function declarations.
12
13 --*/
14
15 #pragma once
16 #include <chrono>
17 #include <optional>
18 #include <string>
19 #include <vector>
20
21 #include <mstcpip.h>
22 #include <ws2ipdef.h>
23 #include <netlistmgr.h>
24 #include <ComputeNetwork.h>
25 #include <wil/winrt.h>
26
27 #include "WslCoreMessageQueue.h"
28 #include "WslCoreAdviseHandler.h"
29 #include "WslCoreNetworkEndpoint.h"
30 #include "WslCoreNetworkEndpointSettings.h"
31 #include "WslCoreNetworkingSupport.h"
32 #include "WslCoreTcpIpStateTracking.h"
33 #include "WslCoreHostDnsInfo.h"
34 #include "hcs.hpp"
35 #include "IMirroredNetworkManager.h"
36
37 /// <summary>
38 /// Creates network-related information for WSL.
39 /// </summary>
40 namespace wsl::core::networking {
41
42 class WslMirroredNetworkManager final : public wsl::core::networking::IMirroredNetworkManager
43 {
44 public:
45 WslMirroredNetworkManager(
46 HCS_SYSTEM hcsSystem,
47 const Config& config,
48 GnsMessageCallbackWithCallbackResult&& GnsMessageCallbackWithCallbackResult,
49 AddNetworkEndpointCallback&& addNetworkEndpointCallback,
50 const std::pair<uint16_t, uint16_t>& ephemeralPortRange);
51
52 ~WslMirroredNetworkManager() noexcept override;
53
54 // Disable copy and assign.
55 WslMirroredNetworkManager(const WslMirroredNetworkManager&) = delete;
56 WslMirroredNetworkManager& operator=(const WslMirroredNetworkManager&) = delete;
57
58 // Disable move semantics.
59 WslMirroredNetworkManager(WslMirroredNetworkManager&&) noexcept = delete;
60 WslMirroredNetworkManager& operator=(WslMirroredNetworkManager&&) = delete;
61
62 HnsStatus Stop() noexcept override;
63
64 _Check_return_ HRESULT EnumerateNetworks(_Out_ std::vector<GUID>& NetworkIds) const noexcept override;
65
66 void AddEndpoint(NetworkEndpoint&& newEndpoint, wsl::shared::hns::HNSEndpoint&& endpointProperties) noexcept override;
67
68 void SendCreateNotificationsForInitialEndpoints() noexcept override;
69
70 HRESULT WaitForMirroredGoalState() noexcept override;
71
72 _Check_return_ bool DoesEndpointExist(GUID networkId) const noexcept override;
73
74 void OnNetworkConnectivityHintChange() noexcept override;
75 void OnNetworkEndpointChange() noexcept override;
76 void OnDnsSuffixChange() noexcept override;
77
78 void TunAdapterStateChanged(_In_ const std::string& interfaceName, _In_ bool up) noexcept override;
79
80 // Client should call this if they detect the network is in a bad state and needs to be reconnected
81 void ReconnectGuestNetwork() override;
82
83 std::shared_ptr<NetworkSettings> GetEndpointSettings(const wsl::shared::hns::HNSEndpoint& endpointProperties) const override;
84
85 void TraceLoggingRundown() const override;
86
87 private:
88 enum class State
89 {
90 Stopped = 0,
91 Started,
92 Starting,
93 };
94
95 static const char* StateToString(State state) noexcept;
96
97 _Requires_lock_held_(m_networkLock)
98 std::vector<GUID> EnumerateMirroredNetworks() const noexcept;
99
100 _Requires_lock_held_(m_networkLock)
101 _Check_return_ HRESULT AddNetwork(const GUID& networkId) noexcept;
102
103 _Requires_lock_held_(m_networkLock)
104 _Check_return_ HRESULT RemoveNetwork(const GUID& networkId) noexcept;
105
106 _Requires_lock_held_(m_networkLock)
107 _Check_return_ HRESULT RemoveEndpoint(const GUID& endpointId) noexcept;
108
109 struct EndpointTracking
110 {
111 EndpointTracking(NetworkEndpoint&& networkEndpoint, wsl::shared::hns::HNSEndpoint&& hnsEndpoint, uint32_t retryCount) :
112 m_networkEndpoint{std::move(networkEndpoint)}, m_hnsEndpoint{std::move(hnsEndpoint)}, m_retryCount{retryCount}
113 {
114 }
115 ~EndpointTracking() noexcept = default;
116 EndpointTracking(const EndpointTracking&) = delete;
117 EndpointTracking& operator=(const EndpointTracking&) = delete;
118 EndpointTracking(EndpointTracking&&) = default;
119 EndpointTracking& operator=(EndpointTracking&&) = default;
120
121 NetworkEndpoint m_networkEndpoint;
122 wsl::shared::hns::HNSEndpoint m_hnsEndpoint;
123 uint32_t m_retryCount = 0;
124 };
125
126 _Requires_lock_held_(m_networkLock)
127 void AddEndpointImpl(EndpointTracking&& endpointTrackingObject) noexcept;
128
129 _Requires_lock_held_(m_networkLock)
130 void ProcessConnectivityChange();
131
132 _Requires_lock_held_(m_networkLock)
133 void ProcessInterfaceChange();
134
135 _Requires_lock_held_(m_networkLock)
136 void ProcessIpAddressChange();
137
138 _Requires_lock_held_(m_networkLock)
139 void ProcessRouteChange();
140
141 _Requires_lock_held_(m_networkLock)
142 void ProcessDNSChange();
143
144 _Requires_lock_held_(m_networkLock)
145 _Check_return_ HRESULT SendAddressRequestToGns(
146 const NetworkEndpoint& endpoint, const TrackedIpAddress& address, wsl::shared::hns::ModifyRequestType requestType) noexcept;
147
148 _Requires_lock_held_(m_networkLock)
149 _Check_return_ HRESULT SendRouteRequestToGns(const NetworkEndpoint& endpoint, const TrackedRoute& route, wsl::shared::hns::ModifyRequestType requestType) noexcept;
150
151 _Requires_lock_held_(m_networkLock)
152 _Check_return_ HRESULT SendLoopbackRequestToGns(
153 const NetworkEndpoint& endpoint, const TrackedIpAddress& address, wsl::shared::hns::OperationType operation) noexcept;
154
155 _Requires_lock_held_(m_networkLock)
156 _Check_return_ HRESULT SendDnsRequestToGns(const NetworkEndpoint& endpoint, const DnsInfo& dnsInfo, wsl::shared::hns::ModifyRequestType requestType) noexcept;
157
158 _Requires_lock_held_(m_networkLock)
159 _Check_return_ HRESULT SendInterfaceRequestToGns(const NetworkEndpoint& endpoint) noexcept;
160
161 _Requires_lock_not_held_(m_networkLock)
162 void UpdateAllEndpoints(_In_ PCSTR sourceName) noexcept;
163
164 _Requires_lock_held_(m_networkLock)
165 void UpdateAllEndpointsImpl(UpdateEndpointFlag updateFlag, _In_ PCSTR callingSource) noexcept;
166
167 _Requires_lock_held_(m_networkLock)
168 _Check_return_ HRESULT UpdateHcnServiceTimer() noexcept;
169
170 _Requires_lock_held_(m_networkLock)
171 _Check_return_ HRESULT ResetHcnServiceSession() noexcept;
172
173 _Requires_lock_held_(m_networkLock)
174 _Check_return_ bool SyncIpStateWithLinux(NetworkEndpoint& endpoint);
175
176 _Requires_lock_held_(m_networkLock)
177 NetworkSettings GetNetworkSettingsOfInterface(DWORD ifIndex) const;
178
179 void TelemetryConnectionCallback(NLM_CONNECTIVITY hostConnectivity, uint32_t telemetryCounter) noexcept;
180
181 // protects access to member variables as well as operations that generate callback messages
182 // methods which lead to GNS messages being sent must maintain the order in which the caller invoked them
183 // thus exclusive access will be guaranteed for these methods, even if we don't need write-protection to member variables
184 mutable wil::srwlock m_networkLock;
185
186 // Member variables used to limit calls through UpdatePreferredEndpoint(UpdateEndpointFlag::Default) to every 350ms.
187 // This is because WslMirroredNetworkManager uses an eventing model where we will often see many 10s of events fired back-to-back
188 static constexpr uint32_t m_debounceUpdateAllEndpointsTimerMs = 350;
189 _Guarded_by_(m_networkLock) uint64_t m_lastUpdateAllEndpointsDefaultTime = 0;
190 bool m_IsDebounceUpdateAllEndpointsDefaultTimerSet = false;
191 _Requires_lock_held_(m_networkLock)
192 wil::unique_threadpool_timer m_debounceUpdateAllEndpointsDefaultTimer;
193 static void __stdcall DebounceUpdateAllEndpointsDefaultTimerFired(_Inout_ PTP_CALLBACK_INSTANCE, _Inout_opt_ PVOID Context, _Inout_ PTP_TIMER);
194
195 // Member variables tracking resiliency attempts to create endpoints in the container for indicated networkIds from HNS
196 static constexpr uint32_t m_maxAddEndpointRetryCount = 3;
197 static constexpr uint32_t m_debounceCreateEndpointFailureTimerMs = 1000;
198 _Requires_lock_held_(m_networkLock)
199 std::vector<EndpointTracking> m_failedEndpointProperties;
200 _Requires_lock_held_(m_networkLock)
201 wil::unique_threadpool_timer m_debounceCreateEndpointFailureTimer;
202 static void __stdcall DebounceCreateEndpointFailureTimerFired(_Inout_ PTP_CALLBACK_INSTANCE, _Inout_opt_ PVOID Context, _Inout_ PTP_TIMER);
203
204 // Member variables tracking the WinRT and COM networking APIs required
205 wsl::windows::common::helpers::unique_mta_cookie m_mtaCookie;
206 wil::com_ptr<ABI::Windows::Networking::Connectivity::INetworkInformationStatics> m_networkInformationStatics;
207 wil::com_ptr<INetworkListManager> m_netListManager;
208 wil::com_ptr<INetworkEvents> m_netListManagerEventSink;
209 WslCoreAdviseHandler m_netListManagerAdviseHandler;
210
211 _Guarded_by_(m_networkLock) HnsStatus m_latestHnsStatus { HnsStatus::NoNetworkEverConnected };
212
213 // Members tracking all endpoints created in the container, and the current networks connected
214 _Guarded_by_(m_networkLock) std::vector<NetworkEndpoint> m_networkEndpoints;
215 _Guarded_by_(m_networkLock) std::set<GUID, wsl::windows::common::helpers::GuidLess> m_hostConnectedInterfaces;
216
217 // Members tracking callback functors back through the parent
218 _Guarded_by_(m_networkLock) GnsMessageCallbackWithCallbackResult m_callbackForGnsMessage;
219 // the AddNetworkEndpointCallback is called through the m_gnsMessageQueue
220 // so we don't risk deadlocks if the callback chooses to call back into WslMirroredNetworkManager
221 _Guarded_by_(m_networkLock) AddNetworkEndpointCallback m_addNetworkEndpointCallback;
222
223 // The DNS info synced into the guest
224 _Guarded_by_(m_networkLock) DnsInfo m_trackedDnsInfo;
225 // The current DNS info on the host
226 _Guarded_by_(m_networkLock) DnsInfo m_dnsInfo;
227
228 std::wstring m_dnsTunnelingIpAddress;
229
230 // Tracks whether we are in the mirrored goal state or not.
231 _Guarded_by_(m_networkLock) wil::unique_event m_inMirroredGoalState { wil::EventOptions::ManualReset };
232
233 ConnectivityTelemetry m_connectivityTelemetry;
234
235 // Used for telemetry to see how long it takes to reach the mirrored goal state for the first time.
236 std::chrono::time_point<std::chrono::steady_clock> m_objectCreationTime = std::chrono::steady_clock::now();
237 std::chrono::time_point<std::chrono::steady_clock> m_initialMirroredGoalStateEndTime;
238
239 // Handle for the Hcn* Api. Owned by the caller (WslCoreVm), this is a non-owning copy
240 const HCS_SYSTEM m_hcsSystem{};
241
242 // Config of the WslCoreVm.
243 const Config& m_vmConfig;
244
245 // Ephemeral port range allocated for the VM.
246 std::pair<uint16_t, uint16_t> m_ephemeralPortRange;
247
248 // All guest related messages sent back through callbacks to Linux (GNS)
249 // must be queued in order into a single queue.
250 WslCoreMessageQueue m_gnsCallbackQueue;
251
252 // All host-configuration messages, either back to the parent MirroredNetworking or to HNS/HCS
253 // must have their own queue as to not be blocked by Linux messages.
254 WslCoreMessageQueue m_hnsQueue;
255
256 // Callback timer that is invoked when the HNS service goes down to attempt to re-establish contact
257 static void __stdcall HcnServiceConnectionTimerCallback(_Inout_ PTP_CALLBACK_INSTANCE, _Inout_opt_ PVOID Context, _Inout_ PTP_TIMER) noexcept;
258 wil::unique_threadpool_timer m_retryHcnServiceConnectionTimer;
259 _Guarded_by_(m_networkLock) DWORD m_retryHcnServiceConnectionDurationMs = 0;
260
261 // Callback that is invoked by HNS when a service-wide notification
262 // is available (e.g. when a HNS network is created or deleted).
263 static void __stdcall HcnCallback(_In_ DWORD NotificationType, _In_opt_ void* Context, _In_ HRESULT NotificationStatus, _In_opt_ PCWSTR NotificationData) noexcept;
264 windows::common::hcs::unique_hcn_service_callback m_hcnCallback;
265
266 _Guarded_by_(m_networkLock) State m_state { State::Stopped };
267
268 // Callback timer that is invoked when we want to retry syncing the latest Windows IP state with Linux
269 static void __stdcall RetryLinuxIpStateSyncTimerCallback(_Inout_ PTP_CALLBACK_INSTANCE, _Inout_opt_ PVOID Context, _Inout_ PTP_TIMER) noexcept;
270 wil::unique_threadpool_timer m_retryLinuxIpStateSyncTimer;
271 static constexpr uint32_t m_linuxIpStateRetryDebounceTimerMinMilliseconds = 100ul;
272 static constexpr uint32_t m_linuxIpStateRetryDebounceTimerMaxMilliseconds = 2000ul;
273 uint32_t m_linuxIpStateRetryDebounceTimerMilliseconds = m_linuxIpStateRetryDebounceTimerMinMilliseconds;
274
275 class PublicNLMSink final : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, INetworkEvents>
276 {
277 WslMirroredNetworkManager* m_parent{};
278
279 public:
280 explicit PublicNLMSink(WslMirroredNetworkManager* parent) : m_parent(parent)
281 {
282 }
283
284 ~PublicNLMSink() override = default;
285
286 PublicNLMSink(const PublicNLMSink&) = delete;
287 PublicNLMSink& operator=(const PublicNLMSink&) = delete;
288 PublicNLMSink(PublicNLMSink&&) = delete;
289 PublicNLMSink& operator=(PublicNLMSink&&) = delete;
290
291 // INetworkEvents
292 IFACEMETHODIMP NetworkAdded(GUID networkId) override
293 {
294 m_parent->UpdateAllEndpoints("INetworkEvents");
295 return S_OK;
296 }
297
298 IFACEMETHODIMP NetworkDeleted(GUID networkId) override
299 {
300 m_parent->UpdateAllEndpoints("INetworkEvents");
301 return S_OK;
302 }
303
304 IFACEMETHODIMP NetworkConnectivityChanged(GUID networkId, NLM_CONNECTIVITY connectivity) override
305 {
306 m_parent->UpdateAllEndpoints("INetworkEvents");
307 return S_OK;
308 }
309
310 IFACEMETHODIMP NetworkPropertyChanged(GUID networkId, NLM_NETWORK_PROPERTY_CHANGE property) override
311 {
312 m_parent->UpdateAllEndpoints("INetworkEvents");
313 return S_OK;
314 }
315 };
316 };
317
318 } // namespace wsl::core::networking