Skip to content
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

quic: add quic version counters in http3 codec stats. #16943

Merged
merged 3 commits into from
Jun 22, 2021
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
6 changes: 6 additions & 0 deletions docs/root/configuration/http/http_conn_man/stats.rst
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ On the upstream side all http3 statistics are rooted at *cluster.<name>.http3.*
rx_reset, Counter, Total number of reset stream frames received by Envoy
tx_reset, Counter, Total number of reset stream frames transmitted by Envoy
metadata_not_supported_error, Counter, Total number of metadata dropped during HTTP/3 encoding
quic_version_43, Counter, Total number of quic connections that use transport version 43. This is expected to be removed when this version is deprecated.
quic_version_46, Counter, Total number of quic connections that use transport version 46. This is expected to be removed when this version is deprecated.
quic_version_50, Counter, Total number of quic connections that use transport version 50. This is expected to be removed when this version is deprecated.
quic_version_51, Counter, Total number of quic connections that use transport version 51. This is expected to be removed when this version is deprecated.
quic_version_h3_29, Counter, Total number of quic connections that use transport version h3-29. This is expected to be removed when this version is deprecated.
quic_version_rfc_v1, Counter, Total number of quic connections that use transport version rfc-v1.


Tracing statistics
Expand Down
8 changes: 7 additions & 1 deletion source/common/http/http3/codec_stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ namespace Http3 {
COUNTER(requests_rejected_with_underscores_in_headers) \
COUNTER(rx_reset) \
COUNTER(tx_reset) \
COUNTER(metadata_not_supported_error)
COUNTER(metadata_not_supported_error) \
COUNTER(quic_version_43) \
COUNTER(quic_version_46) \
COUNTER(quic_version_50) \
COUNTER(quic_version_51) \
COUNTER(quic_version_h3_29) \
COUNTER(quic_version_rfc_v1)

/**
* Wrapper struct for the HTTP/3 codec stats. @see stats_macros.h
Expand Down
2 changes: 1 addition & 1 deletion source/common/quic/envoy_quic_client_session.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ void EnvoyQuicClientSession::connect() {
void EnvoyQuicClientSession::OnConnectionClosed(const quic::QuicConnectionCloseFrame& frame,
quic::ConnectionCloseSource source) {
quic::QuicSpdyClientSession::OnConnectionClosed(frame, source);
onConnectionCloseEvent(frame, source);
onConnectionCloseEvent(frame, source, version());
}

void EnvoyQuicClientSession::Initialize() {
Expand Down
2 changes: 1 addition & 1 deletion source/common/quic/envoy_quic_server_session.cc
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void EnvoyQuicServerSession::setUpRequestDecoder(EnvoyQuicServerStream& stream)
void EnvoyQuicServerSession::OnConnectionClosed(const quic::QuicConnectionCloseFrame& frame,
quic::ConnectionCloseSource source) {
quic::QuicServerSessionBase::OnConnectionClosed(frame, source);
onConnectionCloseEvent(frame, source);
onConnectionCloseEvent(frame, source, version());
}

void EnvoyQuicServerSession::Initialize() {
Expand Down
30 changes: 29 additions & 1 deletion source/common/quic/quic_filter_manager_connection_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ void QuicFilterManagerConnectionImpl::maybeApplyDelayClosePolicy() {
}

void QuicFilterManagerConnectionImpl::onConnectionCloseEvent(
const quic::QuicConnectionCloseFrame& frame, quic::ConnectionCloseSource source) {
const quic::QuicConnectionCloseFrame& frame, quic::ConnectionCloseSource source,
const quic::ParsedQuicVersion& version) {
transport_failure_reason_ = absl::StrCat(quic::QuicErrorCodeToString(frame.quic_error_code),
" with details: ", frame.error_details);
if (network_connection_ != nullptr) {
Expand All @@ -169,6 +170,33 @@ void QuicFilterManagerConnectionImpl::onConnectionCloseEvent(
ASSERT(network_connection_ != nullptr);
network_connection_ = nullptr;
}

if (!codec_stats_.has_value()) {
// The connection was closed before it could be used. Stats are not recorded.
return;
}
switch (version.transport_version) {
case quic::QUIC_VERSION_43:
codec_stats_->quic_version_43_.inc();
return;
case quic::QUIC_VERSION_46:
codec_stats_->quic_version_46_.inc();
return;
case quic::QUIC_VERSION_50:
codec_stats_->quic_version_50_.inc();
return;
case quic::QUIC_VERSION_51:
codec_stats_->quic_version_51_.inc();
return;
case quic::QUIC_VERSION_IETF_DRAFT_29:
codec_stats_->quic_version_h3_29_.inc();
return;
case quic::QUIC_VERSION_IETF_RFC_V1:
codec_stats_->quic_version_rfc_v1_.inc();
return;
default:
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

can we make sure we have unit tests for all of these for coverage?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. I added a new EnvoyClientSessionAllQuicVersionTest for this since none of the existing tests cover all QUIC versions.

}
}

void QuicFilterManagerConnectionImpl::closeConnectionImmediately() {
Expand Down
15 changes: 6 additions & 9 deletions source/common/quic/quic_filter_manager_connection_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,10 @@ class QuicFilterManagerConnectionImpl : public Network::ConnectionImplBase,
uint32_t bytesToSend() { return bytes_to_send_; }

void setHttp3Options(const envoy::config::core::v3::Http3ProtocolOptions& http3_options) {
http3_options_ =
std::reference_wrapper<const envoy::config::core::v3::Http3ProtocolOptions>(http3_options);
http3_options_ = http3_options;
}

void setCodecStats(Http::Http3::CodecStats& stats) {
codec_stats_ = std::reference_wrapper<Http::Http3::CodecStats>(stats);
}
void setCodecStats(Http::Http3::CodecStats& stats) { codec_stats_ = stats; }

uint32_t maxIncomingHeadersCount() { return max_headers_count_; }

Expand All @@ -154,7 +151,8 @@ class QuicFilterManagerConnectionImpl : public Network::ConnectionImplBase,
protected:
// Propagate connection close to network_connection_callbacks_.
void onConnectionCloseEvent(const quic::QuicConnectionCloseFrame& frame,
quic::ConnectionCloseSource source);
quic::ConnectionCloseSource source,
const quic::ParsedQuicVersion& version);

void closeConnectionImmediately() override;

Expand All @@ -166,9 +164,8 @@ class QuicFilterManagerConnectionImpl : public Network::ConnectionImplBase,

QuicNetworkConnection* network_connection_{nullptr};

absl::optional<std::reference_wrapper<Http::Http3::CodecStats>> codec_stats_;
absl::optional<std::reference_wrapper<const envoy::config::core::v3::Http3ProtocolOptions>>
http3_options_;
OptRef<Http::Http3::CodecStats> codec_stats_;
OptRef<const envoy::config::core::v3::Http3ProtocolOptions> http3_options_;
bool initialized_{false};

private:
Expand Down
123 changes: 123 additions & 0 deletions test/common/quic/envoy_quic_client_session_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -259,5 +259,128 @@ TEST_P(EnvoyQuicClientSessionTest, ConnectionCloseWithActiveStream) {
EXPECT_TRUE(stream.write_side_closed() && stream.reading_stopped());
}

class EnvoyQuicClientSessionAllQuicVersionTest
: public testing::TestWithParam<quic::ParsedQuicVersion> {
public:
EnvoyQuicClientSessionAllQuicVersionTest()
: api_(Api::createApiForTest(time_system_)),
dispatcher_(api_->allocateDispatcher("test_thread")), connection_helper_(*dispatcher_),
alarm_factory_(*dispatcher_, *connection_helper_.GetClock()),
peer_addr_(Network::Utility::getAddressWithPort(*Network::Utility::getIpv6LoopbackAddress(),
12345)),
self_addr_(Network::Utility::getAddressWithPort(*Network::Utility::getIpv6LoopbackAddress(),
54321)),
quic_connection_(new TestEnvoyQuicClientConnection(
quic::test::TestConnectionId(), connection_helper_, alarm_factory_, writer_,
quic::test::SupportedVersions(GetParam()), *dispatcher_,
createConnectionSocket(peer_addr_, self_addr_, nullptr))),
crypto_config_(std::make_shared<quic::QuicCryptoClientConfig>(
quic::test::crypto_test_utils::ProofVerifierForTesting())),
envoy_quic_session_(quic_config_, quic::test::SupportedVersions(GetParam()),
std::unique_ptr<TestEnvoyQuicClientConnection>(quic_connection_),
quic::QuicServerId("example.com", 443, false), crypto_config_, nullptr,
*dispatcher_,
/*send_buffer_limit*/ 1024 * 1024, crypto_stream_factory_),
stats_({ALL_HTTP3_CODEC_STATS(POOL_COUNTER_PREFIX(scope_, "http3."),
POOL_GAUGE_PREFIX(scope_, "http3."))}),
http_connection_(envoy_quic_session_, http_connection_callbacks_, stats_, http3_options_,
64 * 1024, 100) {
EXPECT_EQ(time_system_.systemTime(), envoy_quic_session_.streamInfo().startTime());
EXPECT_EQ(EMPTY_STRING, envoy_quic_session_.nextProtocol());
EXPECT_EQ(Http::Protocol::Http3, http_connection_.protocol());

time_system_.advanceTimeWait(std::chrono::milliseconds(1));
ON_CALL(writer_, WritePacket(_, _, _, _, _))
.WillByDefault(testing::Return(quic::WriteResult(quic::WRITE_STATUS_OK, 1)));
}

