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

listener: support keepalive configuration #38467

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
21 changes: 20 additions & 1 deletion api/envoy/config/listener/v3/listener.proto
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ message AdditionalAddress {
// or an empty list of :ref:`socket_options <envoy_v3_api_field_config.core.v3.SocketOptionsOverride.socket_options>`,
// it means no socket option will apply.
core.v3.SocketOptionsOverride socket_options = 2;

// TcpKeepaliveOverride wraps the TCP keepalive settings for the additional address.
// It provides a mechanism to override or disable TCP keepalive on a per-address basis.
message TcpKeepaliveOverride {
// Configures TCP keepalive for the additional address.
core.v3.TcpKeepalive tcp_keepalive = 1;
}

// Configures TCP keepalive settings for the additional address.
// If specified, this will override the listener :ref:`tcp_keepalive <envoy_v3_api_field_config.listener.v3.Listener.tcp_keepalive>` configuration.
// If the :ref:`tcp_keepalive <envoy_v3_api_field_config.listener.v3.AdditionalAddress.TcpKeepaliveOverride.tcp_keepalive>`
// within the override is not specified, it means TCP keepalive settings will not be enabled
// for the additional address.
TcpKeepaliveOverride tcp_keepalive_override = 3;
}

// Listener list collections. Entries are ``Listener`` resources or references.
Expand All @@ -53,7 +67,7 @@ message ListenerCollection {
repeated xds.core.v3.CollectionEntry entries = 1;
}

