Skip to content

Commit f200689

Browse files
danzh2010danzh1989
andauthored
mobile: simplify ConnectivityManager interface (#40329)
Commit Message: decouple `DnsCache::UpdateCallbacks` and `ConnectivityManager` interface. Extract `DnsCache::UpdateCallbacks` implementation from `ConnectivityManagerImpl` into a stand-alone class `RefreshDnsWithPostDrainHandler` which is created and owned by `ConnectivityManagerImpl`. Also remove `clusterManager()` and `getUpstreamSocketOptions()` from `ConnectivityManager` interface. The caller of `clusterManager()` has other way to access the global cluster manager. `getUpstreamSocketOptions()` is only called inside of `ConnectivityManagerImpl`. Additional Description: a few refactories: Refactor `InternalEngine::handleNetworkChange()`; Rename `NetworkState` to `DefaultNetworkState` and move its member `mutex_` from the struct to its parent `ConnectivityManagerImpl` to guard the entire network_state_ and possibly more states of non-default networks in the future. Risk Level: low Testing: existing tests passed Docs Changes: N/A Release Notes: N/A Platform Specific Features: N/A --------- Signed-off-by: Dan Zhang <[email protected]> Co-authored-by: Dan Zhang <[email protected]>
1 parent 94d03f0 commit f200689

File tree

4 files changed

+136
-104
lines changed

4 files changed

+136
-104
lines changed

mobile/library/common/internal_engine.cc

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -415,26 +415,29 @@ void InternalEngine::handleNetworkChange(const int network_type, const bool has_
415415
}
416416
Http::HttpServerPropertiesCacheManager& cache_manager =
417417
server_->httpServerPropertiesCacheManager();
418-
419-
Http::HttpServerPropertiesCacheManager::CacheFn clear_brokenness =
420-
[](Http::HttpServerPropertiesCache& cache) { cache.resetBrokenness(); };
421-
cache_manager.forEachThreadLocalCache(clear_brokenness);
422418
if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.quic_no_tcp_delay")) {
423-
Http::HttpServerPropertiesCacheManager& cache_manager =
424-
server_->httpServerPropertiesCacheManager();
425-
419+
// Reset HTTP/3 status for all origins.
426420
Http::HttpServerPropertiesCacheManager::CacheFn reset_status =
427421
[](Http::HttpServerPropertiesCache& cache) { cache.resetStatus(); };
428422
cache_manager.forEachThreadLocalCache(reset_status);
423+
} else {
424+
// Reset HTTP/3 status only for origins marked as broken.
425+
Http::HttpServerPropertiesCacheManager::CacheFn clear_brokenness =
426+
[](Http::HttpServerPropertiesCache& cache) { cache.resetBrokenness(); };
427+
cache_manager.forEachThreadLocalCache(clear_brokenness);
429428
}
430-
if (!disable_dns_refresh_on_network_change_) {
431-
connectivity_manager_->refreshDns(configuration, /*drain_connections=*/true);
432-
} else if (Runtime::runtimeFeatureEnabled(
433-
"envoy.reloadable_features.drain_pools_on_network_change")) {
434-
ENVOY_LOG_EVENT(debug, "netconf_immediate_drain", "DrainAllHosts");
435-
connectivity_manager_->clusterManager().drainConnections(
436-
[](const Upstream::Host&) { return true; });
429+
430+
if (disable_dns_refresh_on_network_change_) {
431+
if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.drain_pools_on_network_change")) {
432+
// Since DNS refreshing is disabled, explicitly drain all connections.
433+
ENVOY_LOG_EVENT(debug, "netconf_immediate_drain", "DrainAllHosts");
434+
getClusterManager().drainConnections([](const Upstream::Host&) { return true; });
435+
}
436+
return;
437437
}
438+
// Refresh DNS upon network changes.
439+
// This call will possibly drain all connections asynchronously.
440+
connectivity_manager_->refreshDns(configuration, /*drain_connections=*/true);
438441
}
439442

