diff --git a/CODEOWNERS b/CODEOWNERS index f4a9734686c39..cfb59537477f3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -43,6 +43,8 @@ extensions/filters/common/original_src @snowp @klarose /*/extensions/transport_sockets/common @alyssawilk @wez470 # starttls transport socket /*/extensions/transport_sockets/starttls @cpakulski @lizan +# internal upstream transport socket +/*/extensions/transport_sockets/internal_upstream @kyessenov @lambdai # sni_cluster extension /*/extensions/filters/network/sni_cluster @rshriram @lizan # sni_dynamic_forward_proxy extension diff --git a/api/BUILD b/api/BUILD index 6452534f006f1..7099a7abee5da 100644 --- a/api/BUILD +++ b/api/BUILD @@ -254,6 +254,7 @@ proto_library( "//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg", "//envoy/extensions/stat_sinks/wasm/v3:pkg", "//envoy/extensions/transport_sockets/alts/v3:pkg", + "//envoy/extensions/transport_sockets/internal_upstream/v3:pkg", "//envoy/extensions/transport_sockets/proxy_protocol/v3:pkg", "//envoy/extensions/transport_sockets/quic/v3:pkg", "//envoy/extensions/transport_sockets/raw_buffer/v3:pkg", diff --git a/api/envoy/extensions/transport_sockets/internal_upstream/v3/BUILD b/api/envoy/extensions/transport_sockets/internal_upstream/v3/BUILD new file mode 100644 index 0000000000000..1bbba241ba61a --- /dev/null +++ b/api/envoy/extensions/transport_sockets/internal_upstream/v3/BUILD @@ -0,0 +1,13 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/config/core/v3:pkg", + "//envoy/type/metadata/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/api/envoy/extensions/transport_sockets/internal_upstream/v3/internal_upstream.proto b/api/envoy/extensions/transport_sockets/internal_upstream/v3/internal_upstream.proto new file mode 100644 index 0000000000000..97a196a4980e2 --- /dev/null +++ b/api/envoy/extensions/transport_sockets/internal_upstream/v3/internal_upstream.proto @@ -0,0 +1,73 @@ +syntax = "proto3"; + +package envoy.extensions.transport_sockets.internal_upstream.v3; + +import "envoy/config/core/v3/base.proto"; +import "envoy/type/metadata/v3/metadata.proto"; + +import "udpa/annotations/status.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.transport_sockets.internal_upstream.v3"; +option java_outer_classname = "InternalUpstreamProto"; +option java_multiple_files = true; +option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/internal_upstream/v3;internal_upstreamv3"; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Internal Upstream] +// [#extension: envoy.transport_sockets.internal_upstream] + +// Configuration for the internal upstream address. An internal address defines +// a loopback user space socket residing in the same proxy instance. This +// extension allows passing additional structured state across the user space +// socket in addition to the regular byte stream. The purpose is to facilitate +// communication between filters on the downstream and the upstream internal +// connections. +// +// Because the passthrough state is transferred once per the upstream +// connection before the bytes payload, every passthrough filter state object +// is included in the hash key used to select an upstream connection if it +// implements a hashing interface. +// +// .. note:: +// +// Using internal upstream transport affects load balancing decisions if the +// passthrough state is derived from the downstream connection attributes. As +// an example, using the downstream source IP in the passthrough state will +// prevent sharing of an upstream internal connection between different source +// IPs. +message InternalUpstreamTransport { + // Describes the location of the imported metadata value. + // If the metadata with the given name is not present at the source location, + // then no metadata is passed through for this particular instance. + message MetadataValueSource { + // Specifies what kind of metadata. + type.metadata.v3.MetadataKind kind = 1 [(validate.rules).message = {required: true}]; + + // Name is the filter namespace used in the dynamic metadata. + string name = 2 [(validate.rules).string = {min_len: 1}]; + } + + // Describes the location of the imported filter state object from the downstream connection. + message FilterStateSource { + // Name is the imported filter state object name. + string name = 1 [(validate.rules).string = {min_len: 1}]; + } + + // Specifies the metadata namespaces and values to insert into the downstream + // internal connection dynamic metadata when an internal address is used as a + // host. If the destination name is repeated across two metadata source + // locations, and both locations contain the metadata with the given name, + // then the latter in the list overrides the former. + repeated MetadataValueSource passthrough_metadata = 1; + + // Specifies the list of the filter state object names to insert into the + // server internal connection from the downstream connection when an internal + // address is used as a host. The filter state objects must be mutable. These + // objects participate in the connection hashing decisions if they implement a + // hashing function. + repeated FilterStateSource passthrough_filter_state_objects = 2; + + // The underlying transport socket being wrapped. + config.core.v3.TransportSocket transport_socket = 3 [(validate.rules).message = {required: true}]; +} diff --git a/api/versioning/BUILD b/api/versioning/BUILD index 770f535d186a0..fd85c4e0c18f5 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -195,6 +195,7 @@ proto_library( "//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg", "//envoy/extensions/stat_sinks/wasm/v3:pkg", "//envoy/extensions/transport_sockets/alts/v3:pkg", + "//envoy/extensions/transport_sockets/internal_upstream/v3:pkg", "//envoy/extensions/transport_sockets/proxy_protocol/v3:pkg", "//envoy/extensions/transport_sockets/quic/v3:pkg", "//envoy/extensions/transport_sockets/raw_buffer/v3:pkg", diff --git a/changelogs/current.yaml b/changelogs/current.yaml index 77c595a0cc814..201ff253d6f32 100644 --- a/changelogs/current.yaml +++ b/changelogs/current.yaml @@ -249,6 +249,9 @@ new_features: - area: http change: | added :ref:`cluster_header ` in :ref:`request_mirror_policies ` to allow routing shadow request to the cluster specified in the request_header. +- area: upstream + change: | + added :ref:`internal upstream transport ` for passing metadata and filter state across the user space sockets and the internal listeners. - area: router change: added :ref:`keep_empty_value ` to allow keeping empty values in custom headers. diff --git a/docs/root/configuration/other_features/internal_listener.rst b/docs/root/configuration/other_features/internal_listener.rst index c317802bcdc81..8259c016fff5d 100644 --- a/docs/root/configuration/other_features/internal_listener.rst +++ b/docs/root/configuration/other_features/internal_listener.rst @@ -21,6 +21,26 @@ network.connection.client.envoy_internal It is a client connection factory. The factory is implicitly instantiated by the dispatcher to establish a client connection to an internal listener address. This client connection factory is installed automatically when ``envoy.bootstrap.internal_listener`` is specified. +Internal upstream transport +--------------------------- + +:ref:`Internal upstream transport +` +extension enables exchange of the filter state from the downstream listener to +the internal listener through a user space socket. This additional state can be +in the form of the resource metadata obtained from the upstream host or +:ref:`the filter state objects `. + +This extension emits the following statistics: + +.. csv-table:: + :header: Name, Type, Description + :widths: 1, 1, 2 + + no_metadata, Counter, Metadata key is absent from the import location. + no_filter_state, Counter, Filter state object key is absent from the downstream filter state. + filter_state_error, Counter, Unable to copy the filter state object (e.g. it is read only). + Example config -------------- Below is a smallest static config that redirect TCP proxy on port 19000 to the TCP proxy binding to the internal address. diff --git a/envoy/network/transport_socket.h b/envoy/network/transport_socket.h index a78f8f2cf2e2c..f9c75f77f8ed4 100644 --- a/envoy/network/transport_socket.h +++ b/envoy/network/transport_socket.h @@ -14,6 +14,11 @@ #include "absl/types/optional.h" namespace Envoy { + +namespace Upstream { +class HostDescription; +} + namespace Network { class Connection; @@ -259,10 +264,12 @@ class UpstreamTransportSocketFactory : public virtual TransportSocketFactoryBase /** * @param options for creating the transport socket + * @param host description for the destination upstream host * @return Network::TransportSocketPtr a transport socket to be passed to client connection. */ virtual TransportSocketPtr - createTransportSocket(TransportSocketOptionsConstSharedPtr options) const PURE; + createTransportSocket(TransportSocketOptionsConstSharedPtr options, + std::shared_ptr host) const PURE; /** * Returns true if the transport socket created by this factory supports some form of ALPN diff --git a/source/common/network/happy_eyeballs_connection_impl.cc b/source/common/network/happy_eyeballs_connection_impl.cc index 626d3c2478137..d3b06dc8c98ce 100644 --- a/source/common/network/happy_eyeballs_connection_impl.cc +++ b/source/common/network/happy_eyeballs_connection_impl.cc @@ -9,11 +9,12 @@ HappyEyeballsConnectionImpl::HappyEyeballsConnectionImpl( Event::Dispatcher& dispatcher, const std::vector& address_list, Address::InstanceConstSharedPtr source_address, UpstreamTransportSocketFactory& socket_factory, TransportSocketOptionsConstSharedPtr transport_socket_options, + const Upstream::HostDescriptionConstSharedPtr& host, const ConnectionSocket::OptionsSharedPtr options) : id_(ConnectionImpl::next_global_id_++), dispatcher_(dispatcher), address_list_(sortAddresses(address_list)), connection_construction_state_( - {source_address, socket_factory, transport_socket_options, options}), + {source_address, socket_factory, transport_socket_options, host, options}), next_attempt_timer_(dispatcher_.createTimer([this]() -> void { tryAnotherConnection(); })) { ENVOY_LOG_EVENT(debug, "happy_eyeballs_new_cx", "[C{}] addresses={}", id_, address_list_.size()); connections_.push_back(createNextConnection()); @@ -432,7 +433,8 @@ ClientConnectionPtr HappyEyeballsConnectionImpl::createNextConnection() { auto connection = dispatcher_.createClientConnection( address_list_[next_address_++], connection_construction_state_.source_address_, connection_construction_state_.socket_factory_.createTransportSocket( - connection_construction_state_.transport_socket_options_), + connection_construction_state_.transport_socket_options_, + connection_construction_state_.host_), connection_construction_state_.options_); ENVOY_LOG_EVENT(debug, "happy_eyeballs_cx_attempt", "C[{}] address={}", id_, next_address_); callbacks_wrappers_.push_back(std::make_unique(*this, *connection)); diff --git a/source/common/network/happy_eyeballs_connection_impl.h b/source/common/network/happy_eyeballs_connection_impl.h index 38085c51453d7..10424f0efbfde 100644 --- a/source/common/network/happy_eyeballs_connection_impl.h +++ b/source/common/network/happy_eyeballs_connection_impl.h @@ -40,6 +40,7 @@ class HappyEyeballsConnectionImpl : public ClientConnection, Address::InstanceConstSharedPtr source_address, UpstreamTransportSocketFactory& socket_factory, TransportSocketOptionsConstSharedPtr transport_socket_options, + const Upstream::HostDescriptionConstSharedPtr& host, const ConnectionSocket::OptionsSharedPtr options); ~HappyEyeballsConnectionImpl() override; @@ -199,6 +200,7 @@ class HappyEyeballsConnectionImpl : public ClientConnection, Address::InstanceConstSharedPtr source_address_; UpstreamTransportSocketFactory& socket_factory_; TransportSocketOptionsConstSharedPtr transport_socket_options_; + const Upstream::HostDescriptionConstSharedPtr host_; const ConnectionSocket::OptionsSharedPtr options_; }; diff --git a/source/common/network/raw_buffer_socket.cc b/source/common/network/raw_buffer_socket.cc index 0d6dfa28c0c3c..6ad896d095ae0 100644 --- a/source/common/network/raw_buffer_socket.cc +++ b/source/common/network/raw_buffer_socket.cc @@ -87,7 +87,8 @@ absl::string_view RawBufferSocket::failureReason() const { return EMPTY_STRING; void RawBufferSocket::onConnected() { callbacks_->raiseEvent(ConnectionEvent::Connected); } TransportSocketPtr -RawBufferSocketFactory::createTransportSocket(TransportSocketOptionsConstSharedPtr) const { +RawBufferSocketFactory::createTransportSocket(TransportSocketOptionsConstSharedPtr, + Upstream::HostDescriptionConstSharedPtr) const { return std::make_unique(); } diff --git a/source/common/network/raw_buffer_socket.h b/source/common/network/raw_buffer_socket.h index fa7cc9ea2116b..8d1f89c2d9ff8 100644 --- a/source/common/network/raw_buffer_socket.h +++ b/source/common/network/raw_buffer_socket.h @@ -37,8 +37,8 @@ class RawBufferSocketFactory : public DownstreamTransportSocketFactory, public CommonUpstreamTransportSocketFactory { public: // Network::UpstreamTransportSocketFactory - TransportSocketPtr - createTransportSocket(TransportSocketOptionsConstSharedPtr options) const override; + TransportSocketPtr createTransportSocket(TransportSocketOptionsConstSharedPtr, + Upstream::HostDescriptionConstSharedPtr) const override; bool implementsSecureTransport() const override; absl::string_view defaultServerNameIndication() const override { return ""; } // Network::DownstreamTransportSocketFactory diff --git a/source/common/quic/quic_transport_socket_factory.h b/source/common/quic/quic_transport_socket_factory.h index ef974dd108227..3c40e2b728f90 100644 --- a/source/common/quic/quic_transport_socket_factory.h +++ b/source/common/quic/quic_transport_socket_factory.h @@ -117,8 +117,9 @@ class QuicClientTransportSocketFactory : public Network::CommonUpstreamTransport // is needed. In this case the QuicClientTransportSocketFactory falls over to // using the fallback factory. Network::TransportSocketPtr - createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options) const override { - return fallback_factory_->createTransportSocket(options); + createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const override { + return fallback_factory_->createTransportSocket(options, host); } virtual Envoy::Ssl::ClientContextSharedPtr sslCtx() { return fallback_factory_->sslCtx(); } diff --git a/source/common/upstream/logical_host.cc b/source/common/upstream/logical_host.cc index ef8620d4e6395..688573e4bb88f 100644 --- a/source/common/upstream/logical_host.cc +++ b/source/common/upstream/logical_host.cc @@ -9,12 +9,11 @@ Upstream::Host::CreateConnectionData LogicalHost::createConnection( const auto current_address = address(); const std::vector& address_list = addressList(); - return {HostImpl::createConnection(dispatcher, cluster(), current_address, address_list, - transportSocketFactory(), options, - override_transport_socket_options_ != nullptr - ? override_transport_socket_options_ - : transport_socket_options), - std::make_shared(current_address, shared_from_this())}; + return HostImpl::createConnection( + dispatcher, cluster(), current_address, address_list, transportSocketFactory(), options, + override_transport_socket_options_ != nullptr ? override_transport_socket_options_ + : transport_socket_options, + std::make_shared(current_address, shared_from_this())); } } // namespace Upstream diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index c66ee3c3272d1..e9e3c5ce15c6a 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -279,9 +279,8 @@ Network::UpstreamTransportSocketFactory& HostDescriptionImpl::resolveTransportSo Host::CreateConnectionData HostImpl::createConnection( Event::Dispatcher& dispatcher, const Network::ConnectionSocket::OptionsSharedPtr& options, Network::TransportSocketOptionsConstSharedPtr transport_socket_options) const { - return {createConnection(dispatcher, cluster(), address(), addressList(), - transportSocketFactory(), options, transport_socket_options), - shared_from_this()}; + return createConnection(dispatcher, cluster(), address(), addressList(), transportSocketFactory(), + options, transport_socket_options, shared_from_this()); } void HostImpl::setEdsHealthFlag(envoy::config::core::v3::HealthStatus health_status) { @@ -310,9 +309,8 @@ Host::CreateConnectionData HostImpl::createHealthCheckConnection( Network::UpstreamTransportSocketFactory& factory = (metadata != nullptr) ? resolveTransportSocketFactory(healthCheckAddress(), metadata) : transportSocketFactory(); - return {createConnection(dispatcher, cluster(), healthCheckAddress(), {}, factory, nullptr, - transport_socket_options), - shared_from_this()}; + return createConnection(dispatcher, cluster(), healthCheckAddress(), {}, factory, nullptr, + transport_socket_options, shared_from_this()); } Network::ConnectionSocket::OptionsSharedPtr @@ -334,13 +332,14 @@ combineConnectionSocketOptions(const ClusterInfo& cluster, return connection_options; } -Network::ClientConnectionPtr HostImpl::createConnection( +Host::CreateConnectionData HostImpl::createConnection( Event::Dispatcher& dispatcher, const ClusterInfo& cluster, const Network::Address::InstanceConstSharedPtr& address, const std::vector& address_list, Network::UpstreamTransportSocketFactory& socket_factory, const Network::ConnectionSocket::OptionsSharedPtr& options, - Network::TransportSocketOptionsConstSharedPtr transport_socket_options) { + Network::TransportSocketOptionsConstSharedPtr transport_socket_options, + HostDescriptionConstSharedPtr host) { Network::ConnectionSocket::OptionsSharedPtr connection_options = combineConnectionSocketOptions(cluster, options); @@ -351,17 +350,17 @@ Network::ClientConnectionPtr HostImpl::createConnection( address_list.size() > 1 ? std::make_unique( dispatcher, address_list, cluster.sourceAddress(), socket_factory, - transport_socket_options, connection_options) + transport_socket_options, host, connection_options) : dispatcher.createClientConnection( address, cluster.sourceAddress(), - socket_factory.createTransportSocket(std::move(transport_socket_options)), + socket_factory.createTransportSocket(transport_socket_options, host), connection_options); connection->connectionInfoSetter().enableSettingInterfaceName( cluster.setLocalInterfaceNameOnUpstreamConnections()); connection->setBufferLimits(cluster.perConnectionBufferLimitBytes()); cluster.createNetworkFilterChain(*connection); - return connection; + return {std::move(connection), std::move(host)}; } void HostImpl::weight(uint32_t new_weight) { weight_ = std::max(1U, new_weight); } diff --git a/source/common/upstream/upstream_impl.h b/source/common/upstream/upstream_impl.h index 4a8d2c1ea21bc..21d2f64ad144a 100644 --- a/source/common/upstream/upstream_impl.h +++ b/source/common/upstream/upstream_impl.h @@ -289,13 +289,14 @@ class HostImpl : public HostDescriptionImpl, void used(bool new_used) override { used_ = new_used; } protected: - static Network::ClientConnectionPtr + static CreateConnectionData createConnection(Event::Dispatcher& dispatcher, const ClusterInfo& cluster, const Network::Address::InstanceConstSharedPtr& address, const std::vector& address_list, Network::UpstreamTransportSocketFactory& socket_factory, const Network::ConnectionSocket::OptionsSharedPtr& options, - Network::TransportSocketOptionsConstSharedPtr transport_socket_options); + Network::TransportSocketOptionsConstSharedPtr transport_socket_options, + HostDescriptionConstSharedPtr host); private: void setEdsHealthFlag(envoy::config::core::v3::HealthStatus health_status); diff --git a/source/extensions/bootstrap/internal_listener/BUILD b/source/extensions/bootstrap/internal_listener/BUILD index fb0bd97571306..cb2db85312f7d 100644 --- a/source/extensions/bootstrap/internal_listener/BUILD +++ b/source/extensions/bootstrap/internal_listener/BUILD @@ -96,6 +96,7 @@ envoy_cc_library( "//source/common/network:listener_filter_buffer_lib", "//source/common/stats:timespan_lib", "//source/common/stream_info:stream_info_lib", + "//source/extensions/io_socket/user_space:config", "//source/server:active_stream_listener_base", "//source/server:active_tcp_listener", ], diff --git a/source/extensions/bootstrap/internal_listener/active_internal_listener.cc b/source/extensions/bootstrap/internal_listener/active_internal_listener.cc index 45ce47a68bf09..9080807c89db1 100644 --- a/source/extensions/bootstrap/internal_listener/active_internal_listener.cc +++ b/source/extensions/bootstrap/internal_listener/active_internal_listener.cc @@ -5,6 +5,7 @@ #include "source/common/network/address_impl.h" #include "source/common/stats/timespan_impl.h" +#include "source/extensions/io_socket/user_space/io_handle.h" #include "source/server/active_stream_listener_base.h" namespace Envoy { @@ -55,8 +56,14 @@ void ActiveInternalListener::onAccept(Network::ConnectionSocketPtr&& socket) { // connections. incNumConnections(); + auto* io_handle = dynamic_cast(&socket->ioHandle()); auto active_socket = std::make_unique( *this, std::move(socket), false /* do not hand off at internal listener */); + // Transfer internal passthrough state to the active socket from downstream. + if (io_handle != nullptr && io_handle->passthroughState()) { + io_handle->passthroughState()->mergeInto(active_socket->dynamicMetadata(), + active_socket->filterState()); + } onSocketAccepted(std::move(active_socket)); } diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index 840cfca84cae8..0957548c9e73b 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -208,6 +208,7 @@ EXTENSIONS = { "envoy.transport_sockets.tap": "//source/extensions/transport_sockets/tap:config", "envoy.transport_sockets.starttls": "//source/extensions/transport_sockets/starttls:config", "envoy.transport_sockets.tcp_stats": "//source/extensions/transport_sockets/tcp_stats:config", + "envoy.transport_sockets.internal_upstream": "//source/extensions/transport_sockets/internal_upstream:config", # # Retry host predicates diff --git a/source/extensions/extensions_metadata.yaml b/source/extensions/extensions_metadata.yaml index d22739017348d..bfff9c09680f8 100644 --- a/source/extensions/extensions_metadata.yaml +++ b/source/extensions/extensions_metadata.yaml @@ -670,6 +670,11 @@ envoy.transport_sockets.alts: - envoy.transport_sockets.upstream security_posture: robust_to_untrusted_downstream_and_upstream status: stable +envoy.transport_sockets.internal_upstream: + categories: + - envoy.transport_sockets.upstream + security_posture: unknown + status: wip envoy.transport_sockets.raw_buffer: categories: - envoy.transport_sockets.downstream diff --git a/source/extensions/io_socket/user_space/BUILD b/source/extensions/io_socket/user_space/BUILD index 2ea8a3613353c..f54cf9b054cdb 100644 --- a/source/extensions/io_socket/user_space/BUILD +++ b/source/extensions/io_socket/user_space/BUILD @@ -23,9 +23,11 @@ envoy_cc_library( name = "io_handle_lib", hdrs = ["io_handle.h"], deps = [ + "//envoy/stream_info:filter_state_interface", "//source/common/buffer:buffer_lib", "//source/common/buffer:watermark_buffer_lib", "//source/common/common:empty_string", + "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], ) diff --git a/source/extensions/io_socket/user_space/io_handle.h b/source/extensions/io_socket/user_space/io_handle.h index 2098c94172ee2..6019e3e459e6b 100644 --- a/source/extensions/io_socket/user_space/io_handle.h +++ b/source/extensions/io_socket/user_space/io_handle.h @@ -1,13 +1,41 @@ #pragma once #include "envoy/buffer/buffer.h" +#include "envoy/common/optref.h" #include "envoy/common/pure.h" +#include "envoy/config/core/v3/base.pb.h" +#include "envoy/stream_info/filter_state.h" namespace Envoy { namespace Extensions { namespace IoSocket { namespace UserSpace { +using FilterStateObjects = + std::vector>>; + +// Shared state between peering user space IO handles. +class PassthroughState { +public: + virtual ~PassthroughState() = default; + + /** + * Initialize the passthrough state from the downstream. This should be + * called exactly once before `mergeInto`. + */ + virtual void initialize(std::unique_ptr metadata, + std::unique_ptr filter_state_objects) PURE; + + /** + * Merge the passthrough state into a recipient stream metadata and its + * filter state. This should be called at most once after `initialize`. + */ + virtual void mergeInto(envoy::config::core::v3::Metadata& metadata, + StreamInfo::FilterState& filter_state) PURE; +}; + +using PassthroughStateSharedPtr = std::shared_ptr; + /** * The interface for the peer as a writer and supplied read status query. */ @@ -60,6 +88,11 @@ class IoHandle { * @return true if the pending receive buffer is not empty or read_end is set. */ virtual bool isReadable() const PURE; + + /** + * @return shared state between peering user space IO handles. + */ + virtual PassthroughStateSharedPtr passthroughState() PURE; }; } // namespace UserSpace } // namespace IoSocket diff --git a/source/extensions/io_socket/user_space/io_handle_impl.cc b/source/extensions/io_socket/user_space/io_handle_impl.cc index bd928e23778bc..003f42910aaff 100644 --- a/source/extensions/io_socket/user_space/io_handle_impl.cc +++ b/source/extensions/io_socket/user_space/io_handle_impl.cc @@ -54,9 +54,10 @@ const Network::Address::InstanceConstSharedPtr& IoHandleImpl::getCommonInternalA "internal_address_for_user_space_io_handle")); } -IoHandleImpl::IoHandleImpl() +IoHandleImpl::IoHandleImpl(PassthroughStateSharedPtr passthrough_state) : pending_received_data_([&]() -> void { this->onBelowLowWatermark(); }, - [&]() -> void { this->onAboveHighWatermark(); }, []() -> void {}) {} + [&]() -> void { this->onAboveHighWatermark(); }, []() -> void {}), + passthrough_state_(passthrough_state) {} IoHandleImpl::~IoHandleImpl() { if (!closed_) { @@ -376,6 +377,34 @@ Api::SysCallIntResult IoHandleImpl::shutdown(int how) { } return {0, 0}; } + +void PassthroughStateImpl::initialize(std::unique_ptr metadata, + std::unique_ptr filter_state_objects) { + ASSERT(state_ == State::Created); + metadata_ = std::move(metadata); + filter_state_objects_ = std::move(filter_state_objects); + state_ = State::Initialized; +} +void PassthroughStateImpl::mergeInto(envoy::config::core::v3::Metadata& metadata, + StreamInfo::FilterState& filter_state) { + ASSERT(state_ == State::Initialized); + if (metadata_) { + metadata.MergeFrom(*metadata_); + } + if (filter_state_objects_) { + for (const auto& [name, object] : *filter_state_objects_) { + try { + filter_state.setData(name, object, StreamInfo::FilterState::StateType::Mutable, + StreamInfo::FilterState::LifeSpan::Connection); + } catch (const EnvoyException& e) { + ENVOY_LOG(trace, "Failed to set data for '{}': {}", name, e.what()); + } + } + } + metadata_ = nullptr; + filter_state_objects_ = nullptr; + state_ = State::Done; +} } // namespace UserSpace } // namespace IoSocket } // namespace Extensions diff --git a/source/extensions/io_socket/user_space/io_handle_impl.h b/source/extensions/io_socket/user_space/io_handle_impl.h index 12c91a941b7f4..65bfe0084d019 100644 --- a/source/extensions/io_socket/user_space/io_handle_impl.h +++ b/source/extensions/io_socket/user_space/io_handle_impl.h @@ -149,9 +149,11 @@ class IoHandleImpl final : public Network::IoHandle, static_cast(writable_peer)); } + PassthroughStateSharedPtr passthroughState() override { return passthrough_state_; } + private: friend class IoHandleFactory; - IoHandleImpl(); + explicit IoHandleImpl(PassthroughStateSharedPtr passthrough_state = nullptr); static const Network::Address::InstanceConstSharedPtr& getCommonInternalAddress(); @@ -175,20 +177,41 @@ class IoHandleImpl final : public Network::IoHandle, // The flag whether the peer is valid. Any write attempt must check this flag. bool write_shutdown_{false}; + + // Shared state between peer handles. + PassthroughStateSharedPtr passthrough_state_{nullptr}; +}; + +class PassthroughStateImpl : public PassthroughState, public Logger::Loggable { +public: + void initialize(std::unique_ptr metadata, + std::unique_ptr filter_state_objects) override; + void mergeInto(envoy::config::core::v3::Metadata& metadata, + StreamInfo::FilterState& filter_state) override; + +private: + enum class State { Created, Initialized, Done }; + State state_{State::Created}; + std::unique_ptr metadata_; + std::unique_ptr filter_state_objects_; }; using IoHandleImplPtr = std::unique_ptr; class IoHandleFactory { public: static std::pair createIoHandlePair() { - auto p = std::pair{new IoHandleImpl(), new IoHandleImpl()}; + auto state = std::make_shared(); + auto p = std::pair{new IoHandleImpl(state), + new IoHandleImpl(state)}; p.first->setPeerHandle(p.second.get()); p.second->setPeerHandle(p.first.get()); return p; } static std::pair createBufferLimitedIoHandlePair(uint32_t buffer_size) { - auto p = std::pair{new IoHandleImpl(), new IoHandleImpl()}; + auto state = std::make_shared(); + auto p = std::pair{new IoHandleImpl(state), + new IoHandleImpl(state)}; // This buffer watermark setting emulates the OS socket buffer parameter // `/proc/sys/net/ipv4/tcp_{r,w}mem`. p.first->setWatermarks(buffer_size); diff --git a/source/extensions/transport_sockets/alts/tsi_socket.cc b/source/extensions/transport_sockets/alts/tsi_socket.cc index 9dced4f35230d..43e060cb497e5 100644 --- a/source/extensions/transport_sockets/alts/tsi_socket.cc +++ b/source/extensions/transport_sockets/alts/tsi_socket.cc @@ -381,7 +381,8 @@ TsiSocketFactory::TsiSocketFactory(HandshakerFactory handshaker_factory, bool TsiSocketFactory::implementsSecureTransport() const { return true; } Network::TransportSocketPtr -TsiSocketFactory::createTransportSocket(Network::TransportSocketOptionsConstSharedPtr) const { +TsiSocketFactory::createTransportSocket(Network::TransportSocketOptionsConstSharedPtr, + Upstream::HostDescriptionConstSharedPtr) const { return std::make_unique(handshaker_factory_, handshake_validator_); } diff --git a/source/extensions/transport_sockets/alts/tsi_socket.h b/source/extensions/transport_sockets/alts/tsi_socket.h index a95e087debd64..04622fdc88c89 100644 --- a/source/extensions/transport_sockets/alts/tsi_socket.h +++ b/source/extensions/transport_sockets/alts/tsi_socket.h @@ -139,7 +139,8 @@ class TsiSocketFactory : public Network::DownstreamTransportSocketFactory, absl::string_view defaultServerNameIndication() const override { return ""; } Network::TransportSocketPtr - createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options) const override; + createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr) const override; Network::TransportSocketPtr createDownstreamTransportSocket() const override; diff --git a/source/extensions/transport_sockets/internal_upstream/BUILD b/source/extensions/transport_sockets/internal_upstream/BUILD new file mode 100644 index 0000000000000..28253fd0dd7d3 --- /dev/null +++ b/source/extensions/transport_sockets/internal_upstream/BUILD @@ -0,0 +1,40 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_library( + name = "internal_upstream", + srcs = ["internal_upstream.cc"], + hdrs = ["internal_upstream.h"], + deps = [ + "//source/extensions/io_socket/user_space:io_handle_lib", + "//source/extensions/transport_sockets/common:passthrough_lib", + "@envoy_api//envoy/extensions/transport_sockets/internal_upstream/v3:pkg_cc_proto", + ], +) + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + hdrs = ["config.h"], + deps = [ + ":internal_upstream", + "//envoy/common:hashable_interface", + "//envoy/registry", + "//envoy/server:transport_socket_config_interface", + "//envoy/stats:stats_macros", + "//source/common/common:logger_lib", + "//source/common/common:scalar_to_byte_vector_lib", + "//source/common/config:utility_lib", + "//source/extensions/io_socket/user_space:io_handle_lib", + "//source/extensions/transport_sockets/common:passthrough_lib", + "@envoy_api//envoy/extensions/transport_sockets/internal_upstream/v3:pkg_cc_proto", + ], +) diff --git a/source/extensions/transport_sockets/internal_upstream/config.cc b/source/extensions/transport_sockets/internal_upstream/config.cc new file mode 100644 index 0000000000000..984769e9c5609 --- /dev/null +++ b/source/extensions/transport_sockets/internal_upstream/config.cc @@ -0,0 +1,181 @@ +#include "source/extensions/transport_sockets/internal_upstream/config.h" + +#include "envoy/common/hashable.h" +#include "envoy/common/optref.h" +#include "envoy/extensions/transport_sockets/internal_upstream/v3/internal_upstream.pb.validate.h" +#include "envoy/registry/registry.h" + +#include "source/common/common/scalar_to_byte_vector.h" +#include "source/common/config/utility.h" +#include "source/extensions/transport_sockets/internal_upstream/internal_upstream.h" + +namespace Envoy { +namespace Extensions { +namespace TransportSockets { +namespace InternalUpstream { + +namespace { + +class InternalUpstreamConfigFactory + : public Server::Configuration::UpstreamTransportSocketConfigFactory { +public: + std::string name() const override { return "envoy.transport_sockets.internal_upstream"; } + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique< + envoy::extensions::transport_sockets::internal_upstream::v3::InternalUpstreamTransport>(); + } + Network::UpstreamTransportSocketFactoryPtr createTransportSocketFactory( + const Protobuf::Message& config, + Server::Configuration::TransportSocketFactoryContext& context) override { + const auto& outer_config = + MessageUtil::downcastAndValidate( + config, context.messageValidationVisitor()); + auto& inner_config_factory = Envoy::Config::Utility::getAndCheckFactory< + Server::Configuration::UpstreamTransportSocketConfigFactory>( + outer_config.transport_socket()); + ProtobufTypes::MessagePtr inner_factory_config = + Envoy::Config::Utility::translateToFactoryConfig(outer_config.transport_socket(), + context.messageValidationVisitor(), + inner_config_factory); + auto inner_transport_factory = + inner_config_factory.createTransportSocketFactory(*inner_factory_config, context); + return std::make_unique(context, outer_config, + std::move(inner_transport_factory)); + } +}; + +} // namespace + +Config::Config( + const envoy::extensions::transport_sockets::internal_upstream::v3::InternalUpstreamTransport& + config_proto, + Stats::Scope& scope) + : stats_{ALL_INTERNAL_UPSTREAM_STATS(POOL_COUNTER_PREFIX(scope, "internal_upstream."))} { + for (const auto& metadata : config_proto.passthrough_metadata()) { + MetadataKind kind; + switch (metadata.kind().kind_case()) { + case envoy::type::metadata::v3::MetadataKind::KindCase::kHost: + kind = MetadataKind::Host; + break; + case envoy::type::metadata::v3::MetadataKind::KindCase::kCluster: + kind = MetadataKind::Cluster; + break; + default: + throw EnvoyException( + absl::StrCat("metadata type is not supported: ", metadata.kind().DebugString())); + } + metadata_sources_.push_back(MetadataSource(kind, metadata.name())); + } + for (const auto& filter_state_object : config_proto.passthrough_filter_state_objects()) { + filter_state_names_.push_back(filter_state_object.name()); + } +} +std::unique_ptr +Config::extractMetadata(const Upstream::HostDescriptionConstSharedPtr& host) const { + if (metadata_sources_.empty()) { + return nullptr; + } + auto metadata = std::make_unique(); + for (const auto& source : metadata_sources_) { + OptRef source_metadata; + switch (source.kind_) { + case MetadataKind::Host: { + if (host->metadata()) { + source_metadata = makeOptRef(*host->metadata()); + } + break; + } + case MetadataKind::Cluster: + source_metadata = makeOptRef(host->cluster().metadata()); + break; + } + if (source_metadata && source_metadata->filter_metadata().contains(source.name_)) { + (*metadata->mutable_filter_metadata())[source.name_] = + source_metadata->filter_metadata().at(source.name_); + } else { + ENVOY_LOG(trace, "Internal upstream missing metadata: {}", source.name_); + stats_.no_metadata_.inc(); + } + } + return metadata; +} + +std::unique_ptr +Config::extractFilterState(const StreamInfo::FilterStateSharedPtr& filter_state) const { + if (filter_state_names_.empty()) { + return nullptr; + } + auto filter_state_objects = std::make_unique(); + for (const auto& name : filter_state_names_) { + try { + auto object = filter_state->getDataSharedMutableGeneric(name); + if (object == nullptr) { + ENVOY_LOG(trace, "Internal upstream missing filter state: {}", name); + stats_.no_filter_state_.inc(); + continue; + } + filter_state_objects->emplace_back(name, object); + } catch (const EnvoyException& e) { + ENVOY_LOG(trace, "Internal upstream filter state error: {}. Error: {}", name, e.what()); + stats_.filter_state_error_.inc(); + } + } + return filter_state_objects; +} + +void Config::hashKey(std::vector& key, + const StreamInfo::FilterStateSharedPtr& filter_state) const { + for (const auto& name : filter_state_names_) { + if (auto object = filter_state->getDataReadOnly(name); object != nullptr) { + if (auto hash = object->hash(); hash) { + pushScalarToByteVector(hash.value(), key); + } + } + } +} + +InternalSocketFactory::InternalSocketFactory( + Server::Configuration::TransportSocketFactoryContext& context, + const envoy::extensions::transport_sockets::internal_upstream::v3::InternalUpstreamTransport& + config_proto, + Network::UpstreamTransportSocketFactoryPtr&& inner_factory) + : PassthroughFactory(std::move(inner_factory)), config_(config_proto, context.scope()) {} + +Network::TransportSocketPtr +InternalSocketFactory::createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const { + auto inner_socket = transport_socket_factory_->createTransportSocket(options, host); + if (inner_socket == nullptr) { + return nullptr; + } + std::unique_ptr extracted_metadata; + if (host) { + extracted_metadata = config_.extractMetadata(host); + } + std::unique_ptr extracted_filter_state; + if (options && options->filterState()) { + extracted_filter_state = config_.extractFilterState(options->filterState()); + } + return std::make_unique(std::move(inner_socket), std::move(extracted_metadata), + std::move(extracted_filter_state)); +} + +void InternalSocketFactory::hashKey(std::vector& key, + Network::TransportSocketOptionsConstSharedPtr options) const { + PassthroughFactory::hashKey(key, options); + // Filter state should be included in the hash since it can originate from + // the downstream request, but it is only applied once per upstream connection in + // the internal listener. + if (options && options->filterState()) { + config_.hashKey(key, options->filterState()); + } +} + +REGISTER_FACTORY(InternalUpstreamConfigFactory, + Server::Configuration::UpstreamTransportSocketConfigFactory); + +} // namespace InternalUpstream +} // namespace TransportSockets +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/transport_sockets/internal_upstream/config.h b/source/extensions/transport_sockets/internal_upstream/config.h new file mode 100644 index 0000000000000..1c983a5d60179 --- /dev/null +++ b/source/extensions/transport_sockets/internal_upstream/config.h @@ -0,0 +1,74 @@ +#pragma once + +#include "envoy/extensions/transport_sockets/internal_upstream/v3/internal_upstream.pb.h" +#include "envoy/server/transport_socket_config.h" +#include "envoy/stats/stats_macros.h" + +#include "source/common/common/logger.h" +#include "source/extensions/io_socket/user_space/io_handle.h" +#include "source/extensions/transport_sockets/common/passthrough.h" + +namespace Envoy { +namespace Extensions { +namespace TransportSockets { +namespace InternalUpstream { + +#define ALL_INTERNAL_UPSTREAM_STATS(COUNTER) \ + COUNTER(no_metadata) \ + COUNTER(no_filter_state) \ + COUNTER(filter_state_error) + +/** + * Struct definition for all internal transport socket stats. @see stats_macros.h + */ +struct InternalUpstreamStats { + ALL_INTERNAL_UPSTREAM_STATS(GENERATE_COUNTER_STRUCT) +}; + +class Config : public Logger::Loggable { +public: + Config( + const envoy::extensions::transport_sockets::internal_upstream::v3::InternalUpstreamTransport& + config_proto, + Stats::Scope& scope); + std::unique_ptr + extractMetadata(const Upstream::HostDescriptionConstSharedPtr& host) const; + std::unique_ptr + extractFilterState(const StreamInfo::FilterStateSharedPtr& filter_state) const; + void hashKey(std::vector& key, + const StreamInfo::FilterStateSharedPtr& filter_state) const; + +private: + enum class MetadataKind { Host, Cluster }; + struct MetadataSource { + MetadataSource(MetadataKind kind, const std::string& name) : kind_(kind), name_(name) {} + const MetadataKind kind_; + const std::string name_; + }; + InternalUpstreamStats stats_; + std::vector metadata_sources_; + std::vector filter_state_names_; +}; + +class InternalSocketFactory : public PassthroughFactory { +public: + InternalSocketFactory( + Server::Configuration::TransportSocketFactoryContext& context, + const envoy::extensions::transport_sockets::internal_upstream::v3::InternalUpstreamTransport& + config_proto, + Network::UpstreamTransportSocketFactoryPtr&& inner_factory); + + Network::TransportSocketPtr + createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const override; + void hashKey(std::vector& key, + Network::TransportSocketOptionsConstSharedPtr options) const override; + +private: + const Config config_; +}; + +} // namespace InternalUpstream +} // namespace TransportSockets +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/transport_sockets/internal_upstream/internal_upstream.cc b/source/extensions/transport_sockets/internal_upstream/internal_upstream.cc new file mode 100644 index 0000000000000..62b021c10826c --- /dev/null +++ b/source/extensions/transport_sockets/internal_upstream/internal_upstream.cc @@ -0,0 +1,29 @@ +#include "source/extensions/transport_sockets/internal_upstream/internal_upstream.h" + +namespace Envoy { +namespace Extensions { +namespace TransportSockets { +namespace InternalUpstream { + +InternalSocket::InternalSocket( + Network::TransportSocketPtr inner_socket, + std::unique_ptr metadata, + std::unique_ptr filter_state_objects) + : PassthroughSocket(std::move(inner_socket)), metadata_(std::move(metadata)), + filter_state_objects_(std::move(filter_state_objects)) {} + +void InternalSocket::setTransportSocketCallbacks(Network::TransportSocketCallbacks& callbacks) { + transport_socket_->setTransportSocketCallbacks(callbacks); + auto* io_handle = dynamic_cast(&callbacks.ioHandle()); + if (io_handle != nullptr && io_handle->passthroughState()) { + io_handle->passthroughState()->initialize(std::move(metadata_), + std::move(filter_state_objects_)); + } + metadata_ = nullptr; + filter_state_objects_ = nullptr; +} + +} // namespace InternalUpstream +} // namespace TransportSockets +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/transport_sockets/internal_upstream/internal_upstream.h b/source/extensions/transport_sockets/internal_upstream/internal_upstream.h new file mode 100644 index 0000000000000..aad825a68a042 --- /dev/null +++ b/source/extensions/transport_sockets/internal_upstream/internal_upstream.h @@ -0,0 +1,30 @@ +#pragma once + +#include "envoy/extensions/transport_sockets/internal_upstream/v3/internal_upstream.pb.h" + +#include "source/extensions/io_socket/user_space/io_handle.h" +#include "source/extensions/transport_sockets/common/passthrough.h" + +namespace Envoy { +namespace Extensions { +namespace TransportSockets { +namespace InternalUpstream { + +class InternalSocket : public TransportSockets::PassthroughSocket { +public: + InternalSocket(Network::TransportSocketPtr inner_socket, + std::unique_ptr metadata, + std::unique_ptr filter_state_objects); + + // Network::TransportSocket + void setTransportSocketCallbacks(Network::TransportSocketCallbacks& callbacks) override; + +private: + std::unique_ptr metadata_; + std::unique_ptr filter_state_objects_; +}; + +} // namespace InternalUpstream +} // namespace TransportSockets +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.cc b/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.cc index 29cc86aa872ae..73d9c2272a45c 100644 --- a/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.cc +++ b/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.cc @@ -112,8 +112,9 @@ UpstreamProxyProtocolSocketFactory::UpstreamProxyProtocolSocketFactory( : PassthroughFactory(std::move(transport_socket_factory)), config_(config) {} Network::TransportSocketPtr UpstreamProxyProtocolSocketFactory::createTransportSocket( - Network::TransportSocketOptionsConstSharedPtr options) const { - auto inner_socket = transport_socket_factory_->createTransportSocket(options); + Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const { + auto inner_socket = transport_socket_factory_->createTransportSocket(options, host); if (inner_socket == nullptr) { return nullptr; } diff --git a/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.h b/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.h index f91f11eb11014..583f79bca2738 100644 --- a/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.h +++ b/source/extensions/transport_sockets/proxy_protocol/proxy_protocol.h @@ -47,7 +47,8 @@ class UpstreamProxyProtocolSocketFactory : public PassthroughFactory { // Network::UpstreamTransportSocketFactory Network::TransportSocketPtr - createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options) const override; + createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const override; void hashKey(std::vector& key, Network::TransportSocketOptionsConstSharedPtr options) const override; diff --git a/source/extensions/transport_sockets/starttls/starttls_socket.cc b/source/extensions/transport_sockets/starttls/starttls_socket.cc index f7e26c5cfb119..38e2448f23e28 100644 --- a/source/extensions/transport_sockets/starttls/starttls_socket.cc +++ b/source/extensions/transport_sockets/starttls/starttls_socket.cc @@ -23,10 +23,11 @@ bool StartTlsSocket::startSecureTransport() { } Network::TransportSocketPtr StartTlsSocketFactory::createTransportSocket( - Network::TransportSocketOptionsConstSharedPtr transport_socket_options) const { + Network::TransportSocketOptionsConstSharedPtr transport_socket_options, + Upstream::HostDescriptionConstSharedPtr host) const { return std::make_unique( - raw_socket_factory_->createTransportSocket(transport_socket_options), - tls_socket_factory_->createTransportSocket(transport_socket_options), + raw_socket_factory_->createTransportSocket(transport_socket_options, host), + tls_socket_factory_->createTransportSocket(transport_socket_options, host), transport_socket_options); } diff --git a/source/extensions/transport_sockets/starttls/starttls_socket.h b/source/extensions/transport_sockets/starttls/starttls_socket.h index 1bb21cc2fd1ca..93b4c86209830 100644 --- a/source/extensions/transport_sockets/starttls/starttls_socket.h +++ b/source/extensions/transport_sockets/starttls/starttls_socket.h @@ -116,7 +116,8 @@ class StartTlsSocketFactory : public Network::CommonUpstreamTransportSocketFacto tls_socket_factory_(std::move(tls_socket_factory)) {} Network::TransportSocketPtr - createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options) const override; + createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const override; bool implementsSecureTransport() const override { return false; } absl::string_view defaultServerNameIndication() const override { return ""; } diff --git a/source/extensions/transport_sockets/tap/tap.cc b/source/extensions/transport_sockets/tap/tap.cc index 9ba0622512e78..218d4648b69da 100644 --- a/source/extensions/transport_sockets/tap/tap.cc +++ b/source/extensions/transport_sockets/tap/tap.cc @@ -56,10 +56,12 @@ TapSocketFactory::TapSocketFactory( singleton_manager, tls, main_thread_dispatcher), PassthroughFactory(std::move(transport_socket_factory)) {} -Network::TransportSocketPtr TapSocketFactory::createTransportSocket( - Network::TransportSocketOptionsConstSharedPtr options) const { - return std::make_unique(currentConfigHelper(), - transport_socket_factory_->createTransportSocket(options)); +Network::TransportSocketPtr +TapSocketFactory::createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const { + return std::make_unique( + currentConfigHelper(), + transport_socket_factory_->createTransportSocket(options, host)); } DownstreamTapSocketFactory::DownstreamTapSocketFactory( diff --git a/source/extensions/transport_sockets/tap/tap.h b/source/extensions/transport_sockets/tap/tap.h index 0167a029a274b..d944c7f01bd72 100644 --- a/source/extensions/transport_sockets/tap/tap.h +++ b/source/extensions/transport_sockets/tap/tap.h @@ -38,7 +38,8 @@ class TapSocketFactory : public Common::Tap::ExtensionConfigBase, public Passthr // Network::UpstreamTransportSocketFactory Network::TransportSocketPtr - createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options) const override; + createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const override; }; class DownstreamTapSocketFactory : public Common::Tap::ExtensionConfigBase, diff --git a/source/extensions/transport_sockets/tcp_stats/config.cc b/source/extensions/transport_sockets/tcp_stats/config.cc index 7b428c51de40b..aafc940cb01f2 100644 --- a/source/extensions/transport_sockets/tcp_stats/config.cc +++ b/source/extensions/transport_sockets/tcp_stats/config.cc @@ -31,15 +31,17 @@ UpstreamTcpStatsSocketFactory::UpstreamTcpStatsSocketFactory( : TcpStatsSocketFactory(context, config), PassthroughFactory(std::move(inner_factory)) {} Network::TransportSocketPtr UpstreamTcpStatsSocketFactory::createTransportSocket( - Network::TransportSocketOptionsConstSharedPtr options) const { + Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const { #if defined(__linux__) - auto inner_socket = transport_socket_factory_->createTransportSocket(options); + auto inner_socket = transport_socket_factory_->createTransportSocket(options, host); if (inner_socket == nullptr) { return nullptr; } return std::make_unique(config_, std::move(inner_socket)); #else UNREFERENCED_PARAMETER(options); + UNREFERENCED_PARAMETER(host); return nullptr; #endif } diff --git a/source/extensions/transport_sockets/tcp_stats/config.h b/source/extensions/transport_sockets/tcp_stats/config.h index d40a7268ea862..7d16b2127046d 100644 --- a/source/extensions/transport_sockets/tcp_stats/config.h +++ b/source/extensions/transport_sockets/tcp_stats/config.h @@ -30,7 +30,8 @@ class UpstreamTcpStatsSocketFactory : public TcpStatsSocketFactory, public Passt Network::UpstreamTransportSocketFactoryPtr&& inner_factory); Network::TransportSocketPtr - createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options) const override; + createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const override; }; class DownstreamTcpStatsSocketFactory : public TcpStatsSocketFactory, diff --git a/source/extensions/transport_sockets/tls/ssl_socket.cc b/source/extensions/transport_sockets/tls/ssl_socket.cc index 7552b0e92d721..fc4370acc3f9b 100644 --- a/source/extensions/transport_sockets/tls/ssl_socket.cc +++ b/source/extensions/transport_sockets/tls/ssl_socket.cc @@ -370,7 +370,8 @@ ClientSslSocketFactory::ClientSslSocketFactory(Envoy::Ssl::ClientContextConfigPt ClientSslSocketFactory::~ClientSslSocketFactory() { manager_.removeContext(ssl_ctx_); } Network::TransportSocketPtr ClientSslSocketFactory::createTransportSocket( - Network::TransportSocketOptionsConstSharedPtr transport_socket_options) const { + Network::TransportSocketOptionsConstSharedPtr transport_socket_options, + Upstream::HostDescriptionConstSharedPtr) const { // onAddOrUpdateSecret() could be invoked in the middle of checking the existence of ssl_ctx and // creating SslSocket using ssl_ctx. Capture ssl_ctx_ into a local variable so that we check and // use the same ssl_ctx to create SslSocket. diff --git a/source/extensions/transport_sockets/tls/ssl_socket.h b/source/extensions/transport_sockets/tls/ssl_socket.h index 6458f7453c884..b401e7ff5f94b 100644 --- a/source/extensions/transport_sockets/tls/ssl_socket.h +++ b/source/extensions/transport_sockets/tls/ssl_socket.h @@ -108,7 +108,8 @@ class ClientSslSocketFactory : public Network::CommonUpstreamTransportSocketFact ~ClientSslSocketFactory() override; Network::TransportSocketPtr - createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options) const override; + createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr) const override; bool implementsSecureTransport() const override; absl::string_view defaultServerNameIndication() const override { return config().serverNameIndication(); diff --git a/test/common/grpc/grpc_client_integration_test_harness.h b/test/common/grpc/grpc_client_integration_test_harness.h index 8336afff08011..30deec6a01862 100644 --- a/test/common/grpc/grpc_client_integration_test_harness.h +++ b/test/common/grpc/grpc_client_integration_test_harness.h @@ -529,7 +529,7 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { std::make_unique( std::move(cfg), context_manager_, *stats_store_); async_client_transport_socket_ = - mock_host_description_->socket_factory_->createTransportSocket(nullptr); + mock_host_description_->socket_factory_->createTransportSocket(nullptr, nullptr); FakeUpstreamConfig config(test_time_.timeSystem()); config.upstream_protocol_ = Http::CodecType::HTTP2; fake_upstream_ = diff --git a/test/common/http/http1/conn_pool_test.cc b/test/common/http/http1/conn_pool_test.cc index dbc1896775eef..52ae8c044597c 100644 --- a/test/common/http/http1/conn_pool_test.cc +++ b/test/common/http/http1/conn_pool_test.cc @@ -301,14 +301,14 @@ TEST_F(Http1ConnPoolImplTest, VerifyTimingStats) { TEST_F(Http1ConnPoolImplTest, VerifyAlpnFallback) { // Override the TransportSocketFactory with a mock version we can add expectations to. auto factory = std::make_unique(); - EXPECT_CALL(*factory, createTransportSocket(_)) - .WillOnce(Invoke( - [](Network::TransportSocketOptionsConstSharedPtr options) -> Network::TransportSocketPtr { - EXPECT_TRUE(options != nullptr); - EXPECT_EQ(options->applicationProtocolFallback()[0], - Http::Utility::AlpnNames::get().Http11); - return std::make_unique(); - })); + EXPECT_CALL(*factory, createTransportSocket(_, _)) + .WillOnce(Invoke([](Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr) -> Network::TransportSocketPtr { + EXPECT_TRUE(options != nullptr); + EXPECT_EQ(options->applicationProtocolFallback()[0], + Http::Utility::AlpnNames::get().Http11); + return std::make_unique(); + })); cluster_->transport_socket_matcher_ = std::make_unique>(std::move(factory)); diff --git a/test/common/http/http2/conn_pool_test.cc b/test/common/http/http2/conn_pool_test.cc index 163dc45d7cdee..2050ea59b7710 100644 --- a/test/common/http/http2/conn_pool_test.cc +++ b/test/common/http/http2/conn_pool_test.cc @@ -354,14 +354,13 @@ TEST_F(Http2ConnPoolImplTest, VerifyAlpnFallback) { // happens before all the connection set up but after the test client is created (due to some) // of the mocks that are constructed as part of the test client. createTestClients(1); - EXPECT_CALL(*factory_ptr, createTransportSocket(_)) - .WillOnce(Invoke( - [](Network::TransportSocketOptionsConstSharedPtr options) -> Network::TransportSocketPtr { - EXPECT_TRUE(options != nullptr); - EXPECT_EQ(options->applicationProtocolFallback()[0], - Http::Utility::AlpnNames::get().Http2); - return std::make_unique(); - })); + EXPECT_CALL(*factory_ptr, createTransportSocket(_, _)) + .WillOnce(Invoke([](Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr) -> Network::TransportSocketPtr { + EXPECT_TRUE(options != nullptr); + EXPECT_EQ(options->applicationProtocolFallback()[0], Http::Utility::AlpnNames::get().Http2); + return std::make_unique(); + })); expectConnectionSetupForClient(1); ActiveTestRequest r(*this, 0, false); expectClientConnect(0, r); diff --git a/test/common/network/happy_eyeballs_connection_impl_test.cc b/test/common/network/happy_eyeballs_connection_impl_test.cc index aedf283321ff0..ac06ff09ddf3a 100644 --- a/test/common/network/happy_eyeballs_connection_impl_test.cc +++ b/test/common/network/happy_eyeballs_connection_impl_test.cc @@ -25,7 +25,7 @@ class HappyEyeballsConnectionImplTest : public testing::Test { std::make_shared("127.0.0.2"), std::make_shared("ff02::1", 0)}), address_list_({raw_address_list_[0], raw_address_list_[2], raw_address_list_[1]}) { - EXPECT_CALL(transport_socket_factory_, createTransportSocket(_)); + EXPECT_CALL(transport_socket_factory_, createTransportSocket(_, _)); EXPECT_CALL(dispatcher_, createClientConnection_(address_list_[0], _, _, _)) .WillOnce(testing::InvokeWithoutArgs( this, &HappyEyeballsConnectionImplTest::createNextConnection)); @@ -33,7 +33,7 @@ class HappyEyeballsConnectionImplTest : public testing::Test { next_connections_.push_back(std::make_unique>()); impl_ = std::make_unique( dispatcher_, raw_address_list_, Address::InstanceConstSharedPtr(), - transport_socket_factory_, transport_socket_options_, options_); + transport_socket_factory_, transport_socket_options_, nullptr, options_); } // Called by the dispatcher to return a MockClientConnection. In order to allow expectations to @@ -69,7 +69,7 @@ class HappyEyeballsConnectionImplTest : public testing::Test { // Fires the failover timer and creates the next connection. void timeOutAndStartNextAttempt() { - EXPECT_CALL(transport_socket_factory_, createTransportSocket(_)); + EXPECT_CALL(transport_socket_factory_, createTransportSocket(_, _)); EXPECT_CALL(dispatcher_, createClientConnection_(address_list_[1], _, _, _)) .WillOnce(testing::InvokeWithoutArgs( this, &HappyEyeballsConnectionImplTest::createNextConnection)); @@ -113,7 +113,7 @@ TEST_F(HappyEyeballsConnectionImplTest, ConnectTimeout) { // Let the second attempt timeout to start the third and final attempt. next_connections_.push_back(std::make_unique>()); - EXPECT_CALL(transport_socket_factory_, createTransportSocket(_)); + EXPECT_CALL(transport_socket_factory_, createTransportSocket(_, _)); EXPECT_CALL(dispatcher_, createClientConnection_(address_list_[2], _, _, _)) .WillOnce( testing::InvokeWithoutArgs(this, &HappyEyeballsConnectionImplTest::createNextConnection)); @@ -129,7 +129,7 @@ TEST_F(HappyEyeballsConnectionImplTest, ConnectFailed) { // When the first connection attempt fails, the next attempt will be immediately // started and the timer will be armed for the third attempt. next_connections_.push_back(std::make_unique>()); - EXPECT_CALL(transport_socket_factory_, createTransportSocket(_)); + EXPECT_CALL(transport_socket_factory_, createTransportSocket(_, _)); EXPECT_CALL(dispatcher_, createClientConnection_(_, _, _, _)) .WillOnce( testing::InvokeWithoutArgs(this, &HappyEyeballsConnectionImplTest::createNextConnection)); @@ -203,7 +203,7 @@ TEST_F(HappyEyeballsConnectionImplTest, ConnectTimeoutThenSecondFailsAndFirstSuc // When the second attempt fails, the third and final attempt will be started. next_connections_.push_back(std::make_unique>()); - EXPECT_CALL(transport_socket_factory_, createTransportSocket(_)); + EXPECT_CALL(transport_socket_factory_, createTransportSocket(_, _)); EXPECT_CALL(dispatcher_, createClientConnection_(address_list_[2], _, _, _)) .WillOnce( testing::InvokeWithoutArgs(this, &HappyEyeballsConnectionImplTest::createNextConnection)); @@ -230,7 +230,7 @@ TEST_F(HappyEyeballsConnectionImplTest, ConnectThenAllTimeoutAndFail) { // After the second timeout the third and final attempt will be started. next_connections_.push_back(std::make_unique>()); - EXPECT_CALL(transport_socket_factory_, createTransportSocket(_)); + EXPECT_CALL(transport_socket_factory_, createTransportSocket(_, _)); EXPECT_CALL(dispatcher_, createClientConnection_(address_list_[2], _, _, _)) .WillOnce( testing::InvokeWithoutArgs(this, &HappyEyeballsConnectionImplTest::createNextConnection)); diff --git a/test/common/upstream/health_checker_impl_test.cc b/test/common/upstream/health_checker_impl_test.cc index d13a10a849094..f97614ffa5429 100644 --- a/test/common/upstream/health_checker_impl_test.cc +++ b/test/common/upstream/health_checker_impl_test.cc @@ -1105,7 +1105,7 @@ TEST_F(HttpHealthCheckerImplTest, TlsOptions) { Network::UpstreamTransportSocketFactoryPtr(socket_factory)); cluster_->info_->transport_socket_matcher_.reset(transport_socket_match); - EXPECT_CALL(*socket_factory, createTransportSocket(ApplicationProtocolListEq("http1"))); + EXPECT_CALL(*socket_factory, createTransportSocket(ApplicationProtocolListEq("http1"), _)); allocHealthChecker(yaml); cluster_->prioritySet().getMockHostSet(0)->hosts_ = { @@ -2565,7 +2565,7 @@ TEST_F(HttpHealthCheckerImplTest, TransportSocketMatchCriteria) { auto default_socket_factory = std::make_unique(); // We expect that this default_socket_factory will NOT be used to create a transport socket for // the health check connection. - EXPECT_CALL(*default_socket_factory, createTransportSocket(_)).Times(0); + EXPECT_CALL(*default_socket_factory, createTransportSocket(_, _)).Times(0); EXPECT_CALL(*default_socket_factory, implementsSecureTransport()).WillRepeatedly(Return(true)); auto transport_socket_match = std::make_unique(std::move(default_socket_factory)); @@ -2591,7 +2591,7 @@ TEST_F(HttpHealthCheckerImplTest, TransportSocketMatchCriteria) { *health_check_only_socket_factory, health_transport_socket_stats, "health_check_only"))); // The health_check_only_socket_factory should be used to create a transport socket for the health // check connection. - EXPECT_CALL(*health_check_only_socket_factory, createTransportSocket(_)); + EXPECT_CALL(*health_check_only_socket_factory, createTransportSocket(_, _)); cluster_->info_->transport_socket_matcher_ = std::move(transport_socket_match); @@ -2626,7 +2626,7 @@ TEST_F(HttpHealthCheckerImplTest, NoTransportSocketMatchCriteria) { auto default_socket_factory = std::make_unique(); // The default_socket_factory should be used to create a transport socket for the health check // connection. - EXPECT_CALL(*default_socket_factory, createTransportSocket(_)); + EXPECT_CALL(*default_socket_factory, createTransportSocket(_, _)); EXPECT_CALL(*default_socket_factory, implementsSecureTransport()).WillRepeatedly(Return(true)); auto transport_socket_match = std::make_unique(std::move(default_socket_factory)); diff --git a/test/common/upstream/transport_socket_matcher_test.cc b/test/common/upstream/transport_socket_matcher_test.cc index 63ae5efbe1f68..8059fde3ef654 100644 --- a/test/common/upstream/transport_socket_matcher_test.cc +++ b/test/common/upstream/transport_socket_matcher_test.cc @@ -34,7 +34,9 @@ class FakeTransportSocketFactory : public Network::UpstreamTransportSocketFactor MOCK_METHOD(bool, supportsAlpn, (), (const)); MOCK_METHOD(absl::string_view, defaultServerNameIndication, (), (const)); MOCK_METHOD(Network::TransportSocketPtr, createTransportSocket, - (Network::TransportSocketOptionsConstSharedPtr), (const)); + (Network::TransportSocketOptionsConstSharedPtr, + Upstream::HostDescriptionConstSharedPtr), + (const)); MOCK_METHOD(void, hashKey, (std::vector&, Network::TransportSocketOptionsConstSharedPtr), (const)); FakeTransportSocketFactory(std::string id, bool alpn) : supports_alpn_(alpn), id_(std::move(id)) { @@ -55,7 +57,9 @@ class FooTransportSocketFactory public: MOCK_METHOD(bool, implementsSecureTransport, (), (const)); MOCK_METHOD(Network::TransportSocketPtr, createTransportSocket, - (Network::TransportSocketOptionsConstSharedPtr), (const)); + (Network::TransportSocketOptionsConstSharedPtr, + Upstream::HostDescriptionConstSharedPtr), + (const)); MOCK_METHOD(void, hashKey, (std::vector&, Network::TransportSocketOptionsConstSharedPtr), (const)); MOCK_METHOD(absl::string_view, defaultServerNameIndication, (), (const)); diff --git a/test/extensions/filters/listener/tls_inspector/tls_inspector_integration_test.cc b/test/extensions/filters/listener/tls_inspector/tls_inspector_integration_test.cc index 33cc06c17b5dc..1efefc8314227 100644 --- a/test/extensions/filters/listener/tls_inspector/tls_inspector_integration_test.cc +++ b/test/extensions/filters/listener/tls_inspector/tls_inspector_integration_test.cc @@ -102,8 +102,9 @@ class TlsInspectorIntegrationTest : public testing::TestWithParamcreateTransportSocket(std::make_shared( - absl::string_view(""), std::vector(), - std::vector{"envoyalpn"})); + absl::string_view(""), std::vector(), + std::vector{"envoyalpn"}), + nullptr); if (!curves_list.empty()) { auto ssl_socket = @@ -113,7 +114,7 @@ class TlsInspectorIntegrationTest : public testing::TestWithParam(); - transport_socket = transport_socket_factory->createTransportSocket(nullptr); + transport_socket = transport_socket_factory->createTransportSocket(nullptr, nullptr); } client_ = dispatcher_->createClientConnection( address, Network::Address::InstanceConstSharedPtr(), std::move(transport_socket), nullptr); diff --git a/test/extensions/filters/network/sni_dynamic_forward_proxy/proxy_filter_integration_test.cc b/test/extensions/filters/network/sni_dynamic_forward_proxy/proxy_filter_integration_test.cc index 3b0117c6e9ee0..0b238a069b90b 100644 --- a/test/extensions/filters/network/sni_dynamic_forward_proxy/proxy_filter_integration_test.cc +++ b/test/extensions/filters/network/sni_dynamic_forward_proxy/proxy_filter_integration_test.cc @@ -100,7 +100,7 @@ name: envoy.clusters.dynamic_forward_proxy Ssl::createClientSslTransportSocketFactory(options, context_manager_, *api_); return dispatcher_->createClientConnection( address, Network::Address::InstanceConstSharedPtr(), - client_transport_socket_factory_ptr->createTransportSocket({}), nullptr); + client_transport_socket_factory_ptr->createTransportSocket({}, nullptr), nullptr); } std::string upstream_cert_name_{"server"}; diff --git a/test/extensions/io_socket/user_space/BUILD b/test/extensions/io_socket/user_space/BUILD index 458d6345d36da..2881b4eaff4d1 100644 --- a/test/extensions/io_socket/user_space/BUILD +++ b/test/extensions/io_socket/user_space/BUILD @@ -35,6 +35,7 @@ envoy_extension_cc_test( deps = [ "//source/common/common:utility_lib", "//source/common/network:address_lib", + "//source/common/stream_info:filter_state_lib", "//source/extensions/io_socket/user_space:io_handle_impl_lib", "//test/mocks/event:event_mocks", ], diff --git a/test/extensions/io_socket/user_space/file_event_impl_test.cc b/test/extensions/io_socket/user_space/file_event_impl_test.cc index bf5ec8126bec7..784c8cc8b3530 100644 --- a/test/extensions/io_socket/user_space/file_event_impl_test.cc +++ b/test/extensions/io_socket/user_space/file_event_impl_test.cc @@ -51,6 +51,7 @@ class MockIoHandle : public IoHandle { MOCK_METHOD(bool, isPeerWritable, (), (const)); MOCK_METHOD(void, onPeerBufferLowWatermark, ()); MOCK_METHOD(bool, isReadable, (), (const)); + MOCK_METHOD(PassthroughStateSharedPtr, passthroughState, ()); }; class FileEventImplTest : public testing::Test { diff --git a/test/extensions/io_socket/user_space/io_handle_impl_test.cc b/test/extensions/io_socket/user_space/io_handle_impl_test.cc index 1688079c50d0e..ed638b965d2ff 100644 --- a/test/extensions/io_socket/user_space/io_handle_impl_test.cc +++ b/test/extensions/io_socket/user_space/io_handle_impl_test.cc @@ -3,6 +3,7 @@ #include "source/common/buffer/buffer_impl.h" #include "source/common/network/address_impl.h" +#include "source/common/stream_info/filter_state_impl.h" #include "source/extensions/io_socket/user_space/io_handle_impl.h" #include "test/mocks/event/mocks.h" @@ -1118,6 +1119,51 @@ TEST_F(IoHandleImplTest, CreatePlatformDefaultTriggerTypeFailOnWindows) { io_handle_peer_->close(); } +class TestObject : public StreamInfo::FilterState::Object { +public: + TestObject(int value) : value_(value) {} + int value_; +}; + +TEST_F(IoHandleImplTest, PassthroughState) { + auto source_metadata = std::make_unique(); + ProtobufWkt::Struct& map = (*source_metadata->mutable_filter_metadata())["envoy.test"]; + ProtobufWkt::Value val; + val.set_string_value("val"); + (*map.mutable_fields())["key"] = val; + auto source_filter_state = std::make_unique(); + auto object = std::make_shared(1000); + source_filter_state->emplace_back("object_key", object); + ASSERT_NE(nullptr, io_handle_->passthroughState()); + io_handle_->passthroughState()->initialize(std::move(source_metadata), + std::move(source_filter_state)); + + StreamInfo::FilterStateImpl dest_filter_state(StreamInfo::FilterState::LifeSpan::Connection); + envoy::config::core::v3::Metadata dest_metadata; + ASSERT_NE(nullptr, io_handle_peer_->passthroughState()); + io_handle_peer_->passthroughState()->mergeInto(dest_metadata, dest_filter_state); + ASSERT_EQ("val", + dest_metadata.filter_metadata().at("envoy.test").fields().at("key").string_value()); + auto dest_object = dest_filter_state.getDataReadOnly("object_key"); + ASSERT_NE(nullptr, dest_object); + ASSERT_EQ(object->value_, dest_object->value_); +} + +TEST_F(IoHandleImplTest, PassthroughStateReadOnlyObject) { + auto source_filter_state = std::make_unique(); + auto object = std::make_shared(1000); + source_filter_state->emplace_back("object_key", object); + io_handle_->passthroughState()->initialize(nullptr, std::move(source_filter_state)); + StreamInfo::FilterStateImpl dest_filter_state(StreamInfo::FilterState::LifeSpan::Connection); + auto read_only = std::make_shared(1); + dest_filter_state.setData("object_key", read_only, StreamInfo::FilterState::StateType::ReadOnly, + StreamInfo::FilterState::LifeSpan::Connection); + envoy::config::core::v3::Metadata dest_metadata; + io_handle_peer_->passthroughState()->mergeInto(dest_metadata, dest_filter_state); + auto dest_object = dest_filter_state.getDataReadOnly("object_key"); + ASSERT_EQ(read_only->value_, dest_object->value_); +} + class IoHandleImplNotImplementedTest : public testing::Test { public: IoHandleImplNotImplementedTest() { diff --git a/test/extensions/transport_sockets/alts/alts_integration_test.cc b/test/extensions/transport_sockets/alts/alts_integration_test.cc index e85f80f8e53ae..acb4b9b2d5dc1 100644 --- a/test/extensions/transport_sockets/alts/alts_integration_test.cc +++ b/test/extensions/transport_sockets/alts/alts_integration_test.cc @@ -185,7 +185,7 @@ class AltsIntegrationTestBase : public Event::TestUsingSimulatedTime, } Network::TransportSocketPtr makeAltsTransportSocket() { - auto client_transport_socket = client_alts_->createTransportSocket(nullptr); + auto client_transport_socket = client_alts_->createTransportSocket(nullptr, nullptr); client_tsi_socket_ = dynamic_cast(client_transport_socket.get()); client_tsi_socket_->setActualFrameSizeToUse(16384); client_tsi_socket_->setFrameOverheadSize(4); diff --git a/test/extensions/transport_sockets/alts/tsi_socket_test.cc b/test/extensions/transport_sockets/alts/tsi_socket_test.cc index b14bf73e57a90..0828ce5cc334d 100644 --- a/test/extensions/transport_sockets/alts/tsi_socket_test.cc +++ b/test/extensions/transport_sockets/alts/tsi_socket_test.cc @@ -910,7 +910,7 @@ class TsiSocketFactoryTest : public testing::Test { }; TEST_F(TsiSocketFactoryTest, CreateTransportSocket) { - EXPECT_NE(nullptr, socket_factory_->createTransportSocket(nullptr)); + EXPECT_NE(nullptr, socket_factory_->createTransportSocket(nullptr, nullptr)); } TEST_F(TsiSocketFactoryTest, ImplementsSecureTransport) { diff --git a/test/extensions/transport_sockets/internal_upstream/BUILD b/test/extensions/transport_sockets/internal_upstream/BUILD new file mode 100644 index 0000000000000..c965c5f90f395 --- /dev/null +++ b/test/extensions/transport_sockets/internal_upstream/BUILD @@ -0,0 +1,58 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_package", +) +load( + "//test/extensions:extensions_build_system.bzl", + "envoy_extension_cc_test", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_extension_cc_test( + name = "internal_upstream_test", + srcs = ["internal_upstream_test.cc"], + extension_names = ["envoy.transport_sockets.internal_upstream"], + deps = [ + "//envoy/common:hashable_interface", + "//source/common/stream_info:filter_state_lib", + "//source/extensions/io_socket/user_space:io_handle_lib", + "//source/extensions/transport_sockets/internal_upstream", + "//source/extensions/transport_sockets/internal_upstream:config", + "//test/mocks/network:io_handle_mocks", + "//test/mocks/network:network_mocks", + "//test/mocks/network:transport_socket_mocks", + "//test/mocks/stats:stats_mocks", + "//test/mocks/upstream:host_mocks", + "//test/test_common:utility_lib", + "@envoy_api//envoy/extensions/transport_sockets/internal_upstream/v3:pkg_cc_proto", + ], +) + +envoy_extension_cc_test( + name = "internal_upstream_integration_test", + srcs = [ + "internal_upstream_integration_test.cc", + ], + extension_names = ["envoy.bootstrap.internal_listener"], + deps = [ + "//source/common/network:connection_lib", + "//source/common/network:utility_lib", + "//source/extensions/access_loggers/file:config", + "//source/extensions/bootstrap/internal_listener:config", + "//source/extensions/filters/network/tcp_proxy:config", + "//source/extensions/io_socket/user_space:config", + "//source/extensions/transport_sockets/internal_upstream:config", + "//source/extensions/transport_sockets/raw_buffer:config", + "//test/integration:http_integration_lib", + "//test/integration/filters:header_to_filter_state_lib", + "//test/test_common:network_utility_lib", + "//test/test_common:resources_lib", + "//test/test_common:utility_lib", + "@envoy_api//envoy/config/bootstrap/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/filters/network/tcp_proxy/v3:pkg_cc_proto", + "@envoy_api//envoy/extensions/transport_sockets/internal_upstream/v3:pkg_cc_proto", + ], +) diff --git a/test/extensions/transport_sockets/internal_upstream/internal_upstream_integration_test.cc b/test/extensions/transport_sockets/internal_upstream/internal_upstream_integration_test.cc new file mode 100644 index 0000000000000..079721fceddc8 --- /dev/null +++ b/test/extensions/transport_sockets/internal_upstream/internal_upstream_integration_test.cc @@ -0,0 +1,165 @@ +#include "envoy/config/bootstrap/v3/bootstrap.pb.h" +#include "envoy/extensions/filters/network/tcp_proxy/v3/tcp_proxy.pb.h" +#include "envoy/extensions/transport_sockets/internal_upstream/v3/internal_upstream.pb.h" +#include "envoy/network/connection.h" + +#include "source/extensions/transport_sockets/internal_upstream/config.h" + +#include "test/integration/http_integration.h" +#include "test/test_common/network_utility.h" +#include "test/test_common/resources.h" + +#include "absl/strings/str_cat.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace { + +class InternalUpstreamIntegrationTest : public testing::Test, public HttpIntegrationTest { +public: + InternalUpstreamIntegrationTest() + : HttpIntegrationTest(Http::CodecType::HTTP1, TestEnvironment::getIpVersionsForTest().front(), + ConfigHelper::httpProxyConfig()) { + setUpstreamCount(1); + } + + void initialize() override { + config_helper_.addConfigModifier([&](envoy::config::bootstrap::v3::Bootstrap& bootstrap) { + auto* static_resources = bootstrap.mutable_static_resources(); + auto* cluster = static_resources->mutable_clusters()->Add(); + cluster->set_name("internal_upstream"); + // Insert internal upstream transport. + TestUtility::loadFromYaml(R"EOF( + name: envoy.transport_sockets.internal_upstream + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.internal_upstream.v3.InternalUpstreamTransport + passthrough_metadata: + - name: host_metadata + kind: { host: {}} + - name: cluster_metadata + kind: { cluster: {}} + passthrough_filter_state_objects: + - name: internal_state + transport_socket: + name: envoy.transport_sockets.raw_buffer + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer + )EOF", + *cluster->mutable_transport_socket()); + // Insert internal address endpoint. + cluster->clear_load_assignment(); + auto* load_assignment = cluster->mutable_load_assignment(); + load_assignment->set_cluster_name(cluster->name()); + auto* endpoints = load_assignment->add_endpoints(); + auto* lb_endpoint = endpoints->add_lb_endpoints(); + auto* endpoint = lb_endpoint->mutable_endpoint(); + auto* addr = endpoint->mutable_address()->mutable_envoy_internal_address(); + addr->set_server_listener_name("internal_address"); + if (add_metadata_) { + auto* metadata = lb_endpoint->mutable_metadata(); + Config::Metadata::mutableMetadataValue(*metadata, "host_metadata", "value") + .set_string_value("HOST"); + // Insert cluster metadata. + Config::Metadata::mutableMetadataValue(*(cluster->mutable_metadata()), "cluster_metadata", + "value") + .set_string_value("CLUSTER"); + } + // Emit metadata to access log. + access_log_name_ = TestEnvironment::temporaryPath(TestUtility::uniqueFilename()); + + // Insert internal listener. + auto* listener = static_resources->mutable_listeners()->Add(); + TestUtility::loadFromYaml(fmt::format(R"EOF( + name: internal_address + address: + envoy_internal_address: + server_listener_name: internal_address + filter_chains: + - filters: + - name: tcp_proxy + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy + cluster: cluster_0 + stat_prefix: internal_address + access_log: + - name: envoy.file_access_log + typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog + path: {} + log_format: + text_format_source: + inline_string: "%DYNAMIC_METADATA(host_metadata:value)%,%DYNAMIC_METADATA(cluster_metadata:value)%,%FILTER_STATE(internal_state:PLAIN)%\n" + )EOF", + access_log_name_), + *listener); + }); + config_helper_.addConfigModifier( + [&](envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager& + hcm) -> void { + auto* route_config = hcm.mutable_route_config(); + auto* virtual_host = route_config->mutable_virtual_hosts(0); + auto* route = virtual_host->mutable_routes(0); + route->mutable_route()->set_cluster("internal_upstream"); + }); + config_helper_.addBootstrapExtension(R"EOF( + name: envoy.bootstrap.internal_listener + typed_config: + "@type": type.googleapis.com/envoy.extensions.bootstrap.internal_listener.v3.InternalListener + )EOF"); + config_helper_.prependFilter(R"EOF( + name: header-to-filter-state + typed_config: + "@type": type.googleapis.com/test.integration.filters.HeaderToFilterStateFilterConfig + header_name: internal-header + state_name: internal_state + read_only: false + )EOF"); + HttpIntegrationTest::initialize(); + } + + bool add_metadata_{true}; +}; + +TEST_F(InternalUpstreamIntegrationTest, BasicFlow) { + initialize(); + codec_client_ = makeHttpConnection(lookupPort("http")); + + auto response = codec_client_->makeHeaderOnlyRequest(Http::TestRequestHeaderMapImpl{ + {":method", "GET"}, + {":path", "/"}, + {":scheme", "http"}, + {":authority", "host.com"}, + {"internal-header", "FOO"}, + }); + waitForNextUpstreamRequest(); + upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, true); + ASSERT_TRUE(response->waitForEndStream()); + ASSERT_TRUE(response->complete()); + EXPECT_EQ("200", response->headers().getStatusValue()); + cleanupUpstreamAndDownstream(); + EXPECT_THAT(waitForAccessLog(access_log_name_), ::testing::HasSubstr("HOST,CLUSTER,FOO")); +} + +TEST_F(InternalUpstreamIntegrationTest, BasicFlowMissing) { + add_metadata_ = false; + initialize(); + codec_client_ = makeHttpConnection(lookupPort("http")); + + auto response = codec_client_->makeHeaderOnlyRequest(Http::TestRequestHeaderMapImpl{ + {":method", "GET"}, + {":path", "/"}, + {":scheme", "http"}, + {":authority", "host.com"}, + }); + waitForNextUpstreamRequest(); + upstream_request_->encodeHeaders(Http::TestResponseHeaderMapImpl{{":status", "200"}}, true); + ASSERT_TRUE(response->waitForEndStream()); + ASSERT_TRUE(response->complete()); + EXPECT_EQ("200", response->headers().getStatusValue()); + cleanupUpstreamAndDownstream(); + EXPECT_THAT(waitForAccessLog(access_log_name_), ::testing::HasSubstr("-,-,-")); +} + +} // namespace +} // namespace Envoy diff --git a/test/extensions/transport_sockets/internal_upstream/internal_upstream_test.cc b/test/extensions/transport_sockets/internal_upstream/internal_upstream_test.cc new file mode 100644 index 0000000000000..5652ae269d95c --- /dev/null +++ b/test/extensions/transport_sockets/internal_upstream/internal_upstream_test.cc @@ -0,0 +1,280 @@ +#include "envoy/common/hashable.h" +#include "envoy/extensions/transport_sockets/internal_upstream/v3/internal_upstream.pb.h" +#include "envoy/extensions/transport_sockets/internal_upstream/v3/internal_upstream.pb.validate.h" + +#include "source/common/stream_info/filter_state_impl.h" +#include "source/extensions/io_socket/user_space/io_handle.h" +#include "source/extensions/transport_sockets/internal_upstream/config.h" +#include "source/extensions/transport_sockets/internal_upstream/internal_upstream.h" + +#include "test/mocks/network/io_handle.h" +#include "test/mocks/network/mocks.h" +#include "test/mocks/network/transport_socket.h" +#include "test/mocks/stats/mocks.h" +#include "test/mocks/upstream/host.h" +#include "test/test_common/utility.h" + +namespace Envoy { +namespace Extensions { +namespace TransportSockets { +namespace InternalUpstream { + +namespace { + +using IoSocket::UserSpace::FilterStateObjects; +using IoSocket::UserSpace::IoHandle; +using IoSocket::UserSpace::PassthroughState; + +class NonHashable : public StreamInfo::FilterState::Object {}; +class HashableObj : public StreamInfo::FilterState::Object, public Hashable { + absl::optional hash() const override { return 12345; }; +}; + +class MockUserSpaceIoHandle : public Network::MockIoHandle, public IoHandle { +public: + MOCK_METHOD(void, setWriteEnd, ()); + MOCK_METHOD(bool, isPeerShutDownWrite, (), (const)); + MOCK_METHOD(void, onPeerDestroy, ()); + MOCK_METHOD(void, setNewDataAvailable, ()); + MOCK_METHOD(Buffer::Instance*, getWriteBuffer, ()); + MOCK_METHOD(bool, isWritable, (), (const)); + MOCK_METHOD(bool, isPeerWritable, (), (const)); + MOCK_METHOD(void, onPeerBufferLowWatermark, ()); + MOCK_METHOD(bool, isReadable, (), (const)); + MOCK_METHOD(std::shared_ptr, passthroughState, ()); +}; + +class MockPassthroughState : public PassthroughState { +public: + MOCK_METHOD(void, initialize, + (std::unique_ptr metadata, + std::unique_ptr filter_state_objects)); + MOCK_METHOD(void, mergeInto, + (envoy::config::core::v3::Metadata & metadata, + StreamInfo::FilterState& filter_state)); +}; + +class InternalSocketTest : public testing::Test { +public: + InternalSocketTest() + : metadata_(std::make_unique()), + filter_state_objects_(std::make_unique()) {} + + void initialize(Network::IoHandle& io_handle) { + auto inner_socket = std::make_unique>(); + inner_socket_ = inner_socket.get(); + ON_CALL(transport_callbacks_, ioHandle()).WillByDefault(testing::ReturnRef(io_handle)); + socket_ = std::make_unique(std::move(inner_socket), std::move(metadata_), + std::move(filter_state_objects_)); + EXPECT_CALL(*inner_socket_, setTransportSocketCallbacks(_)); + socket_->setTransportSocketCallbacks(transport_callbacks_); + } + + std::unique_ptr metadata_; + std::unique_ptr filter_state_objects_; + NiceMock* inner_socket_; + std::unique_ptr socket_; + NiceMock transport_callbacks_; +}; + +// Test that the internal transport socket works for the regular sockets. +TEST_F(InternalSocketTest, NativeSocket) { + NiceMock io_handle; + initialize(io_handle); +} + +// Test that internal transport socket updates the passthrough state for the user space sockets. +TEST_F(InternalSocketTest, PassthroughStateInjected) { + auto filter_state_object = std::make_shared(); + filter_state_objects_->emplace_back("test.object", filter_state_object); + ProtobufWkt::Struct& map = (*metadata_->mutable_filter_metadata())["envoy.test"]; + ProtobufWkt::Value val; + val.set_string_value("val"); + (*map.mutable_fields())["key"] = val; + + auto state = std::make_shared>(); + NiceMock io_handle; + EXPECT_CALL(io_handle, passthroughState()).WillRepeatedly(testing::Return(state)); + EXPECT_CALL(*state, initialize(_, _)) + .WillOnce(Invoke([&](std::unique_ptr metadata, + std::unique_ptr filter_state_objects) -> void { + ASSERT_EQ("val", + metadata->filter_metadata().at("envoy.test").fields().at("key").string_value()); + ASSERT_EQ(1, filter_state_objects->size()); + const auto& [name, object] = filter_state_objects->at(0); + ASSERT_EQ("test.object", name); + ASSERT_EQ(filter_state_object.get(), object.get()); + })); + initialize(io_handle); +} + +TEST_F(InternalSocketTest, EmptyPassthroughState) { + metadata_ = nullptr; + filter_state_objects_ = nullptr; + auto state = std::make_shared>(); + NiceMock io_handle; + EXPECT_CALL(io_handle, passthroughState()).WillRepeatedly(testing::Return(state)); + EXPECT_CALL(*state, initialize(_, _)) + .WillOnce(Invoke([&](std::unique_ptr metadata, + std::unique_ptr filter_state_objects) -> void { + ASSERT_EQ(nullptr, metadata); + ASSERT_EQ(nullptr, filter_state_objects); + })); + initialize(io_handle); +} + +class ConfigTest : public testing::Test { +public: + ConfigTest() + : host_(std::make_shared>()), + host_metadata_(std::make_shared()), + filter_state_(std::make_shared( + StreamInfo::FilterState::LifeSpan::FilterChain)) { + ON_CALL(*host_, metadata()).WillByDefault(testing::Return(host_metadata_)); + } + +protected: + void initialize() { config_ = std::make_unique(config_proto_, stats_store_); } + envoy::extensions::transport_sockets::internal_upstream::v3::InternalUpstreamTransport + config_proto_; + NiceMock stats_store_; + std::unique_ptr config_; + std::shared_ptr> host_; + std::shared_ptr host_metadata_; + std::shared_ptr filter_state_; +}; + +constexpr absl::string_view SampleConfig = R"EOF( + passthrough_metadata: + - kind: { host: {}} + name: host.metadata + - kind: { cluster: {}} + name: cluster.metadata + passthrough_filter_state_objects: + - name: filter_state_key + - name: readonly_filter_state + transport_socket: + name: raw_buffer + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer +)EOF"; + +TEST_F(ConfigTest, Basic) { + TestUtility::loadFromYaml(std::string(SampleConfig), config_proto_); + initialize(); + + TestUtility::loadFromYaml(R"EOF( + filter_metadata: + cluster.metadata: + key0: value0 + other.metadata: + key2: value2 + )EOF", + host_->cluster_.metadata_); + TestUtility::loadFromYaml(R"EOF( + filter_metadata: + host.metadata: + key1: value1 + other.metadata: + key3: value3 + )EOF", + *host_metadata_); + auto metadata = config_->extractMetadata(host_); + envoy::config::core::v3::Metadata expected; + TestUtility::loadFromYaml(R"EOF( + filter_metadata: + host.metadata: + key1: value1 + cluster.metadata: + key0: value0 + )EOF", + expected); + EXPECT_THAT(*metadata, ProtoEq(expected)); + + auto filter_state_object = std::make_shared(); + filter_state_->setData("filter_state_key", filter_state_object, + StreamInfo::FilterState::StateType::Mutable); + auto filter_state_objects = config_->extractFilterState(filter_state_); + const auto& [name, object] = filter_state_objects->at(0); + EXPECT_EQ("filter_state_key", name); + EXPECT_EQ(filter_state_object.get(), object.get()); + + std::vector keys; + config_->hashKey(keys, filter_state_); + EXPECT_GT(keys.size(), 0); + + EXPECT_EQ(0, stats_store_.counter("internal_upstream.no_metadata").value()); + EXPECT_EQ(1, stats_store_.counter("internal_upstream.no_filter_state").value()); + EXPECT_EQ(0, stats_store_.counter("internal_upstream.filter_state_error").value()); +} + +TEST_F(ConfigTest, FilterStateError) { + TestUtility::loadFromYaml(std::string(SampleConfig), config_proto_); + initialize(); + auto filter_state_object = std::make_shared(); + filter_state_->setData("filter_state_key", filter_state_object, + StreamInfo::FilterState::StateType::ReadOnly); + auto filter_state_objects = config_->extractFilterState(filter_state_); + EXPECT_EQ(0, filter_state_objects->size()); + EXPECT_EQ(1, stats_store_.counter("internal_upstream.no_filter_state").value()); + EXPECT_EQ(1, stats_store_.counter("internal_upstream.filter_state_error").value()); +} + +TEST_F(ConfigTest, UnsupportedMetadata) { + TestUtility::loadFromYaml(R"EOF( + passthrough_metadata: + - kind: { route: {}} + name: route.metadata + transport_socket: + name: raw_buffer + typed_config: + "@type": type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer + )EOF", + config_proto_); + EXPECT_THROW_WITH_MESSAGE(initialize(), EnvoyException, + "metadata type is not supported: route {\n}\n"); +} + +TEST_F(ConfigTest, NonHashable) { + TestUtility::loadFromYaml(std::string(SampleConfig), config_proto_); + initialize(); + auto filter_state_object = std::make_shared(); + filter_state_->setData("filter_state_key", filter_state_object, + StreamInfo::FilterState::StateType::Mutable); + std::vector keys; + config_->hashKey(keys, filter_state_); + EXPECT_EQ(keys.size(), 0); +} + +TEST_F(ConfigTest, MissingState) { + TestUtility::loadFromYaml(std::string(SampleConfig), config_proto_); + initialize(); + auto metadata = config_->extractMetadata(host_); + EXPECT_EQ(0, metadata->filter_metadata().size()); + auto filter_state_objects = config_->extractFilterState(filter_state_); + EXPECT_EQ(0, filter_state_objects->size()); + std::vector keys; + config_->hashKey(keys, filter_state_); + EXPECT_EQ(keys.size(), 0); + EXPECT_EQ(2, stats_store_.counter("internal_upstream.no_metadata").value()); + EXPECT_EQ(2, stats_store_.counter("internal_upstream.no_filter_state").value()); + EXPECT_EQ(0, stats_store_.counter("internal_upstream.filter_state_error").value()); +} + +TEST_F(ConfigTest, Empty) { + initialize(); + EXPECT_EQ(nullptr, config_->extractMetadata(host_)); + EXPECT_EQ(nullptr, config_->extractFilterState(filter_state_)); + std::vector keys; + config_->hashKey(keys, filter_state_); + EXPECT_EQ(keys.size(), 0); + EXPECT_EQ(0, stats_store_.counter("internal_upstream.no_metadata").value()); + EXPECT_EQ(0, stats_store_.counter("internal_upstream.no_filter_state").value()); + EXPECT_EQ(0, stats_store_.counter("internal_upstream.filter_state_error").value()); +} + +} // namespace +} // namespace InternalUpstream +} // namespace TransportSockets +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/transport_sockets/proxy_protocol/proxy_protocol_test.cc b/test/extensions/transport_sockets/proxy_protocol/proxy_protocol_test.cc index 17c0fafd34ee1..ac11d61b95cb3 100644 --- a/test/extensions/transport_sockets/proxy_protocol/proxy_protocol_test.cc +++ b/test/extensions/transport_sockets/proxy_protocol/proxy_protocol_test.cc @@ -457,8 +457,8 @@ class ProxyProtocolSocketFactoryTest : public testing::Test { // Test createTransportSocket returns nullptr if inner call returns nullptr TEST_F(ProxyProtocolSocketFactoryTest, CreateSocketReturnsNullWhenInnerFactoryReturnsNull) { initialize(); - EXPECT_CALL(*inner_factory_, createTransportSocket(_)).WillOnce(ReturnNull()); - ASSERT_EQ(nullptr, factory_->createTransportSocket(nullptr)); + EXPECT_CALL(*inner_factory_, createTransportSocket(_, _)).WillOnce(ReturnNull()); + ASSERT_EQ(nullptr, factory_->createTransportSocket(nullptr, nullptr)); } // Test implementsSecureTransport calls inner factory diff --git a/test/extensions/transport_sockets/starttls/starttls_integration_test.cc b/test/extensions/transport_sockets/starttls/starttls_integration_test.cc index da59a7d71f245..d57b130930a97 100644 --- a/test/extensions/transport_sockets/starttls/starttls_integration_test.cc +++ b/test/extensions/transport_sockets/starttls/starttls_integration_test.cc @@ -220,7 +220,8 @@ void StartTlsIntegrationTest::initialize() { *dispatcher_, address, Network::Address::InstanceConstSharedPtr(), cleartext_context_->createTransportSocket( std::make_shared( - absl::string_view(""), std::vector(), std::vector())), + absl::string_view(""), std::vector(), std::vector()), + nullptr), nullptr); conn_->enableHalfClose(true); @@ -280,10 +281,10 @@ TEST_P(StartTlsIntegrationTest, SwitchToTlsFromClient) { dispatcher_->run(Event::Dispatcher::RunType::Block); // Without closing the connection, switch to tls. - conn_->setTransportSocket( - tls_context_->createTransportSocket(std::make_shared( - absl::string_view(""), std::vector(), - std::vector{"envoyalpn"}))); + conn_->setTransportSocket(tls_context_->createTransportSocket( + std::make_shared( + absl::string_view(""), std::vector(), std::vector{"envoyalpn"}), + nullptr)); connect_callbacks_.reset(); while (!connect_callbacks_.connected() && !connect_callbacks_.closed()) { dispatcher_->run(Event::Dispatcher::RunType::NonBlock); @@ -347,10 +348,10 @@ TEST_P(StartTlsIntegrationTest, SwitchToTlsFromUpstream) { dispatcher_->run(Event::Dispatcher::RunType::Block); // Without closing the connection, switch to tls. - conn_->setTransportSocket( - tls_context_->createTransportSocket(std::make_shared( - absl::string_view(""), std::vector(), - std::vector{"envoyalpn"}))); + conn_->setTransportSocket(tls_context_->createTransportSocket( + std::make_shared( + absl::string_view(""), std::vector(), std::vector{"envoyalpn"}), + nullptr)); connect_callbacks_.reset(); while (!connect_callbacks_.connected() && !connect_callbacks_.closed()) { dispatcher_->run(Event::Dispatcher::RunType::NonBlock); diff --git a/test/extensions/transport_sockets/tcp_stats/tcp_stats_test.cc b/test/extensions/transport_sockets/tcp_stats/tcp_stats_test.cc index e5453ec814070..8da7a276299f9 100644 --- a/test/extensions/transport_sockets/tcp_stats/tcp_stats_test.cc +++ b/test/extensions/transport_sockets/tcp_stats/tcp_stats_test.cc @@ -272,8 +272,8 @@ class TcpStatsSocketFactoryTest : public testing::Test { // Test createTransportSocket returns nullptr if inner call returns nullptr TEST_F(TcpStatsSocketFactoryTest, CreateSocketReturnsNullWhenInnerFactoryReturnsNull) { initialize(); - EXPECT_CALL(*inner_factory_, createTransportSocket(_)).WillOnce(ReturnNull()); - EXPECT_EQ(nullptr, factory_->createTransportSocket(nullptr)); + EXPECT_CALL(*inner_factory_, createTransportSocket(_, _)).WillOnce(ReturnNull()); + EXPECT_EQ(nullptr, factory_->createTransportSocket(nullptr, nullptr)); } // Test implementsSecureTransport calls inner factory diff --git a/test/extensions/transport_sockets/tls/cert_validator/default_validator_integration_test.cc b/test/extensions/transport_sockets/tls/cert_validator/default_validator_integration_test.cc index 2f7def576c575..b874b4d3c20f8 100644 --- a/test/extensions/transport_sockets/tls/cert_validator/default_validator_integration_test.cc +++ b/test/extensions/transport_sockets/tls/cert_validator/default_validator_integration_test.cc @@ -38,7 +38,7 @@ SslCertValidatorIntegrationTest::makeSslClientConnection(const ClientSslTranspor createClientSslTransportSocketFactory(modified_options, *context_manager_, *api_); return dispatcher_->createClientConnection( address, Network::Address::InstanceConstSharedPtr(), - client_transport_socket_factory_ptr->createTransportSocket({}), nullptr); + client_transport_socket_factory_ptr->createTransportSocket({}, nullptr), nullptr); } INSTANTIATE_TEST_SUITE_P( diff --git a/test/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator_integration_test.cc b/test/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator_integration_test.cc index fe47ef14f6e3c..0fe9cab9283e2 100644 --- a/test/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator_integration_test.cc +++ b/test/extensions/transport_sockets/tls/cert_validator/spiffe/spiffe_validator_integration_test.cc @@ -43,7 +43,7 @@ Network::ClientConnectionPtr SslSPIFFECertValidatorIntegrationTest::makeSslClien createClientSslTransportSocketFactory(modified_options, *context_manager_, *api_); return dispatcher_->createClientConnection( address, Network::Address::InstanceConstSharedPtr(), - client_transport_socket_factory_ptr->createTransportSocket({}), nullptr); + client_transport_socket_factory_ptr->createTransportSocket({}, nullptr), nullptr); } void SslSPIFFECertValidatorIntegrationTest::checkVerifyErrorCouter(uint64_t value) { diff --git a/test/extensions/transport_sockets/tls/handshaker_factory_test.cc b/test/extensions/transport_sockets/tls/handshaker_factory_test.cc index 1e5230dbbf822..212a8b1b09ecd 100644 --- a/test/extensions/transport_sockets/tls/handshaker_factory_test.cc +++ b/test/extensions/transport_sockets/tls/handshaker_factory_test.cc @@ -137,7 +137,8 @@ TEST_F(HandshakerFactoryTest, SetMockFunctionCb) { tls_context_, "", mock_factory_ctx), *context_manager_, stats_store_); - std::unique_ptr socket = socket_factory.createTransportSocket(nullptr); + std::unique_ptr socket = + socket_factory.createTransportSocket(nullptr, nullptr); SSL_CTX* ssl_ctx = extractSslCtx(socket.get()); @@ -162,7 +163,8 @@ TEST_F(HandshakerFactoryTest, SetSpecificSslCtxOption) { tls_context_, "", mock_factory_ctx), *context_manager_, stats_store_); - std::unique_ptr socket = socket_factory.createTransportSocket(nullptr); + std::unique_ptr socket = + socket_factory.createTransportSocket(nullptr, nullptr); SSL_CTX* ssl_ctx = extractSslCtx(socket.get()); @@ -198,7 +200,8 @@ TEST_F(HandshakerFactoryTest, HandshakerContextProvidesObjectsFromParentContext) tls_context_, "", mock_factory_ctx), *context_manager_, stats_store_); - std::unique_ptr socket = socket_factory.createTransportSocket(nullptr); + std::unique_ptr socket = + socket_factory.createTransportSocket(nullptr, nullptr); } } // namespace diff --git a/test/extensions/transport_sockets/tls/integration/ssl_integration_test.cc b/test/extensions/transport_sockets/tls/integration/ssl_integration_test.cc index 129da67f3ca92..7551f5fbe9f75 100644 --- a/test/extensions/transport_sockets/tls/integration/ssl_integration_test.cc +++ b/test/extensions/transport_sockets/tls/integration/ssl_integration_test.cc @@ -81,7 +81,7 @@ SslIntegrationTestBase::makeSslClientConnection(const ClientSslTransportOptions& createClientSslTransportSocketFactory(options, *context_manager_, *api_); return dispatcher_->createClientConnection( address, Network::Address::InstanceConstSharedPtr(), - client_transport_socket_factory_ptr->createTransportSocket({}), nullptr); + client_transport_socket_factory_ptr->createTransportSocket({}, nullptr), nullptr); } void SslIntegrationTestBase::checkStats() { @@ -360,7 +360,7 @@ class RawWriteSslIntegrationTest : public SslIntegrationTest { [&](Network::ClientConnection&, const Buffer::Instance& data) -> void { response.append(data.toString()); }, - client_transport_socket_factory_ptr->createTransportSocket({})); + client_transport_socket_factory_ptr->createTransportSocket({}, nullptr)); // Drive the connection until we get a response. while (response.empty()) { diff --git a/test/extensions/transport_sockets/tls/ssl_socket_test.cc b/test/extensions/transport_sockets/tls/ssl_socket_test.cc index 0e45d1bc5b3a8..5593c4f3888ea 100644 --- a/test/extensions/transport_sockets/tls/ssl_socket_test.cc +++ b/test/extensions/transport_sockets/tls/ssl_socket_test.cc @@ -372,7 +372,7 @@ void testUtil(const TestUtilOptions& options) { client_stats_store); Network::ClientConnectionPtr client_connection = dispatcher->createClientConnection( socket->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - client_ssl_socket_factory.createTransportSocket(nullptr), nullptr); + client_ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); Network::ConnectionPtr server_connection; Network::MockConnectionCallbacks server_connection_callbacks; NiceMock stream_info; @@ -710,7 +710,8 @@ void testUtilV2(const TestUtilOptionsV2& options) { client_stats_store); Network::ClientConnectionPtr client_connection = dispatcher->createClientConnection( socket->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - client_ssl_socket_factory.createTransportSocket(options.transportSocketOptions()), nullptr); + client_ssl_socket_factory.createTransportSocket(options.transportSocketOptions(), nullptr), + nullptr); if (!options.clientSession().empty()) { const SslHandshakerImpl* ssl_socket = @@ -2650,7 +2651,7 @@ TEST_P(SslSocketTest, HalfClose) { client_stats_store); Network::ClientConnectionPtr client_connection = dispatcher_->createClientConnection( socket->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - client_ssl_socket_factory.createTransportSocket(nullptr), nullptr); + client_ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); client_connection->enableHalfClose(true); client_connection->addReadFilter(client_read_filter); client_connection->connect(); @@ -2732,7 +2733,7 @@ TEST_P(SslSocketTest, ShutdownWithCloseNotify) { client_stats_store); Network::ClientConnectionPtr client_connection = dispatcher_->createClientConnection( socket->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - client_ssl_socket_factory.createTransportSocket(nullptr), nullptr); + client_ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); Network::MockConnectionCallbacks client_connection_callbacks; client_connection->enableHalfClose(true); client_connection->addReadFilter(client_read_filter); @@ -2820,7 +2821,7 @@ TEST_P(SslSocketTest, ShutdownWithoutCloseNotify) { client_stats_store); Network::ClientConnectionPtr client_connection = dispatcher_->createClientConnection( socket->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - client_ssl_socket_factory.createTransportSocket(nullptr), nullptr); + client_ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); Network::MockConnectionCallbacks client_connection_callbacks; client_connection->enableHalfClose(true); client_connection->addReadFilter(client_read_filter); @@ -2926,7 +2927,7 @@ TEST_P(SslSocketTest, ClientAuthMultipleCAs) { ClientSslSocketFactory ssl_socket_factory(std::move(client_cfg), manager, client_stats_store); Network::ClientConnectionPtr client_connection = dispatcher_->createClientConnection( socket->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - ssl_socket_factory.createTransportSocket(nullptr), nullptr); + ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); // Verify that server sent list with 2 acceptable client certificate CA names. const SslHandshakerImpl* ssl_socket = @@ -3025,7 +3026,7 @@ void testTicketSessionResumption(const std::string& server_ctx_yaml1, ClientSslSocketFactory ssl_socket_factory(std::move(client_cfg), manager, client_stats_store); Network::ClientConnectionPtr client_connection = dispatcher->createClientConnection( socket1->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - ssl_socket_factory.createTransportSocket(nullptr), nullptr); + ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); Network::MockConnectionCallbacks client_connection_callbacks; client_connection->addConnectionCallbacks(client_connection_callbacks); @@ -3068,7 +3069,7 @@ void testTicketSessionResumption(const std::string& server_ctx_yaml1, client_connection = dispatcher->createClientConnection( socket2->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - ssl_socket_factory.createTransportSocket(nullptr), nullptr); + ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); client_connection->addConnectionCallbacks(client_connection_callbacks); const SslHandshakerImpl* ssl_socket = dynamic_cast(client_connection->ssl().get()); @@ -3165,8 +3166,8 @@ void testSupportForStatelessSessionResumption(const std::string& server_ctx_yaml ClientSslSocketFactory ssl_socket_factory(std::move(client_cfg), manager, client_stats_store); Network::ClientConnectionPtr client_connection = dispatcher->createClientConnection( tcp_socket->connectionInfoProvider().localAddress(), - Network::Address::InstanceConstSharedPtr(), ssl_socket_factory.createTransportSocket(nullptr), - nullptr); + Network::Address::InstanceConstSharedPtr(), + ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); Network::MockConnectionCallbacks client_connection_callbacks; client_connection->addConnectionCallbacks(client_connection_callbacks); @@ -3770,7 +3771,7 @@ TEST_P(SslSocketTest, ClientAuthCrossListenerSessionResumption) { ClientSslSocketFactory ssl_socket_factory(std::move(client_cfg), manager, client_stats_store); Network::ClientConnectionPtr client_connection = dispatcher_->createClientConnection( socket->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - ssl_socket_factory.createTransportSocket(nullptr), nullptr); + ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); Network::MockConnectionCallbacks client_connection_callbacks; client_connection->addConnectionCallbacks(client_connection_callbacks); @@ -3812,7 +3813,7 @@ TEST_P(SslSocketTest, ClientAuthCrossListenerSessionResumption) { client_connection = dispatcher_->createClientConnection( socket2->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - ssl_socket_factory.createTransportSocket(nullptr), nullptr); + ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); client_connection->addConnectionCallbacks(client_connection_callbacks); const SslHandshakerImpl* ssl_socket = dynamic_cast(client_connection->ssl().get()); @@ -3890,7 +3891,7 @@ void SslSocketTest::testClientSessionResumption(const std::string& server_ctx_ya client_stats_store); Network::ClientConnectionPtr client_connection = dispatcher->createClientConnection( socket->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - client_ssl_socket_factory.createTransportSocket(nullptr), nullptr); + client_ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); Network::MockConnectionCallbacks client_connection_callbacks; client_connection->addConnectionCallbacks(client_connection_callbacks); @@ -3952,7 +3953,7 @@ void SslSocketTest::testClientSessionResumption(const std::string& server_ctx_ya client_connection = dispatcher->createClientConnection( socket->connectionInfoProvider().localAddress(), Network::Address::InstanceConstSharedPtr(), - client_ssl_socket_factory.createTransportSocket(nullptr), nullptr); + client_ssl_socket_factory.createTransportSocket(nullptr, nullptr), nullptr); client_connection->addConnectionCallbacks(client_connection_callbacks); client_connection->connect(); @@ -5167,7 +5168,7 @@ TEST_P(SslSocketTest, UpstreamNotReadySslSocket) { ContextManagerImpl manager(time_system_); ClientSslSocketFactory client_ssl_socket_factory(std::move(client_cfg), manager, stats_store); - auto transport_socket = client_ssl_socket_factory.createTransportSocket(nullptr); + auto transport_socket = client_ssl_socket_factory.createTransportSocket(nullptr, nullptr); EXPECT_EQ(EMPTY_STRING, transport_socket->protocol()); EXPECT_EQ(nullptr, transport_socket->ssl()); EXPECT_EQ(true, transport_socket->canFlushClose()); @@ -5199,7 +5200,7 @@ TEST_P(SslSocketTest, TestTransportSocketCallback) { ClientSslSocketFactory client_ssl_socket_factory(std::move(client_cfg), manager, stats_store); Network::TransportSocketPtr transport_socket = - client_ssl_socket_factory.createTransportSocket(nullptr); + client_ssl_socket_factory.createTransportSocket(nullptr, nullptr); SslSocket* ssl_socket = dynamic_cast(transport_socket.get()); @@ -5232,7 +5233,7 @@ class SslReadBufferLimitTest : public SslSocketTest { client_ssl_socket_factory_ = std::make_unique( std::move(client_cfg), *manager_, client_stats_store_); - auto transport_socket = client_ssl_socket_factory_->createTransportSocket(nullptr); + auto transport_socket = client_ssl_socket_factory_->createTransportSocket(nullptr, nullptr); client_transport_socket_ = transport_socket.get(); client_connection_ = dispatcher_->createClientConnection(socket_->connectionInfoProvider().localAddress(), diff --git a/test/integration/sds_dynamic_integration_test.cc b/test/integration/sds_dynamic_integration_test.cc index 07c0002c5b224..cda67a208358a 100644 --- a/test/integration/sds_dynamic_integration_test.cc +++ b/test/integration/sds_dynamic_integration_test.cc @@ -309,7 +309,7 @@ version_info: "0" Network::Address::InstanceConstSharedPtr address = getSslAddress(version_, port); return dispatcher_->createClientConnection( address, Network::Address::InstanceConstSharedPtr(), - client_ssl_ctx_->createTransportSocket(nullptr), nullptr); + client_ssl_ctx_->createTransportSocket(nullptr, nullptr), nullptr); } return makeClientConnectionWithOptions(port, nullptr); } diff --git a/test/integration/sds_static_integration_test.cc b/test/integration/sds_static_integration_test.cc index 24a4efe1ae36a..9de5d0dc0aef1 100644 --- a/test/integration/sds_static_integration_test.cc +++ b/test/integration/sds_static_integration_test.cc @@ -83,9 +83,9 @@ class SdsStaticDownstreamIntegrationTest Network::ClientConnectionPtr makeSslClientConnection() { Network::Address::InstanceConstSharedPtr address = getSslAddress(version_, lookupPort("http")); - return dispatcher_->createClientConnection(address, Network::Address::InstanceConstSharedPtr(), - client_ssl_ctx_->createTransportSocket(nullptr), - nullptr); + return dispatcher_->createClientConnection( + address, Network::Address::InstanceConstSharedPtr(), + client_ssl_ctx_->createTransportSocket(nullptr, nullptr), nullptr); } private: diff --git a/test/integration/tcp_proxy_integration_test.cc b/test/integration/tcp_proxy_integration_test.cc index 3835c7629e0ba..446d8930100df 100644 --- a/test/integration/tcp_proxy_integration_test.cc +++ b/test/integration/tcp_proxy_integration_test.cc @@ -1314,9 +1314,9 @@ void TcpProxySslIntegrationTest::setupConnections() { Network::Address::InstanceConstSharedPtr address = Ssl::getSslAddress(version_, lookupPort("tcp_proxy")); context_ = Ssl::createClientSslTransportSocketFactory({}, *context_manager_, *api_); - ssl_client_ = - dispatcher_->createClientConnection(address, Network::Address::InstanceConstSharedPtr(), - context_->createTransportSocket(nullptr), nullptr); + ssl_client_ = dispatcher_->createClientConnection( + address, Network::Address::InstanceConstSharedPtr(), + context_->createTransportSocket(nullptr, nullptr), nullptr); // Perform the SSL handshake. Loopback is allowlisted in tcp_proxy.json for the ssl_auth // filter so there will be no pause waiting on auth data. diff --git a/test/integration/upstream_filter_state_integration_test.cc b/test/integration/upstream_filter_state_integration_test.cc index 3b87ee8b40148..c95440adf2d97 100644 --- a/test/integration/upstream_filter_state_integration_test.cc +++ b/test/integration/upstream_filter_state_integration_test.cc @@ -62,8 +62,9 @@ class SocketFactory : public Extensions::TransportSockets::PassthroughFactory { : PassthroughFactory(std::move(inner_factory)) {} Network::TransportSocketPtr - createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options) const override { - auto inner_socket = transport_socket_factory_->createTransportSocket(options); + createTransportSocket(Network::TransportSocketOptionsConstSharedPtr options, + Upstream::HostDescriptionConstSharedPtr host) const override { + auto inner_socket = transport_socket_factory_->createTransportSocket(options, host); if (inner_socket == nullptr) { return nullptr; } diff --git a/test/integration/xds_integration_test.cc b/test/integration/xds_integration_test.cc index 490117984b807..901c56c77d3ce 100644 --- a/test/integration/xds_integration_test.cc +++ b/test/integration/xds_integration_test.cc @@ -202,8 +202,10 @@ class LdsInplaceUpdateTcpProxyIntegrationTest response.append(data.toString()); }, version_, *dispatcher_, - context_->createTransportSocket(std::make_shared( - absl::string_view(""), std::vector(), std::vector{alpn}))); + context_->createTransportSocket( + std::make_shared( + absl::string_view(""), std::vector(), std::vector{alpn}), + nullptr)); } std::unique_ptr context_manager_; @@ -466,8 +468,10 @@ class LdsInplaceUpdateHttpIntegrationTest TestListenerFilter::setAlpn(alpn); auto ssl_conn = dispatcher_->createClientConnection( address_, Network::Address::InstanceConstSharedPtr(), - context_->createTransportSocket(std::make_shared( - absl::string_view(""), std::vector(), std::vector{alpn})), + context_->createTransportSocket( + std::make_shared( + absl::string_view(""), std::vector(), std::vector{alpn}), + nullptr), nullptr); return makeHttpConnection(std::move(ssl_conn)); } diff --git a/test/integration/xfcc_integration_test.cc b/test/integration/xfcc_integration_test.cc index 87eb80723ce77..5e38a84f26852 100644 --- a/test/integration/xfcc_integration_test.cc +++ b/test/integration/xfcc_integration_test.cc @@ -130,9 +130,9 @@ Network::ClientConnectionPtr XfccIntegrationTest::makeMtlsClientConnection() { Network::Address::InstanceConstSharedPtr address = Network::Utility::resolveUrl("tcp://" + Network::Test::getLoopbackAddressUrlString(version_) + ":" + std::to_string(lookupPort("http"))); - return dispatcher_->createClientConnection(address, Network::Address::InstanceConstSharedPtr(), - client_mtls_ssl_ctx_->createTransportSocket(nullptr), - nullptr); + return dispatcher_->createClientConnection( + address, Network::Address::InstanceConstSharedPtr(), + client_mtls_ssl_ctx_->createTransportSocket(nullptr, nullptr), nullptr); } void XfccIntegrationTest::createUpstreams() { diff --git a/test/mocks/network/transport_socket.h b/test/mocks/network/transport_socket.h index 9437ad76a1e03..276d49c38bc36 100644 --- a/test/mocks/network/transport_socket.h +++ b/test/mocks/network/transport_socket.h @@ -44,7 +44,9 @@ class MockTransportSocketFactory : public UpstreamTransportSocketFactory { MOCK_METHOD(bool, implementsSecureTransport, (), (const)); MOCK_METHOD(bool, supportsAlpn, (), (const)); MOCK_METHOD(absl::string_view, defaultServerNameIndication, (), (const)); - MOCK_METHOD(TransportSocketPtr, createTransportSocket, (TransportSocketOptionsConstSharedPtr), + MOCK_METHOD(TransportSocketPtr, createTransportSocket, + (TransportSocketOptionsConstSharedPtr, + std::shared_ptr), (const)); MOCK_METHOD(void, hashKey, (std::vector & key, TransportSocketOptionsConstSharedPtr options), (const));