// [#next-free-field: 36]
// [#next-free-field: 37]
message Listener {
option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener";

Expand Down Expand Up @@ -390,6 +404,11 @@ message Listener {

// Whether the listener bypasses configured overload manager actions.
bool bypass_overload_manager = 35;

// If set, then TCP keepalive settings are configured for the listener address
// and additional addresses. See :ref:`tcp_keepalive_override <envoy_v3_api_field_config.listener.v3.AdditionalAddress.tcp_keepalive_override>`
// to override TCP keepalive settings for additional addresses.
core.v3.TcpKeepalive tcp_keepalive = 36;
}

// A placeholder proto so that users can explicitly configure the standard
Expand Down
6 changes: 6 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,11 @@ new_features:
change: |
Made the :ref:`credential injector filter <envoy_v3_api_msg_extensions.filters.http.credential_injector.v3.CredentialInjector>`
work as an upstream filter.
- area: listener
change: |
Added support for configuring TCP keepalive settings on both primary and additional listener addresses
by setting :ref:`tcp_keepalive <envoy_v3_api_field_config.listener.v3.Listener.tcp_keepalive>` on the primary
address and :ref:`tcp_keepalive <envoy_v3_api_field_config.listener.v3.AdditionalAddress.tcp_keepalive>`
on additional addresses.

deprecated:
51 changes: 36 additions & 15 deletions source/common/listener_manager/listener_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -340,13 +340,12 @@ ListenerImpl::ListenerImpl(const envoy::config::listener::v3::Listener& config,
quic_stat_names_(parent_.quicStatNames()),
missing_listener_config_stats_({ALL_MISSING_LISTENER_CONFIG_STATS(
POOL_COUNTER(listener_factory_context_->listenerScope()))}) {
std::vector<std::reference_wrapper<
const Protobuf::RepeatedPtrField<envoy::config::core::v3::SocketOption>>>
address_opts_list;
std::vector<Network::Socket::OptionsSharedPtr> address_opts_list;
if (config.has_internal_listener()) {
addresses_.emplace_back(
std::make_shared<Network::Address::EnvoyInternalInstance>(config.name()));
address_opts_list.emplace_back(std::ref(config.socket_options()));
address_opts_list.emplace_back(
Network::SocketOptionFactory::buildLiteralOptions(config.socket_options()));
} else {
// All the addresses should be same socket type, so get the first address's socket type is
// enough.
Expand All @@ -355,7 +354,16 @@ ListenerImpl::ListenerImpl(const envoy::config::listener::v3::Listener& config,
auto address = std::move(address_or_error.value());
SET_AND_RETURN_IF_NOT_OK(checkIpv4CompatAddress(address, config.address()), creation_status);
addresses_.emplace_back(address);
address_opts_list.emplace_back(std::ref(config.socket_options()));
auto opts = std::make_shared<Network::Socket::Options>();
auto keepalive_opts = std::make_shared<Network::Socket::Options>();
if (config.has_tcp_keepalive()) {
keepalive_opts = Network::SocketOptionFactory::buildTcpKeepaliveOptions(
Network::parseTcpKeepaliveConfig(config.tcp_keepalive()));
}
addListenSocketOptions(opts, keepalive_opts);
addListenSocketOptions(
opts, Network::SocketOptionFactory::buildLiteralOptions(config.socket_options()));
address_opts_list.emplace_back(opts);

for (auto i = 0; i < config.additional_addresses_size(); i++) {
if (socket_type_ !=
Expand All @@ -374,12 +382,29 @@ ListenerImpl::ListenerImpl(const envoy::config::listener::v3::Listener& config,
checkIpv4CompatAddress(address, config.additional_addresses(i).address()),
creation_status);
addresses_.emplace_back(additional_address);
auto opts = std::make_shared<Network::Socket::Options>();

if (config.additional_addresses(i).has_tcp_keepalive_override()) {
if (config.additional_addresses(i).tcp_keepalive_override().has_tcp_keepalive()) {
addListenSocketOptions(
opts,
Network::SocketOptionFactory::buildTcpKeepaliveOptions(
Network::parseTcpKeepaliveConfig(
config.additional_addresses(i).tcp_keepalive_override().tcp_keepalive())));
}
} else if (config.has_tcp_keepalive()) {
addListenSocketOptions(opts, keepalive_opts);
}

if (config.additional_addresses(i).has_socket_options()) {
address_opts_list.emplace_back(
std::ref(config.additional_addresses(i).socket_options().socket_options()));
addListenSocketOptions(
opts, Network::SocketOptionFactory::buildLiteralOptions(
config.additional_addresses(i).socket_options().socket_options()));
} else {
address_opts_list.emplace_back(std::ref(config.socket_options()));
addListenSocketOptions(
opts, Network::SocketOptionFactory::buildLiteralOptions(config.socket_options()));
}
address_opts_list.emplace_back(opts);
}
}

Expand Down Expand Up @@ -663,9 +688,7 @@ ListenerImpl::buildUdpListenerFactory(const envoy::config::listener::v3::Listene

void ListenerImpl::buildListenSocketOptions(
const envoy::config::listener::v3::Listener& config,
std::vector<std::reference_wrapper<
const Protobuf::RepeatedPtrField<envoy::config::core::v3::SocketOption>>>&
address_opts_list) {
std::vector<Network::Socket::OptionsSharedPtr>& address_opts_list) {
listen_socket_options_list_.insert(listen_socket_options_list_.begin(), addresses_.size(),
nullptr);
for (std::vector<std::reference_wrapper<
Expand All @@ -690,10 +713,8 @@ void ListenerImpl::buildListenSocketOptions(
addListenSocketOptions(listen_socket_options_list_[i],
Network::SocketOptionFactory::buildReusePortOptions());
}
if (!address_opts_list[i].get().empty()) {
addListenSocketOptions(
listen_socket_options_list_[i],
Network::SocketOptionFactory::buildLiteralOptions(address_opts_list[i]));
if (!address_opts_list[i]->empty()) {
addListenSocketOptions(listen_socket_options_list_[i], address_opts_list[i]);
}
if (socket_type_ == Network::Socket::Type::Datagram) {
// Needed for recvmsg to return destination address in IP header.
Expand Down
3 changes: 1 addition & 2 deletions source/common/listener_manager/listener_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,7 @@ class ListenerImpl final : public Network::ListenerConfig,
absl::Status buildUdpListenerFactory(const envoy::config::listener::v3::Listener& config,
uint32_t concurrency);
void buildListenSocketOptions(const envoy::config::listener::v3::Listener& config,
std::vector<std::reference_wrapper<const Protobuf::RepeatedPtrField<
envoy::config::core::v3::SocketOption>>>& address_opts_list);
std::vector<Network::Socket::OptionsSharedPtr>& address_opts_list);
absl::Status createListenerFilterFactories(const envoy::config::listener::v3::Listener& config);
absl::Status validateFilterChains(const envoy::config::listener::v3::Listener& config);
absl::Status buildFilterChains(const envoy::config::listener::v3::Listener& config);
Expand Down
9 changes: 9 additions & 0 deletions source/common/network/socket_option_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "source/common/common/logger.h"
#include "source/common/protobuf/protobuf.h"
#include "source/common/protobuf/utility.h"

#include "absl/types/optional.h"

Expand All @@ -19,6 +20,14 @@ struct TcpKeepaliveConfig {
absl::optional<uint32_t> keepalive_interval_; // Interval between probes, in ms
};

static inline Network::TcpKeepaliveConfig
parseTcpKeepaliveConfig(const envoy::config::core::v3::TcpKeepalive& options) {
return Network::TcpKeepaliveConfig{
PROTOBUF_GET_WRAPPED_OR_DEFAULT(options, keepalive_probes, absl::optional<uint32_t>()),
PROTOBUF_GET_WRAPPED_OR_DEFAULT(options, keepalive_time, absl::optional<uint32_t>()),
PROTOBUF_GET_WRAPPED_OR_DEFAULT(options, keepalive_interval, absl::optional<uint32_t>())};
}

class SocketOptionFactory : Logger::Loggable<Logger::Id::connection> {
public:
static std::unique_ptr<Socket::Options>
Expand Down
17 changes: 4 additions & 13 deletions source/common/upstream/upstream_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,6 @@ std::string addressToString(Network::Address::InstanceConstSharedPtr address) {
return address->asString();
}

Network::TcpKeepaliveConfig
parseTcpKeepaliveConfig(const envoy::config::cluster::v3::Cluster& config) {
const envoy::config::core::v3::TcpKeepalive& options =
config.upstream_connection_options().tcp_keepalive();
return Network::TcpKeepaliveConfig{
PROTOBUF_GET_WRAPPED_OR_DEFAULT(options, keepalive_probes, absl::optional<uint32_t>()),
PROTOBUF_GET_WRAPPED_OR_DEFAULT(options, keepalive_time, absl::optional<uint32_t>()),
PROTOBUF_GET_WRAPPED_OR_DEFAULT(options, keepalive_interval, absl::optional<uint32_t>())};
}

absl::StatusOr<ProtocolOptionsConfigConstSharedPtr>
createProtocolOptionsConfig(const std::string& name, const ProtobufWkt::Any& typed_config,
Server::Configuration::ProtocolOptionsFactoryContext& factory_context) {
Expand Down Expand Up @@ -196,9 +186,10 @@ buildBaseSocketOptions(const envoy::config::cluster::v3::Cluster& cluster_config
Network::SocketOptionFactory::buildIpFreebindOptions());
}
if (cluster_config.upstream_connection_options().has_tcp_keepalive()) {
Network::Socket::appendOptions(base_options,
Network::SocketOptionFactory::buildTcpKeepaliveOptions(
parseTcpKeepaliveConfig(cluster_config)));
Network::Socket::appendOptions(
base_options,
Network::SocketOptionFactory::buildTcpKeepaliveOptions(Network::parseTcpKeepaliveConfig(
cluster_config.upstream_connection_options().tcp_keepalive())));
}

return base_options;
Expand Down
1 change: 1 addition & 0 deletions test/common/listener_manager/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ envoy_cc_test(
shard_count = 5,
deps = [
":listener_manager_impl_test_lib",
"//envoy/network:socket_interface",
"//source/common/api:os_sys_calls_lib",
"//source/common/config:metadata_lib",
"//source/common/listener_manager:active_raw_udp_listener_config",
Expand Down
Loading
Loading