diff --git a/envoy/config/extension_config_provider.h b/envoy/config/extension_config_provider.h index 6524f10270881..ce84225eb6236 100644 --- a/envoy/config/extension_config_provider.h +++ b/envoy/config/extension_config_provider.h @@ -35,9 +35,10 @@ template class ExtensionConfigProvider { virtual absl::optional config() PURE; }; -template -class DynamicExtensionConfigProvider : public ExtensionConfigProvider { +template class DynamicExtensionConfigProviderBase { public: + virtual ~DynamicExtensionConfigProviderBase() = default; + /** * Update the provider with a new configuration. * @param config is an extension factory callback to replace the existing configuration. @@ -59,5 +60,9 @@ class DynamicExtensionConfigProvider : public ExtensionConfigProvider +class DynamicExtensionConfigProvider : public DynamicExtensionConfigProviderBase, + public ExtensionConfigProvider {}; + } // namespace Config } // namespace Envoy diff --git a/source/common/filter/config_discovery_impl.cc b/source/common/filter/config_discovery_impl.cc index f472d157761a1..a88074f30490c 100644 --- a/source/common/filter/config_discovery_impl.cc +++ b/source/common/filter/config_discovery_impl.cc @@ -28,84 +28,42 @@ void validateTypeUrlHelper(const std::string& type_url, } // namespace -DynamicFilterConfigProviderImpl::DynamicFilterConfigProviderImpl( +DynamicFilterConfigProviderImplBase::DynamicFilterConfigProviderImplBase( FilterConfigSubscriptionSharedPtr& subscription, - const absl::flat_hash_set& require_type_urls, - - Server::Configuration::FactoryContext& factory_context, - Envoy::Http::FilterFactoryCb default_config, bool last_filter_in_filter_chain, + const absl::flat_hash_set& require_type_urls, bool last_filter_in_filter_chain, const std::string& filter_chain_type) : subscription_(subscription), require_type_urls_(require_type_urls), - default_configuration_(default_config ? absl::make_optional(default_config) : absl::nullopt), - tls_(factory_context.threadLocal()), init_target_("DynamicFilterConfigProviderImpl", - [this]() { - subscription_->start(); - // This init target is used to activate - // the subscription but not wait for a - // response. It is used whenever a default - // config is provided to be used while - // waiting for a response. - init_target_.ready(); - }), + init_target_("DynamicFilterConfigProviderImpl", + [this]() { + subscription_->start(); + // This init target is used to activate the subscription but not wait for a + // response. It is used whenever a default config is provided to be used while + // waiting for a response. + init_target_.ready(); + }), last_filter_in_filter_chain_(last_filter_in_filter_chain), filter_chain_type_(filter_chain_type) { subscription_->filter_config_providers_.insert(this); - tls_.set([](Event::Dispatcher&) { return std::make_shared(); }); } -DynamicFilterConfigProviderImpl::~DynamicFilterConfigProviderImpl() { +DynamicFilterConfigProviderImplBase::~DynamicFilterConfigProviderImplBase() { subscription_->filter_config_providers_.erase(this); } -void DynamicFilterConfigProviderImpl::validateTypeUrl(const std::string& type_url) const { +void DynamicFilterConfigProviderImplBase::validateTypeUrl(const std::string& type_url) const { validateTypeUrlHelper(type_url, require_type_urls_); } -const std::string& DynamicFilterConfigProviderImpl::name() { return subscription_->name(); } - -absl::optional DynamicFilterConfigProviderImpl::config() { - return tls_->config_; -} - -void DynamicFilterConfigProviderImpl::onConfigUpdate(Envoy::Http::FilterFactoryCb config, - const std::string&, - Config::ConfigAppliedCb cb) { - tls_.runOnAllThreads( - [config, cb](OptRef tls) { - tls->config_ = config; - if (cb) { - cb(); - } - }, - [this, config]() { - // This happens after all workers have discarded the previous config so it can be safely - // deleted on the main thread by an update with the new config. - this->current_config_ = config; - }); -} +const std::string& DynamicFilterConfigProviderImplBase::name() { return subscription_->name(); } -void DynamicFilterConfigProviderImpl::validateTerminalFilter(const std::string& name, - const std::string& filter_type, - bool is_terminal_filter) { +void DynamicFilterConfigProviderImplBase::validateTerminalFilter(const std::string& name, + const std::string& filter_type, + bool is_terminal_filter) { Config::Utility::validateTerminalFilters(name, filter_type, filter_chain_type_, is_terminal_filter, last_filter_in_filter_chain_); } -void DynamicFilterConfigProviderImpl::onConfigRemoved( - Config::ConfigAppliedCb applied_on_all_threads) { - tls_.runOnAllThreads( - [config = default_configuration_](OptRef tls) { tls->config_ = config; }, - [this, applied_on_all_threads]() { - // This happens after all workers have discarded the previous config so it can be safely - // deleted on the main thread by an update with the new config. - this->current_config_ = default_configuration_; - if (applied_on_all_threads) { - applied_on_all_threads(); - } - }); -} - FilterConfigSubscription::FilterConfigSubscription( const envoy::config::core::v3::ConfigSource& config_source, const std::string& filter_config_name, Server::Configuration::FactoryContext& factory_context, @@ -178,9 +136,9 @@ void FilterConfigSubscription::onConfigUpdate( factory.createFilterFactoryFromProto(*message, stat_prefix_, factory_context_); ENVOY_LOG(debug, "Updating filter config {}", filter_config_name_); - Common::applyToAllWithCleanup( + Common::applyToAllWithCleanup( filter_config_providers_, - [&factory_callback, &version_info](DynamicFilterConfigProviderImpl* provider, + [&factory_callback, &version_info](DynamicFilterConfigProviderImplBase* provider, std::shared_ptr cleanup) { provider->onConfigUpdate(factory_callback, version_info, [cleanup] {}); }, @@ -199,9 +157,9 @@ void FilterConfigSubscription::onConfigUpdate( if (!removed_resources.empty()) { ASSERT(removed_resources.size() == 1); ENVOY_LOG(debug, "Removing filter config {}", filter_config_name_); - Common::applyToAllWithCleanup( + Common::applyToAllWithCleanup( filter_config_providers_, - [](DynamicFilterConfigProviderImpl* provider, std::shared_ptr cleanup) { + [](DynamicFilterConfigProviderImplBase* provider, std::shared_ptr cleanup) { provider->onConfigRemoved([cleanup] {}); }, [this]() { stats_.config_reload_.inc(); }); @@ -304,7 +262,7 @@ DynamicFilterConfigProviderPtr FilterConfigProviderManagerImpl::createDynamicFil // Ensure the subscription starts if it has not already. if (config_source.apply_default_config_without_warming()) { - factory_context.initManager().add(provider->init_target_); + factory_context.initManager().add(provider->initTarget()); } // If the subscription already received a config, attempt to apply it. diff --git a/source/common/filter/config_discovery_impl.h b/source/common/filter/config_discovery_impl.h index 7be2509d69b00..2c550fd3faa62 100644 --- a/source/common/filter/config_discovery_impl.h +++ b/source/common/filter/config_discovery_impl.h @@ -28,31 +28,92 @@ class FilterConfigSubscription; using FilterConfigSubscriptionSharedPtr = std::shared_ptr; +/** + * Base class for a filter config provider using discovery subscriptions. + **/ +class DynamicFilterConfigProviderImplBase + : public Config::DynamicExtensionConfigProviderBase { +public: + DynamicFilterConfigProviderImplBase(FilterConfigSubscriptionSharedPtr& subscription, + const absl::flat_hash_set& require_type_urls, + bool last_filter_in_filter_chain, + const std::string& filter_chain_type); + + ~DynamicFilterConfigProviderImplBase() override; + const Init::Target& initTarget() const { return init_target_; } + + void validateTypeUrl(const std::string& type_url) const; + void validateTerminalFilter(const std::string& name, const std::string& filter_type, + bool is_terminal_filter); + + const std::string& name(); + +private: + FilterConfigSubscriptionSharedPtr subscription_; + const absl::flat_hash_set require_type_urls_; + + // Local initialization target to ensure that the subscription starts in + // case no warming is requested by any other filter config provider. + Init::TargetImpl init_target_; + + const bool last_filter_in_filter_chain_; + const std::string filter_chain_type_; +}; + /** * Implementation of a filter config provider using discovery subscriptions. **/ -class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProvider { +class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProviderImplBase, + public DynamicFilterConfigProvider { public: DynamicFilterConfigProviderImpl(FilterConfigSubscriptionSharedPtr& subscription, const absl::flat_hash_set& require_type_urls, Server::Configuration::FactoryContext& factory_context, Envoy::Http::FilterFactoryCb default_config, bool last_filter_in_filter_chain, - const std::string& filter_chain_type); - - ~DynamicFilterConfigProviderImpl() override; + const std::string& filter_chain_type) + : DynamicFilterConfigProviderImplBase(subscription, require_type_urls, + last_filter_in_filter_chain, filter_chain_type), + default_configuration_(default_config ? absl::make_optional(default_config) + : absl::nullopt), + tls_(factory_context.threadLocal()) { + tls_.set([](Event::Dispatcher&) { return std::make_shared(); }); + }; - void validateTypeUrl(const std::string& type_url) const; - void validateTerminalFilter(const std::string& name, const std::string& filter_type, - bool is_terminal_filter); // Config::ExtensionConfigProvider - const std::string& name() override; - absl::optional config() override; + const std::string& name() override { return DynamicFilterConfigProviderImplBase::name(); } + absl::optional config() override { return tls_->config_; } // Config::DynamicExtensionConfigProvider void onConfigUpdate(Envoy::Http::FilterFactoryCb config, const std::string&, - Config::ConfigAppliedCb cb) override; - void onConfigRemoved(Config::ConfigAppliedCb cb) override; + Config::ConfigAppliedCb cb) override { + tls_.runOnAllThreads( + [config, cb](OptRef tls) { + tls->config_ = config; + if (cb) { + cb(); + } + }, + [this, config]() { + // This happens after all workers have discarded the previous config so it can be safely + // deleted on the main thread by an update with the new config. + this->current_config_ = config; + }); + } + + void onConfigRemoved(Config::ConfigAppliedCb applied_on_all_threads) override { + tls_.runOnAllThreads( + [config = default_configuration_](OptRef tls) { tls->config_ = config; }, + [this, applied_on_all_threads]() { + // This happens after all workers have discarded the previous config so it can be safely + // deleted on the main thread by an update with the new config. + this->current_config_ = default_configuration_; + if (applied_on_all_threads) { + applied_on_all_threads(); + } + }); + } + void applyDefaultConfiguration() override { if (default_configuration_) { onConfigUpdate(*default_configuration_, "", nullptr); @@ -65,21 +126,11 @@ class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProvider { absl::optional config_{}; }; - FilterConfigSubscriptionSharedPtr subscription_; - const absl::flat_hash_set require_type_urls_; // Currently applied configuration to ensure that the main thread deletes the last reference to // it. absl::optional current_config_{absl::nullopt}; const absl::optional default_configuration_; ThreadLocal::TypedSlot tls_; - - // Local initialization target to ensure that the subscription starts in - // case no warming is requested by any other filter config provider. - Init::TargetImpl init_target_; - - const bool last_filter_in_filter_chain_; - const std::string filter_chain_type_; - friend class FilterConfigProviderManagerImpl; }; /** @@ -156,8 +207,8 @@ class FilterConfigSubscription // FilterConfigProviderManagerImpl maintains active subscriptions in a map. FilterConfigProviderManagerImpl& filter_config_provider_manager_; const std::string subscription_id_; - absl::flat_hash_set filter_config_providers_; - friend class DynamicFilterConfigProviderImpl; + absl::flat_hash_set filter_config_providers_; + friend class DynamicFilterConfigProviderImplBase; // This must be the last since its destructor may call out to stats to report // on draining requests.