Skip to content

Commit 73fe00f

Browse files
authored
connection: add functionality to set downstream socket option dynamically (envoyproxy#39200)
Signed-off-by: Jacob Lisi <[email protected]>
1 parent ff3d484 commit 73fe00f

21 files changed

+232
-3
lines changed

envoy/network/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ envoy_cc_library(
3232
"//envoy/ssl:connection_interface",
3333
"//envoy/stream_info:stream_info_interface",
3434
"@com_google_absl//absl/numeric:int128",
35+
"@com_google_absl//absl/types:span",
3536
],
3637
)
3738

envoy/network/connection.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,12 @@ class Connection : public Event::DeferredDeletable,
347347
*/
348348
virtual const ConnectionSocket::OptionsSharedPtr& socketOptions() const PURE;
349349

350+
/**
351+
* Set a socket option on the underlying socket(s) of this connection.
352+
* @param option The socket option to set.
353+
* @return boolean telling if the socket option was set successfully.
354+
*/
355+
virtual bool setSocketOption(Network::SocketOptionName name, absl::Span<uint8_t> value) PURE;
350356
/**
351357
* The StreamInfo object associated with this connection. This is typically
352358
* used for logging purposes. Individual filters may add specific information

source/common/network/connection_impl.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,23 @@ bool ConnectionImpl::bothSidesHalfClosed() {
921921
return read_end_stream_ && write_end_stream_ && write_buffer_->length() == 0;
922922
}
923923

924+
bool ConnectionImpl::setSocketOption(Network::SocketOptionName name, absl::Span<uint8_t> value) {
925+
Api::SysCallIntResult result =
926+
SocketOptionImpl::setSocketOption(*socket_, name, value.data(), value.size());
927+
if (result.return_value_ != 0) {
928+
ENVOY_LOG(warn, "Setting option on socket failed, errno: {}, message: {}", result.errno_,
929+
errorDetails(result.errno_));
930+
return false;
931+
}
932+
933+
// Only add a sockopt if it's added successfully.
934+
auto sockopt = std::make_shared<SocketOptionImpl>(
935+
name, absl::string_view(reinterpret_cast<const char*>(value.data()), value.size()));
936+
socket_->addOption(sockopt);
937+
938+
return true;
939+
}
940+
924941
absl::string_view ConnectionImpl::transportFailureReason() const {
925942
if (!failure_reason_.empty()) {
926943
return failure_reason_;

source/common/network/connection_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class ConnectionImpl : public ConnectionImplBase, public TransportSocketCallback
106106
const ConnectionSocket::OptionsSharedPtr& socketOptions() const override {
107107
return socket_->options();
108108
}
109+
bool setSocketOption(Network::SocketOptionName name, absl::Span<uint8_t> value) override;
109110
absl::string_view requestedServerName() const override { return socket_->requestedServerName(); }
110111
StreamInfo::StreamInfo& streamInfo() override { return stream_info_; }
111112
const StreamInfo::StreamInfo& streamInfo() const override { return stream_info_; }

source/common/network/multi_connection_base_impl.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,17 @@ bool MultiConnectionBaseImpl::isHalfCloseEnabled() const {
106106
return connections_[0]->isHalfCloseEnabled();
107107
}
108108

109+
bool MultiConnectionBaseImpl::setSocketOption(Network::SocketOptionName name,
110+
absl::Span<uint8_t> value) {
111+
bool success = true;
112+
for (auto& connection : connections_) {
113+
if (!connection->setSocketOption(name, value)) {
114+
success = false;
115+
}
116+
}
117+
return success;
118+
}
119+
109120
std::string MultiConnectionBaseImpl::nextProtocol() const {
110121
return connections_[0]->nextProtocol();
111122
}

source/common/network/multi_connection_base_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ class MultiConnectionBaseImpl : public ClientConnection,
101101

102102
// Simple getters which always delegate to the first connection in connections_.
103103
bool isHalfCloseEnabled() const override;
104+
bool setSocketOption(Network::SocketOptionName name, absl::Span<uint8_t> value) override;
104105
std::string nextProtocol() const override;
105106
// Note, this might change before connect finishes.
106107
ConnectionInfoSetter& connectionInfoSetter() override;

source/common/network/socket_option_impl.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace Network {
1515
// Socket::Option
1616
bool SocketOptionImpl::setOption(Socket& socket,
1717
envoy::config::core::v3::SocketOption::SocketState state) const {
18-
if (in_state_ == state) {
18+
if (!in_state_.has_value() || in_state_ == state) {
1919
if (!optname_.hasValue()) {
2020
ENVOY_LOG(warn, "Failed to set unsupported option on socket");
2121
return false;
@@ -49,7 +49,7 @@ void SocketOptionImpl::hashKey(std::vector<uint8_t>& hash_key) const {
4949
absl::optional<Socket::Option::Details>
5050
SocketOptionImpl::getOptionDetails(const Socket&,
5151
envoy::config::core::v3::SocketOption::SocketState state) const {
52-
if (state != in_state_ || !isSupported()) {
52+
if ((in_state_.has_value() && state != in_state_) || !isSupported()) {
5353
return absl::nullopt;
5454
}
5555

source/common/network/socket_option_impl.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ class SocketOptionImpl : public Socket::Option, Logger::Loggable<Logger::Id::con
3030
ASSERT(reinterpret_cast<uintptr_t>(value_.data()) % alignof(void*) == 0);
3131
}
3232

33+
SocketOptionImpl(Network::SocketOptionName optname, absl::string_view value,
34+
absl::optional<Network::Socket::Type> socket_type = absl::nullopt)
35+
: in_state_(absl::nullopt), optname_(optname), value_(value.begin(), value.end()),
36+
socket_type_(socket_type) {
37+
ASSERT(reinterpret_cast<uintptr_t>(value_.data()) % alignof(void*) == 0);
38+
}
39+
3340
// Socket::Option
3441
bool setOption(Socket& socket,
3542
envoy::config::core::v3::SocketOption::SocketState state) const override;
@@ -61,7 +68,9 @@ class SocketOptionImpl : public Socket::Option, Logger::Loggable<Logger::Id::con
6168
const void* value, size_t size);
6269

6370
private:
64-
const envoy::config::core::v3::SocketOption::SocketState in_state_;
71+
// The state this option expects the socket to be in when it is applied. If the state is not set,
72+
// then this option will be applied in any state.
73+
absl::optional<const envoy::config::core::v3::SocketOption::SocketState> in_state_;
6574
const Network::SocketOptionName optname_;
6675
// The vector's data() is used by the setsockopt syscall, which needs to be int-size-aligned on
6776
// some platforms, the AlignedAllocator here makes it pointer-size-aligned, which satisfies the

source/common/quic/envoy_quic_client_session.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ class EnvoyQuicClientSession : public QuicFilterManagerConnectionImpl,
5454
// Set up socket and start handshake.
5555
void connect() override;
5656

57+
bool setSocketOption(Envoy::Network::SocketOptionName, absl::Span<uint8_t>) override {
58+
return false;
59+
}
60+
5761
// quic::QuicSession
5862
void OnConnectionClosed(const quic::QuicConnectionCloseFrame& frame,
5963
quic::ConnectionCloseSource source) override;

source/common/quic/envoy_quic_server_session.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ class EnvoyQuicServerSession : public quic::QuicServerSessionBase,
9999
const Network::FilterChain& filter_chain,
100100
ConnectionMapIter position);
101101

102+
bool setSocketOption(Envoy::Network::SocketOptionName, absl::Span<uint8_t>) override {
103+
return false;
104+
}
105+
102106
void setHttp3Options(const envoy::config::core::v3::Http3ProtocolOptions& http3_options) override;
103107
using quic::QuicSession::PerformActionOnActiveStreams;
104108

0 commit comments

Comments
 (0)