440443
envoy_status_t InternalEngine::recordCounterInc(absl::string_view elements, envoy_stats_tags tags,

mobile/library/common/network/connectivity_manager.cc

Lines changed: 58 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <net/if.h>
44

5+
#include <memory>
6+
57
#include "envoy/common/platform.h"
68

79
#include "source/common/api/os_sys_calls_impl.h"
@@ -79,11 +81,13 @@ constexpr unsigned int InitialFaultThreshold = 1;
7981
// L7 bytes) before switching socket mode.
8082
constexpr unsigned int MaxFaultThreshold = 3;
8183

82-
ConnectivityManagerImpl::NetworkState ConnectivityManagerImpl::network_state_{
83-
1, 0, MaxFaultThreshold, SocketMode::DefaultPreferredNetworkMode, Thread::MutexBasicLockable{}};
84+
ConnectivityManagerImpl::DefaultNetworkState ConnectivityManagerImpl::network_state_{
85+
1, 0, MaxFaultThreshold, SocketMode::DefaultPreferredNetworkMode};
86+
87+
Thread::MutexBasicLockable ConnectivityManagerImpl::network_mutex_{};
8488

8589
envoy_netconf_t ConnectivityManagerImpl::setPreferredNetwork(int network) {
86-
Thread::LockGuard lock{network_state_.mutex_};
90+
Thread::LockGuard lock{network_mutex_};
8791

8892
// TODO(goaway): Re-enable this guard. There's some concern that this will miss network updates
8993
// moving from offline to online states. We should address this then re-enable this guard to
@@ -120,17 +124,17 @@ void ConnectivityManagerImpl::setProxySettings(ProxySettingsConstSharedPtr new_p
120124
ProxySettingsConstSharedPtr ConnectivityManagerImpl::getProxySettings() { return proxy_settings_; }
121125

122126
int ConnectivityManagerImpl::getPreferredNetwork() {
123-
Thread::LockGuard lock{network_state_.mutex_};
127+
Thread::LockGuard lock{network_mutex_};
124128
return network_state_.network_;
125129
}
126130

127131
SocketMode ConnectivityManagerImpl::getSocketMode() {
128-
Thread::LockGuard lock{network_state_.mutex_};
132+
Thread::LockGuard lock{network_mutex_};
129133
return network_state_.socket_mode_;
130134
}
131135

132136
envoy_netconf_t ConnectivityManagerImpl::getConfigurationKey() {
133-
Thread::LockGuard lock{network_state_.mutex_};
137+
Thread::LockGuard lock{network_mutex_};
134138
return network_state_.configuration_key_;
135139
}
136140

@@ -152,7 +156,7 @@ void ConnectivityManagerImpl::reportNetworkUsage(envoy_netconf_t configuration_k
152156

153157
bool configuration_updated = false;
154158
{
155-
Thread::LockGuard lock{network_state_.mutex_};
159+
Thread::LockGuard lock{network_mutex_};
156160

157161
// If the configuration_key isn't current, don't do anything.
158162
if (configuration_key != network_state_.configuration_key_) {
@@ -200,40 +204,55 @@ void ConnectivityManagerImpl::reportNetworkUsage(envoy_netconf_t configuration_k
200204
}
201205
}
202206

203-
void ConnectivityManagerImpl::onDnsResolutionComplete(
207+
void RefreshDnsWithPostDrainHandler::refreshDnsAndDrainHosts() {
208+
Extensions::Common::DynamicForwardProxy::DnsCacheSharedPtr dns_cache =
209+
dns_cache_manager_->lookUpCacheByName(BaseDnsCache);
210+
if (!dns_cache) {
211+
// There may not be a DNS cache during initialization, but if one is available, it should always
212+
// exist by the time this handler is instantiated from the NetworkConfigurationFilter.
213+
ENVOY_LOG_EVENT(warn, "netconf_dns_cache_missing", "{}", std::string(BaseDnsCache));
214+
return;
215+
}
216+
if (dns_callbacks_handle_ == nullptr) {
217+
// Register callbacks once, on demand, using the handler as a sentinel.
218+
dns_callbacks_handle_ = dns_cache->addUpdateCallbacks(*this);
219+
}
220+
dns_cache->iterateHostMap(
221+
[&](absl::string_view host,
222+
const Extensions::Common::DynamicForwardProxy::DnsHostInfoSharedPtr&) {
223+
hosts_to_drain_.emplace(host);
224+
});
225+
226+
dns_cache->forceRefreshHosts();
227+
}
228+
229+
void RefreshDnsWithPostDrainHandler::onDnsResolutionComplete(
204230
const std::string& resolved_host,
205231
const Extensions::Common::DynamicForwardProxy::DnsHostInfoSharedPtr&,
206232
Network::DnsResolver::ResolutionStatus) {
207-
if (enable_drain_post_dns_refresh_) {
208-
// Check if the set of hosts pending drain contains the current resolved host.
209-
if (hosts_to_drain_.erase(resolved_host) == 0) {
210-
return;
211-
}
233+
// Check if the set of hosts pending drain contains the current resolved host.
234+
if (hosts_to_drain_.erase(resolved_host) == 0) {
235+
return;
236+
}
212237

213-
// We ignore whether DNS resolution has succeeded here. If it failed, we may be offline and
214-
// should probably drain connections. If it succeeds, we may have new DNS entries and so we
215-
// drain connections. It may be possible to refine this logic in the future.
216-
// TODO(goaway): check the set of cached hosts from the last triggered DNS refresh for this
217-
// host, and if present, remove it and trigger connection drain for this host specifically.
218-
ENVOY_LOG_EVENT(debug, "netconf_post_dns_drain_cx", "{}", resolved_host);
238+
// We ignore whether DNS resolution has succeeded here. If it failed, we may be offline and
239+
// should probably drain connections. If it succeeds, we may have new DNS entries and so we
240+
// drain connections. It may be possible to refine this logic in the future.
241+
// TODO(goaway): check the set of cached hosts from the last triggered DNS refresh for this
242+
// host, and if present, remove it and trigger connection drain for this host specifically.
243+
ENVOY_LOG_EVENT(debug, "netconf_post_dns_drain_cx", "{}", resolved_host);
219244

220-
// Pass predicate to only drain connections to the resolved host (for any cluster).
221-
cluster_manager_.drainConnections(
222-
[resolved_host](const Upstream::Host& host) { return host.hostname() == resolved_host; });
223-
}
245+
// Pass predicate to only drain connections to the resolved host (for any cluster).
246+
cluster_manager_.drainConnections(
247+
[resolved_host](const Upstream::Host& host) { return host.hostname() == resolved_host; });
224248
}
225249

226250
void ConnectivityManagerImpl::setDrainPostDnsRefreshEnabled(bool enabled) {
227-
enable_drain_post_dns_refresh_ = enabled;
228251
if (!enabled) {
229-
hosts_to_drain_.clear();
230-
} else if (!dns_callbacks_handle_) {
231-
// Register callbacks once, on demand, using the handle as a sentinel. There may not be
232-
// a DNS cache during initialization, but if one is available, it should always exist by the
233-
// time this function is called from the NetworkConfigurationFilter.
234-
if (auto dns_cache = dnsCache()) {
235-
dns_callbacks_handle_ = dns_cache->addUpdateCallbacks(*this);
236-
}
252+
dns_refresh_handler_ = nullptr;
253+
} else if (!dns_refresh_handler_) {
254+
dns_refresh_handler_ =
255+
std::make_unique<RefreshDnsWithPostDrainHandler>(dns_cache_manager_, cluster_manager_);
237256
}
238257
}
239258

@@ -244,7 +263,7 @@ void ConnectivityManagerImpl::setInterfaceBindingEnabled(bool enabled) {
244263
void ConnectivityManagerImpl::refreshDns(envoy_netconf_t configuration_key,
245264
bool drain_connections) {
246265
{
247-
Thread::LockGuard lock{network_state_.mutex_};
266+
Thread::LockGuard lock{network_mutex_};
248267

249268
// refreshDns must be queued on Envoy's event loop, whereas network_state_ is updated
250269
// synchronously. In the event that multiple refreshes become queued on the event loop,
@@ -260,15 +279,11 @@ void ConnectivityManagerImpl::refreshDns(envoy_netconf_t configuration_key,
260279
if (auto dns_cache = dnsCache()) {
261280
ENVOY_LOG_EVENT(debug, "netconf_refresh_dns", "{}", std::to_string(configuration_key));
262281

263-
if (drain_connections && enable_drain_post_dns_refresh_) {
264-
dns_cache->iterateHostMap(
265-
[&](absl::string_view host,
266-
const Extensions::Common::DynamicForwardProxy::DnsHostInfoSharedPtr&) {
267-
hosts_to_drain_.emplace(host);
268-
});
282+
if (drain_connections && (dns_refresh_handler_ != nullptr)) {
283+
dns_refresh_handler_->refreshDnsAndDrainHosts();
284+
} else {
285+
dns_cache->forceRefreshHosts();
269286
}
270-
271-
dns_cache->forceRefreshHosts();
272287
}
273288
}
274289

@@ -283,7 +298,7 @@ Extensions::Common::DynamicForwardProxy::DnsCacheSharedPtr ConnectivityManagerIm
283298
void ConnectivityManagerImpl::resetConnectivityState() {
284299
envoy_netconf_t configuration_key;
285300
{
286-
Thread::LockGuard lock{network_state_.mutex_};
301+
Thread::LockGuard lock{network_mutex_};
287302
network_state_.network_ = 0;
288303
network_state_.remaining_faults_ = 1;
289304
network_state_.socket_mode_ = SocketMode::DefaultPreferredNetworkMode;
@@ -359,7 +374,7 @@ ConnectivityManagerImpl::addUpstreamSocketOptions(Socket::OptionsSharedPtr optio
359374
SocketMode socket_mode;
360375

361376
{
362-
Thread::LockGuard lock{network_state_.mutex_};
377+
Thread::LockGuard lock{network_mutex_};
363378
configuration_key = network_state_.configuration_key_;
364379
network = network_state_.network_;
365380
socket_mode = network_state_.socket_mode_;

mobile/library/common/network/connectivity_manager.h

Lines changed: 47 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@ using InterfacePair = std::pair<const std::string, Address::InstanceConstSharedP
7878
* if that cache is missing either due to alternate configurations, or lifecycle-related timing.
7979
*
8080
*/
81-
class ConnectivityManager
82-
: public Extensions::Common::DynamicForwardProxy::DnsCache::UpdateCallbacks {
81+
class ConnectivityManager {
8382
public:
8483
virtual ~ConnectivityManager() = default;
8584

@@ -168,13 +167,10 @@ class ConnectivityManager
168167
virtual void resetConnectivityState() PURE;
169168

170169
/**
171-
* @returns the current socket options that should be used for connections.
172-
*/
173-
virtual Socket::OptionsSharedPtr getUpstreamSocketOptions(int network,
174-
SocketMode socket_mode) PURE;
175-
176-
/**
177-
* @param options, upstream connection options to which additional options should be appended.
170+
* Add socket options to be applied to the upstream connection which could
171+
* potentially affect which network interface the requests will be sent on.
172+
* @param options, upstream connection options to which additional options relate to the current
173+
* network states should be appended.
178174
* @returns configuration key to associate with any related calls.
179175
*/
180176
virtual envoy_netconf_t addUpstreamSocketOptions(Socket::OptionsSharedPtr options) PURE;
@@ -187,11 +183,38 @@ class ConnectivityManager
187183
* @returns the default DNS cache set up in base configuration or nullptr.
188184
*/
189185
virtual Extensions::Common::DynamicForwardProxy::DnsCacheSharedPtr dnsCache() PURE;
186+
};
190187

191-
/**
192-
* Returns the cluster manager for this Envoy Mobile instance
193-
*/
194-
virtual Upstream::ClusterManager& clusterManager() PURE;
188+
// Used when draining hosts upon DNS refreshing is desired.
189+
class RefreshDnsWithPostDrainHandler
190+
: public Extensions::Common::DynamicForwardProxy::DnsCache::UpdateCallbacks,
191+
public Logger::Loggable<Logger::Id::upstream> {
192+
public:
193+
RefreshDnsWithPostDrainHandler(DnsCacheManagerSharedPtr dns_cache_manager,
194+
Upstream::ClusterManager& cluster_manager)
195+
: dns_cache_manager_(std::move(dns_cache_manager)), cluster_manager_(cluster_manager) {}
196+
197+
// Extensions::Common::DynamicForwardProxy::DnsCache::UpdateCallbacks
198+
absl::Status onDnsHostAddOrUpdate(
199+
const std::string& /*host*/,
200+
const Extensions::Common::DynamicForwardProxy::DnsHostInfoSharedPtr&) override {
201+
return absl::OkStatus();
202+
}
203+
void onDnsHostRemove(const std::string& /*host*/) override {}
204+
void onDnsResolutionComplete(const std::string& /*host*/,
205+
const Extensions::Common::DynamicForwardProxy::DnsHostInfoSharedPtr&,
206+
Network::DnsResolver::ResolutionStatus) override;
207+
208+
// Refresh DNS and drain all hosts upon completion.
209+
// No-op if the default DNS cache in base configuration is not available.
210+
void refreshDnsAndDrainHosts();
211+
212+
private:
213+
DnsCacheManagerSharedPtr dns_cache_manager_;
214+
Upstream::ClusterManager& cluster_manager_;
215+
absl::flat_hash_set<std::string> hosts_to_drain_;
216+
Extensions::Common::DynamicForwardProxy::DnsCache::AddUpdateCallbacksHandlePtr
217+
dns_callbacks_handle_;
195218
};
196219

197220
class ConnectivityManagerImpl : public ConnectivityManager,
@@ -210,17 +233,6 @@ class ConnectivityManagerImpl : public ConnectivityManager,
210233
DnsCacheManagerSharedPtr dns_cache_manager)
211234
: cluster_manager_(cluster_manager), dns_cache_manager_(dns_cache_manager) {}
212235

213-
// Extensions::Common::DynamicForwardProxy::DnsCache::UpdateCallbacks
214-
absl::Status onDnsHostAddOrUpdate(
215-
const std::string& /*host*/,
216-
const Extensions::Common::DynamicForwardProxy::DnsHostInfoSharedPtr&) override {
217-
return absl::OkStatus();
218-
}
219-
void onDnsHostRemove(const std::string& /*host*/) override {}
220-
void onDnsResolutionComplete(const std::string& /*host*/,
221-
const Extensions::Common::DynamicForwardProxy::DnsHostInfoSharedPtr&,
222-
Network::DnsResolver::ResolutionStatus) override;
223-
224236
// ConnectivityManager
225237
std::vector<InterfacePair> enumerateV4Interfaces() override;
226238
std::vector<InterfacePair> enumerateV6Interfaces() override;
@@ -236,33 +248,31 @@ class ConnectivityManagerImpl : public ConnectivityManager,
236248
void setInterfaceBindingEnabled(bool enabled) override;
237249
void refreshDns(envoy_netconf_t configuration_key, bool drain_connections) override;
238250
void resetConnectivityState() override;
239-
Socket::OptionsSharedPtr getUpstreamSocketOptions(int network, SocketMode socket_mode) override;
240251
envoy_netconf_t addUpstreamSocketOptions(Socket::OptionsSharedPtr options) override;
241252
Extensions::Common::DynamicForwardProxy::DnsCacheSharedPtr dnsCache() override;
242-
Upstream::ClusterManager& clusterManager() override { return cluster_manager_; }
243253

244254
private:
245-
struct NetworkState {
255+
// The states of the current default network picked by the platform.
256+
struct DefaultNetworkState {
246257
// The configuration key is passed through calls dispatched on the run loop to determine if
247258
// they're still valid/relevant at time of execution.
248-
envoy_netconf_t configuration_key_ ABSL_GUARDED_BY(mutex_);
249-
int network_ ABSL_GUARDED_BY(mutex_);
250-
uint8_t remaining_faults_ ABSL_GUARDED_BY(mutex_);
251-
SocketMode socket_mode_ ABSL_GUARDED_BY(mutex_);
252-
Thread::MutexBasicLockable mutex_;
259+
envoy_netconf_t configuration_key_;
260+
int network_;
261+
uint8_t remaining_faults_;
262+
SocketMode socket_mode_;
253263
};
254264
Socket::OptionsSharedPtr getAlternateInterfaceSocketOptions(int network);
255265
InterfacePair getActiveAlternateInterface(int network, unsigned short family);
266+
Socket::OptionsSharedPtr getUpstreamSocketOptions(int network, SocketMode socket_mode);
256267

257-
bool enable_drain_post_dns_refresh_{false};
258268
bool enable_interface_binding_{false};
259-
absl::flat_hash_set<std::string> hosts_to_drain_;
260-
Extensions::Common::DynamicForwardProxy::DnsCache::AddUpdateCallbacksHandlePtr
261-
dns_callbacks_handle_{nullptr};
262269
Upstream::ClusterManager& cluster_manager_;
270+
// nullptr if draining hosts after refreshing DNS is disabled via setDrainPostDnsRefreshEnabled().
271+
std::unique_ptr<RefreshDnsWithPostDrainHandler> dns_refresh_handler_;
263272
DnsCacheManagerSharedPtr dns_cache_manager_;
264273
ProxySettingsConstSharedPtr proxy_settings_;
265-
static NetworkState network_state_;
274+
static DefaultNetworkState network_state_ ABSL_GUARDED_BY(network_mutex_);
275+
static Thread::MutexBasicLockable network_mutex_;
266276
};
267277

268278
using ConnectivityManagerSharedPtr = std::shared_ptr<ConnectivityManager>;

0 commit comments

Comments
 (0)