diff --git a/include/envoy/router/BUILD b/include/envoy/router/BUILD index 6ed49171af71f..3ab69917c6f91 100644 --- a/include/envoy/router/BUILD +++ b/include/envoy/router/BUILD @@ -53,6 +53,7 @@ envoy_cc_library( hdrs = ["router.h"], external_deps = ["abseil_optional"], deps = [ + ":upstream_endpoint_interface", "//include/envoy/access_log:access_log_interface", "//include/envoy/common:matchers_interface", "//include/envoy/config:typed_metadata_interface", @@ -64,12 +65,20 @@ envoy_cc_library( "//include/envoy/upstream:resource_manager_interface", "//include/envoy/upstream:retry_interface", "//source/common/protobuf", - "//source/common/protobuf:utility_lib", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", "@envoy_api//envoy/type/v3:pkg_cc_proto", ], ) +envoy_cc_library( + name = "upstream_endpoint_interface", + hdrs = ["upstream_endpoint_info.h"], + deps = [ + "//source/common/protobuf", + "//source/common/protobuf:protobuf_utility_lib", + ], +) + envoy_cc_library( name = "scopes_interface", hdrs = ["scopes.h"], diff --git a/include/envoy/router/router.h b/include/envoy/router/router.h index d3b9c3c500890..ad8ec6d6a8a7b 100644 --- a/include/envoy/router/router.h +++ b/include/envoy/router/router.h @@ -16,13 +16,13 @@ #include "envoy/http/codes.h" #include "envoy/http/hash_policy.h" #include "envoy/http/header_map.h" +#include "envoy/router/upstream_endpoint_info.h" #include "envoy/tracing/http_tracer.h" #include "envoy/type/v3/percent.pb.h" #include "envoy/upstream/resource_manager.h" #include "envoy/upstream/retry.h" #include "common/protobuf/protobuf.h" -#include "common/protobuf/utility.h" #include "absl/types/optional.h" @@ -487,59 +487,6 @@ class HedgePolicy { virtual bool hedgeOnPerTryTimeout() const PURE; }; -class MetadataMatchCriterion { -public: - virtual ~MetadataMatchCriterion() = default; - - /* - * @return const std::string& the name of the metadata key - */ - virtual const std::string& name() const PURE; - - /* - * @return const Envoy::HashedValue& the value for the metadata key - */ - virtual const HashedValue& value() const PURE; -}; - -using MetadataMatchCriterionConstSharedPtr = std::shared_ptr; - -class MetadataMatchCriteria; -using MetadataMatchCriteriaConstPtr = std::unique_ptr; - -class MetadataMatchCriteria { -public: - virtual ~MetadataMatchCriteria() = default; - - /* - * @return std::vector& a vector of - * metadata to be matched against upstream endpoints when load - * balancing, sorted lexically by name. - */ - virtual const std::vector& - metadataMatchCriteria() const PURE; - - /** - * Creates a new MetadataMatchCriteria, merging existing - * metadata criteria with the provided criteria. The result criteria is the - * combination of both sets of criteria, with those from the metadata_matches - * ProtobufWkt::Struct taking precedence. - * @param metadata_matches supplies the new criteria. - * @return MetadataMatchCriteriaConstPtr the result criteria. - */ - virtual MetadataMatchCriteriaConstPtr - mergeMatchCriteria(const ProtobufWkt::Struct& metadata_matches) const PURE; - - /** - * Creates a new MetadataMatchCriteria with criteria vector reduced to given names - * @param names names of metadata keys to preserve - * @return MetadataMatchCriteriaConstPtr the result criteria. Returns nullptr if the result - * criteria are empty. - */ - virtual MetadataMatchCriteriaConstPtr - filterMatchCriteria(const std::set& names) const PURE; -}; - /** * Criterion that a route entry uses for matching TLS connection context. */ @@ -597,15 +544,10 @@ class HttpRouteTypedMetadataFactory : public Envoy::Config::TypedMetadataFactory /** * An individual resolved route entry. */ -class RouteEntry : public ResponseEntry { +class RouteEntry : public ResponseEntry, public UpstreamEndpointInfo { public: ~RouteEntry() override = default; - /** - * @return const std::string& the upstream cluster that owns the route. - */ - virtual const std::string& clusterName() const PURE; - /** * Returns the HTTP status code to use when configured cluster is not found. * @return Http::Code to use when configured cluster is not found. @@ -713,12 +655,6 @@ class RouteEntry : public ResponseEntry { */ virtual bool autoHostRewrite() const PURE; - /** - * @return MetadataMatchCriteria* the metadata that a subset load balancer should match when - * selecting an upstream host - */ - virtual const MetadataMatchCriteria* metadataMatchCriteria() const PURE; - /** * @return const std::multimap the opaque configuration associated * with the route @@ -893,7 +829,7 @@ class Route { /** * @return the route entry or nullptr if there is no matching route for the request. */ - virtual const RouteEntry* routeEntry() const PURE; + virtual const std::shared_ptr routeEntry() const PURE; /** * @return the decorator or nullptr if not defined for the request. diff --git a/include/envoy/router/upstream_endpoint_info.h b/include/envoy/router/upstream_endpoint_info.h new file mode 100644 index 0000000000000..fc14c232bf986 --- /dev/null +++ b/include/envoy/router/upstream_endpoint_info.h @@ -0,0 +1,88 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "common/protobuf/protobuf.h" +#include "common/protobuf/protobuf_utility.h" + +namespace Envoy { +namespace Router { + +class MetadataMatchCriterion { +public: + virtual ~MetadataMatchCriterion() = default; + + /* + * @return const std::string& the name of the metadata key + */ + virtual const std::string& name() const PURE; + + /* + * @return const Envoy::HashedValue& the value for the metadata key + */ + virtual const HashedValue& value() const PURE; +}; + +using MetadataMatchCriterionConstSharedPtr = std::shared_ptr; + +class MetadataMatchCriteria; +using MetadataMatchCriteriaConstPtr = std::unique_ptr; + +class MetadataMatchCriteria { +public: + virtual ~MetadataMatchCriteria() = default; + + /* + * @return std::vector& a vector of + * metadata to be matched against upstream endpoints when load + * balancing, sorted lexically by name. + */ + virtual const std::vector& + metadataMatchCriteria() const PURE; + + /** + * Creates a new MetadataMatchCriteria, merging existing + * metadata criteria with the provided criteria. The result criteria is the + * combination of both sets of criteria, with those from the metadata_matches + * ProtobufWkt::Struct taking precedence. + * @param metadata_matches supplies the new criteria. + * @return MetadataMatchCriteriaConstPtr the result criteria. + */ + virtual MetadataMatchCriteriaConstPtr + mergeMatchCriteria(const ProtobufWkt::Struct& metadata_matches) const PURE; + + /** + * Creates a new MetadataMatchCriteria with criteria vector reduced to given names + * @param names names of metadata keys to preserve + * @return MetadataMatchCriteriaConstPtr the result criteria. Returns nullptr if the result + * criteria are empty. + */ + virtual MetadataMatchCriteriaConstPtr + filterMatchCriteria(const std::set& names) const PURE; +}; + +class UpstreamEndpointInfo { +public: + virtual ~UpstreamEndpointInfo() = default; + + /** + * @return const std::string& the upstream cluster that owns the route. + */ + virtual const std::string& clusterName() const PURE; + + /** + * @return MetadataMatchCriteria* the metadata that a subset load balancer should match when + * selecting an upstream host + */ + virtual const MetadataMatchCriteria* metadataMatchCriteria() const PURE; +}; + +using UpstreamEndpointInfoConstSharedPtr = std::shared_ptr; +} // namespace Router +} // namespace Envoy diff --git a/include/envoy/stream_info/BUILD b/include/envoy/stream_info/BUILD index fbaf756c785cf..d71715765da95 100644 --- a/include/envoy/stream_info/BUILD +++ b/include/envoy/stream_info/BUILD @@ -17,6 +17,7 @@ envoy_cc_library( "//include/envoy/common:time_interface", "//include/envoy/http:header_map_interface", "//include/envoy/http:protocol_interface", + "//include/envoy/router:upstream_endpoint_interface", "//include/envoy/ssl:connection_interface", "//include/envoy/upstream:host_description_interface", "//source/common/common:assert_lib", diff --git a/include/envoy/stream_info/stream_info.h b/include/envoy/stream_info/stream_info.h index 6a0bbd05e2669..e8076c020244c 100644 --- a/include/envoy/stream_info/stream_info.h +++ b/include/envoy/stream_info/stream_info.h @@ -9,6 +9,7 @@ #include "envoy/config/core/v3/base.pb.h" #include "envoy/http/header_map.h" #include "envoy/http/protocol.h" +#include "envoy/router/upstream_endpoint_info.h" #include "envoy/ssl/connection.h" #include "envoy/stream_info/filter_state.h" #include "envoy/upstream/host_description.h" @@ -453,6 +454,22 @@ class StreamInfo { */ virtual Ssl::ConnectionInfoConstSharedPtr upstreamSslConnection() const PURE; + /** + * @param upstream_endpoint_info sets the upstream endpoint info like cluster_name. + */ + virtual void setUpstreamEndpointInfo( + const Router::UpstreamEndpointInfoConstSharedPtr& upstream_endpoint_info) PURE; + /** + * @return const Router::UpstreamEndpointInfo* Get the upstream endpoint info selected for this + * request. Note: this will be nullptr if no route was selected. + */ + virtual const Router::UpstreamEndpointInfo* upstreamEndpointInfo() const PURE; + + /** + * @param route_entry sets the RouteEntry for HTTP and UpstreamEndpointInfo for TCP. + */ + virtual void setRouteEntry(const std::shared_ptr& route_entry) PURE; + /** * @return const Router::RouteEntry* Get the route entry selected for this request. Note: this * will be nullptr if no route was selected. diff --git a/include/envoy/upstream/BUILD b/include/envoy/upstream/BUILD index 6bf20f77a8e28..28285a63cd7dc 100644 --- a/include/envoy/upstream/BUILD +++ b/include/envoy/upstream/BUILD @@ -106,6 +106,7 @@ envoy_cc_library( hdrs = ["retry.h"], deps = [ "//include/envoy/config:typed_config_interface", + "//include/envoy/protobuf:message_validator_interface", "//include/envoy/upstream:types_interface", "//include/envoy/upstream:upstream_interface", ], diff --git a/include/envoy/upstream/retry.h b/include/envoy/upstream/retry.h index 3e6ca2890a901..4e492e8100ef4 100644 --- a/include/envoy/upstream/retry.h +++ b/include/envoy/upstream/retry.h @@ -1,6 +1,7 @@ #pragma once #include "envoy/config/typed_config.h" +#include "envoy/protobuf/message_validator.h" #include "envoy/upstream/types.h" #include "envoy/upstream/upstream.h" diff --git a/source/common/http/async_client_impl.h b/source/common/http/async_client_impl.h index 608b2188dc1bd..d9bae8a49f78c 100644 --- a/source/common/http/async_client_impl.h +++ b/source/common/http/async_client_impl.h @@ -300,18 +300,20 @@ class AsyncStreamImpl : public AsyncClient::Stream, const absl::optional& timeout, const Protobuf::RepeatedPtrField& hash_policy) - : route_entry_(cluster_name, timeout, hash_policy) {} + : route_entry_(std::make_shared(cluster_name, timeout, hash_policy)) {} // Router::Route const Router::DirectResponseEntry* directResponseEntry() const override { return nullptr; } - const Router::RouteEntry* routeEntry() const override { return &route_entry_; } + const std::shared_ptr routeEntry() const override { + return route_entry_; + } const Router::Decorator* decorator() const override { return nullptr; } const Router::RouteTracing* tracingConfig() const override { return nullptr; } const Router::RouteSpecificFilterConfig* perFilterConfig(const std::string&) const override { return nullptr; } - RouteEntryImpl route_entry_; + std::shared_ptr route_entry_; }; void cleanup(); diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index 010c3fb9b9fa4..8bb53266d263e 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -918,7 +918,7 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(RequestHeaderMapPtr&& he } if (hasCachedRoute()) { - const Router::RouteEntry* route_entry = cached_route_.value()->routeEntry(); + const auto route_entry = cached_route_.value()->routeEntry(); if (route_entry != nullptr && route_entry->idleTimeout()) { idle_timeout_ms_ = route_entry->idleTimeout().value(); if (idle_timeout_ms_.count()) { @@ -1396,7 +1396,10 @@ void ConnectionManagerImpl::ActiveStream::refreshCachedRoute() { route = snapped_route_config_->route(*request_headers_, stream_info_, stream_id_); } } - stream_info_.route_entry_ = route ? route->routeEntry() : nullptr; + stream_info_.setRouteEntry(route ? route->routeEntry() : nullptr); + stream_info_.setUpstreamEndpointInfo( + route ? std::dynamic_pointer_cast(route->routeEntry()) + : nullptr); cached_route_ = std::move(route); if (nullptr == stream_info_.route_entry_) { cached_cluster_info_ = nullptr; diff --git a/source/common/http/utility.cc b/source/common/http/utility.cc index 8821ca2f46c19..d59cee9988637 100644 --- a/source/common/http/utility.cc +++ b/source/common/http/utility.cc @@ -668,7 +668,7 @@ void Utility::traversePerFilterConfigGeneric( return; } - const Router::RouteEntry* routeEntry = route->routeEntry(); + const std::shared_ptr routeEntry = route->routeEntry(); if (routeEntry != nullptr) { auto maybe_vhost_config = routeEntry->virtualHost().perFilterConfig(filter_name); diff --git a/source/common/protobuf/BUILD b/source/common/protobuf/BUILD index 9a9aa1f306241..8fba80d6e39ef 100644 --- a/source/common/protobuf/BUILD +++ b/source/common/protobuf/BUILD @@ -34,8 +34,8 @@ envoy_cc_library( "//include/envoy/protobuf:message_validator_interface", "//include/envoy/stats:stats_interface", "//source/common/common:hash_lib", - "//source/common/common:logger_lib", "//source/common/common:macros", + "//source/common/common:minimal_logger_lib", ], ) @@ -48,6 +48,18 @@ envoy_cc_library( deps = [":cc_wkt_protos"], ) +envoy_cc_library( + name = "protobuf_utility_lib", + hdrs = ["protobuf_utility.h"], + external_deps = [ + "protobuf", + ], + deps = [ + ":protobuf", + "//source/common/common:hash_lib", + ], +) + envoy_cc_library( name = "utility_lib", srcs = ["utility.cc"], @@ -59,6 +71,7 @@ envoy_cc_library( deps = [ ":message_validator_lib", ":protobuf", + ":protobuf_utility_lib", ":well_known_lib", "//include/envoy/api:api_interface", "//include/envoy/protobuf:message_validator_interface", diff --git a/source/common/protobuf/protobuf_utility.h b/source/common/protobuf/protobuf_utility.h new file mode 100644 index 0000000000000..9922c82781576 --- /dev/null +++ b/source/common/protobuf/protobuf_utility.h @@ -0,0 +1,123 @@ +#pragma once + +#include "common/common/hash.h" +#include "common/protobuf/protobuf.h" + +namespace Envoy { +// class ProtobufMessageHash { +// public: +/** + * A hash function uses Protobuf::TextFormat to force deterministic serialization recursively + * including known types in google.protobuf.Any. See + * https://github.com/protocolbuffers/protobuf/issues/5731 for the context. + * Using this function is discouraged, see discussion in + * https://github.com/envoyproxy/envoy/issues/8301. + */ +// static std::size_t hash(const Protobuf::Message& message); +//} ; + +class ValueUtil { +public: + static std::size_t hash(const ProtobufWkt::Value& value) { + std::string text_format; + { + Protobuf::TextFormat::Printer printer; + printer.SetExpandAny(true); + printer.SetUseFieldNumber(true); + printer.SetSingleLineMode(true); + printer.PrintToString(value, &text_format); + } + + return HashUtil::xxHash64(text_format); + } + + /** + * Load YAML string into ProtobufWkt::Value. + */ + static ProtobufWkt::Value loadFromYaml(const std::string& yaml); + + /** + * Compare two ProtobufWkt::Values for equality. + * @param v1 message of type type.googleapis.com/google.protobuf.Value + * @param v2 message of type type.googleapis.com/google.protobuf.Value + * @return true if v1 and v2 are identical + */ + static bool equal(const ProtobufWkt::Value& v1, const ProtobufWkt::Value& v2); + + /** + * @return wrapped ProtobufWkt::NULL_VALUE. + */ + static const ProtobufWkt::Value& nullValue(); + + /** + * Wrap std::string into ProtobufWkt::Value string value. + * @param str string to be wrapped. + * @return wrapped string. + */ + static ProtobufWkt::Value stringValue(const std::string& str); + + /** + * Wrap boolean into ProtobufWkt::Value boolean value. + * @param str boolean to be wrapped. + * @return wrapped boolean. + */ + static ProtobufWkt::Value boolValue(bool b); + + /** + * Wrap ProtobufWkt::Struct into ProtobufWkt::Value struct value. + * @param obj struct to be wrapped. + * @return wrapped struct. + */ + static ProtobufWkt::Value structValue(const ProtobufWkt::Struct& obj); + + /** + * Wrap number into ProtobufWkt::Value double value. + * @param num number to be wrapped. + * @return wrapped number. + */ + template static ProtobufWkt::Value numberValue(const T num) { + ProtobufWkt::Value val; + val.set_number_value(static_cast(num)); + return val; + } + + /** + * Wrap a collection of ProtobufWkt::Values into ProtobufWkt::Value list value. + * @param values collection of ProtobufWkt::Values to be wrapped. + * @return wrapped list value. + */ + static ProtobufWkt::Value listValue(const std::vector& values); +}; + +/** + * HashedValue is a wrapper around ProtobufWkt::Value that computes + * and stores a hash code for the Value at construction. + */ +class HashedValue { +public: + HashedValue(const ProtobufWkt::Value& value) : value_(value), hash_(ValueUtil::hash(value)){}; + HashedValue(const HashedValue& v) = default; + + const ProtobufWkt::Value& value() const { return value_; } + std::size_t hash() const { return hash_; } + + bool operator==(const HashedValue& rhs) const { + return hash_ == rhs.hash_ && ValueUtil::equal(value_, rhs.value_); + } + + bool operator!=(const HashedValue& rhs) const { return !(*this == rhs); } + +private: + const ProtobufWkt::Value value_; + const std::size_t hash_; +}; + +} // namespace Envoy + +namespace std { +// Inject an implementation of std::hash for Envoy::HashedValue into the std namespace. +template <> struct hash { + std::size_t operator()(Envoy::HashedValue const& v) const { return v.hash(); } +}; + +} // namespace std diff --git a/source/common/protobuf/utility.h b/source/common/protobuf/utility.h index b2d4b828be1ac..25f62c78513b3 100644 --- a/source/common/protobuf/utility.h +++ b/source/common/protobuf/utility.h @@ -12,6 +12,7 @@ #include "common/common/utility.h" #include "common/config/version_converter.h" #include "common/protobuf/protobuf.h" +#include "common/protobuf/protobuf_utility.h" #include "common/singleton/const_singleton.h" #include "absl/strings/str_join.h" @@ -401,91 +402,6 @@ class MessageUtil { static void redact(Protobuf::Message& message); }; -class ValueUtil { -public: - static std::size_t hash(const ProtobufWkt::Value& value) { return MessageUtil::hash(value); } - - /** - * Load YAML string into ProtobufWkt::Value. - */ - static ProtobufWkt::Value loadFromYaml(const std::string& yaml); - - /** - * Compare two ProtobufWkt::Values for equality. - * @param v1 message of type type.googleapis.com/google.protobuf.Value - * @param v2 message of type type.googleapis.com/google.protobuf.Value - * @return true if v1 and v2 are identical - */ - static bool equal(const ProtobufWkt::Value& v1, const ProtobufWkt::Value& v2); - - /** - * @return wrapped ProtobufWkt::NULL_VALUE. - */ - static const ProtobufWkt::Value& nullValue(); - - /** - * Wrap std::string into ProtobufWkt::Value string value. - * @param str string to be wrapped. - * @return wrapped string. - */ - static ProtobufWkt::Value stringValue(const std::string& str); - - /** - * Wrap boolean into ProtobufWkt::Value boolean value. - * @param str boolean to be wrapped. - * @return wrapped boolean. - */ - static ProtobufWkt::Value boolValue(bool b); - - /** - * Wrap ProtobufWkt::Struct into ProtobufWkt::Value struct value. - * @param obj struct to be wrapped. - * @return wrapped struct. - */ - static ProtobufWkt::Value structValue(const ProtobufWkt::Struct& obj); - - /** - * Wrap number into ProtobufWkt::Value double value. - * @param num number to be wrapped. - * @return wrapped number. - */ - template static ProtobufWkt::Value numberValue(const T num) { - ProtobufWkt::Value val; - val.set_number_value(static_cast(num)); - return val; - } - - /** - * Wrap a collection of ProtobufWkt::Values into ProtobufWkt::Value list value. - * @param values collection of ProtobufWkt::Values to be wrapped. - * @return wrapped list value. - */ - static ProtobufWkt::Value listValue(const std::vector& values); -}; - -/** - * HashedValue is a wrapper around ProtobufWkt::Value that computes - * and stores a hash code for the Value at construction. - */ -class HashedValue { -public: - HashedValue(const ProtobufWkt::Value& value) : value_(value), hash_(ValueUtil::hash(value)){}; - HashedValue(const HashedValue& v) = default; - - const ProtobufWkt::Value& value() const { return value_; } - std::size_t hash() const { return hash_; } - - bool operator==(const HashedValue& rhs) const { - return hash_ == rhs.hash_ && ValueUtil::equal(value_, rhs.value_); - } - - bool operator!=(const HashedValue& rhs) const { return !(*this == rhs); } - -private: - const ProtobufWkt::Value value_; - const std::size_t hash_; -}; - class DurationUtil { public: class OutOfRangeException : public EnvoyException { @@ -525,11 +441,3 @@ class TimestampUtil { }; } // namespace Envoy - -namespace std { -// Inject an implementation of std::hash for Envoy::HashedValue into the std namespace. -template <> struct hash { - std::size_t operator()(Envoy::HashedValue const& v) const { return v.hash(); } -}; - -} // namespace std diff --git a/source/common/router/config_impl.cc b/source/common/router/config_impl.cc index 64e0e33f91f9e..d28ddbcff0642 100644 --- a/source/common/router/config_impl.cc +++ b/source/common/router/config_impl.cc @@ -734,13 +734,13 @@ const DirectResponseEntry* RouteEntryImplBase::directResponseEntry() const { } } -const RouteEntry* RouteEntryImplBase::routeEntry() const { +const std::shared_ptr RouteEntryImplBase::routeEntry() const { // A route for a request can exclusively be a route entry, a direct response entry, // or a redirect entry. if (isDirectResponse()) { return nullptr; } else { - return this; + return shared_from_this(); } } diff --git a/source/common/router/config_impl.h b/source/common/router/config_impl.h index c2e654b00e847..899367d819dc8 100644 --- a/source/common/router/config_impl.h +++ b/source/common/router/config_impl.h @@ -93,7 +93,7 @@ class SslRedirectRoute : public Route { public: // Router::Route const DirectResponseEntry* directResponseEntry() const override { return &SSL_REDIRECTOR; } - const RouteEntry* routeEntry() const override { return nullptr; } + const std::shared_ptr routeEntry() const override { return nullptr; } const Decorator* decorator() const override { return nullptr; } const RouteTracing* tracingConfig() const override { return nullptr; } const RouteSpecificFilterConfig* perFilterConfig(const std::string&) const override { @@ -476,7 +476,7 @@ class RouteEntryImplBase : public RouteEntry, // Router::Route const DirectResponseEntry* directResponseEntry() const override; - const RouteEntry* routeEntry() const override; + const std::shared_ptr routeEntry() const override; const Decorator* decorator() const override { return decorator_.get(); } const RouteTracing* tracingConfig() const override { return route_tracing_.get(); } const RouteSpecificFilterConfig* perFilterConfig(const std::string&) const override; @@ -507,7 +507,9 @@ class RouteEntryImplBase : public RouteEntry, envoy::type::v3::FractionalPercent fractional_runtime_default_{}; }; - class DynamicRouteEntry : public RouteEntry, public Route { + class DynamicRouteEntry : public RouteEntry, + public Route, + public std::enable_shared_from_this { public: DynamicRouteEntry(const RouteEntryImplBase* parent, const std::string& name) : parent_(parent), cluster_name_(name) {} @@ -593,7 +595,9 @@ class RouteEntryImplBase : public RouteEntry, // Router::Route const DirectResponseEntry* directResponseEntry() const override { return nullptr; } - const RouteEntry* routeEntry() const override { return this; } + const std::shared_ptr routeEntry() const override { + return shared_from_this(); + } const Decorator* decorator() const override { return parent_->decorator(); } const RouteTracing* tracingConfig() const override { return parent_->tracingConfig(); } diff --git a/source/common/router/router.h b/source/common/router/router.h index 7eaf5daeddd15..c703bf4a17c9c 100644 --- a/source/common/router/router.h +++ b/source/common/router/router.h @@ -451,7 +451,7 @@ class Filter : Logger::Loggable, FilterConfig& config_; Http::StreamDecoderFilterCallbacks* callbacks_{}; RouteConstSharedPtr route_; - const RouteEntry* route_entry_{}; + std::shared_ptr route_entry_{}; Upstream::ClusterInfoConstSharedPtr cluster_; std::unique_ptr alt_stat_prefix_; const VirtualCluster* request_vcluster_; diff --git a/source/common/stream_info/stream_info_impl.h b/source/common/stream_info/stream_info_impl.h index 00707bf9c6b87..0f0d6c21fc97b 100644 --- a/source/common/stream_info/stream_info_impl.h +++ b/source/common/stream_info/stream_info_impl.h @@ -207,7 +207,18 @@ struct StreamInfoImpl : public StreamInfo { return upstream_ssl_info_; } - const Router::RouteEntry* routeEntry() const override { return route_entry_; } + void setUpstreamEndpointInfo( + const Router::UpstreamEndpointInfoConstSharedPtr& upstream_endpoint_info) override { + upstream_endpoint_info_ = upstream_endpoint_info; + } + const Router::UpstreamEndpointInfo* upstreamEndpointInfo() const override { + return upstream_endpoint_info_.get(); + } + + void setRouteEntry(const std::shared_ptr& route_entry) override { + route_entry_ = route_entry; + } + const Router::RouteEntry* routeEntry() const override { return route_entry_.get(); } envoy::config::core::v3::Metadata& dynamicMetadata() override { return metadata_; }; const envoy::config::core::v3::Metadata& dynamicMetadata() const override { return metadata_; }; @@ -268,11 +279,12 @@ struct StreamInfoImpl : public StreamInfo { uint64_t response_flags_{}; Upstream::HostDescriptionConstSharedPtr upstream_host_{}; bool health_check_request_{}; - const Router::RouteEntry* route_entry_{}; + std::shared_ptr route_entry_{}; envoy::config::core::v3::Metadata metadata_{}; FilterStateSharedPtr filter_state_; FilterStateSharedPtr upstream_filter_state_; std::string route_name_; + Router::UpstreamEndpointInfoConstSharedPtr upstream_endpoint_info_{}; private: uint64_t bytes_received_{}; diff --git a/source/common/tcp_proxy/tcp_proxy.cc b/source/common/tcp_proxy/tcp_proxy.cc index 62182d0ebe9c2..5653957b6be6a 100644 --- a/source/common/tcp_proxy/tcp_proxy.cc +++ b/source/common/tcp_proxy/tcp_proxy.cc @@ -391,6 +391,8 @@ Network::FilterStatus Filter::initializeUpstreamConnection() { route_ = pickRoute(); const std::string& cluster_name = route_ ? route_->clusterName() : EMPTY_STRING; + getStreamInfo().setUpstreamEndpointInfo(route_); + // getStreamInfo().setRouteEntry(std::dynamic_pointer_cast(route_)); Upstream::ThreadLocalCluster* thread_local_cluster = cluster_manager_.get(cluster_name); diff --git a/source/common/tcp_proxy/tcp_proxy.h b/source/common/tcp_proxy/tcp_proxy.h index 25dd3353ec64c..2ee9e44fe1461 100644 --- a/source/common/tcp_proxy/tcp_proxy.h +++ b/source/common/tcp_proxy/tcp_proxy.h @@ -61,7 +61,7 @@ class UpstreamDrainManager; /** * Route is an individual resolved route for a connection. */ -class Route { +class Route : public Router::UpstreamEndpointInfo { public: virtual ~Route() = default; @@ -71,17 +71,6 @@ class Route { * @return bool true if this route matches a given connection. */ virtual bool matches(Network::Connection& connection) const PURE; - - /** - * @return const std::string& the upstream cluster that owns the route. - */ - virtual const std::string& clusterName() const PURE; - - /** - * @return MetadataMatchCriteria* the metadata that a subset load balancer should match when - * selecting an upstream host - */ - virtual const Router::MetadataMatchCriteria* metadataMatchCriteria() const PURE; }; using RouteConstSharedPtr = std::shared_ptr; diff --git a/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc b/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc index d90e5a410567a..d125db7790675 100644 --- a/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc +++ b/source/extensions/filters/http/aws_lambda/aws_lambda_filter.cc @@ -64,7 +64,7 @@ absl::optional Filter::calculateRouteArn() { if (!decoder_callbacks_->route() || !decoder_callbacks_->route()->routeEntry()) { return absl::nullopt; } - const auto* route_entry = decoder_callbacks_->route()->routeEntry(); + const auto route_entry = decoder_callbacks_->route()->routeEntry(); const auto* settings = route_entry->mostSpecificPerFilterConfigTyped( HttpFilterNames::get().AwsLambda); if (!settings) { diff --git a/source/extensions/filters/http/buffer/buffer_filter.cc b/source/extensions/filters/http/buffer/buffer_filter.cc index eeb4c81304fa7..7388154a13168 100644 --- a/source/extensions/filters/http/buffer/buffer_filter.cc +++ b/source/extensions/filters/http/buffer/buffer_filter.cc @@ -50,7 +50,7 @@ void BufferFilter::initConfig() { } const std::string& name = HttpFilterNames::get().Buffer; - const auto* entry = callbacks_->route()->routeEntry(); + const auto entry = callbacks_->route()->routeEntry(); const auto* route_local = entry->mostSpecificPerFilterConfigTyped(name); settings_ = route_local ? route_local : settings_; diff --git a/source/extensions/filters/http/dynamic_forward_proxy/proxy_filter.cc b/source/extensions/filters/http/dynamic_forward_proxy/proxy_filter.cc index 47d08e0dcab8d..49acb8352f755 100644 --- a/source/extensions/filters/http/dynamic_forward_proxy/proxy_filter.cc +++ b/source/extensions/filters/http/dynamic_forward_proxy/proxy_filter.cc @@ -42,7 +42,7 @@ void ProxyFilter::onDestroy() { Http::FilterHeadersStatus ProxyFilter::decodeHeaders(Http::RequestHeaderMap& headers, bool) { Router::RouteConstSharedPtr route = decoder_callbacks_->route(); - const Router::RouteEntry* route_entry; + std::shared_ptr route_entry; if (!route || !(route_entry = route->routeEntry())) { return Http::FilterHeadersStatus::Continue; } diff --git a/source/extensions/filters/http/fault/fault_filter.cc b/source/extensions/filters/http/fault/fault_filter.cc index f396f5a12ff68..9517f8cda8e65 100644 --- a/source/extensions/filters/http/fault/fault_filter.cc +++ b/source/extensions/filters/http/fault/fault_filter.cc @@ -109,7 +109,7 @@ Http::FilterHeadersStatus FaultFilter::decodeHeaders(Http::RequestHeaderMap& hea fault_settings_ = config_->settings(); if (decoder_callbacks_->route() && decoder_callbacks_->route()->routeEntry()) { const std::string& name = Extensions::HttpFilters::HttpFilterNames::get().Fault; - const auto* route_entry = decoder_callbacks_->route()->routeEntry(); + const auto route_entry = decoder_callbacks_->route()->routeEntry(); const auto* per_route_settings = route_entry->mostSpecificPerFilterConfigTyped(name); diff --git a/source/extensions/filters/http/ratelimit/ratelimit.cc b/source/extensions/filters/http/ratelimit/ratelimit.cc index cc4b8dd5bb770..8f9b7f73d8c62 100644 --- a/source/extensions/filters/http/ratelimit/ratelimit.cc +++ b/source/extensions/filters/http/ratelimit/ratelimit.cc @@ -44,7 +44,7 @@ void Filter::initiateCall(const Http::RequestHeaderMap& headers) { std::vector descriptors; - const Router::RouteEntry* route_entry = route->routeEntry(); + const auto route_entry = route->routeEntry(); // Get all applicable rate limit policy entries for the route. populateRateLimitDescriptors(route_entry->rateLimitPolicy(), descriptors, route_entry, headers); @@ -188,10 +188,11 @@ void Filter::complete(Filters::Common::RateLimit::LimitStatus status, } } -void Filter::populateRateLimitDescriptors(const Router::RateLimitPolicy& rate_limit_policy, - std::vector& descriptors, - const Router::RouteEntry* route_entry, - const Http::HeaderMap& headers) const { +void Filter::populateRateLimitDescriptors( + const Router::RateLimitPolicy& rate_limit_policy, + std::vector& descriptors, + const std::shared_ptr& route_entry, + const Http::HeaderMap& headers) const { for (const Router::RateLimitPolicyEntry& rate_limit : rate_limit_policy.getApplicableRateLimit(config_->stage())) { const std::string& disable_key = rate_limit.disableKey(); diff --git a/source/extensions/filters/http/ratelimit/ratelimit.h b/source/extensions/filters/http/ratelimit/ratelimit.h index c47e93cfde4f1..c45557bb0129f 100644 --- a/source/extensions/filters/http/ratelimit/ratelimit.h +++ b/source/extensions/filters/http/ratelimit/ratelimit.h @@ -122,10 +122,11 @@ class Filter : public Http::StreamFilter, public Filters::Common::RateLimit::Req private: void initiateCall(const Http::RequestHeaderMap& headers); - void populateRateLimitDescriptors(const Router::RateLimitPolicy& rate_limit_policy, - std::vector& descriptors, - const Router::RouteEntry* route_entry, - const Http::HeaderMap& headers) const; + void + populateRateLimitDescriptors(const Router::RateLimitPolicy& rate_limit_policy, + std::vector& descriptors, + const std::shared_ptr& route_entry, + const Http::HeaderMap& headers) const; void populateResponseHeaders(Http::HeaderMap& response_headers); void appendRequestHeaders(Http::HeaderMapPtr& request_headers_to_add); diff --git a/source/extensions/filters/http/rbac/rbac_filter.cc b/source/extensions/filters/http/rbac/rbac_filter.cc index 3c7b0df3ea0a9..334b0ce209fb5 100644 --- a/source/extensions/filters/http/rbac/rbac_filter.cc +++ b/source/extensions/filters/http/rbac/rbac_filter.cc @@ -35,7 +35,7 @@ RoleBasedAccessControlFilterConfig::engine(const Router::RouteConstSharedPtr rou } const std::string& name = HttpFilterNames::get().Rbac; - const auto* entry = route->routeEntry(); + const auto entry = route->routeEntry(); const auto* route_local = entry->mostSpecificPerFilterConfigTyped( name); diff --git a/source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.cc b/source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.cc index 694831013a42a..508adaed0d97b 100644 --- a/source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.cc +++ b/source/extensions/filters/network/thrift_proxy/router/router_ratelimit_impl.cc @@ -4,6 +4,8 @@ #include "envoy/config/route/v3/route_components.pb.h" #include "envoy/ratelimit/ratelimit.h" +#include "common/protobuf/utility.h" + #include "extensions/filters/network/thrift_proxy/router/router.h" namespace Envoy { diff --git a/test/common/stream_info/test_util.h b/test/common/stream_info/test_util.h index 81d47b23924ec..2dc244055439c 100644 --- a/test/common/stream_info/test_util.h +++ b/test/common/stream_info/test_util.h @@ -108,7 +108,18 @@ class TestStreamInfo : public StreamInfo::StreamInfo { } const std::string& getRouteName() const override { return route_name_; } - const Router::RouteEntry* routeEntry() const override { return route_entry_; } + void setUpstreamEndpointInfo( + const Router::UpstreamEndpointInfoConstSharedPtr& upstream_endpoint_info) override { + upstream_endpoint_info_ = upstream_endpoint_info; + } + const Router::UpstreamEndpointInfo* upstreamEndpointInfo() const override { + return upstream_endpoint_info_.get(); + } + + void setRouteEntry(const std::shared_ptr& route_entry) override { + route_entry_ = route_entry; + } + const Router::RouteEntry* routeEntry() const override { return route_entry_.get(); } absl::optional duration(const absl::optional& time) const { @@ -234,7 +245,7 @@ class TestStreamInfo : public StreamInfo::StreamInfo { Network::Address::InstanceConstSharedPtr downstream_remote_address_; Ssl::ConnectionInfoConstSharedPtr downstream_connection_info_; Ssl::ConnectionInfoConstSharedPtr upstream_connection_info_; - const Router::RouteEntry* route_entry_{}; + std::shared_ptr route_entry_{}; envoy::config::core::v3::Metadata metadata_{}; Envoy::StreamInfo::FilterStateSharedPtr filter_state_{ std::make_shared( @@ -245,6 +256,7 @@ class TestStreamInfo : public StreamInfo::StreamInfo { std::string upstream_transport_failure_reason_; const Http::RequestHeaderMap* request_headers_{}; Envoy::Event::SimulatedTimeSystem test_time_; + Router::UpstreamEndpointInfoConstSharedPtr upstream_endpoint_info_{}; }; } // namespace Envoy diff --git a/test/common/tcp_proxy/tcp_proxy_test.cc b/test/common/tcp_proxy/tcp_proxy_test.cc index 80d676f5b97a0..d085793bb1a27 100644 --- a/test/common/tcp_proxy/tcp_proxy_test.cc +++ b/test/common/tcp_proxy/tcp_proxy_test.cc @@ -1927,6 +1927,25 @@ TEST_F(TcpProxyRoutingTest, DEPRECATED_FEATURE_TEST(ApplicationProtocols)) { filter_->onNewConnection(); } +// Test that cluster name can be retrieved from streaminfo +TEST_F(TcpProxyRoutingTest, DEPRECATED_FEATURE_TEST(ClusterName)) { + setup(); + initializeFilter(); + + // Expect filter to try to open a connection to specified cluster. + EXPECT_CALL(factory_context_.cluster_manager_, tcpConnPoolForCluster("fake_cluster", _, _)) + .WillOnce(Return(nullptr)); + EXPECT_CALL(connection_.stream_info_, setUpstreamEndpointInfo(_)) + .WillOnce( + Invoke([](const Router::UpstreamEndpointInfoConstSharedPtr& upstream_endpoint_info) { + EXPECT_EQ(upstream_endpoint_info->clusterName(), "fake_cluster"); + })); + // Port 9999 is within the specified destination port range. + connection_.local_address_ = std::make_shared("1.2.3.4", 9999); + + filter_->onNewConnection(); +} + class TcpProxyHashingTest : public testing::Test { public: TcpProxyHashingTest() = default; diff --git a/test/mocks/router/mocks.cc b/test/mocks/router/mocks.cc index 5f4f8d487c1ef..9aff7d8367aa2 100644 --- a/test/mocks/router/mocks.cc +++ b/test/mocks/router/mocks.cc @@ -120,7 +120,7 @@ MockRouteTracing::MockRouteTracing() = default; MockRouteTracing::~MockRouteTracing() = default; MockRoute::MockRoute() { - ON_CALL(*this, routeEntry()).WillByDefault(Return(&route_entry_)); + ON_CALL(*this, routeEntry()).WillByDefault(Return(route_entry_)); ON_CALL(*this, decorator()).WillByDefault(Return(&decorator_)); ON_CALL(*this, tracingConfig()).WillByDefault(Return(nullptr)); } diff --git a/test/mocks/router/mocks.h b/test/mocks/router/mocks.h index b5ef51ca4dbcf..b173571629c50 100644 --- a/test/mocks/router/mocks.h +++ b/test/mocks/router/mocks.h @@ -405,12 +405,13 @@ class MockRoute : public Route { // Router::Route MOCK_METHOD(const DirectResponseEntry*, directResponseEntry, (), (const)); - MOCK_METHOD(const RouteEntry*, routeEntry, (), (const)); + MOCK_METHOD(const std::shared_ptr, routeEntry, (), (const)); MOCK_METHOD(const Decorator*, decorator, (), (const)); MOCK_METHOD(const RouteTracing*, tracingConfig, (), (const)); MOCK_METHOD(const RouteSpecificFilterConfig*, perFilterConfig, (const std::string&), (const)); - testing::NiceMock route_entry_; + std::shared_ptr> route_entry_{ + new testing::NiceMock()}; testing::NiceMock decorator_; testing::NiceMock route_tracing_; }; diff --git a/test/mocks/stream_info/mocks.h b/test/mocks/stream_info/mocks.h index 9a49ad4220027..69838530c01f5 100644 --- a/test/mocks/stream_info/mocks.h +++ b/test/mocks/stream_info/mocks.h @@ -73,6 +73,9 @@ class MockStreamInfo : public StreamInfo { MOCK_METHOD(Ssl::ConnectionInfoConstSharedPtr, downstreamSslConnection, (), (const)); MOCK_METHOD(void, setUpstreamSslConnection, (const Ssl::ConnectionInfoConstSharedPtr&)); MOCK_METHOD(Ssl::ConnectionInfoConstSharedPtr, upstreamSslConnection, (), (const)); + MOCK_METHOD(void, setUpstreamEndpointInfo, (const Router::UpstreamEndpointInfoConstSharedPtr&)); + MOCK_METHOD(const Router::UpstreamEndpointInfo*, upstreamEndpointInfo, (), (const)); + MOCK_METHOD(void, setRouteEntry, (const std::shared_ptr&)); MOCK_METHOD(const Router::RouteEntry*, routeEntry, (), (const)); MOCK_METHOD(envoy::config::core::v3::Metadata&, dynamicMetadata, ()); MOCK_METHOD(const envoy::config::core::v3::Metadata&, dynamicMetadata, (), (const));