Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 34 additions & 39 deletions source/common/http/http3/conn_pool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,50 +12,45 @@
#include "common/network/utility.h"
#include "common/runtime/runtime_features.h"

#ifdef ENVOY_ENABLE_QUIC
#include "common/quic/client_connection_factory_impl.h"
#include "common/quic/envoy_quic_utils.h"
#include "common/quic/quic_transport_socket_factory.h"
#else
#error "http3 conn pool should not be built with QUIC disabled"
#endif

namespace Envoy {
namespace Http {
namespace Http3 {

// Http3 subclass of FixedHttpConnPoolImpl which exists to store quic data.
class Http3ConnPoolImpl : public FixedHttpConnPoolImpl {
public:
Http3ConnPoolImpl(Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority,
Event::Dispatcher& dispatcher,
const Network::ConnectionSocket::OptionsSharedPtr& options,
const Network::TransportSocketOptionsSharedPtr& transport_socket_options,
Random::RandomGenerator& random_generator,
Upstream::ClusterConnectivityState& state, CreateClientFn client_fn,
CreateCodecFn codec_fn, std::vector<Http::Protocol> protocol,
TimeSource& time_source)
: FixedHttpConnPoolImpl(host, priority, dispatcher, options, transport_socket_options,
random_generator, state, client_fn, codec_fn, protocol) {
auto source_address = host_->cluster().sourceAddress();
if (!source_address.get()) {
auto host_address = host->address();
source_address = Network::Utility::getLocalAddress(host_address->ip()->version());
}
Network::TransportSocketFactory& transport_socket_factory = host->transportSocketFactory();
quic_info_ = std::make_unique<Quic::PersistentQuicInfoImpl>(
dispatcher, transport_socket_factory, time_source, source_address);
Quic::configQuicInitialFlowControlWindow(
host_->cluster().http3Options().quic_protocol_options(), quic_info_->quic_config_);
}
void Http3ConnPoolImpl::setQuicConfigFromClusterConfig(const Upstream::ClusterInfo& cluster,
quic::QuicConfig& quic_config) {
quic::QuicTime::Delta crypto_timeout =
quic::QuicTime::Delta::FromMilliseconds(cluster.connectTimeout().count());
quic_config.set_max_time_before_crypto_handshake(crypto_timeout);
int32_t max_streams =
cluster.http3Options().quic_protocol_options().max_concurrent_streams().value();
quic_config.SetMaxBidirectionalStreamsToSend(max_streams);
quic_config.SetMaxUnidirectionalStreamsToSend(max_streams);
Quic::configQuicInitialFlowControlWindow(cluster.http3Options().quic_protocol_options(),
quic_config);
}

// Make sure all connections are torn down before quic_info_ is deleted.
~Http3ConnPoolImpl() override { destructAllConnections(); }
Http3ConnPoolImpl::Http3ConnPoolImpl(
Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority,
Event::Dispatcher& dispatcher, const Network::ConnectionSocket::OptionsSharedPtr& options,
const Network::TransportSocketOptionsSharedPtr& transport_socket_options,
Random::RandomGenerator& random_generator, Upstream::ClusterConnectivityState& state,
CreateClientFn client_fn, CreateCodecFn codec_fn, std::vector<Http::Protocol> protocol,
TimeSource& time_source)
: FixedHttpConnPoolImpl(host, priority, dispatcher, options, transport_socket_options,
random_generator, state, client_fn, codec_fn, protocol) {
auto source_address = host_->cluster().sourceAddress();
if (!source_address.get()) {
auto host_address = host->address();
source_address = Network::Utility::getLocalAddress(host_address->ip()->version());
}
Network::TransportSocketFactory& transport_socket_factory = host->transportSocketFactory();
quic_info_ = std::make_unique<Quic::PersistentQuicInfoImpl>(dispatcher, transport_socket_factory,
time_source, source_address);
setQuicConfigFromClusterConfig(host_->cluster(), quic_info_->quic_config_);
}

// Store quic helpers which can be shared between connections and must live
// beyond the lifetime of individual connections.
std::unique_ptr<Quic::PersistentQuicInfoImpl> quic_info_;
};
// Make sure all connections are torn down before quic_info_ is deleted.
Http3ConnPoolImpl::~Http3ConnPoolImpl() { destructAllConnections(); }

ConnectionPool::InstancePtr
allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_generator,
Expand All @@ -81,7 +76,7 @@ allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_
source_address = Network::Utility::getLocalAddress(host_address->ip()->version());
}
data.connection_ = Quic::createQuicNetworkConnection(
*h3_pool->quic_info_, pool->dispatcher(), host_address, source_address);
h3_pool->quicInfo(), pool->dispatcher(), host_address, source_address);
return std::make_unique<ActiveClient>(*pool, data);
},
[](Upstream::Host::CreateConnectionData& data, HttpConnPoolImplBase* pool) {
Expand Down
35 changes: 35 additions & 0 deletions source/common/http/http3/conn_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
#include "common/http/codec_client.h"
#include "common/http/conn_pool_base.h"

#ifdef ENVOY_ENABLE_QUIC
#include "common/quic/client_connection_factory_impl.h"
#include "common/quic/envoy_quic_utils.h"
#include "common/quic/quic_transport_socket_factory.h"
#else
#error "http3 conn pool should not be built with QUIC disabled"
#endif

namespace Envoy {
namespace Http {
namespace Http3 {
Expand All @@ -26,6 +34,33 @@ class ActiveClient : public MultiplexedActiveClientBase {
data) {}
};

// Http3 subclass of FixedHttpConnPoolImpl which exists to store quic data.
class Http3ConnPoolImpl : public FixedHttpConnPoolImpl {
public:
Http3ConnPoolImpl(Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority,
Event::Dispatcher& dispatcher,
const Network::ConnectionSocket::OptionsSharedPtr& options,
const Network::TransportSocketOptionsSharedPtr& transport_socket_options,
Random::RandomGenerator& random_generator,
Upstream::ClusterConnectivityState& state, CreateClientFn client_fn,
CreateCodecFn codec_fn, std::vector<Http::Protocol> protocol,
TimeSource& time_source);

~Http3ConnPoolImpl() override;

// Set relevant fields in quic_config based on the cluster configuration
// supplied in cluster.
static void setQuicConfigFromClusterConfig(const Upstream::ClusterInfo& cluster,
quic::QuicConfig& quic_config);

Quic::PersistentQuicInfoImpl& quicInfo() { return *quic_info_; }

private:
// Store quic helpers which can be shared between connections and must live
// beyond the lifetime of individual connections.
std::unique_ptr<Quic::PersistentQuicInfoImpl> quic_info_;
};

ConnectionPool::InstancePtr
allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_generator,
Upstream::HostConstSharedPtr host, Upstream::ResourcePriority priority,
Expand Down
34 changes: 34 additions & 0 deletions test/common/http/http3/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_test",
"envoy_package",
"envoy_select_enable_http3",
)

licenses(["notice"]) # Apache 2

envoy_package()

envoy_cc_test(
name = "conn_pool_test",
srcs = envoy_select_enable_http3(["conn_pool_test.cc"]),
tags = ["nofips"],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nofips? As in the compliance standard?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah. they did a fips version of boring a year or two back but we need a more modern version of boringssl for some of the QUIC crypto functions, so our QUIC impl is not compatible with Envoy builds latched to the fips boring.

deps =
envoy_select_enable_http3([
"//source/common/event:dispatcher_lib",
"//source/common/http/http3:conn_pool_lib",
"//source/common/network:utility_lib",
"//source/common/upstream:upstream_includes",
"//source/common/upstream:upstream_lib",
"//test/common/http:common_lib",
"//test/common/upstream:utility_lib",
"//test/mocks/event:event_mocks",
"//test/mocks/http:http_mocks",
"//test/mocks/network:network_mocks",
"//test/mocks/runtime:runtime_mocks",
"//test/mocks/server:transport_socket_factory_context_mocks",
"//test/mocks/upstream:cluster_info_mocks",
"//test/mocks/upstream:transport_socket_match_mocks",
"//test/test_common:test_runtime_lib",
]),
)
83 changes: 83 additions & 0 deletions test/common/http/http3/conn_pool_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#include "common/http/http3/conn_pool.h"
#include "common/quic/quic_transport_socket_factory.h"

#include "test/common/upstream/utility.h"
#include "test/mocks/common.h"
#include "test/mocks/event/mocks.h"
#include "test/mocks/server/transport_socket_factory_context.h"
#include "test/mocks/ssl/mocks.h"
#include "test/mocks/upstream/cluster_info.h"
#include "test/mocks/upstream/host.h"
#include "test/test_common/simulated_time_system.h"

using testing::NiceMock;
using testing::Return;

namespace Envoy {
namespace Http {
namespace Http3 {

TEST(Convert, Basic) {
NiceMock<Upstream::MockClusterInfo> cluster_info;
quic::QuicConfig config;

EXPECT_CALL(cluster_info, connectTimeout).WillOnce(Return(std::chrono::milliseconds(42)));
auto* protocol_options = cluster_info.http3_options_.mutable_quic_protocol_options();
protocol_options->mutable_max_concurrent_streams()->set_value(43);
protocol_options->mutable_initial_stream_window_size()->set_value(65555);

Http3ConnPoolImpl::setQuicConfigFromClusterConfig(cluster_info, config);

EXPECT_EQ(config.max_time_before_crypto_handshake(), quic::QuicTime::Delta::FromMilliseconds(42));
EXPECT_EQ(config.GetMaxBidirectionalStreamsToSend(),
protocol_options->max_concurrent_streams().value());
EXPECT_EQ(config.GetMaxUnidirectionalStreamsToSend(),
protocol_options->max_concurrent_streams().value());
EXPECT_EQ(config.GetInitialMaxStreamDataBytesIncomingBidirectionalToSend(),
protocol_options->initial_stream_window_size().value());
}

class Http3ConnPoolImplTest : public Event::TestUsingSimulatedTime, public testing::Test {
public:
void initialize() {
EXPECT_CALL(mockHost(), address()).WillRepeatedly(Return(test_address_));
EXPECT_CALL(mockHost(), transportSocketFactory()).WillRepeatedly(testing::ReturnRef(factory_));
new Event::MockSchedulableCallback(&dispatcher_);
Network::ConnectionSocket::OptionsSharedPtr options;
Network::TransportSocketOptionsSharedPtr transport_options;
pool_ = allocateConnPool(dispatcher_, random_, host_, Upstream::ResourcePriority::Default,
options, transport_options, state_, simTime());
}

Upstream::MockHost& mockHost() { return static_cast<Upstream::MockHost&>(*host_); }

NiceMock<Event::MockDispatcher> dispatcher_;
Upstream::HostSharedPtr host_{new NiceMock<Upstream::MockHost>};
NiceMock<Random::MockRandomGenerator> random_;
Upstream::ClusterConnectivityState state_;
Network::Address::InstanceConstSharedPtr test_address_ =
Network::Utility::resolveUrl("tcp://127.0.0.1:3000");
NiceMock<Server::Configuration::MockTransportSocketFactoryContext> context_;
Quic::QuicClientTransportSocketFactory factory_{
std::unique_ptr<Envoy::Ssl::ClientContextConfig>(new NiceMock<Ssl::MockClientContextConfig>),
context_};
ConnectionPool::InstancePtr pool_;
};

TEST_F(Http3ConnPoolImplTest, CreationWithConfig) {
// Set a couple of options from setQuicConfigFromClusterConfig to make sure they are applied.
auto* options = mockHost().cluster_.http3_options_.mutable_quic_protocol_options();
options->mutable_max_concurrent_streams()->set_value(15);
options->mutable_initial_stream_window_size()->set_value(65555);
initialize();

Quic::PersistentQuicInfoImpl& info = static_cast<Http3ConnPoolImpl*>(pool_.get())->quicInfo();
EXPECT_EQ(info.quic_config_.GetMaxUnidirectionalStreamsToSend(),
options->max_concurrent_streams().value());
EXPECT_EQ(info.quic_config_.GetInitialMaxStreamDataBytesIncomingBidirectionalToSend(),
options->initial_stream_window_size().value());
}

} // namespace Http3
} // namespace Http
} // namespace Envoy