void SetUp() override {
envoy_quic_session_.Initialize();
setQuicConfigWithDefaultValues(envoy_quic_session_.config());
envoy_quic_session_.OnConfigNegotiated();
envoy_quic_session_.addConnectionCallbacks(network_connection_callbacks_);
envoy_quic_session_.setConnectionStats(
{read_total_, read_current_, write_total_, write_current_, nullptr, nullptr});
EXPECT_EQ(&read_total_, &quic_connection_->connectionStats().read_total_);
}

void TearDown() override {
if (quic_connection_->connected()) {
EXPECT_CALL(*quic_connection_,
SendConnectionClosePacket(quic::QUIC_NO_ERROR, _, "Closed by application"));
EXPECT_CALL(network_connection_callbacks_, onEvent(Network::ConnectionEvent::LocalClose));
envoy_quic_session_.close(Network::ConnectionCloseType::NoFlush);
}
}

protected:
Event::SimulatedTimeSystemHelper time_system_;
Api::ApiPtr api_;
Event::DispatcherPtr dispatcher_;
EnvoyQuicConnectionHelper connection_helper_;
EnvoyQuicAlarmFactory alarm_factory_;
testing::NiceMock<quic::test::MockPacketWriter> writer_;
Network::Address::InstanceConstSharedPtr peer_addr_;
Network::Address::InstanceConstSharedPtr self_addr_;
TestEnvoyQuicClientConnection* quic_connection_;
quic::QuicConfig quic_config_;
std::shared_ptr<quic::QuicCryptoClientConfig> crypto_config_;
TestQuicCryptoClientStreamFactory crypto_stream_factory_;
EnvoyQuicClientSession envoy_quic_session_;
Network::MockConnectionCallbacks network_connection_callbacks_;
Http::MockServerConnectionCallbacks http_connection_callbacks_;
testing::StrictMock<Stats::MockCounter> read_total_;
testing::StrictMock<Stats::MockGauge> read_current_;
testing::StrictMock<Stats::MockCounter> write_total_;
testing::StrictMock<Stats::MockGauge> write_current_;
Stats::IsolatedStoreImpl scope_;
Http::Http3::CodecStats stats_;
envoy::config::core::v3::Http3ProtocolOptions http3_options_;
QuicHttpClientConnectionImpl http_connection_;
};

