Skip to content

Commit

Permalink
quic: enable sending server preferred address to non-quiche clients (e…
Browse files Browse the repository at this point in the history
…nvoyproxy#32130)

Signed-off-by: Greg Greenway <[email protected]>
  • Loading branch information
ggreenway authored Feb 13, 2024
1 parent 0eb7048 commit c813cde
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 10 deletions.
2 changes: 1 addition & 1 deletion api/envoy/config/listener/v3/quic_config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ message QuicProtocolOptions {
core.v3.TypedExtensionConfig connection_id_generator_config = 8;

// Configure the server's preferred address to advertise so that client can migrate to it. See :ref:`example <envoy_v3_api_msg_extensions.quic.server_preferred_address.v3.FixedServerPreferredAddressConfig>` which configures a pair of v4 and v6 preferred addresses.
// The current QUICHE implementation will advertise only one of the preferred IPv4 and IPv6 addresses based on the address family the client initially connects with, and only if the client is also QUICHE-based.
// The current QUICHE implementation will advertise only one of the preferred IPv4 and IPv6 addresses based on the address family the client initially connects with.
// If not specified, Envoy will not advertise any server's preferred address.
// [#extension-category: envoy.quic.server_preferred_address]
core.v3.TypedExtensionConfig server_preferred_address_config = 9
Expand Down
5 changes: 5 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ minor_behavior_changes:
- area: adaptive concurrency filter stats
change: |
Multiply the gradient value stat by 1000 to make it more granular (values will range between 500 and 2000).
- area: quic
change: |
:ref:`Server preferred address <envoy_v3_api_field_config.listener.v3.QuicProtocolOptions.server_preferred_address_config>` is
now sent to non-quiche quic clients when configured. This behavior can be disabled with runtime flag
``envoy.reloadable_features.quic_send_server_preferred_address_to_all_clients``.
- area: dns
change: |
Allowing <envoy_v3_api_field_extensions.common.dynamic_forward_proxy.v3.DnsCacheConfig.dns_min_refresh_rate>` to go as low as 1s.
Expand Down
4 changes: 4 additions & 0 deletions source/common/quic/platform/quiche_flags_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ template <> constexpr bool maybeOverride<bool>(absl::string_view name, bool val)
// Do not include 32-byte per-entry overhead while counting header size.
return false;
}
if (name == "quic_always_support_server_preferred_address") {
// Envoy should send server preferred address without a client option by default.
return true;
}

return val;
}
Expand Down
3 changes: 3 additions & 0 deletions source/common/runtime/runtime_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ RUNTIME_GUARD(envoy_reloadable_features_oauth_use_url_encoding);
RUNTIME_GUARD(envoy_reloadable_features_original_dst_rely_on_idle_timeout);
RUNTIME_GUARD(envoy_reloadable_features_proxy_status_upstream_request_timeout);
RUNTIME_GUARD(envoy_reloadable_features_quic_fix_filter_manager_uaf);
// Ignore the automated "remove this flag" issue: we should keep this for 1 year. Confirm with
// @danzh2010 or @RyanTheOptimist before removing.
RUNTIME_GUARD(envoy_reloadable_features_quic_send_server_preferred_address_to_all_clients);
RUNTIME_GUARD(envoy_reloadable_features_sanitize_te);
RUNTIME_GUARD(envoy_reloadable_features_send_header_raw_value);
RUNTIME_GUARD(envoy_reloadable_features_skip_dns_lookup_for_proxied_requests);
Expand Down
8 changes: 8 additions & 0 deletions source/common/runtime/runtime_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#ifdef ENVOY_ENABLE_QUIC
#include "quiche_platform_impl/quiche_flags_impl.h"
#include "quiche/common/platform/api/quiche_flags.h"
#endif

namespace Envoy {
Expand Down Expand Up @@ -59,6 +60,13 @@ void refreshReloadableFlags(const Snapshot::EntryMap& flag_map) {
}
#ifdef ENVOY_ENABLE_QUIC
quiche::FlagRegistry::getInstance().updateReloadableFlags(quiche_flags_override);

// Because this is a QUICHE protocol flag, this behavior can't be flipped with the above
// code, so it needs its own runtime flag and code to set it.
SetQuicheFlag(quic_always_support_server_preferred_address,
Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.quic_send_server_preferred_address_to_all_clients"));

#endif
// Make sure ints are parsed after the flag allowing deprecated ints is parsed.
for (const auto& it : flag_map) {
Expand Down
68 changes: 59 additions & 9 deletions test/integration/quic_http_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1838,9 +1838,6 @@ TEST_P(QuicHttpIntegrationTest, UsesPreferredAddress) {
});

initialize();
quic::QuicTagVector connection_options{quic::kSPAD};
dynamic_cast<Quic::PersistentQuicInfoImpl&>(*quic_connection_persistent_info_)
.quic_config_.SetConnectionOptionsToSend(connection_options);
codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http")));
EnvoyQuicClientSession* quic_session =
static_cast<EnvoyQuicClientSession*>(codec_client_->connection());
Expand Down Expand Up @@ -1871,6 +1868,65 @@ TEST_P(QuicHttpIntegrationTest, UsesPreferredAddress) {
}
}

TEST_P(QuicHttpIntegrationTest, PreferredAddressRuntimeFlag) {
autonomous_upstream_ = true;
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.quic_send_server_preferred_address_to_all_clients", "false");
config_helper_.addConfigModifier([=](envoy::config::bootstrap::v3::Bootstrap& bootstrap) -> void {
auto* listen_address = bootstrap.mutable_static_resources()
->mutable_listeners(0)
->mutable_address()
->mutable_socket_address();
// Change listening address to Any.
listen_address->set_address(version_ == Network::Address::IpVersion::v4 ? "0.0.0.0" : "::");
auto* preferred_address_config = bootstrap.mutable_static_resources()
->mutable_listeners(0)
->mutable_udp_listener_config()
->mutable_quic_options()
->mutable_server_preferred_address_config();
// Configure a loopback interface as the server's preferred address.
preferred_address_config->set_name("quic.server_preferred_address.fixed");
envoy::extensions::quic::server_preferred_address::v3::FixedServerPreferredAddressConfig
server_preferred_address;
server_preferred_address.set_ipv4_address("127.0.0.2");
server_preferred_address.set_ipv6_address("::2");
preferred_address_config->mutable_typed_config()->PackFrom(server_preferred_address);

// Configure a test listener filter which is incompatible with any server preferred addresses
// but with any matcher, which effectively disables the filter.
auto* listener_filter =
bootstrap.mutable_static_resources()->mutable_listeners(0)->add_listener_filters();
listener_filter->set_name("dumb_filter");
auto configuration = test::integration::filters::TestQuicListenerFilterConfig();
configuration.set_added_value("foo");
configuration.set_allow_server_migration(false);
configuration.set_allow_client_migration(false);
listener_filter->mutable_typed_config()->PackFrom(configuration);
listener_filter->mutable_filter_disabled()->set_any_match(true);
});

initialize();
codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http")));
EnvoyQuicClientSession* quic_session =
static_cast<EnvoyQuicClientSession*>(codec_client_->connection());
EXPECT_EQ(Network::Test::getLoopbackAddressString(version_),
quic_connection_->peer_address().host().ToString());
EXPECT_TRUE(!quic_session->config()->HasReceivedIPv4AlternateServerAddress() &&
!quic_session->config()->HasReceivedIPv6AlternateServerAddress());
ASSERT_TRUE(quic_connection_->waitForHandshakeDone());
EXPECT_FALSE(quic_connection_->IsValidatingServerPreferredAddress());
Http::TestRequestHeaderMapImpl request_headers{
{":method", "GET"},
{":path", "/test/long/url"},
{":authority", "sni.lyft.com"},
{":scheme", "http"},
{AutonomousStream::RESPONSE_SIZE_BYTES, std::to_string(1024 * 1024)}};
IntegrationStreamDecoderPtr response =
codec_client_->makeHeaderOnlyRequest(default_request_headers_);
EXPECT_TRUE(response->waitForEndStream());
ASSERT_TRUE(response->complete());
}

TEST_P(QuicHttpIntegrationTest, UsesPreferredAddressDualStack) {
if (!(TestEnvironment::shouldRunTestForIpVersion(Network::Address::IpVersion::v6) &&
version_ == Network::Address::IpVersion::v4)) {
Expand Down Expand Up @@ -1901,9 +1957,6 @@ TEST_P(QuicHttpIntegrationTest, UsesPreferredAddressDualStack) {
});

initialize();
quic::QuicTagVector connection_options{quic::kSPAD};
dynamic_cast<Quic::PersistentQuicInfoImpl&>(*quic_connection_persistent_info_)
.quic_config_.SetConnectionOptionsToSend(connection_options);
codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http")));
EnvoyQuicClientSession* quic_session =
static_cast<EnvoyQuicClientSession*>(codec_client_->connection());
Expand Down Expand Up @@ -1971,9 +2024,6 @@ TEST_P(QuicHttpIntegrationTest, PreferredAddressDroppedByIncompatibleListenerFil
});

initialize();
quic::QuicTagVector connection_options{quic::kSPAD};
dynamic_cast<Quic::PersistentQuicInfoImpl&>(*quic_connection_persistent_info_)
.quic_config_.SetConnectionOptionsToSend(connection_options);
codec_client_ = makeHttpConnection(makeClientConnection(lookupPort("http")));
EnvoyQuicClientSession* quic_session =
static_cast<EnvoyQuicClientSession*>(codec_client_->connection());
Expand Down

0 comments on commit c813cde

Please sign in to comment.