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 downstream connection close error stats. #16584

Merged
merged 18 commits into from
Jun 3, 2021
Merged
Show file tree
Hide file tree
Changes from 6 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
14 changes: 14 additions & 0 deletions source/common/quic/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down Expand Up @@ -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",
Expand Down
20 changes: 11 additions & 9 deletions source/common/quic/active_quic_listener.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -87,7 +87,7 @@ ActiveQuicListener::ActiveQuicListener(
quic_dispatcher_ = std::make_unique<EnvoyQuicDispatcher>(
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 =
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -314,9 +315,10 @@ Network::ConnectionHandler::ActiveUdpListenerPtr ActiveQuicListenerFactory::crea
}
#endif

return std::make_unique<ActiveQuicListener>(
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<ActiveQuicListener>(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
Expand Down
5 changes: 4 additions & 1 deletion source/common/quic/active_quic_listener.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ 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,
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,
QuicStatNames& quic_stat_names,
uint32_t packets_to_read_to_connection_count_ratio);

~ActiveQuicListener() override;
Expand Down Expand Up @@ -87,7 +89,7 @@ class ActiveQuicListenerFactory : public Network::ActiveUdpListenerFactory,
Logger::Loggable<Logger::Id::quic> {
public:
ActiveQuicListenerFactory(const envoy::config::listener::v3::QuicProtocolOptions& config,
uint32_t concurrency);
uint32_t concurrency, QuicStatNames& quic_stat_names);

// Network::ActiveUdpListenerFactory.
Network::ConnectionHandler::ActiveUdpListenerPtr
Expand All @@ -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_;
};

Expand Down
6 changes: 4 additions & 2 deletions source/common/quic/envoy_quic_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<EnvoyQuicCryptoServerStreamHelper>(),
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
Expand All @@ -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<quic::QuicSession> EnvoyQuicDispatcher::CreateQuicSession(
Expand Down
22 changes: 11 additions & 11 deletions source/common/quic/envoy_quic_dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<quic::QuicConnectionHelperInterface> helper,
std::unique_ptr<quic::QuicAlarmFactory> 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<quic::QuicConnectionHelperInterface> helper,
std::unique_ptr<quic::QuicAlarmFactory> 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,
Expand Down Expand Up @@ -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
Expand Down
42 changes: 42 additions & 0 deletions source/common/quic/quic_stat_names.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "common/quic/quic_stat_names.h"

namespace Envoy {
namespace Quic {

QuicStatNames::QuicStatNames(Stats::SymbolTable& symbol_table)
: stat_name_pool_(symbol_table), symbol_table_(symbol_table),
downstream_(stat_name_pool_.add("downstream")), upstream_(stat_name_pool_.add("upstream")),
from_self_(stat_name_pool_.add("self")), from_peer_(stat_name_pool_.add("peer")) {
// Preallocate most used counters
connectionCloseStatName(quic::QUIC_NETWORK_IDLE_TIMEOUT);
RenjieTang marked this conversation as resolved.
Show resolved Hide resolved
}

void QuicStatNames::incCounter(Stats::Scope& scope, const Stats::StatNameVec& names) {
Stats::SymbolTable::StoragePtr stat_name_storage = symbol_table_.join(names);
RenjieTang marked this conversation as resolved.
Show resolved Hide resolved
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());

const Stats::StatName connection_close = connectionCloseStatName(error_code);
incCounter(scope, {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
39 changes: 39 additions & 0 deletions source/common/quic/quic_stat_names.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#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:
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 downstream_;
const Stats::StatName upstream_;
alyssawilk marked this conversation as resolved.
Show resolved Hide resolved
const Stats::StatName from_self_;
const Stats::StatName from_peer_;
Thread::AtomicPtrArray<const uint8_t, quic::QUIC_LAST_ERROR,
Thread::AtomicPtrAllocMode::DoNotDelete>
connection_error_stat_names_;
};

} // namespace Quic
} // namespace Envoy
1 change: 1 addition & 0 deletions source/server/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]),
)