INSTANTIATE_TEST_SUITE_P(EnvoyQuicClientSessionAllQuicVersionTests,
EnvoyQuicClientSessionAllQuicVersionTest,
testing::ValuesIn(quic::AllSupportedVersions()));

TEST_P(EnvoyQuicClientSessionAllQuicVersionTest, ConnectionClosePopulatesQuicVersionStats) {
std::string error_details("dummy details");
quic::QuicErrorCode error(quic::QUIC_INVALID_FRAME_DATA);
quic::QuicConnectionCloseFrame frame(GetParam().transport_version, error,
quic::NO_IETF_QUIC_ERROR, error_details,
/* transport_close_frame_type = */ 0);
EXPECT_CALL(network_connection_callbacks_, onEvent(Network::ConnectionEvent::RemoteClose));
quic_connection_->OnConnectionCloseFrame(frame);
EXPECT_EQ(absl::StrCat(quic::QuicErrorCodeToString(error), " with details: ", error_details),
envoy_quic_session_.transportFailureReason());
EXPECT_EQ(Network::Connection::State::Closed, envoy_quic_session_.state());
std::string quic_version_stat_name;
switch (GetParam().transport_version) {
case quic::QUIC_VERSION_43:
quic_version_stat_name = "43";
break;
case quic::QUIC_VERSION_46:
quic_version_stat_name = "46";
break;
case quic::QUIC_VERSION_50:
quic_version_stat_name = "50";
break;
case quic::QUIC_VERSION_51:
quic_version_stat_name = "51";
break;
case quic::QUIC_VERSION_IETF_DRAFT_29:
quic_version_stat_name = "h3_29";
break;
case quic::QUIC_VERSION_IETF_RFC_V1:
quic_version_stat_name = "rfc_v1";
break;
default:
break;
}
EXPECT_EQ(1U, TestUtility::findCounter(
scope_, absl::StrCat("http3.quic_version_", quic_version_stat_name))
->value());
}

} // namespace Quic
} // namespace Envoy
7 changes: 7 additions & 0 deletions test/integration/quic_http_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ TEST_P(QuicHttpIntegrationTest, ZeroRtt) {
"error_code_QUIC_NO_ERROR",
2u);
}
if (GetParam().second == QuicVersionType::GquicQuicCrypto) {
test_server_->waitForCounterEq("http3.quic_version_50", 2u);
} else if (GetParam().second == QuicVersionType::GquicTls) {
test_server_->waitForCounterEq("http3.quic_version_51", 2u);
} else {
test_server_->waitForCounterEq("http3.quic_version_rfc_v1", 2u);
}
}

// Ensure multiple quic connections work, regardless of platform BPF support
Expand Down