Skip to content

Commit

Permalink
quic: add quic version counters in http3 codec stats. (#16943)
Browse files Browse the repository at this point in the history
Commit Message: add quic version counters in http3 codec stats.
Additional Description:
Risk Level: Low
Testing: Integration tests
Docs Changes: docs/root/configuration/http/http_conn_man/stats.rst

Signed-off-by: Renjie Tang <renjietang@google.com>
  • Loading branch information
RenjieTang authored Jun 22, 2021
1 parent 59c2c1a commit 4cfda99
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 13 deletions.
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 @@ -195,6 +195,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 @@ -88,7 +88,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;
}
}

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 @@ -298,5 +298,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

0 comments on commit 4cfda99

Please sign in to comment.