Expand Down
3 changes: 2 additions & 1 deletion source/server/listener_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,9 @@ void ListenerImpl::buildUdpListenerFactory(Network::Socket::Type socket_type,
udp_listener_config_ = std::make_unique<UdpListenerConfigImpl>(config_.udp_listener_config());
if (config_.udp_listener_config().has_quic_options()) {
#if defined(ENVOY_ENABLE_QUIC)
RenjieTang marked this conversation as resolved.
Show resolved Hide resolved
ASSERT(quic_stat_names_.has_value());
udp_listener_config_->listener_factory_ = std::make_unique<Quic::ActiveQuicListenerFactory>(
config_.udp_listener_config().quic_options(), concurrency);
config_.udp_listener_config().quic_options(), concurrency, quic_stat_names_.value());
#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
Expand Down
15 changes: 15 additions & 0 deletions source/server/listener_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -228,6 +232,7 @@ class ListenerImpl final : public Network::ListenerConfig,
ListenerImpl(const envoy::config::listener::v3::Listener& config, const std::string& version_info,
ListenerManagerImpl& parent, const std::string& name, bool added_via_api,
bool workers_started, uint64_t hash, uint32_t concurrency);

RenjieTang marked this conversation as resolved.
Show resolved Hide resolved
~ListenerImpl() override;

// TODO(lambdai): Explore using the same ListenerImpl object to execute in place filter chain
Expand Down Expand Up @@ -330,6 +335,12 @@ class ListenerImpl final : public Network::ListenerConfig,
void createUdpListenerFilterChain(Network::UdpListenerFilterManager& udp_listener,
Network::UdpReadFilterCallbacks& callbacks) override;

#ifdef ENVOY_ENABLE_QUIC
void setQuicStatNames(Quic::QuicStatNames& quic_stat_names) {
RenjieTang marked this conversation as resolved.
Show resolved Hide resolved
quic_stat_names_ = quic_stat_names;
}
#endif

SystemTime last_updated_;

private:
Expand Down Expand Up @@ -424,6 +435,10 @@ class ListenerImpl final : public Network::ListenerConfig,
// callback during the destroy of ListenerImpl.
Init::WatcherImpl local_init_watcher_;

#ifdef ENVOY_ENABLE_QUIC
OptRef<Quic::QuicStatNames> quic_stat_names_;
#endif

// to access ListenerManagerImpl::factory_.
friend class ListenerFilterChainFactoryBuilder;
};
Expand Down
4 changes: 4 additions & 0 deletions source/server/listener_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,10 @@ bool ListenerManagerImpl::addOrUpdateListenerInternal(
workers_started_, hash, server_.options().concurrency());
}

#ifdef ENVOY_ENABLE_QUIC
new_listener->setQuicStatNames(quic_stat_names_);
Copy link
Contributor

Choose a reason for hiding this comment

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

As above I think ListenerImpl can just grab the QuicStatNames& object from the manager.

Copy link
Contributor

Choose a reason for hiding this comment

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

Or...if that involves changes to the base class you'd prefer not to do, you can just pass in the stats to the constructor rather than setting it after construction.

That just means you need to ifdef the arg-list.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fortunately ListenerImpl takes ListenerManagerImpl in its constructors. So I added getter in ListenerManagerImpl and let ListenerImpl grab it during constructions.

#endif

ListenerImpl& new_listener_ref = *new_listener;

bool added = false;
Expand Down
7 changes: 7 additions & 0 deletions source/server/listener_manager_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -316,6 +320,9 @@ class ListenerManagerImpl : public ListenerManager, Logger::Loggable<Logger::Id:
using UpdateFailureState = envoy::admin::v3::UpdateFailureState;
absl::flat_hash_map<std::string, std::unique_ptr<UpdateFailureState>> 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 {
Expand Down
12 changes: 12 additions & 0 deletions test/common/quic/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down
Loading