diff --git a/docs/root/configuration/advanced/advanced.rst b/docs/root/configuration/advanced/advanced.rst index 2753c5bb8995..d84ba2f53225 100644 --- a/docs/root/configuration/advanced/advanced.rst +++ b/docs/root/configuration/advanced/advanced.rst @@ -5,3 +5,4 @@ Advanced :maxdepth: 2 well_known_dynamic_metadata + well_known_filter_state diff --git a/docs/root/configuration/advanced/well_known_filter_state.rst b/docs/root/configuration/advanced/well_known_filter_state.rst new file mode 100644 index 000000000000..307facd3c9fc --- /dev/null +++ b/docs/root/configuration/advanced/well_known_filter_state.rst @@ -0,0 +1,12 @@ +.. _well_known_filter_state: + +Well Known Filter State Objects +=============================== + +The following list of filter state objects are consumed by Envoy extensions: + +.. csv-table:: + :header: Filter state key, Purpose + :widths: 1, 3 + + ``envoy.tcp_proxy.cluster``, :ref:`TCP proxy ` dynamic cluster selection on a per-connection basis diff --git a/docs/root/intro/arch_overview/advanced/data_sharing_between_filters.rst b/docs/root/intro/arch_overview/advanced/data_sharing_between_filters.rst index d0ade88f1503..695b8b80edf1 100644 --- a/docs/root/intro/arch_overview/advanced/data_sharing_between_filters.rst +++ b/docs/root/intro/arch_overview/advanced/data_sharing_between_filters.rst @@ -90,6 +90,10 @@ addition, it provides a facility to store typed objects in a map (``map``). The state stored per filter can be either write-once (immutable), or write-many (mutable). +See :ref:`the well-known dynamic metadata ` and +:ref:`the well-known filter state ` for the reference +list of the dynamic metadata and the filter state objects. + .. _arch_overview_advanced_filter_state_sharing: Filter state sharing diff --git a/envoy/stream_info/BUILD b/envoy/stream_info/BUILD index 49014a375d98..cb79d23921d8 100644 --- a/envoy/stream_info/BUILD +++ b/envoy/stream_info/BUILD @@ -34,6 +34,7 @@ envoy_cc_library( hdrs = ["filter_state.h"], external_deps = ["abseil_optional"], deps = [ + "//envoy/config:typed_config_interface", "//source/common/common:fmt_lib", "//source/common/common:utility_lib", "//source/common/protobuf", diff --git a/envoy/stream_info/filter_state.h b/envoy/stream_info/filter_state.h index b119b4d776d4..eea698edac12 100644 --- a/envoy/stream_info/filter_state.h +++ b/envoy/stream_info/filter_state.h @@ -4,6 +4,7 @@ #include #include "envoy/common/pure.h" +#include "envoy/config/typed_config.h" #include "source/common/common/fmt.h" #include "source/common/common/utility.h" @@ -103,6 +104,23 @@ class FilterState { virtual absl::optional serializeAsString() const { return absl::nullopt; } }; + /** + * Generic factory for filter state objects. The factory registry uses the + * object data name as the index for the object factory. This factory should be used by the + * dynamic extensions that cannot use the object constructors directly. + */ + class ObjectFactory : public Config::UntypedFactory { + public: + // Config::UntypedFactory + std::string category() const override { return "filter_state.object"; } + + /** + * @return std::unique_ptr from the serialized object data or nullptr if the input + * is malformed. + */ + virtual std::unique_ptr createFromBytes(absl::string_view data) const PURE; + }; + struct FilterObject { std::shared_ptr data_; StateType state_type_{StateType::ReadOnly}; diff --git a/source/common/tcp_proxy/BUILD b/source/common/tcp_proxy/BUILD index db2c5b1895e4..07d5c5995d29 100644 --- a/source/common/tcp_proxy/BUILD +++ b/source/common/tcp_proxy/BUILD @@ -45,6 +45,7 @@ envoy_cc_library( "//envoy/event:dispatcher_interface", "//envoy/network:connection_interface", "//envoy/network:filter_interface", + "//envoy/registry", "//envoy/router:router_interface", "//envoy/server:filter_config_interface", "//envoy/stats:stats_interface", diff --git a/source/common/tcp_proxy/tcp_proxy.cc b/source/common/tcp_proxy/tcp_proxy.cc index 4d611627a32b..30cee0a654f3 100644 --- a/source/common/tcp_proxy/tcp_proxy.cc +++ b/source/common/tcp_proxy/tcp_proxy.cc @@ -11,6 +11,7 @@ #include "envoy/event/timer.h" #include "envoy/extensions/filters/network/tcp_proxy/v3/tcp_proxy.pb.h" #include "envoy/extensions/filters/network/tcp_proxy/v3/tcp_proxy.pb.validate.h" +#include "envoy/registry/registry.h" #include "envoy/stats/scope.h" #include "envoy/upstream/cluster_manager.h" #include "envoy/upstream/upstream.h" @@ -41,6 +42,17 @@ const std::string& PerConnectionCluster::key() { CONSTRUCT_ON_FIRST_USE(std::string, "envoy.tcp_proxy.cluster"); } +class PerConnectionClusterFactory : public StreamInfo::FilterState::ObjectFactory { +public: + std::string name() const override { return PerConnectionCluster::key(); } + std::unique_ptr + createFromBytes(absl::string_view data) const override { + return std::make_unique(data); + } +}; + +REGISTER_FACTORY(PerConnectionClusterFactory, StreamInfo::FilterState::ObjectFactory); + Config::SimpleRouteImpl::SimpleRouteImpl(const Config& parent, absl::string_view cluster_name) : parent_(parent), cluster_name_(cluster_name) {} diff --git a/source/common/tcp_proxy/tcp_proxy.h b/source/common/tcp_proxy/tcp_proxy.h index 4ce8a350abdb..929953d273c5 100644 --- a/source/common/tcp_proxy/tcp_proxy.h +++ b/source/common/tcp_proxy/tcp_proxy.h @@ -374,6 +374,7 @@ class PerConnectionCluster : public StreamInfo::FilterState::Object { public: PerConnectionCluster(absl::string_view cluster) : cluster_(cluster) {} const std::string& value() const { return cluster_; } + absl::optional serializeAsString() const override { return cluster_; } static const std::string& key(); private: diff --git a/test/common/tcp_proxy/tcp_proxy_test.cc b/test/common/tcp_proxy/tcp_proxy_test.cc index 7faa95fb5d2d..130addf2c3e1 100644 --- a/test/common/tcp_proxy/tcp_proxy_test.cc +++ b/test/common/tcp_proxy/tcp_proxy_test.cc @@ -1410,6 +1410,18 @@ TEST_F(TcpProxyTest, UpstreamStartSecureTransport) { filter_->startUpstreamSecureTransport(); } +TEST(PerConnectionCluster, ObjectFactory) { + const std::string name = "envoy.tcp_proxy.cluster"; + auto* factory = + Registry::FactoryRegistry::getFactory(name); + ASSERT_NE(nullptr, factory); + EXPECT_EQ(name, factory->name()); + const std::string cluster = "per_connection_cluster"; + auto object = factory->createFromBytes(cluster); + ASSERT_NE(nullptr, object); + EXPECT_EQ(cluster, object->serializeAsString()); +} + } // namespace } // namespace TcpProxy } // namespace Envoy