Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions envoy/config/extension_config_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ template <class Factory, class FactoryCallback> class ExtensionConfigProvider {
virtual absl::optional<FactoryCallback> config() PURE;
};

template <class Factory, class FactoryCallback>
class DynamicExtensionConfigProvider : public ExtensionConfigProvider<Factory, FactoryCallback> {
template <class FactoryCallback> 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.
Expand All @@ -59,5 +60,9 @@ class DynamicExtensionConfigProvider : public ExtensionConfigProvider<Factory, F
virtual void applyDefaultConfiguration() PURE;
};

template <class Factory, class FactoryCallback>
class DynamicExtensionConfigProvider : public DynamicExtensionConfigProviderBase<FactoryCallback>,
public ExtensionConfigProvider<Factory, FactoryCallback> {};

} // namespace Config
} // namespace Envoy
84 changes: 21 additions & 63 deletions source/common/filter/config_discovery_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,84 +28,42 @@ void validateTypeUrlHelper(const std::string& type_url,

} // namespace

DynamicFilterConfigProviderImpl::DynamicFilterConfigProviderImpl(
DynamicFilterConfigProviderImplBase::DynamicFilterConfigProviderImplBase(
FilterConfigSubscriptionSharedPtr& subscription,
const absl::flat_hash_set<std::string>& require_type_urls,

Server::Configuration::FactoryContext& factory_context,
Envoy::Http::FilterFactoryCb default_config, bool last_filter_in_filter_chain,
const absl::flat_hash_set<std::string>& 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<ThreadLocalConfig>(); });
}

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<Envoy::Http::FilterFactoryCb> DynamicFilterConfigProviderImpl::config() {
return tls_->config_;
}

void DynamicFilterConfigProviderImpl::onConfigUpdate(Envoy::Http::FilterFactoryCb config,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for moving these implementations to the header? Is DynamicFilterConfigProviderImpl going to become a template?

@tbarrella tbarrella Aug 17, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry yes, that's the plan. DynamicFilterConfigProviderImplBase will not be a template, while DynamicFilterConfigProviderImpl will be with FactoryCallback as a parameter

const std::string&,
Config::ConfigAppliedCb cb) {
tls_.runOnAllThreads(
[config, cb](OptRef<ThreadLocalConfig> 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<ThreadLocalConfig> 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,
Expand Down Expand Up @@ -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<DynamicFilterConfigProviderImpl*>(
Common::applyToAllWithCleanup<DynamicFilterConfigProviderImplBase*>(
filter_config_providers_,
[&factory_callback, &version_info](DynamicFilterConfigProviderImpl* provider,
[&factory_callback, &version_info](DynamicFilterConfigProviderImplBase* provider,
std::shared_ptr<Cleanup> cleanup) {
provider->onConfigUpdate(factory_callback, version_info, [cleanup] {});
},
Expand All @@ -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<DynamicFilterConfigProviderImpl*>(
Common::applyToAllWithCleanup<DynamicFilterConfigProviderImplBase*>(
filter_config_providers_,
[](DynamicFilterConfigProviderImpl* provider, std::shared_ptr<Cleanup> cleanup) {
[](DynamicFilterConfigProviderImplBase* provider, std::shared_ptr<Cleanup> cleanup) {
provider->onConfigRemoved([cleanup] {});
},
[this]() { stats_.config_reload_.inc(); });
Expand Down Expand Up @@ -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.
Expand Down
97 changes: 74 additions & 23 deletions source/common/filter/config_discovery_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,92 @@ class FilterConfigSubscription;

using FilterConfigSubscriptionSharedPtr = std::shared_ptr<FilterConfigSubscription>;

/**
* Base class for a filter config provider using discovery subscriptions.
**/
class DynamicFilterConfigProviderImplBase
: public Config::DynamicExtensionConfigProviderBase<Envoy::Http::FilterFactoryCb> {
public:
DynamicFilterConfigProviderImplBase(FilterConfigSubscriptionSharedPtr& subscription,
const absl::flat_hash_set<std::string>& 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<std::string> 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<std::string>& 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<ThreadLocalConfig>(); });
};

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<Envoy::Http::FilterFactoryCb> config() override;
const std::string& name() override { return DynamicFilterConfigProviderImplBase::name(); }
absl::optional<Envoy::Http::FilterFactoryCb> 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<ThreadLocalConfig> 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<ThreadLocalConfig> 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);
Expand All @@ -65,21 +126,11 @@ class DynamicFilterConfigProviderImpl : public DynamicFilterConfigProvider {
absl::optional<Envoy::Http::FilterFactoryCb> config_{};
};

FilterConfigSubscriptionSharedPtr subscription_;
const absl::flat_hash_set<std::string> require_type_urls_;
// Currently applied configuration to ensure that the main thread deletes the last reference to
// it.
absl::optional<Envoy::Http::FilterFactoryCb> current_config_{absl::nullopt};
const absl::optional<Envoy::Http::FilterFactoryCb> default_configuration_;
ThreadLocal::TypedSlot<ThreadLocalConfig> 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;
};

/**
Expand Down Expand Up @@ -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<DynamicFilterConfigProviderImpl*> filter_config_providers_;
friend class DynamicFilterConfigProviderImpl;
absl::flat_hash_set<DynamicFilterConfigProviderImplBase*> filter_config_providers_;
friend class DynamicFilterConfigProviderImplBase;

// This must be the last since its destructor may call out to stats to report
// on draining requests.
Expand Down