-
Notifications
You must be signed in to change notification settings - Fork 5.5k
upstream adding QUIC-to-TCP failover #15894
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
745132d
fdede29
91df86b
c3f7e0a
99d30d3
0cd983b
7cdb07c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,13 @@ | ||
| #pragma once | ||
|
|
||
| #include "envoy/extensions/transport_sockets/quic/v3/quic_transport.pb.h" | ||
| #include "envoy/network/transport_socket.h" | ||
| #include "envoy/server/transport_socket_config.h" | ||
| #include "envoy/ssl/context_config.h" | ||
|
|
||
| #include "common/common/assert.h" | ||
|
|
||
| #include "extensions/transport_sockets/tls/ssl_socket.h" | ||
| #include "extensions/transport_sockets/well_known_names.h" | ||
|
|
||
| namespace Envoy { | ||
|
|
@@ -25,6 +27,7 @@ class QuicTransportSocketFactoryBase : public Network::TransportSocketFactory { | |
| } | ||
| bool implementsSecureTransport() const override { return true; } | ||
| bool usesProxyProtocolOptions() const override { return false; } | ||
| bool supportsAlpn() const override { return true; } | ||
| }; | ||
|
|
||
| // TODO(danzh): when implement ProofSource, examine of it's necessary to | ||
|
|
@@ -42,13 +45,41 @@ class QuicServerTransportSocketFactory : public QuicTransportSocketFactoryBase { | |
|
|
||
| class QuicClientTransportSocketFactory : public QuicTransportSocketFactoryBase { | ||
| public: | ||
| QuicClientTransportSocketFactory(Envoy::Ssl::ClientContextConfigPtr config) | ||
| : config_(std::move(config)) {} | ||
| QuicClientTransportSocketFactory( | ||
| Ssl::ClientContextConfigPtr config, | ||
| Server::Configuration::TransportSocketFactoryContext& factory_context) | ||
| : config_(std::move(config)), manager_(factory_context.sslContextManager()), | ||
| scope_(factory_context.scope()) {} | ||
|
|
||
| // As documented above for QuicTransportSocketFactoryBase, the actual HTTP/3 | ||
| // code does not create transport sockets. | ||
| // QuicClientTransportSocketFactory::createTransportSocket is called by the | ||
| // connection grid when upstream HTTP/3 fails over to TCP, and a raw SSL socket | ||
| // is needed. In this case the QuicClientTransportSocketFactory falls over to | ||
| // using the fallback factory. | ||
| Network::TransportSocketPtr | ||
| createTransportSocket(Network::TransportSocketOptionsSharedPtr options) const override { | ||
| // TODO(#15649) make createTransportSocket non-const to avoid the const cast. | ||
| const_cast<QuicClientTransportSocketFactory*>(this)->maybeCreateFallbackFactory(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are factories per worker or can createTransportSocket be called concurrently by multiple theads? If the later, there's a thread race in this code. I would consider creating this fallback factory in QuicClientTransportSocketFactory's constructor in order to guarantee that it always exists if createTransportSocket is ever called. |
||
| return fallback_factory_->createTransportSocket(options); | ||
| } | ||
|
|
||
| const Ssl::ClientContextConfig& clientContextConfig() const { return *config_; } | ||
| // Creates fallback_factory_ if it does not already exist. | ||
| void maybeCreateFallbackFactory(); | ||
|
|
||
| // Generally the QuicClientTransportSocketFactory owns its own client context | ||
| // config, but in the case of failover to TCP, it hands it off to the fallback_factory_ | ||
| const Ssl::ClientContextConfig& clientContextConfig() const { | ||
| return fallback_factory_ ? fallback_factory_->config() : *config_; | ||
| } | ||
|
|
||
| private: | ||
| std::unique_ptr<const Ssl::ClientContextConfig> config_; | ||
| Envoy::Ssl::ClientContextConfigPtr config_; | ||
| Envoy::Ssl::ContextManager& manager_; | ||
| Stats::Scope& scope_; | ||
| envoy::extensions::transport_sockets::quic::v3::QuicUpstreamTransport quic_config_; | ||
| // The QUIC client transport socket can create TLS sockets for fallback to TCP. | ||
| std::unique_ptr<Extensions::TransportSockets::Tls::ClientSslSocketFactory> fallback_factory_; | ||
| }; | ||
|
|
||
| // Base class to create above QuicTransportSocketFactory for server and client | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,6 +45,7 @@ | |
| #include "common/upstream/subset_lb.h" | ||
|
|
||
| #ifdef ENVOY_ENABLE_QUIC | ||
| #include "common/http/conn_pool_grid.h" | ||
| #include "common/http/http3/conn_pool.h" | ||
| #endif | ||
|
|
||
|
|
@@ -59,6 +60,18 @@ void addOptionsIfNotNull(Network::Socket::OptionsSharedPtr& options, | |
| } | ||
| } | ||
|
|
||
| // Helper function to make sure each protocol in expected_protocols is present | ||
| // in protocols (only used for an ASSERT in debug builds) | ||
| bool contains(const std::vector<Http::Protocol>& protocols, | ||
| const std::vector<Http::Protocol>& expected_protocols) { | ||
| for (auto protocol : expected_protocols) { | ||
| if (std::find(protocols.begin(), protocols.end(), protocol) == protocols.end()) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| void ClusterManagerInitHelper::addCluster(ClusterManagerCluster& cm_cluster) { | ||
|
|
@@ -1505,14 +1518,26 @@ Http::ConnectionPool::InstancePtr ProdClusterManagerFactory::allocateConnPool( | |
| const Network::ConnectionSocket::OptionsSharedPtr& options, | ||
| const Network::TransportSocketOptionsSharedPtr& transport_socket_options, TimeSource& source, | ||
| ClusterConnectivityState& state) { | ||
| if (protocols.size() == 2) { | ||
| if (protocols.size() == 3 && runtime_.snapshot().featureEnabled("upstream.use_http3", 100)) { | ||
|
alyssawilk marked this conversation as resolved.
|
||
| ASSERT(contains(protocols, | ||
| {Http::Protocol::Http11, Http::Protocol::Http2, Http::Protocol::Http3})); | ||
| #ifdef ENVOY_ENABLE_QUIC | ||
| Envoy::Http::ConnectivityGrid::ConnectivityOptions coptions{protocols}; | ||
| return std::make_unique<Http::ConnectivityGrid>( | ||
| dispatcher, api_.randomGenerator(), host, priority, options, transport_socket_options, | ||
| state, source, std::chrono::milliseconds(300), coptions); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Curious, are there plans to make next_attempt_duration configurable in the future?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, I figured I'd make @RyanTheOptimist take that on both as a simple API change, and to reduce bikeshedding on this PR |
||
| #else | ||
| // Should be blocked by configuration checking at an earlier point. | ||
| NOT_REACHED_GCOVR_EXCL_LINE; | ||
| #endif | ||
| } | ||
| if (protocols.size() >= 2) { | ||
|
alyssawilk marked this conversation as resolved.
|
||
| ASSERT((protocols[0] == Http::Protocol::Http2 && protocols[1] == Http::Protocol::Http11) || | ||
| (protocols[1] == Http::Protocol::Http2 && protocols[0] == Http::Protocol::Http11)); | ||
| return std::make_unique<Http::HttpConnPoolImplMixed>(dispatcher, api_.randomGenerator(), host, | ||
| priority, options, | ||
| transport_socket_options, state); | ||
| } | ||
|
|
||
| if (protocols.size() == 1 && protocols[0] == Http::Protocol::Http2 && | ||
| runtime_.snapshot().featureEnabled("upstream.use_http2", 100)) { | ||
| return Http::Http2::allocateConnPool(dispatcher, api_.randomGenerator(), host, priority, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.