diff --git a/docs/root/configuration/http/http_conn_man/stats.rst b/docs/root/configuration/http/http_conn_man/stats.rst
index dd6891ce2d220..30a016594812e 100644
--- a/docs/root/configuration/http/http_conn_man/stats.rst
+++ b/docs/root/configuration/http/http_conn_man/stats.rst
@@ -87,7 +87,12 @@ the following statistics:
Per listener statistics
-----------------------
-Additional per listener statistics are rooted at *listener.
.http..* with the
+Per listener statistics are rooted at *listener.*.
+
+HTTP per listener statistics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Additional HTTP statistics are of the form *http..* with the
following statistics:
.. csv-table::
@@ -101,15 +106,27 @@ following statistics:
downstream_rq_4xx, Counter, Total 4xx responses
downstream_rq_5xx, Counter, Total 5xx responses
+HTTP/3 per listener statistics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+HTTP/3 statistics with the form of *http3.downstream..*:
+
+.. csv-table::
+ :header: Name, Type, Description
+ :widths: 1, 1, 2
+
+ .quic_connection_close_error_code_, Counter, A collection of counters that are lazily initialized to record each quic connection close error code that's present.
+
+
.. _config_http_conn_man_stats_per_codec:
Per codec statistics
-----------------------
-Each codec has the option of adding per-codec statistics. Both http1 and http2 have codec stats.
+Each codec has the option of adding per-codec statistics. http1, http2, and http3 all have codec stats.
-Http1 codec statistics
-~~~~~~~~~~~~~~~~~~~~~~
+HTTP/1 codec statistics
+~~~~~~~~~~~~~~~~~~~~~~~
On the downstream side all http1 statistics are rooted at *http1.*
@@ -124,8 +141,8 @@ On the upstream side all http1 statistics are rooted at *cluster..http1.*
response_flood, Counter, Total number of connections closed due to response flooding
requests_rejected_with_underscores_in_headers, Counter, Total numbers of rejected requests due to header names containing underscores. This action is configured by setting the :ref:`headers_with_underscores_action config setting `.
-Http2 codec statistics
-~~~~~~~~~~~~~~~~~~~~~~
+HTTP/2 codec statistics
+~~~~~~~~~~~~~~~~~~~~~~~
On the downstream side all http2 statistics are rooted at *http2.*
@@ -160,8 +177,8 @@ On the upstream side all http2 statistics are rooted at *cluster..http2.*
`downstream_rq_active` gauge due to differences in stream accounting between the codec and the
HTTP connection manager.
-Http3 codec statistics
-~~~~~~~~~~~~~~~~~~~~~~
+HTTP/3 codec statistics
+~~~~~~~~~~~~~~~~~~~~~~~
On the downstream side all http3 statistics are rooted at *http3.*
diff --git a/source/common/quic/BUILD b/source/common/quic/BUILD
index ba0c0401ea00c..60061ec64963a 100644
--- a/source/common/quic/BUILD
+++ b/source/common/quic/BUILD
@@ -51,6 +51,19 @@ envoy_cc_library(
],
)
+envoy_cc_library(
+ name = "quic_stat_names_lib",
+ srcs = ["quic_stat_names.cc"],
+ hdrs = ["quic_stat_names.h"],
+ tags = ["nofips"],
+ deps = [
+ "//include/envoy/stats:stats_interface",
+ "//source/common/stats:symbol_table_lib",
+ "@com_googlesource_quiche//:quic_core_error_codes_lib",
+ "@com_googlesource_quiche//:quic_core_types_lib",
+ ],
+)
+
envoy_cc_library(
name = "envoy_quic_proof_source_base_lib",
srcs = ["envoy_quic_proof_source_base.cc"],
@@ -314,6 +327,7 @@ envoy_cc_library(
hdrs = ["envoy_quic_dispatcher.h"],
tags = ["nofips"],
deps = [
+ "quic_stat_names_lib",
":envoy_quic_proof_source_lib",
":envoy_quic_server_connection_lib",
":envoy_quic_server_session_lib",
diff --git a/source/common/quic/active_quic_listener.cc b/source/common/quic/active_quic_listener.cc
index 75d32d5792cfe..eaa3991c94d55 100644
--- a/source/common/quic/active_quic_listener.cc
+++ b/source/common/quic/active_quic_listener.cc
@@ -28,18 +28,18 @@ ActiveQuicListener::ActiveQuicListener(
Network::UdpConnectionHandler& parent, Network::ListenerConfig& listener_config,
const quic::QuicConfig& quic_config, Network::Socket::OptionsSharedPtr options,
bool kernel_worker_routing, const envoy::config::core::v3::RuntimeFeatureFlag& enabled,
- uint32_t packets_received_to_connection_count_ratio)
+ QuicStatNames& quic_stat_names, uint32_t packets_received_to_connection_count_ratio)
: ActiveQuicListener(worker_index, concurrency, dispatcher, parent,
listener_config.listenSocketFactory().getListenSocket(), listener_config,
quic_config, std::move(options), kernel_worker_routing, enabled,
- packets_received_to_connection_count_ratio) {}
+ quic_stat_names, packets_received_to_connection_count_ratio) {}
ActiveQuicListener::ActiveQuicListener(
uint32_t worker_index, uint32_t concurrency, Event::Dispatcher& dispatcher,
Network::UdpConnectionHandler& parent, Network::SocketSharedPtr listen_socket,
Network::ListenerConfig& listener_config, const quic::QuicConfig& quic_config,
Network::Socket::OptionsSharedPtr options, bool kernel_worker_routing,
- const envoy::config::core::v3::RuntimeFeatureFlag& enabled,
+ const envoy::config::core::v3::RuntimeFeatureFlag& enabled, QuicStatNames& quic_stat_names,
uint32_t packets_to_read_to_connection_count_ratio)
: Server::ActiveUdpListenerBase(
worker_index, concurrency, parent, *listen_socket,
@@ -87,7 +87,7 @@ ActiveQuicListener::ActiveQuicListener(
quic_dispatcher_ = std::make_unique(
crypto_config_.get(), quic_config, &version_manager_, std::move(connection_helper),
std::move(alarm_factory), quic::kQuicDefaultConnectionIdLength, parent, *config_, stats_,
- per_worker_stats_, dispatcher, listen_socket_);
+ per_worker_stats_, dispatcher, listen_socket_, quic_stat_names);
// Create udp_packet_writer
Network::UdpPacketWriterPtr udp_packet_writer =
@@ -227,8 +227,9 @@ size_t ActiveQuicListener::numPacketsExpectedPerEventLoop() const {
}
ActiveQuicListenerFactory::ActiveQuicListenerFactory(
- const envoy::config::listener::v3::QuicProtocolOptions& config, uint32_t concurrency)
- : concurrency_(concurrency), enabled_(config.enabled()),
+ const envoy::config::listener::v3::QuicProtocolOptions& config, uint32_t concurrency,
+ QuicStatNames& quic_stat_names)
+ : concurrency_(concurrency), enabled_(config.enabled()), quic_stat_names_(quic_stat_names),
packets_to_read_to_connection_count_ratio_(
PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, packets_to_read_to_connection_count_ratio,
DEFAULT_PACKETS_TO_READ_PER_CONNECTION)) {
@@ -314,9 +315,10 @@ Network::ConnectionHandler::ActiveUdpListenerPtr ActiveQuicListenerFactory::crea
}
#endif
- return std::make_unique(
- worker_index, concurrency_, disptacher, parent, config, quic_config_, std::move(options),
- kernel_worker_routing, enabled_, packets_to_read_to_connection_count_ratio_);
+ return std::make_unique(worker_index, concurrency_, disptacher, parent,
+ config, quic_config_, std::move(options),
+ kernel_worker_routing, enabled_, quic_stat_names_,
+ packets_to_read_to_connection_count_ratio_);
} // namespace Quic
} // namespace Quic
diff --git a/source/common/quic/active_quic_listener.h b/source/common/quic/active_quic_listener.h
index 7c2264d2da9e1..8eccfa075333e 100644
--- a/source/common/quic/active_quic_listener.h
+++ b/source/common/quic/active_quic_listener.h
@@ -29,6 +29,7 @@ class ActiveQuicListener : public Envoy::Server::ActiveUdpListenerBase,
Network::ListenerConfig& listener_config, const quic::QuicConfig& quic_config,
Network::Socket::OptionsSharedPtr options, bool kernel_worker_routing,
const envoy::config::core::v3::RuntimeFeatureFlag& enabled,
+ QuicStatNames& quic_stat_names,
uint32_t packets_to_read_to_connection_count_ratio);
ActiveQuicListener(uint32_t worker_index, uint32_t concurrency, Event::Dispatcher& dispatcher,
@@ -36,6 +37,7 @@ class ActiveQuicListener : public Envoy::Server::ActiveUdpListenerBase,
Network::ListenerConfig& listener_config, const quic::QuicConfig& quic_config,
Network::Socket::OptionsSharedPtr options, bool kernel_worker_routing,
const envoy::config::core::v3::RuntimeFeatureFlag& enabled,
+ QuicStatNames& quic_stat_names,
uint32_t packets_to_read_to_connection_count_ratio);
~ActiveQuicListener() override;
@@ -87,7 +89,7 @@ class ActiveQuicListenerFactory : public Network::ActiveUdpListenerFactory,
Logger::Loggable {
public:
ActiveQuicListenerFactory(const envoy::config::listener::v3::QuicProtocolOptions& config,
- uint32_t concurrency);
+ uint32_t concurrency, QuicStatNames& quic_stat_names);
// Network::ActiveUdpListenerFactory.
Network::ConnectionHandler::ActiveUdpListenerPtr
@@ -102,6 +104,7 @@ class ActiveQuicListenerFactory : public Network::ActiveUdpListenerFactory,
const uint32_t concurrency_;
absl::once_flag install_bpf_once_;
envoy::config::core::v3::RuntimeFeatureFlag enabled_;
+ QuicStatNames& quic_stat_names_;
const uint32_t packets_to_read_to_connection_count_ratio_;
};
diff --git a/source/common/quic/envoy_quic_dispatcher.cc b/source/common/quic/envoy_quic_dispatcher.cc
index 4191e80d4d793..602a610736ca7 100644
--- a/source/common/quic/envoy_quic_dispatcher.cc
+++ b/source/common/quic/envoy_quic_dispatcher.cc
@@ -17,13 +17,13 @@ EnvoyQuicDispatcher::EnvoyQuicDispatcher(
uint8_t expected_server_connection_id_length, Network::ConnectionHandler& connection_handler,
Network::ListenerConfig& listener_config, Server::ListenerStats& listener_stats,
Server::PerHandlerListenerStats& per_worker_stats, Event::Dispatcher& dispatcher,
- Network::Socket& listen_socket)
+ Network::Socket& listen_socket, QuicStatNames& quic_stat_names)
: quic::QuicDispatcher(&quic_config, crypto_config, version_manager, std::move(helper),
std::make_unique(),
std::move(alarm_factory), expected_server_connection_id_length),
connection_handler_(connection_handler), listener_config_(listener_config),
listener_stats_(listener_stats), per_worker_stats_(per_worker_stats), dispatcher_(dispatcher),
- listen_socket_(listen_socket) {
+ listen_socket_(listen_socket), quic_stat_names_(quic_stat_names) {
// Set send buffer twice of max flow control window to ensure that stream send
// buffer always takes all the data.
// The max amount of data buffered is the per-stream high watermark + the max
@@ -46,6 +46,8 @@ void EnvoyQuicDispatcher::OnConnectionClosed(quic::QuicConnectionId connection_i
listener_stats_.downstream_cx_active_.dec();
per_worker_stats_.downstream_cx_active_.dec();
connection_handler_.decNumConnections();
+ quic_stat_names_.chargeQuicConnectionCloseStats(listener_config_.listenerScope(), error, source,
+ /*is_upstream*/ false);
}
std::unique_ptr EnvoyQuicDispatcher::CreateQuicSession(
diff --git a/source/common/quic/envoy_quic_dispatcher.h b/source/common/quic/envoy_quic_dispatcher.h
index 987dd2b450651..81058fcedf808 100644
--- a/source/common/quic/envoy_quic_dispatcher.h
+++ b/source/common/quic/envoy_quic_dispatcher.h
@@ -19,6 +19,7 @@
#include "envoy/network/listener.h"
#include "server/connection_handler_impl.h"
#include "server/active_listener_base.h"
+#include "common/quic/quic_stat_names.h"
namespace Envoy {
namespace Quic {
@@ -43,17 +44,15 @@ class EnvoyQuicCryptoServerStreamHelper : public quic::QuicCryptoServerStreamBas
class EnvoyQuicDispatcher : public quic::QuicDispatcher {
public:
- EnvoyQuicDispatcher(const quic::QuicCryptoServerConfig* crypto_config,
- const quic::QuicConfig& quic_config,
- quic::QuicVersionManager* version_manager,
- std::unique_ptr helper,
- std::unique_ptr alarm_factory,
- uint8_t expected_server_connection_id_length,
- Network::ConnectionHandler& connection_handler,
- Network::ListenerConfig& listener_config,
- Server::ListenerStats& listener_stats,
- Server::PerHandlerListenerStats& per_worker_stats,
- Event::Dispatcher& dispatcher, Network::Socket& listen_socket);
+ EnvoyQuicDispatcher(
+ const quic::QuicCryptoServerConfig* crypto_config, const quic::QuicConfig& quic_config,
+ quic::QuicVersionManager* version_manager,
+ std::unique_ptr helper,
+ std::unique_ptr alarm_factory,
+ uint8_t expected_server_connection_id_length, Network::ConnectionHandler& connection_handler,
+ Network::ListenerConfig& listener_config, Server::ListenerStats& listener_stats,
+ Server::PerHandlerListenerStats& per_worker_stats, Event::Dispatcher& dispatcher,
+ Network::Socket& listen_socket, QuicStatNames& quic_stat_names);
void OnConnectionClosed(quic::QuicConnectionId connection_id, quic::QuicErrorCode error,
const std::string& error_details,
@@ -81,6 +80,7 @@ class EnvoyQuicDispatcher : public quic::QuicDispatcher {
Server::PerHandlerListenerStats& per_worker_stats_;
Event::Dispatcher& dispatcher_;
Network::Socket& listen_socket_;
+ QuicStatNames& quic_stat_names_;
};
} // namespace Quic
diff --git a/source/common/quic/quic_stat_names.cc b/source/common/quic/quic_stat_names.cc
new file mode 100644
index 0000000000000..d5d4eb0e49396
--- /dev/null
+++ b/source/common/quic/quic_stat_names.cc
@@ -0,0 +1,52 @@
+#include "common/quic/quic_stat_names.h"
+
+namespace Envoy {
+namespace Quic {
+
+// TODO(renjietang): Currently these stats are only available in downstream. Wire it up to upstream
+// QUIC also.
+QuicStatNames::QuicStatNames(Stats::SymbolTable& symbol_table)
+ : stat_name_pool_(symbol_table), symbol_table_(symbol_table),
+ http3_prefix_(stat_name_pool_.add("http3")), downstream_(stat_name_pool_.add("downstream")),
+ upstream_(stat_name_pool_.add("upstream")), from_self_(stat_name_pool_.add("tx")),
+ from_peer_(stat_name_pool_.add("rx")) {
+ // Preallocate most used counters
+ // Most popular in client initiated connection close.
+ connectionCloseStatName(quic::QUIC_NETWORK_IDLE_TIMEOUT);
+ // Most popular in server initiated connection close.
+ connectionCloseStatName(quic::QUIC_SILENT_IDLE_TIMEOUT);
+}
+
+void QuicStatNames::incCounter(Stats::Scope& scope, const Stats::StatNameVec& names) {
+ Stats::SymbolTable::StoragePtr stat_name_storage = symbol_table_.join(names);
+ scope.counterFromStatName(Stats::StatName(stat_name_storage.get())).inc();
+}
+
+void QuicStatNames::chargeQuicConnectionCloseStats(Stats::Scope& scope,
+ quic::QuicErrorCode error_code,
+ quic::ConnectionCloseSource source,
+ bool is_upstream) {
+ ASSERT(&symbol_table_ == &scope.symbolTable());
+
+ if (error_code > quic::QUIC_LAST_ERROR) {
+ error_code = quic::QUIC_LAST_ERROR;
+ }
+
+ const Stats::StatName connection_close = connectionCloseStatName(error_code);
+ incCounter(scope, {http3_prefix_, is_upstream ? upstream_ : downstream_,
+ source == quic::ConnectionCloseSource::FROM_SELF ? from_self_ : from_peer_,
+ connection_close});
+}
+
+Stats::StatName QuicStatNames::connectionCloseStatName(quic::QuicErrorCode error_code) {
+ ASSERT(error_code <= quic::QUIC_LAST_ERROR);
+
+ return Stats::StatName(
+ connection_error_stat_names_.get(error_code, [this, error_code]() -> const uint8_t* {
+ return stat_name_pool_.addReturningStorage(
+ absl::StrCat("quic_connection_close_error_code_", QuicErrorCodeToString(error_code)));
+ }));
+}
+
+} // namespace Quic
+} // namespace Envoy
diff --git a/source/common/quic/quic_stat_names.h b/source/common/quic/quic_stat_names.h
new file mode 100644
index 0000000000000..89255aa99cfda
--- /dev/null
+++ b/source/common/quic/quic_stat_names.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "envoy/stats/scope.h"
+
+#include "common/common/thread.h"
+#include "common/stats/symbol_table_impl.h"
+
+#include "quiche/quic/core/quic_error_codes.h"
+#include "quiche/quic/core/quic_types.h"
+
+namespace Envoy {
+namespace Quic {
+
+class QuicStatNames {
+public:
+ // This class holds lazily symbolized stat names and is responsible for charging them.
+ explicit QuicStatNames(Stats::SymbolTable& symbol_table);
+
+ void chargeQuicConnectionCloseStats(Stats::Scope& scope, quic::QuicErrorCode error_code,
+ quic::ConnectionCloseSource source, bool is_upstream);
+
+private:
+ // Find the actual counter in |scope| and increment it.
+ // An example counter name: "http3.downstream.tx.quic_connection_close_error_code_QUIC_NO_ERROR".
+ void incCounter(Stats::Scope& scope, const Stats::StatNameVec& names);
+
+ Stats::StatName connectionCloseStatName(quic::QuicErrorCode error_code);
+
+ Stats::StatNamePool stat_name_pool_;
+ Stats::SymbolTable& symbol_table_;
+ const Stats::StatName http3_prefix_;
+ const Stats::StatName downstream_;
+ const Stats::StatName upstream_;
+ const Stats::StatName from_self_;
+ const Stats::StatName from_peer_;
+ Thread::AtomicPtrArray
+ connection_error_stat_names_;
+};
+
+} // namespace Quic
+} // namespace Envoy
diff --git a/source/server/BUILD b/source/server/BUILD
index bd71a70146747..c9004b42cdf00 100644
--- a/source/server/BUILD
+++ b/source/server/BUILD
@@ -421,6 +421,7 @@ envoy_cc_library(
"//source/common/quic:quic_factory_lib",
"//source/common/quic:quic_transport_socket_factory_lib",
"//source/common/quic:udp_gso_batch_writer_lib",
+ "//source/common/quic:quic_stat_names_lib",
]),
)
diff --git a/source/server/listener_impl.cc b/source/server/listener_impl.cc
index 405937f7cf7b1..852dbe5d4137c 100644
--- a/source/server/listener_impl.cc
+++ b/source/server/listener_impl.cc
@@ -33,7 +33,7 @@
#include "extensions/filters/listener/well_known_names.h"
-#if defined(ENVOY_ENABLE_QUIC)
+#ifdef ENVOY_ENABLE_QUIC
#include "common/quic/active_quic_listener.h"
#include "common/quic/udp_gso_batch_writer.h"
#endif
@@ -289,15 +289,21 @@ ListenerImpl::ListenerImpl(const envoy::config::listener::v3::Listener& config,
open_connections_(std::make_shared(
std::numeric_limits::max(), listener_factory_context_->runtime(),
cx_limit_runtime_key_)),
- local_init_watcher_(fmt::format("Listener-local-init-watcher {}", name), [this] {
- if (workers_started_) {
- parent_.onListenerWarmed(*this);
- } else {
- // Notify Server that this listener is
- // ready.
- listener_init_target_.ready();
- }
- }) {
+ local_init_watcher_(fmt::format("Listener-local-init-watcher {}", name),
+ [this] {
+ if (workers_started_) {
+ parent_.onListenerWarmed(*this);
+ } else {
+ // Notify Server that this listener is
+ // ready.
+ listener_init_target_.ready();
+ }
+ })
+#ifdef ENVOY_ENABLE_QUIC
+ ,
+ quic_stat_names_(parent_.quicStatNames())
+#endif
+{
const absl::optional runtime_val =
listener_factory_context_->runtime().snapshot().get(cx_limit_runtime_key_);
@@ -360,10 +366,16 @@ ListenerImpl::ListenerImpl(ListenerImpl& origin,
origin.listener_factory_context_->listener_factory_context_base_, this, *this)),
filter_chain_manager_(address_, origin.listener_factory_context_->parentFactoryContext(),
initManager(), origin.filter_chain_manager_),
- local_init_watcher_(fmt::format("Listener-local-init-watcher {}", name), [this] {
- ASSERT(workers_started_);
- parent_.inPlaceFilterChainUpdate(*this);
- }) {
+ local_init_watcher_(fmt::format("Listener-local-init-watcher {}", name),
+ [this] {
+ ASSERT(workers_started_);
+ parent_.inPlaceFilterChainUpdate(*this);
+ })
+#ifdef ENVOY_ENABLE_QUIC
+ ,
+ quic_stat_names_(parent_.quicStatNames())
+#endif
+{
buildAccessLog();
auto socket_type = Network::Utility::protobufAddressSocketType(config.address());
buildListenSocketOptions(socket_type);
@@ -401,9 +413,9 @@ void ListenerImpl::buildUdpListenerFactory(Network::Socket::Type socket_type,
udp_listener_config_ = std::make_unique(config_.udp_listener_config());
if (config_.udp_listener_config().has_quic_options()) {
-#if defined(ENVOY_ENABLE_QUIC)
+#ifdef ENVOY_ENABLE_QUIC
udp_listener_config_->listener_factory_ = std::make_unique(
- config_.udp_listener_config().quic_options(), concurrency);
+ config_.udp_listener_config().quic_options(), concurrency, quic_stat_names_);
#if UDP_GSO_BATCH_WRITER_COMPILETIME_SUPPORT
// TODO(mattklein123): We should be able to use GSO without QUICHE/QUIC. Right now this causes
// non-QUIC integration tests to fail, which I haven't investigated yet. Additionally, from
diff --git a/source/server/listener_impl.h b/source/server/listener_impl.h
index 2f0b860bd1332..10f5e3a4a760f 100644
--- a/source/server/listener_impl.h
+++ b/source/server/listener_impl.h
@@ -22,6 +22,10 @@
#include "absl/base/call_once.h"
+#ifdef ENVOY_ENABLE_QUIC
+#include "common/quic/quic_stat_names.h"
+#endif
+
namespace Envoy {
namespace Server {
@@ -424,6 +428,10 @@ class ListenerImpl final : public Network::ListenerConfig,
// callback during the destroy of ListenerImpl.
Init::WatcherImpl local_init_watcher_;
+#ifdef ENVOY_ENABLE_QUIC
+ Quic::QuicStatNames& quic_stat_names_;
+#endif
+
// to access ListenerManagerImpl::factory_.
friend class ListenerFilterChainFactoryBuilder;
};
diff --git a/source/server/listener_manager_impl.h b/source/server/listener_manager_impl.h
index 045465f837cee..ad09d62ffb0e2 100644
--- a/source/server/listener_manager_impl.h
+++ b/source/server/listener_manager_impl.h
@@ -23,6 +23,10 @@
#include "server/lds_api.h"
#include "server/listener_impl.h"
+#ifdef ENVOY_ENABLE_QUIC
+#include "common/quic/quic_stat_names.h"
+#endif
+
namespace Envoy {
namespace Server {
@@ -202,6 +206,10 @@ class ListenerManagerImpl : public ListenerManager, Logger::Loggable> error_state_tracker_;
FailureStates overall_error_state_;
+#ifdef ENVOY_ENABLE_QUIC
+ Quic::QuicStatNames quic_stat_names_ = Quic::QuicStatNames(server_.stats().symbolTable());
+#endif
};
class ListenerFilterChainFactoryBuilder : public FilterChainFactoryBuilder {
diff --git a/test/common/quic/BUILD b/test/common/quic/BUILD
index 9f432b55c200a..950bd64e15802 100644
--- a/test/common/quic/BUILD
+++ b/test/common/quic/BUILD
@@ -54,6 +54,18 @@ envoy_cc_test(
],
)
+envoy_cc_test(
+ name = "quic_stat_names_test",
+ srcs = ["quic_stat_names_test.cc"],
+ tags = ["nofips"],
+ deps = [
+ "//source/common/quic:quic_stat_names_lib",
+ "//source/common/stats:stats_lib",
+ "//test/mocks/stats:stats_mocks",
+ "//test/test_common:utility_lib",
+ ],
+)
+
envoy_cc_test(
name = "envoy_quic_session_cache_test",
srcs = ["envoy_quic_session_cache_test.cc"],
diff --git a/test/common/quic/active_quic_listener_test.cc b/test/common/quic/active_quic_listener_test.cc
index ffb12a05b56bf..6cbda761c2df2 100644
--- a/test/common/quic/active_quic_listener_test.cc
+++ b/test/common/quic/active_quic_listener_test.cc
@@ -87,7 +87,8 @@ class ActiveQuicListenerTest : public QuicMultiVersionTest {
bool use_http3 = GetParam().second == QuicVersionType::Iquic;
SetQuicReloadableFlag(quic_disable_version_draft_29, !use_http3);
return quic::CurrentSupportedVersions();
- }()[0]) {}
+ }()[0]),
+ quic_stat_names_(listener_config_.listenerScope().symbolTable()) {}
template
std::unique_ptr staticUniquePointerCast(std::unique_ptr&& source) {
@@ -155,7 +156,8 @@ class ActiveQuicListenerTest : public QuicMultiVersionTest {
Network::ActiveUdpListenerFactoryPtr createQuicListenerFactory(const std::string& yaml) {
envoy::config::listener::v3::QuicProtocolOptions options;
TestUtility::loadFromYamlAndValidate(yaml, options);
- return std::make_unique(options, /*concurrency=*/1);
+ return std::make_unique(options, /*concurrency=*/1,
+ quic_stat_names_);
}
void maybeConfigureMocks(int connection_count) {
@@ -311,6 +313,7 @@ class ActiveQuicListenerTest : public QuicMultiVersionTest {
quic::ParsedQuicVersion quic_version_;
uint32_t connection_window_size_{1024u};
uint32_t stream_window_size_{1024u};
+ QuicStatNames quic_stat_names_;
};
INSTANTIATE_TEST_SUITE_P(ActiveQuicListenerTests, ActiveQuicListenerTest,
@@ -329,7 +332,7 @@ TEST_P(ActiveQuicListenerTest, FailSocketOptionUponCreation) {
listener_config_, quic_config_, options, false,
ActiveQuicListenerFactoryPeer::runtimeEnabled(
static_cast(listener_factory_.get())),
- 32u),
+ quic_stat_names_, 32u),
Network::CreateListenerException, "Failed to apply socket options.");
}
diff --git a/test/common/quic/envoy_quic_dispatcher_test.cc b/test/common/quic/envoy_quic_dispatcher_test.cc
index f46bac22788c2..e9b3844bd903b 100644
--- a/test/common/quic/envoy_quic_dispatcher_test.cc
+++ b/test/common/quic/envoy_quic_dispatcher_test.cc
@@ -76,13 +76,14 @@ class EnvoyQuicDispatcherTest : public QuicMultiVersionTest,
per_worker_stats_({ALL_PER_HANDLER_LISTENER_STATS(
POOL_COUNTER_PREFIX(listener_config_.listenerScope(), "worker."),
POOL_GAUGE_PREFIX(listener_config_.listenerScope(), "worker."))}),
+ quic_stat_names_(listener_config_.listenerScope().symbolTable()),
connection_handler_(*dispatcher_, absl::nullopt),
envoy_quic_dispatcher_(
&crypto_config_, quic_config_, &version_manager_,
std::make_unique(*dispatcher_),
std::make_unique(*dispatcher_, *connection_helper_.GetClock()),
quic::kQuicDefaultConnectionIdLength, connection_handler_, listener_config_,
- listener_stats_, per_worker_stats_, *dispatcher_, *listen_socket_),
+ listener_stats_, per_worker_stats_, *dispatcher_, *listen_socket_, quic_stat_names_),
connection_id_(quic::test::TestConnectionId(1)) {
auto writer = new testing::NiceMock();
envoy_quic_dispatcher_.InitializeWithWriter(writer);
@@ -252,6 +253,7 @@ class EnvoyQuicDispatcherTest : public QuicMultiVersionTest,
testing::NiceMock listener_config_;
Server::ListenerStats listener_stats_;
Server::PerHandlerListenerStats per_worker_stats_;
+ QuicStatNames quic_stat_names_;
Server::ConnectionHandlerImpl connection_handler_;
EnvoyQuicDispatcher envoy_quic_dispatcher_;
const quic::QuicConnectionId connection_id_;
diff --git a/test/common/quic/quic_stat_names_test.cc b/test/common/quic/quic_stat_names_test.cc
new file mode 100644
index 0000000000000..4eeda27eabddb
--- /dev/null
+++ b/test/common/quic/quic_stat_names_test.cc
@@ -0,0 +1,40 @@
+#include
+
+#include "common/quic/quic_stat_names.h"
+
+#include "test/mocks/stats/mocks.h"
+
+#include "gtest/gtest.h"
+
+namespace Envoy {
+namespace Quic {
+
+class QuicStatNamesTest : public testing::Test {
+public:
+ QuicStatNamesTest() : scope_(*symbol_table_), quic_stat_names_(*symbol_table_) {}
+
+ Stats::TestUtil::TestSymbolTable symbol_table_;
+ Stats::TestUtil::TestStore scope_;
+ QuicStatNames quic_stat_names_;
+};
+
+TEST_F(QuicStatNamesTest, QuicConnectionCloseStats) {
+ quic_stat_names_.chargeQuicConnectionCloseStats(scope_, quic::QUIC_NO_ERROR,
+ quic::ConnectionCloseSource::FROM_SELF, false);
+ EXPECT_EQ(
+ 1U,
+ scope_.counter("http3.downstream.tx.quic_connection_close_error_code_QUIC_NO_ERROR").value());
+}
+
+TEST_F(QuicStatNamesTest, OutOfRangeQuicConnectionCloseStats) {
+ uint64_t bad_error_code = quic::QUIC_LAST_ERROR + 1;
+ quic_stat_names_.chargeQuicConnectionCloseStats(scope_,
+ static_cast(bad_error_code),
+ quic::ConnectionCloseSource::FROM_SELF, false);
+ EXPECT_EQ(1U,
+ scope_.counter("http3.downstream.tx.quic_connection_close_error_code_QUIC_LAST_ERROR")
+ .value());
+}
+
+} // namespace Quic
+} // namespace Envoy
diff --git a/test/integration/fake_upstream.h b/test/integration/fake_upstream.h
index 184c2a7d96591..5ae48faf275bf 100644
--- a/test/integration/fake_upstream.h
+++ b/test/integration/fake_upstream.h
@@ -37,6 +37,7 @@
#if defined(ENVOY_ENABLE_QUIC)
#include "common/quic/active_quic_listener.h"
+#include "common/quic/quic_stat_names.h"
#endif
#include "server/active_raw_udp_listener_config.h"
@@ -751,7 +752,7 @@ class FakeUpstream : Logger::Loggable,
if (is_quic) {
#if defined(ENVOY_ENABLE_QUIC)
udp_listener_config_.listener_factory_ = std::make_unique(
- envoy::config::listener::v3::QuicProtocolOptions(), 1);
+ envoy::config::listener::v3::QuicProtocolOptions(), 1, parent_.quic_stat_names_);
#else
ASSERT(false, "Running a test that requires QUIC without compiling QUIC");
#endif
@@ -840,6 +841,9 @@ class FakeUpstream : Logger::Loggable,
Http::Http1::CodecStats::AtomicPtr http1_codec_stats_;
Http::Http2::CodecStats::AtomicPtr http2_codec_stats_;
Http::Http3::CodecStats::AtomicPtr http3_codec_stats_;
+#ifdef ENVOY_ENABLE_QUIC
+ Quic::QuicStatNames quic_stat_names_ = Quic::QuicStatNames(stats_store_.symbolTable());
+#endif
};
using FakeUpstreamPtr = std::unique_ptr;
diff --git a/test/integration/quic_http_integration_test.cc b/test/integration/quic_http_integration_test.cc
index 3790873bc89a6..7011445430d25 100644
--- a/test/integration/quic_http_integration_test.cc
+++ b/test/integration/quic_http_integration_test.cc
@@ -313,6 +313,16 @@ TEST_P(QuicHttpIntegrationTest, ZeroRtt) {
->EarlyDataAccepted());
// Close the second connection.
codec_client_->close();
+ if (GetParam().first == Network::Address::IpVersion::v4) {
+ test_server_->waitForCounterEq(
+ "listener.127.0.0.1_0.http3.downstream.rx.quic_connection_close_error_"
+ "code_QUIC_NO_ERROR",
+ 2u);
+ } else {
+ test_server_->waitForCounterEq("listener.[__1]_0.http3.downstream.rx.quic_connection_close_"
+ "error_code_QUIC_NO_ERROR",
+ 2u);
+ }
}
// Ensure multiple quic connections work, regardless of platform BPF support