master
h 287 lines 9.67 KB
Raw
1 // Copyright (C) Microsoft Corporation. All rights reserved.
2
3 #pragma once
4 #include "WslCoreNetworkEndpointSettings.h"
5 #include "WslCoreHostDnsInfo.h"
6
7 namespace wsl::core::networking {
8 enum class TrackedIpStateSyncStatus
9 {
10 PendingAdd,
11 PendingUpdate,
12 PendingRemoval,
13 Synced
14 };
15 constexpr auto ToString(networking::TrackedIpStateSyncStatus status) noexcept
16 {
17 switch (status)
18 {
19 case networking::TrackedIpStateSyncStatus::PendingAdd:
20 return "PendingAdd";
21 case networking::TrackedIpStateSyncStatus::PendingUpdate:
22 return "PendingUpdate";
23 case networking::TrackedIpStateSyncStatus::PendingRemoval:
24 return "PendingRemoval";
25 case networking::TrackedIpStateSyncStatus::Synced:
26 return "Synced";
27 default:
28 return "Unknown";
29 }
30 }
31
32 struct TrackedIpAddress
33 {
34 EndpointIpAddress Address{};
35
36 // The following fields need to be changed from a std::set iterator (which is always const)
37 // in SyncIpStateWithLinux - that's why they're marked mutable.
38 mutable TrackedIpStateSyncStatus SyncStatus = TrackedIpStateSyncStatus::PendingAdd;
39 mutable uint32_t SyncRetryCount = MaxSyncRetryCount;
40 mutable uint32_t LoopbackSyncRetryCount = MaxLoopbackSyncRetryCount;
41
42 static constexpr uint32_t MaxSyncRetryCount = 15;
43 static constexpr uint32_t MaxLoopbackSyncRetryCount = 5;
44
45 TrackedIpAddress() = default;
46 ~TrackedIpAddress() noexcept = default;
47
48 // not copyable to avoid subtle bugs where 2 objects are trying to track state of the same address
49 TrackedIpAddress(const TrackedIpAddress&) = delete;
50 TrackedIpAddress& operator=(const TrackedIpAddress&) = delete;
51 TrackedIpAddress(TrackedIpAddress&&) = default;
52 TrackedIpAddress& operator=(TrackedIpAddress&&) = default;
53
54 explicit TrackedIpAddress(const EndpointIpAddress& other)
55 {
56 Address = other;
57 }
58
59 TrackedIpAddress& operator=(const EndpointIpAddress& other)
60 {
61 Address = other;
62 SyncStatus = TrackedIpStateSyncStatus::PendingAdd;
63 SyncRetryCount = MaxSyncRetryCount;
64 LoopbackSyncRetryCount = MaxLoopbackSyncRetryCount;
65 return *this;
66 }
67
68 wsl::shared::hns::IPAddress ConvertToHnsSettingsMsg() const
69 {
70 wsl::shared::hns::IPAddress addr{};
71 addr.Family = Address.Address.si_family;
72 addr.Address = Address.AddressString;
73 addr.OnLinkPrefixLength = Address.PrefixLength;
74 addr.PreferredLifetime = Address.PreferredLifetime;
75 addr.PrefixOrigin = Address.PrefixOrigin;
76 addr.SuffixOrigin = Address.SuffixOrigin;
77 return addr;
78 }
79
80 bool operator==(const TrackedIpAddress& other) const noexcept
81 {
82 return Address == other.Address;
83 }
84
85 bool operator!=(const TrackedIpAddress& other) const noexcept
86 {
87 return !(*this == other);
88 }
89
90 bool operator<(const TrackedIpAddress& other) const noexcept
91 {
92 return Address < other.Address;
93 }
94 };
95
96 struct TrackedRoute
97 {
98 EndpointRoute Route{};
99
100 // The following fields need to be changed from a std::set iterator (which is always const)
101 // in SyncIpStateWithLinux - that's why they're marked mutable.
102 mutable TrackedIpStateSyncStatus SyncStatus = TrackedIpStateSyncStatus::PendingAdd;
103 mutable uint32_t SyncRetryCount = MaxSyncRetryCount;
104 mutable bool LinuxConflictRemoved = false; // only used for prefix routes
105
106 static constexpr uint32_t MaxSyncRetryCount = 15;
107
108 TrackedRoute() = default;
109 ~TrackedRoute() noexcept = default;
110
111 // not copyable to avoid subtle bugs where 2 objects are trying to track state of the same route
112 TrackedRoute(const TrackedRoute&) = delete;
113 TrackedRoute& operator=(const TrackedRoute&) = delete;
114 TrackedRoute(TrackedRoute&&) = default;
115 TrackedRoute& operator=(TrackedRoute&&) = default;
116
117 explicit TrackedRoute(const EndpointRoute& other)
118 {
119 Route = other;
120 }
121
122 TrackedRoute& operator=(const EndpointRoute& other)
123 {
124 Route = other;
125 SyncStatus = TrackedIpStateSyncStatus::PendingAdd;
126 SyncRetryCount = MaxSyncRetryCount;
127 LinuxConflictRemoved = false;
128 return *this;
129 }
130
131 unsigned int LinuxAutoGenRouteMetric() const
132 {
133 return (Route.Family == AF_INET6) ? 1024 : 0;
134 }
135
136 bool CanConflictWithLinuxAutoGenRoute() const
137 {
138 return Route.IsAutoGeneratedPrefixRoute && (Route.Metric != LinuxAutoGenRouteMetric());
139 }
140
141 wsl::shared::hns::Route ConvertToHnsSettingsMsg() const
142 {
143 wsl::shared::hns::Route route{};
144 route.Family = Route.Family;
145 route.DestinationPrefix = Route.GetFullDestinationPrefix();
146 route.SitePrefixLength = Route.SitePrefixLength;
147 route.NextHop = Route.NextHopString;
148 route.Metric = Route.Metric;
149 return route;
150 }
151
152 bool operator==(const TrackedRoute& other) const noexcept
153 {
154 return Route == other.Route;
155 }
156
157 bool operator!=(const TrackedRoute& other) const noexcept
158 {
159 return !(*this == other);
160 }
161
162 bool operator<(const TrackedRoute& other) const noexcept
163 {
164 const auto routeClass = [](const EndpointRoute& route) noexcept {
165 if (route.IsAutoGeneratedPrefixRoute)
166 {
167 return 0;
168 }
169
170 return route.IsNextHopOnlink() ? 1 : 2;
171 };
172
173 const auto thisRouteClass = routeClass(Route);
174 const auto otherRouteClass = routeClass(other.Route);
175 if (thisRouteClass != otherRouteClass)
176 {
177 return thisRouteClass < otherRouteClass;
178 }
179
180 return Route < other.Route;
181 }
182 };
183
184 struct IpStateTracking
185 {
186 bool InitialSyncComplete = false;
187
188 GUID InterfaceGuid{};
189 std::set<TrackedIpAddress> IpAddresses{};
190 std::set<TrackedRoute> Routes{};
191 std::vector<std::wstring> DnsServers{};
192 // currently DnsServersSyncStatus is only tracked for tracing purposes - it's not being set through Linux
193 TrackedIpStateSyncStatus DnsServersSyncStatus = TrackedIpStateSyncStatus::PendingAdd;
194 DnsInfo DnsInfo{};
195 ULONG InterfaceMtu = 0;
196 bool IsMetered = false;
197
198 IpStateTracking() = default;
199 IpStateTracking(const std::optional<GUID>& vmCreatorId) : FirewallVmCreatorId(vmCreatorId)
200 {
201 }
202
203 ~IpStateTracking() noexcept
204 {
205 if (FirewallVmCreatorId)
206 {
207 ResetState();
208 }
209 }
210
211 // cannot copy - the d'tor clears FW rules so move-operators must track when moved-from
212 // it does this by clearing the std::optional FirewallVmCreatorId when moved-from
213 IpStateTracking(const IpStateTracking&) = delete;
214 IpStateTracking& operator=(const IpStateTracking&) = delete;
215
216 IpStateTracking(IpStateTracking&& lhs) noexcept :
217 InitialSyncComplete(std::move(lhs.InitialSyncComplete)),
218 InterfaceGuid(std::move(lhs.InterfaceGuid)),
219 IpAddresses(std::move(lhs.IpAddresses)),
220 Routes(std::move(lhs.Routes)),
221 InterfaceMtu(std::move(lhs.InterfaceMtu)),
222 IsMetered(std::move(lhs.IsMetered)),
223 FirewallVmCreatorId(std::move(lhs.FirewallVmCreatorId)),
224 FirewallTrackedIpAddresses(std::move(lhs.FirewallTrackedIpAddresses))
225 {
226 // must reset FirewallVmCreatorId so the d'tor won't reset FW state from the moved-from object
227 lhs.FirewallVmCreatorId.reset();
228 }
229
230 IpStateTracking& operator=(IpStateTracking&& lhs) noexcept
231 {
232 InterfaceGuid = std::move(lhs.InterfaceGuid);
233 IpAddresses = std::move(lhs.IpAddresses);
234 Routes = std::move(lhs.Routes);
235 InterfaceMtu = std::move(lhs.InterfaceMtu);
236 IsMetered = std::move(lhs.IsMetered);
237 InitialSyncComplete = std::move(lhs.InitialSyncComplete);
238 FirewallVmCreatorId = std::move(lhs.FirewallVmCreatorId);
239 FirewallTrackedIpAddresses = std::move(lhs.FirewallTrackedIpAddresses);
240
241 // must reset FirewallVmCreatorId so the d'tor won't reset FW state from the moved-from object
242 lhs.FirewallVmCreatorId.reset();
243
244 return *this;
245 }
246
247 void ResetState() noexcept
248 {
249 WSL_LOG("IpStateTracking::ResetState");
250 InitialSyncComplete = false;
251 InterfaceGuid = {};
252 IpAddresses.clear();
253 Routes.clear();
254 DnsServers.clear();
255 DnsServersSyncStatus = TrackedIpStateSyncStatus::PendingAdd;
256 InterfaceMtu = 0;
257 IsMetered = false;
258 SyncFirewallState({});
259 }
260
261 void SeedInitialState(const NetworkSettings& settings) noexcept
262 {
263 InterfaceGuid = settings.InterfaceGuid;
264 InterfaceMtu = settings.GetEffectiveMtu();
265 IsMetered = settings.IsMetered;
266
267 WSL_LOG(
268 "IpStateTracking::SeedInitialState",
269 TraceLoggingValue(InterfaceGuid, "InterfaceGuid"),
270 TraceLoggingValue(InterfaceMtu, "InterfaceMtu"),
271 TraceLoggingValue(IsMetered, "IsMetered"),
272 TraceLoggingValue(IpAddresses.size(), "IpAddresses.size()"),
273 TraceLoggingValue(Routes.size(), "Routes.size()"),
274 TraceLoggingValue(FirewallVmCreatorId.value_or(GUID{}), "FirewallVmCreatorId"));
275
276 // not updating any other fields in this SeedInitialState
277 // Address/Route/DnsServer objects are cleared when disconnected
278 // and updated as we confirm they are pushed to the container
279 }
280
281 void SyncFirewallState(const NetworkSettings& preferredNetwork) noexcept;
282
283 private:
284 std::optional<GUID> FirewallVmCreatorId{};
285 std::set<EndpointIpAddress> FirewallTrackedIpAddresses{};
286 };
287 } // namespace wsl::core::networking