diff --git a/source/common/filter/config_discovery_impl.h b/source/common/filter/config_discovery_impl.h index 7d0cb1c3f7b8..1218971810b3 100644 --- a/source/common/filter/config_discovery_impl.h +++ b/source/common/filter/config_discovery_impl.h @@ -347,6 +347,41 @@ class UdpListenerDynamicFilterConfigProviderImpl } }; +class UdpSessionDynamicFilterConfigProviderImpl + : public DynamicFilterConfigProviderImpl { +public: + UdpSessionDynamicFilterConfigProviderImpl( + FilterConfigSubscriptionSharedPtr& subscription, + const absl::flat_hash_set& require_type_urls, + Server::Configuration::ServerFactoryContext&, + Server::Configuration::FactoryContext& factory_context, + ProtobufTypes::MessagePtr&& default_config, bool last_filter_in_filter_chain, + const std::string& filter_chain_type, absl::string_view stat_prefix, + const Network::ListenerFilterMatcherSharedPtr& listener_filter_matcher) + : DynamicFilterConfigProviderImpl( + subscription, require_type_urls, factory_context.serverFactoryContext().threadLocal(), + std::move(default_config), last_filter_in_filter_chain, filter_chain_type, stat_prefix, + listener_filter_matcher), + factory_context_(factory_context) {} + + void validateMessage(const std::string&, const Protobuf::Message&, + const std::string&) const override { + // UDP session filters don't use the concept of terminal filters. + } + +protected: + Server::Configuration::FactoryContext& factory_context_; + +private: + absl::StatusOr + instantiateFilterFactory(const Protobuf::Message& message) const override { + auto* factory = + Registry::FactoryRegistry:: + getFactoryByType(message.GetTypeName()); + return factory->createFilterFactoryFromProto(message, factory_context_); + } +}; + class QuicListenerDynamicFilterConfigProviderImpl : public ListenerDynamicFilterConfigProviderImpl { public: @@ -774,6 +809,19 @@ class UdpListenerFilterConfigProviderManagerImpl const std::string getConfigDumpType() const override { return "ecds_filter_udp_listener"; } }; +// UDP session filter +class UdpSessionFilterConfigProviderManagerImpl + : public FilterConfigProviderManagerImpl< + Server::Configuration::NamedUdpSessionFilterConfigFactory, + Network::UdpSessionFilterFactoryCb, Server::Configuration::FactoryContext, + UdpSessionDynamicFilterConfigProviderImpl> { +public: + absl::string_view statPrefix() const override { return "udp_session_filter."; } + +protected: + const std::string getConfigDumpType() const override { return "ecds_filter_udp_session"; } +}; + // QUIC listener filter class QuicListenerFilterConfigProviderManagerImpl : public FilterConfigProviderManagerImpl< diff --git a/source/extensions/filters/udp/udp_proxy/config.cc b/source/extensions/filters/udp/udp_proxy/config.cc index 1fee7deedc54..7e157a3305b5 100644 --- a/source/extensions/filters/udp/udp_proxy/config.cc +++ b/source/extensions/filters/udp/udp_proxy/config.cc @@ -1,5 +1,6 @@ #include "source/extensions/filters/udp/udp_proxy/config.h" +#include "source/common/filter/config_discovery_impl.h" #include "source/common/formatter/substitution_format_string.h" namespace Envoy { @@ -88,6 +89,8 @@ UdpProxyFilterConfigImpl::UdpProxyFilterConfigImpl( stats_(generateStats(config.stat_prefix(), context.scope())), // Default prefer_gro to true for upstream client traffic. upstream_socket_config_(config.upstream_socket_config(), true), + udp_session_filter_config_provider_manager_( + createSingletonUdpSessionFilterConfigProviderManager(context.serverFactoryContext())), random_generator_(context.serverFactoryContext().api().randomGenerator()) { if (use_per_packet_load_balancing_ && config.has_tunneling_config()) { throw EnvoyException( @@ -149,12 +152,25 @@ UdpProxyFilterConfigImpl::UdpProxyFilterConfigImpl( Server::Configuration::NamedUdpSessionFilterConfigFactory>(filter); ProtobufTypes::MessagePtr message = Envoy::Config::Utility::translateToFactoryConfig( filter, context.messageValidationVisitor(), factory); + Network::UdpSessionFilterFactoryCb callback = factory.createFilterFactoryFromProto(*message, context); - filter_factories_.push_back(callback); + filter_factories_.push_back( + udp_session_filter_config_provider_manager_->createStaticFilterConfigProvider( + callback, filter.name())); } } +SINGLETON_MANAGER_REGISTRATION(udp_session_filter_config_provider_manager); + +std::shared_ptr +UdpProxyFilterConfigImpl::createSingletonUdpSessionFilterConfigProviderManager( + Server::Configuration::ServerFactoryContext& context) { + return context.singletonManager().getTyped( + SINGLETON_MANAGER_REGISTERED_NAME(udp_session_filter_config_provider_manager), + [] { return std::make_shared(); }); +} + static Registry::RegisterFactory register_; diff --git a/source/extensions/filters/udp/udp_proxy/config.h b/source/extensions/filters/udp/udp_proxy/config.h index 3ecc10711c6d..3fc39ca71d22 100644 --- a/source/extensions/filters/udp/udp_proxy/config.h +++ b/source/extensions/filters/udp/udp_proxy/config.h @@ -2,6 +2,7 @@ #include "envoy/extensions/filters/udp/udp_proxy/v3/udp_proxy.pb.h" #include "envoy/extensions/filters/udp/udp_proxy/v3/udp_proxy.pb.validate.h" +#include "envoy/filter/config_provider_manager.h" #include "envoy/server/filter_config.h" #include "source/extensions/filters/udp/udp_proxy/udp_proxy_filter.h" @@ -106,6 +107,12 @@ class TunnelingConfigImpl : public UdpTunnelingConfig { bool propagate_response_trailers_; }; +using UdpSessionFilterConfigProviderManager = + Filter::FilterConfigProviderManager; +using UdpSessionFilterFactoriesList = + std::vector>; + class UdpProxyFilterConfigImpl : public UdpProxyFilterConfig, public UdpSessionFilterChainFactory, Logger::Loggable { @@ -151,8 +158,12 @@ class UdpProxyFilterConfigImpl : public UdpProxyFilterConfig, // UdpSessionFilterChainFactory void createFilterChain(Network::UdpSessionFilterChainFactoryCallbacks& callbacks) const override { - for (const Network::UdpSessionFilterFactoryCb& factory : filter_factories_) { - factory(callbacks); + for (const auto& filter_config_provider : filter_factories_) { + auto config = filter_config_provider->config(); + if (config.has_value()) { + Network::UdpSessionFilterFactoryCb& factory = config.value(); + factory(callbacks); + } } }; @@ -164,6 +175,10 @@ class UdpProxyFilterConfigImpl : public UdpProxyFilterConfig, POOL_GAUGE_PREFIX(scope, final_prefix))}; } + std::shared_ptr + createSingletonUdpSessionFilterConfigProviderManager( + Server::Configuration::ServerFactoryContext& context); + Upstream::ClusterManager& cluster_manager_; TimeSource& time_source_; Router::RouterConstSharedPtr router_; @@ -178,7 +193,9 @@ class UdpProxyFilterConfigImpl : public UdpProxyFilterConfig, std::vector session_access_logs_; std::vector proxy_access_logs_; UdpTunnelingConfigPtr tunneling_config_; - std::list filter_factories_; + std::shared_ptr + udp_session_filter_config_provider_manager_; + UdpSessionFilterFactoriesList filter_factories_; Random::RandomGenerator& random_generator_; }; diff --git a/test/common/filter/config_discovery_impl_test.cc b/test/common/filter/config_discovery_impl_test.cc index cb580db0ffde..0c7582279fda 100644 --- a/test/common/filter/config_discovery_impl_test.cc +++ b/test/common/filter/config_discovery_impl_test.cc @@ -130,6 +130,22 @@ class TestUdpListenerFilterFactory std::string name() const override { return "envoy.test.filter"; } }; +class TestUdpSessionFilterFactory + : public TestFilterFactory, + public Server::Configuration::NamedUdpSessionFilterConfigFactory { +public: + Network::UdpSessionFilterFactoryCb + createFilterFactoryFromProto(const Protobuf::Message&, + Server::Configuration::FactoryContext&) override { + created_ = true; + return [](Network::UdpSessionFilterChainFactoryCallbacks&) -> void {}; + } + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + std::string name() const override { return "envoy.test.filter"; } +}; + class TestQuicListenerFilterFactory : public TestFilterFactory, public Server::Configuration::NamedQuicListenerFilterConfigFactory { @@ -374,6 +390,23 @@ class UdpListenerFilterConfigDiscoveryImplTest } }; +// UDP session filter test +class UdpSessionFilterConfigDiscoveryImplTest + : public FilterConfigDiscoveryImplTest< + Network::UdpSessionFilterFactoryCb, Server::Configuration::FactoryContext, + UdpSessionFilterConfigProviderManagerImpl, TestUdpSessionFilterFactory, + Server::Configuration::NamedUdpSessionFilterConfigFactory, + Server::Configuration::MockFactoryContext> { +public: + const std::string getFilterType() const override { return "udp_session"; } + const std::string getConfigReloadCounter() const override { + return "extension_config_discovery.udp_session_filter.foo.config_reload"; + } + const std::string getConfigFailCounter() const override { + return "extension_config_discovery.udp_session_filter.foo.config_fail"; + } +}; + // QUIC listener filter test class QuicListenerFilterConfigDiscoveryImplTest : public FilterConfigDiscoveryImplTest< @@ -393,7 +426,8 @@ class QuicListenerFilterConfigDiscoveryImplTest /*************************************************************************************** * Parameterized test for * - * HTTP filter, Network filter, TCP listener filter And UDP listener filter * + * HTTP filter, Network filter, TCP listener filter, UDP session filter and * + * UDP listener filter * * * ***************************************************************************************/ template @@ -404,7 +438,7 @@ using FilterConfigDiscoveryTestTypes = ::testing::Types< HttpFilterConfigDiscoveryImplTest, HttpUpstreamFilterConfigDiscoveryImplTest, NetworkFilterConfigDiscoveryImplTest, NetworkUpstreamFilterConfigDiscoveryImplTest, TcpListenerFilterConfigDiscoveryImplTest, UdpListenerFilterConfigDiscoveryImplTest, - QuicListenerFilterConfigDiscoveryImplTest>; + UdpSessionFilterConfigDiscoveryImplTest, QuicListenerFilterConfigDiscoveryImplTest>; TYPED_TEST_SUITE(FilterConfigDiscoveryImplTestParameter, FilterConfigDiscoveryTestTypes); @@ -646,7 +680,8 @@ TYPED_TEST(FilterConfigDiscoveryImplTestParameter, TerminalFilterInvalid) { EXPECT_CALL(config_discovery_test.init_watcher_, ready()); if (config_discovery_test.getFilterType() == "listener" || - config_discovery_test.getFilterType() == "upstream_network") { + config_discovery_test.getFilterType() == "upstream_network" || + config_discovery_test.getFilterType() == "udp_session") { ASSERT_TRUE(config_discovery_test.callbacks_ ->onConfigUpdate(decoded_resources.refvec_, response.version_info()) .ok());