From 7c745ae89e5eabb6f6d53b3163ac6b8c7021b1de Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Fri, 17 Jul 2020 11:08:53 -0700 Subject: [PATCH] network: add socket interface factory and config option (#11630) Add bootstrap config option that allows startup injection of a custom SocketInterface. Risk Level: Low Testing: n/a Docs Changes: n/a Release Notes: n/a Signed-off-by: Florin Coras Signed-off-by: scheler --- api/BUILD | 1 + api/envoy/config/bootstrap/v3/bootstrap.proto | 6 +- .../config/bootstrap/v4alpha/bootstrap.proto | 6 +- .../network/socket_interface/v3/BUILD | 9 +++ .../v3/default_socket_interface.proto | 17 +++++ api/versioning/BUILD | 1 + .../common_messages/common_messages.rst | 1 + .../envoy/config/bootstrap/v3/bootstrap.proto | 6 +- .../config/bootstrap/v4alpha/bootstrap.proto | 6 +- .../network/socket_interface/v3/BUILD | 9 +++ .../v3/default_socket_interface.proto | 17 +++++ include/envoy/network/BUILD | 1 + include/envoy/network/socket.h | 2 + source/common/network/BUILD | 16 ++++- source/common/network/address_impl.cc | 2 +- source/common/network/socket_interface.h | 56 ++++++++++++++++ .../common/network/socket_interface_impl.cc | 14 ++++ source/common/network/socket_interface_impl.h | 17 +++-- source/server/BUILD | 1 + source/server/server.cc | 31 ++++++--- test/integration/BUILD | 11 +++ .../socket_interface_integration_test.cc | 67 +++++++++++++++++++ 22 files changed, 276 insertions(+), 21 deletions(-) create mode 100644 api/envoy/extensions/network/socket_interface/v3/BUILD create mode 100644 api/envoy/extensions/network/socket_interface/v3/default_socket_interface.proto create mode 100644 generated_api_shadow/envoy/extensions/network/socket_interface/v3/BUILD create mode 100644 generated_api_shadow/envoy/extensions/network/socket_interface/v3/default_socket_interface.proto create mode 100644 source/common/network/socket_interface.h create mode 100644 test/integration/socket_interface_integration_test.cc diff --git a/api/BUILD b/api/BUILD index 3bbdd21a64fa..9d4f802dfe5f 100644 --- a/api/BUILD +++ b/api/BUILD @@ -227,6 +227,7 @@ proto_library( "//envoy/extensions/internal_redirect/allow_listed_routes/v3:pkg", "//envoy/extensions/internal_redirect/previous_routes/v3:pkg", "//envoy/extensions/internal_redirect/safe_cross_scheme/v3:pkg", + "//envoy/extensions/network/socket_interface/v3:pkg", "//envoy/extensions/retry/host/omit_host_metadata/v3:pkg", "//envoy/extensions/retry/priority/previous_priorities/v3:pkg", "//envoy/extensions/transport_sockets/alts/v3:pkg", diff --git a/api/envoy/config/bootstrap/v3/bootstrap.proto b/api/envoy/config/bootstrap/v3/bootstrap.proto index 57a455444579..27c59bfc8cc9 100644 --- a/api/envoy/config/bootstrap/v3/bootstrap.proto +++ b/api/envoy/config/bootstrap/v3/bootstrap.proto @@ -39,7 +39,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // ` for more detail. // Bootstrap :ref:`configuration overview `. -// [#next-free-field: 24] +// [#next-free-field: 25] message Bootstrap { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v2.Bootstrap"; @@ -222,6 +222,10 @@ message Bootstrap { // other resolution fails. // [#not-implemented-hide:] core.v3.ConfigSource default_config_source = 23; + + // Optional overriding of default socket interface. The value must be the name of one of the + // socket interface factories initialized through a bootstrap extension + string default_socket_interface = 24; } // Administration interface :ref:`operations documentation diff --git a/api/envoy/config/bootstrap/v4alpha/bootstrap.proto b/api/envoy/config/bootstrap/v4alpha/bootstrap.proto index b5a4bef5f65e..41de2a875d2e 100644 --- a/api/envoy/config/bootstrap/v4alpha/bootstrap.proto +++ b/api/envoy/config/bootstrap/v4alpha/bootstrap.proto @@ -37,7 +37,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // ` for more detail. // Bootstrap :ref:`configuration overview `. -// [#next-free-field: 24] +// [#next-free-field: 25] message Bootstrap { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v3.Bootstrap"; @@ -213,6 +213,10 @@ message Bootstrap { // other resolution fails. // [#not-implemented-hide:] core.v4alpha.ConfigSource default_config_source = 23; + + // Optional overriding of default socket interface. The value must be the name of one of the + // socket interface factories initialized through a bootstrap extension + string default_socket_interface = 24; } // Administration interface :ref:`operations documentation diff --git a/api/envoy/extensions/network/socket_interface/v3/BUILD b/api/envoy/extensions/network/socket_interface/v3/BUILD new file mode 100644 index 000000000000..ef3541ebcb1d --- /dev/null +++ b/api/envoy/extensions/network/socket_interface/v3/BUILD @@ -0,0 +1,9 @@ +# DO NOT EDIT. This file is generated by tools/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], +) diff --git a/api/envoy/extensions/network/socket_interface/v3/default_socket_interface.proto b/api/envoy/extensions/network/socket_interface/v3/default_socket_interface.proto new file mode 100644 index 000000000000..d2c747ec49fb --- /dev/null +++ b/api/envoy/extensions/network/socket_interface/v3/default_socket_interface.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package envoy.extensions.network.socket_interface.v3; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.network.socket_interface.v3"; +option java_outer_classname = "DefaultSocketInterfaceProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Default Socket Interface configuration] + +// Configuration for default socket interface that relies on OS dependent syscall to create +// sockets. +message DefaultSocketInterface { +} diff --git a/api/versioning/BUILD b/api/versioning/BUILD index 1d91b1724b1c..e00a0fbbb55d 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -110,6 +110,7 @@ proto_library( "//envoy/extensions/internal_redirect/allow_listed_routes/v3:pkg", "//envoy/extensions/internal_redirect/previous_routes/v3:pkg", "//envoy/extensions/internal_redirect/safe_cross_scheme/v3:pkg", + "//envoy/extensions/network/socket_interface/v3:pkg", "//envoy/extensions/retry/host/omit_host_metadata/v3:pkg", "//envoy/extensions/retry/priority/previous_priorities/v3:pkg", "//envoy/extensions/transport_sockets/alts/v3:pkg", diff --git a/docs/root/api-v3/common_messages/common_messages.rst b/docs/root/api-v3/common_messages/common_messages.rst index 59e40f63b7fb..ceff6d6681ee 100644 --- a/docs/root/api-v3/common_messages/common_messages.rst +++ b/docs/root/api-v3/common_messages/common_messages.rst @@ -20,3 +20,4 @@ Common messages ../config/core/v3/substitution_format_string.proto ../extensions/common/ratelimit/v3/ratelimit.proto ../extensions/filters/common/fault/v3/fault.proto + ../extensions/network/socket_interface/v3/default_socket_interface.proto diff --git a/generated_api_shadow/envoy/config/bootstrap/v3/bootstrap.proto b/generated_api_shadow/envoy/config/bootstrap/v3/bootstrap.proto index 26752b16ebdc..53b587c8bc0b 100644 --- a/generated_api_shadow/envoy/config/bootstrap/v3/bootstrap.proto +++ b/generated_api_shadow/envoy/config/bootstrap/v3/bootstrap.proto @@ -39,7 +39,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE; // ` for more detail. // Bootstrap :ref:`configuration overview `. -// [#next-free-field: 24] +// [#next-free-field: 25] message Bootstrap { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v2.Bootstrap"; @@ -221,6 +221,10 @@ message Bootstrap { // [#not-implemented-hide:] core.v3.ConfigSource default_config_source = 23; + // Optional overriding of default socket interface. The value must be the name of one of the + // socket interface factories initialized through a bootstrap extension + string default_socket_interface = 24; + Runtime hidden_envoy_deprecated_runtime = 11 [deprecated = true, (envoy.annotations.disallowed_by_default) = true]; } diff --git a/generated_api_shadow/envoy/config/bootstrap/v4alpha/bootstrap.proto b/generated_api_shadow/envoy/config/bootstrap/v4alpha/bootstrap.proto index f75d169486a5..6690c6cd0c30 100644 --- a/generated_api_shadow/envoy/config/bootstrap/v4alpha/bootstrap.proto +++ b/generated_api_shadow/envoy/config/bootstrap/v4alpha/bootstrap.proto @@ -38,7 +38,7 @@ option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSIO // ` for more detail. // Bootstrap :ref:`configuration overview `. -// [#next-free-field: 24] +// [#next-free-field: 25] message Bootstrap { option (udpa.annotations.versioning).previous_message_type = "envoy.config.bootstrap.v3.Bootstrap"; @@ -221,6 +221,10 @@ message Bootstrap { // other resolution fails. // [#not-implemented-hide:] core.v4alpha.ConfigSource default_config_source = 23; + + // Optional overriding of default socket interface. The value must be the name of one of the + // socket interface factories initialized through a bootstrap extension + string default_socket_interface = 24; } // Administration interface :ref:`operations documentation diff --git a/generated_api_shadow/envoy/extensions/network/socket_interface/v3/BUILD b/generated_api_shadow/envoy/extensions/network/socket_interface/v3/BUILD new file mode 100644 index 000000000000..ef3541ebcb1d --- /dev/null +++ b/generated_api_shadow/envoy/extensions/network/socket_interface/v3/BUILD @@ -0,0 +1,9 @@ +# DO NOT EDIT. This file is generated by tools/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], +) diff --git a/generated_api_shadow/envoy/extensions/network/socket_interface/v3/default_socket_interface.proto b/generated_api_shadow/envoy/extensions/network/socket_interface/v3/default_socket_interface.proto new file mode 100644 index 000000000000..d2c747ec49fb --- /dev/null +++ b/generated_api_shadow/envoy/extensions/network/socket_interface/v3/default_socket_interface.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package envoy.extensions.network.socket_interface.v3; + +import "udpa/annotations/status.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.network.socket_interface.v3"; +option java_outer_classname = "DefaultSocketInterfaceProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Default Socket Interface configuration] + +// Configuration for default socket interface that relies on OS dependent syscall to create +// sockets. +message DefaultSocketInterface { +} diff --git a/include/envoy/network/BUILD b/include/envoy/network/BUILD index f4a342d26bb8..a9f4dc7bd739 100644 --- a/include/envoy/network/BUILD +++ b/include/envoy/network/BUILD @@ -96,6 +96,7 @@ envoy_cc_library( deps = [ ":address_interface", ":io_handle_interface", + "//include/envoy/config:typed_config_interface", "@envoy_api//envoy/config/core/v3:pkg_cc_proto", ], ) diff --git a/include/envoy/network/socket.h b/include/envoy/network/socket.h index 0951f0a04617..ff558f7760b9 100644 --- a/include/envoy/network/socket.h +++ b/include/envoy/network/socket.h @@ -271,5 +271,7 @@ class SocketInterface { virtual bool ipFamilySupported(int domain) PURE; }; +using SocketInterfacePtr = std::unique_ptr; + } // namespace Network } // namespace Envoy \ No newline at end of file diff --git a/source/common/network/BUILD b/source/common/network/BUILD index e97330223d37..95d412a0a71a 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -17,10 +17,10 @@ envoy_cc_library( hdrs = [ "address_impl.h", "io_socket_handle_impl.h", - "socket_interface_impl.h", ], deps = [ ":io_socket_error_lib", + ":socket_interface_lib", "//include/envoy/buffer:buffer_interface", "//include/envoy/network:address_interface", "//include/envoy/network:io_handle_interface", @@ -172,6 +172,17 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "socket_interface_lib", + hdrs = ["socket_interface.h"], + deps = [ + "//include/envoy/config:typed_config_interface", + "//include/envoy/network:socket_interface", + "//include/envoy/registry", + "//include/envoy/server:bootstrap_extension_config_interface", + ], +) + envoy_cc_library( name = "socket_lib", srcs = [ @@ -184,10 +195,11 @@ envoy_cc_library( ], deps = [ ":address_lib", + ":socket_interface_lib", "//include/envoy/network:socket_interface", "//source/common/common:assert_lib", "//source/common/common:utility_lib", - "//source/common/singleton:threadsafe_singleton", + "@envoy_api//envoy/extensions/network/socket_interface/v3:pkg_cc_proto", ], ) diff --git a/source/common/network/address_impl.cc b/source/common/network/address_impl.cc index 1f3dcbb3fb74..5b4d57e55bd4 100644 --- a/source/common/network/address_impl.cc +++ b/source/common/network/address_impl.cc @@ -10,7 +10,7 @@ #include "common/common/assert.h" #include "common/common/fmt.h" #include "common/common/utility.h" -#include "common/network/socket_interface_impl.h" +#include "common/network/socket_interface.h" namespace Envoy { namespace Network { diff --git a/source/common/network/socket_interface.h b/source/common/network/socket_interface.h new file mode 100644 index 000000000000..66d717857500 --- /dev/null +++ b/source/common/network/socket_interface.h @@ -0,0 +1,56 @@ +#pragma once + +#include "envoy/config/typed_config.h" +#include "envoy/network/socket.h" +#include "envoy/registry/registry.h" +#include "envoy/server/bootstrap_extension_config.h" + +#include "common/singleton/threadsafe_singleton.h" + +#include "absl/container/flat_hash_map.h" + +namespace Envoy { +namespace Network { + +// Wrapper for SocketInterface instances returned by createBootstrapExtension() which must be +// implemented by all factories that derive SocketInterfaceBase +class SocketInterfaceExtension : public Server::BootstrapExtension { +public: + SocketInterfaceExtension(SocketInterface& sock_interface) : sock_interface_(sock_interface) {} + SocketInterface& socketInterface() { return sock_interface_; } + +private: + SocketInterface& sock_interface_; +}; + +// Class to be derived by all SocketInterface implementations. +// +// It acts both as a SocketInterface and as a BootstrapExtensionFactory. The latter is used, on the +// one hand, to configure and initialize the interface and, on the other, for SocketInterface lookup +// by leveraging the FactoryRegistry. As required for all bootstrap extensions, all derived classes +// should register via the REGISTER_FACTORY() macro as BootstrapExtensionFactory. +// +// SocketInterface instances can be retrieved using the factory name, i.e., string returned by +// name() function implemented by all classes that derive SocketInterfaceBase, via +// Network::socketInterface(). When instantiating addresses, address resolvers should +// set the socket interface field to the name of the socket interface implementation that should +// be used to create sockets for said addresses. +class SocketInterfaceBase : public SocketInterface, + public Server::Configuration::BootstrapExtensionFactory {}; + +/** + * Lookup SocketInterface instance by name + * @param name Name of the socket interface to be looked up + * @return Pointer to @ref SocketInterface instance that registered using the name of nullptr + */ +static inline const SocketInterface* socketInterface(std::string name) { + auto factory = + Registry::FactoryRegistry::getFactory(name); + return dynamic_cast(factory); +} + +using SocketInterfaceSingleton = InjectableSingleton; +using SocketInterfaceLoader = ScopedInjectableLoader; + +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/socket_interface_impl.cc b/source/common/network/socket_interface_impl.cc index acdc8214c55d..ba0b4a9b3fc5 100644 --- a/source/common/network/socket_interface_impl.cc +++ b/source/common/network/socket_interface_impl.cc @@ -1,6 +1,7 @@ #include "common/network/socket_interface_impl.h" #include "envoy/common/exception.h" +#include "envoy/extensions/network/socket_interface/v3/default_socket_interface.pb.h" #include "envoy/network/socket.h" #include "common/api/os_sys_calls_impl.h" @@ -81,6 +82,19 @@ bool SocketInterfaceImpl::ipFamilySupported(int domain) { return SOCKET_VALID(result.rc_); } +Server::BootstrapExtensionPtr +SocketInterfaceImpl::createBootstrapExtension(const Protobuf::Message&, + Server::Configuration::ServerFactoryContext&) { + return std::make_unique(*this); +} + +ProtobufTypes::MessagePtr SocketInterfaceImpl::createEmptyConfigProto() { + return std::make_unique< + envoy::extensions::network::socket_interface::v3::DefaultSocketInterface>(); +} + +REGISTER_FACTORY(SocketInterfaceImpl, Server::Configuration::BootstrapExtensionFactory); + static SocketInterfaceLoader* socket_interface_ = new SocketInterfaceLoader(std::make_unique()); diff --git a/source/common/network/socket_interface_impl.h b/source/common/network/socket_interface_impl.h index 88798559844a..034aea25feaf 100644 --- a/source/common/network/socket_interface_impl.h +++ b/source/common/network/socket_interface_impl.h @@ -3,22 +3,31 @@ #include "envoy/network/address.h" #include "envoy/network/socket.h" -#include "common/singleton/threadsafe_singleton.h" +#include "common/network/socket_interface.h" namespace Envoy { namespace Network { -class SocketInterfaceImpl : public SocketInterface { +class SocketInterfaceImpl : public SocketInterfaceBase { public: + // SocketInterface IoHandlePtr socket(Socket::Type socket_type, Address::Type addr_type, Address::IpVersion version) override; IoHandlePtr socket(Socket::Type socket_type, const Address::InstanceConstSharedPtr addr) override; IoHandlePtr socket(os_fd_t fd) override; bool ipFamilySupported(int domain) override; + + // Server::Configuration::BootstrapExtensionFactory + Server::BootstrapExtensionPtr + createBootstrapExtension(const Protobuf::Message& config, + Server::Configuration::ServerFactoryContext& context) override; + ProtobufTypes::MessagePtr createEmptyConfigProto() override; + std::string name() const override { + return "envoy.extensions.network.socket_interface.default_socket_interface"; + }; }; -using SocketInterfaceSingleton = InjectableSingleton; -using SocketInterfaceLoader = ScopedInjectableLoader; +DECLARE_FACTORY(SocketInterfaceImpl); } // namespace Network } // namespace Envoy \ No newline at end of file diff --git a/source/server/BUILD b/source/server/BUILD index 33266f13f3f8..10ed76a2d077 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -46,6 +46,7 @@ envoy_cc_library( "//source/common/config:runtime_utility_lib", "//source/common/config:utility_lib", "//source/common/network:resolver_lib", + "//source/common/network:socket_interface_lib", "//source/common/network:socket_option_factory_lib", "//source/common/network:socket_option_lib", "//source/common/network:utility_lib", diff --git a/source/server/server.cc b/source/server/server.cc index 80c48c279c06..b91177ef38bd 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -35,6 +35,8 @@ #include "common/memory/stats.h" #include "common/network/address_impl.h" #include "common/network/listener_impl.h" +#include "common/network/socket_interface.h" +#include "common/network/socket_interface_impl.h" #include "common/protobuf/utility.h" #include "common/router/rds_impl.h" #include "common/runtime/runtime_impl.h" @@ -395,6 +397,25 @@ void InstanceImpl::initialize(const Options& options, heap_shrinker_ = std::make_unique(*dispatcher_, *overload_manager_, stats_store_); + for (const auto& bootstrap_extension : bootstrap_.bootstrap_extensions()) { + auto& factory = Config::Utility::getAndCheckFactory( + bootstrap_extension); + auto config = Config::Utility::translateAnyToFactoryConfig( + bootstrap_extension.typed_config(), messageValidationContext().staticValidationVisitor(), + factory); + bootstrap_extensions_.push_back( + factory.createBootstrapExtension(*config, serverFactoryContext())); + } + + if (!bootstrap_.default_socket_interface().empty()) { + auto& sock_name = bootstrap_.default_socket_interface(); + auto sock = const_cast(Network::socketInterface(sock_name)); + if (sock != nullptr) { + Network::SocketInterfaceSingleton::clear(); + Network::SocketInterfaceSingleton::initialize(sock); + } + } + // Workers get created first so they register for thread local updates. listener_manager_ = std::make_unique( *this, listener_component_factory_, worker_factory_, bootstrap_.enable_dispatcher_stats()); @@ -493,16 +514,6 @@ void InstanceImpl::initialize(const Options& options, // GuardDog (deadlock detection) object and thread setup before workers are // started and before our own run() loop runs. guard_dog_ = std::make_unique(stats_store_, config_, *api_); - - for (const auto& bootstrap_extension : bootstrap_.bootstrap_extensions()) { - auto& factory = Config::Utility::getAndCheckFactory( - bootstrap_extension); - auto config = Config::Utility::translateAnyToFactoryConfig( - bootstrap_extension.typed_config(), messageValidationContext().staticValidationVisitor(), - factory); - bootstrap_extensions_.push_back( - factory.createBootstrapExtension(*config, serverFactoryContext())); - } } void InstanceImpl::onClusterManagerPrimaryInitializationComplete() { diff --git a/test/integration/BUILD b/test/integration/BUILD index b08549380079..40bcd665e111 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -744,6 +744,17 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "socket_interface_integration_test", + srcs = ["socket_interface_integration_test.cc"], + tags = ["fails_on_windows"], + deps = [ + ":http_integration_lib", + "//source/common/network:socket_interface_lib", + "//source/extensions/filters/network/echo:config", + ], +) + envoy_cc_test( name = "stats_integration_test", srcs = ["stats_integration_test.cc"], diff --git a/test/integration/socket_interface_integration_test.cc b/test/integration/socket_interface_integration_test.cc new file mode 100644 index 000000000000..c2b798c9801e --- /dev/null +++ b/test/integration/socket_interface_integration_test.cc @@ -0,0 +1,67 @@ +#include "common/network/socket_interface.h" + +#include "test/integration/integration.h" +#include "test/test_common/environment.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace { + +class SocketInterfaceIntegrationTest : public BaseIntegrationTest, + public testing::TestWithParam { +public: + SocketInterfaceIntegrationTest() : BaseIntegrationTest(GetParam(), config()) { + use_lds_ = false; + }; + + static std::string config() { + // At least one empty filter chain needs to be specified. + return absl::StrCat(echoConfig(), R"EOF( +bootstrap_extensions: + - name: envoy.extensions.network.socket_interface.default_socket_interface + typed_config: + "@type": type.googleapis.com/envoy.extensions.network.socket_interface.v3.DefaultSocketInterface +default_socket_interface: "envoy.extensions.network.socket_interface.default_socket_interface" + )EOF"); + } + static std::string echoConfig() { + return absl::StrCat(ConfigHelper::baseConfig(), R"EOF( + filter_chains: + filters: + name: ratelimit + typed_config: + "@type": type.googleapis.com/envoy.config.filter.network.rate_limit.v2.RateLimit + domain: foo + stats_prefix: name + descriptors: [{"key": "foo", "value": "bar"}] + filters: + name: envoy.filters.network.echo + )EOF"); + } +}; + +INSTANTIATE_TEST_SUITE_P(IpVersions, SocketInterfaceIntegrationTest, + testing::ValuesIn(TestEnvironment::getIpVersionsForTest()), + TestUtility::ipTestParamsToString); + +TEST_P(SocketInterfaceIntegrationTest, Basic) { + BaseIntegrationTest::initialize(); + const Network::SocketInterface* factory = Network::socketInterface( + "envoy.extensions.network.socket_interface.default_socket_interface"); + ASSERT_TRUE(Network::SocketInterfaceSingleton::getExisting() == factory); + + std::string response; + auto connection = createConnectionDriver( + lookupPort("listener_0"), "hello", + [&response](Network::ClientConnection& conn, const Buffer::Instance& data) -> void { + response.append(data.toString()); + conn.close(Network::ConnectionCloseType::FlushWrite); + }); + connection->run(); + EXPECT_EQ("hello", response); +} + +} // namespace +} // namespace Envoy \ No newline at end of file