diff --git a/source/common/filter/config_discovery_impl.cc b/source/common/filter/config_discovery_impl.cc index 7c686d1664361..354789fa7c819 100644 --- a/source/common/filter/config_discovery_impl.cc +++ b/source/common/filter/config_discovery_impl.cc @@ -67,7 +67,8 @@ void DynamicFilterConfigProviderImplBase::validateTerminalFilter(const std::stri FilterConfigSubscription::FilterConfigSubscription( const envoy::config::core::v3::ConfigSource& config_source, const std::string& filter_config_name, Server::Configuration::FactoryContext& factory_context, - const std::string& stat_prefix, FilterConfigProviderManagerImpl& filter_config_provider_manager, + const std::string& stat_prefix, + FilterConfigProviderManagerImplBase& filter_config_provider_manager, const std::string& subscription_id) : Config::SubscriptionBase( factory_context.messageValidationContext().dynamicValidationVisitor(), "name"), @@ -190,7 +191,7 @@ FilterConfigSubscription::~FilterConfigSubscription() { void FilterConfigSubscription::incrementConflictCounter() { stats_.config_conflict_.inc(); } -std::shared_ptr FilterConfigProviderManagerImpl::getSubscription( +std::shared_ptr FilterConfigProviderManagerImplBase::getSubscription( const envoy::config::core::v3::ConfigSource& config_source, const std::string& name, Server::Configuration::FactoryContext& factory_context, const std::string& stat_prefix) { // FilterConfigSubscriptions are unique based on their config source and filter config name @@ -212,6 +213,39 @@ std::shared_ptr FilterConfigProviderManagerImpl::getSu } } +void FilterConfigProviderManagerImplBase::applyLastOrDefaultConfig( + std::shared_ptr& subscription, + DynamicFilterConfigProviderImplBase& provider, const std::string& filter_config_name) { + // If the subscription already received a config, attempt to apply it. + // It is possible that the received extension config fails to satisfy the listener + // type URL constraints. This may happen if ECDS and LDS updates are racing, and the LDS + // update arrives first. In this case, use the default config, increment a metric, + // and the applied config eventually converges once ECDS update arrives. + bool last_config_valid = false; + if (subscription->lastConfig().has_value()) { + TRY_ASSERT_MAIN_THREAD { + provider.validateTypeUrl(subscription->lastTypeUrl()); + provider.validateTerminalFilter(filter_config_name, subscription->lastFilterName(), + subscription->isLastFilterTerminal()); + last_config_valid = true; + } + END_TRY catch (const EnvoyException& e) { + ENVOY_LOG(debug, "ECDS subscription {} is invalid in a listener context: {}.", + filter_config_name, e.what()); + subscription->incrementConflictCounter(); + } + if (last_config_valid) { + provider.onConfigUpdate(subscription->lastConfig().value(), subscription->lastVersionInfo(), + nullptr); + } + } + + // Apply the default config if none has been applied. + if (!last_config_valid) { + provider.applyDefaultConfiguration(); + } +} + DynamicFilterConfigProviderPtr FilterConfigProviderManagerImpl::createDynamicFilterConfigProvider( const envoy::config::core::v3::ExtensionConfigSource& config_source, const std::string& filter_config_name, Server::Configuration::FactoryContext& factory_context, @@ -233,26 +267,9 @@ DynamicFilterConfigProviderPtr FilterConfigProviderManagerImpl::createDynamicFil Envoy::Http::FilterFactoryCb default_config = nullptr; if (config_source.has_default_config()) { - auto* default_factory = - Config::Utility::getFactoryByType( - config_source.default_config()); - if (default_factory == nullptr) { - throw EnvoyException(fmt::format("Error: cannot find filter factory {} for default filter " - "configuration with type URL {}.", - filter_config_name, - config_source.default_config().type_url())); - } - validateTypeUrlHelper(Config::Utility::getFactoryType(config_source.default_config()), - require_type_urls); - ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( - config_source.default_config(), factory_context.messageValidationVisitor(), - *default_factory); - Config::Utility::validateTerminalFilters( - filter_config_name, default_factory->name(), filter_chain_type, - default_factory->isTerminalFilterByProto(*message, factory_context), - last_filter_in_filter_config); - default_config = - default_factory->createFilterFactoryFromProto(*message, stat_prefix, factory_context); + default_config = getDefaultConfig(config_source.default_config(), filter_config_name, + factory_context, stat_prefix, last_filter_in_filter_config, + filter_chain_type, require_type_urls); } auto provider = std::make_unique( @@ -263,36 +280,31 @@ DynamicFilterConfigProviderPtr FilterConfigProviderManagerImpl::createDynamicFil if (config_source.apply_default_config_without_warming()) { factory_context.initManager().add(provider->initTarget()); } + applyLastOrDefaultConfig(subscription, *provider, filter_config_name); + return provider; +} - // If the subscription already received a config, attempt to apply it. - // It is possible that the received extension config fails to satisfy the listener - // type URL constraints. This may happen if ECDS and LDS updates are racing, and the LDS - // update arrives first. In this case, use the default config, increment a metric, - // and the applied config eventually converges once ECDS update arrives. - bool last_config_valid = false; - if (subscription->lastConfig().has_value()) { - TRY_ASSERT_MAIN_THREAD { - provider->validateTypeUrl(subscription->lastTypeUrl()); - provider->validateTerminalFilter(filter_config_name, subscription->lastFilterName(), - subscription->isLastFilterTerminal()); - last_config_valid = true; - } - END_TRY catch (const EnvoyException& e) { - ENVOY_LOG(debug, "ECDS subscription {} is invalid in a listener context: {}.", - filter_config_name, e.what()); - subscription->incrementConflictCounter(); - } - if (last_config_valid) { - provider->onConfigUpdate(subscription->lastConfig().value(), subscription->lastVersionInfo(), - nullptr); - } - } - - // Apply the default config if none has been applied. - if (!last_config_valid) { - provider->applyDefaultConfiguration(); +Http::FilterFactoryCb HttpFilterConfigProviderManagerImpl::getDefaultConfig( + const ProtobufWkt::Any& proto_config, const std::string& filter_config_name, + Server::Configuration::FactoryContext& factory_context, const std::string& stat_prefix, + bool last_filter_in_filter_config, const std::string& filter_chain_type, + const absl::flat_hash_set require_type_urls) const { + auto* default_factory = + Config::Utility::getFactoryByType( + proto_config); + if (default_factory == nullptr) { + throw EnvoyException(fmt::format("Error: cannot find filter factory {} for default filter " + "configuration with type URL {}.", + filter_config_name, proto_config.type_url())); } - return provider; + validateTypeUrlHelper(Config::Utility::getFactoryType(proto_config), require_type_urls); + ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( + proto_config, factory_context.messageValidationVisitor(), *default_factory); + Config::Utility::validateTerminalFilters( + filter_config_name, default_factory->name(), filter_chain_type, + default_factory->isTerminalFilterByProto(*message, factory_context), + last_filter_in_filter_config); + return default_factory->createFilterFactoryFromProto(*message, stat_prefix, factory_context); } } // namespace Filter diff --git a/source/common/filter/config_discovery_impl.h b/source/common/filter/config_discovery_impl.h index 2c550fd3faa62..c44a9bfbd43fa 100644 --- a/source/common/filter/config_discovery_impl.h +++ b/source/common/filter/config_discovery_impl.h @@ -23,7 +23,7 @@ namespace Envoy { namespace Filter { -class FilterConfigProviderManagerImpl; +class FilterConfigProviderManagerImplBase; class FilterConfigSubscription; using FilterConfigSubscriptionSharedPtr = std::shared_ptr; @@ -161,7 +161,7 @@ class FilterConfigSubscription const std::string& filter_config_name, Server::Configuration::FactoryContext& factory_context, const std::string& stat_prefix, - FilterConfigProviderManagerImpl& filter_config_provider_manager, + FilterConfigProviderManagerImplBase& filter_config_provider_manager, const std::string& subscription_id); ~FilterConfigSubscription() override; @@ -204,8 +204,8 @@ class FilterConfigSubscription const std::string stat_prefix_; ExtensionConfigDiscoveryStats stats_; - // FilterConfigProviderManagerImpl maintains active subscriptions in a map. - FilterConfigProviderManagerImpl& filter_config_provider_manager_; + // FilterConfigProviderManagerImplBase maintains active subscriptions in a map. + FilterConfigProviderManagerImplBase& filter_config_provider_manager_; const std::string subscription_id_; absl::flat_hash_set filter_config_providers_; friend class DynamicFilterConfigProviderImplBase; @@ -233,17 +233,35 @@ class StaticFilterConfigProviderImpl : public FilterConfigProvider { const std::string filter_config_name_; }; +/** + * Base class for a FilterConfigProviderManager. + */ +class FilterConfigProviderManagerImplBase : Logger::Loggable { +protected: + std::shared_ptr + getSubscription(const envoy::config::core::v3::ConfigSource& config_source, + const std::string& name, Server::Configuration::FactoryContext& factory_context, + const std::string& stat_prefix); + void applyLastOrDefaultConfig(std::shared_ptr& subscription, + DynamicFilterConfigProviderImplBase& provider, + const std::string& filter_config_name); + +private: + absl::flat_hash_map> subscriptions_; + friend class FilterConfigSubscription; +}; + /** * An implementation of FilterConfigProviderManager. */ -class FilterConfigProviderManagerImpl : public FilterConfigProviderManager, - public Singleton::Instance, - Logger::Loggable { +class FilterConfigProviderManagerImpl : public FilterConfigProviderManagerImplBase, + public FilterConfigProviderManager, + public Singleton::Instance { public: DynamicFilterConfigProviderPtr createDynamicFilterConfigProvider( const envoy::config::core::v3::ExtensionConfigSource& config_source, const std::string& filter_config_name, Server::Configuration::FactoryContext& factory_context, - const std::string& stat_prefix, bool last_filter_in_filter_chain, + const std::string& stat_prefix, bool last_filter_in_filter_config, const std::string& filter_chain_type) override; FilterConfigProviderPtr @@ -252,16 +270,24 @@ class FilterConfigProviderManagerImpl : public FilterConfigProviderManager, return std::make_unique(config, filter_config_name); } -private: - std::shared_ptr - getSubscription(const envoy::config::core::v3::ConfigSource& config_source, - const std::string& name, Server::Configuration::FactoryContext& factory_context, - const std::string& stat_prefix); - absl::flat_hash_map> subscriptions_; - friend class FilterConfigSubscription; +protected: + virtual Http::FilterFactoryCb + getDefaultConfig(const ProtobufWkt::Any& proto_config, const std::string& filter_config_name, + Server::Configuration::FactoryContext& factory_context, + const std::string& stat_prefix, bool last_filter_in_filter_config, + const std::string& filter_chain_type, + const absl::flat_hash_set require_type_urls) const PURE; }; -class HttpFilterConfigProviderManagerImpl : public FilterConfigProviderManagerImpl {}; +class HttpFilterConfigProviderManagerImpl : public FilterConfigProviderManagerImpl { +protected: + Http::FilterFactoryCb + getDefaultConfig(const ProtobufWkt::Any& proto_config, const std::string& filter_config_name, + Server::Configuration::FactoryContext& factory_context, + const std::string& stat_prefix, bool last_filter_in_filter_config, + const std::string& filter_chain_type, + const absl::flat_hash_set require_type_urls) const override; +}; } // namespace Filter } // namespace Envoy