Skip to content

Commit c7a303e

Browse files
committed
network_filter: Pass connection close from upstream to downstream
Monitor connection close events on the upstream filter and close the downstream connection if both connections have the same 5-tuple. This fixes the issue where a newly reopened upstream connection with the same 5-tuple causes the downstream connection to become non-functional. Signed-off-by: Jarno Rajahalme <jarno@isovalent.com>
1 parent 03739a1 commit c7a303e

2 files changed

Lines changed: 65 additions & 3 deletions

File tree

cilium/network_filter.cc

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,61 @@ void Config::log(Cilium::AccessLog::Entry& entry, ::cilium::EntryType type) {
123123
}
124124
}
125125

126+
void Instance::onEvent(Network::ConnectionEvent event) {
127+
auto& conn = callbacks_->connection();
128+
switch (event) {
129+
case Network::ConnectionEvent::LocalClose:
130+
case Network::ConnectionEvent::RemoteClose:
131+
// close downstream connection when upstream is closed, but only if the original source address
132+
// and port are used on the upstream side.
133+
if (config_->is_upstream_) {
134+
auto& stream_info = conn.streamInfo();
135+
136+
// check if the downstream connection exists
137+
const auto downstream_connection_fs =
138+
stream_info.filterState()->getDataReadOnly<Network::Cilium::DownstreamConnection>(
139+
Network::Cilium::DownstreamConnection::key());
140+
if (downstream_connection_fs) {
141+
Network::Connection* ds_conn = downstream_connection_fs->connection_;
142+
if (ds_conn) {
143+
// check if upstream and downstream connections have the same source and destination
144+
// addresses, respectively
145+
if (*conn.connectionInfoProvider().remoteAddress() ==
146+
*ds_conn->connectionInfoProvider().localAddress() &&
147+
*conn.connectionInfoProvider().localAddress() ==
148+
*ds_conn->connectionInfoProvider().remoteAddress()) {
149+
ENVOY_CONN_LOG(
150+
debug,
151+
"Upstream connection closed, closing downstream connection due to the same 5-tuple",
152+
conn);
153+
ds_conn->close(Network::ConnectionCloseType::FlushWrite);
154+
} else {
155+
ENVOY_CONN_LOG(debug,
156+
"Upstream connection closed, but it has different 5-tuple, downstream "
157+
"connection not closed (src: {}/{}, dst: {}/{})",
158+
conn, ds_conn->connectionInfoProvider().remoteAddress()->asStringView(),
159+
conn.connectionInfoProvider().localAddress()->asStringView(),
160+
ds_conn->connectionInfoProvider().localAddress()->asStringView(),
161+
conn.connectionInfoProvider().remoteAddress()->asStringView());
162+
}
163+
} else {
164+
ENVOY_CONN_LOG(debug, "Upstream connection closed, downstream connection == nullptr",
165+
conn);
166+
}
167+
} else {
168+
ENVOY_CONN_LOG(
169+
debug, "Upstream connection closed, but no downstream connection filter state found",
170+
conn);
171+
}
172+
} else {
173+
ENVOY_CONN_LOG(debug, "Downstream filter ignoring connection close event", conn);
174+
}
175+
break;
176+
default:
177+
break;
178+
}
179+
}
180+
126181
bool Instance::enforceNetworkPolicy(const Cilium::CiliumPolicyFilterState* policy_fs,
127182
Cilium::CiliumDestinationFilterState* dest_fs,
128183
uint32_t destination_identity,
@@ -138,7 +193,7 @@ bool Instance::enforceNetworkPolicy(const Cilium::CiliumPolicyFilterState* polic
138193

139194
// Is there a pod egress policy?
140195
bool use_proxy_lib = false;
141-
if (policy_fs->pod_ip_.length() > 0) {
196+
if (!policy_fs->pod_ip_.empty()) {
142197
if (!policy_fs->enforcePodNetworkPolicy(conn, destination_identity, destination_port_, sni,
143198
use_proxy_lib, l7proto_)) {
144199
log_entry_.initFromConnection(policy_fs->pod_ip_, policy_fs->proxy_id_, false,
@@ -152,7 +207,7 @@ bool Instance::enforceNetworkPolicy(const Cilium::CiliumPolicyFilterState* polic
152207
}
153208

154209
// Is there an Ingress policy?
155-
if (policy_fs->ingress_policy_name_.length() > 0) {
210+
if (!policy_fs->ingress_policy_name_.empty()) {
156211
log_entry_.initFromConnection(policy_fs->ingress_policy_name_, policy_fs->proxy_id_, false,
157212
policy_fs->source_identity_,
158213
stream_info.downstreamAddressProvider().remoteAddress(),

cilium/network_filter.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ using ConfigSharedPtr = std::shared_ptr<Config>;
5353
/**
5454
* Implementation of a Cilium network filter.
5555
*/
56-
class Instance : public Network::Filter, Logger::Loggable<Logger::Id::filter> {
56+
class Instance : public Network::Filter,
57+
public Network::ConnectionCallbacks,
58+
Logger::Loggable<Logger::Id::filter> {
5759
public:
5860
Instance(const ConfigSharedPtr& config) : config_(config) {}
5961

@@ -70,6 +72,11 @@ class Instance : public Network::Filter, Logger::Loggable<Logger::Id::filter> {
7072
// Network::WriteFilter
7173
Network::FilterStatus onWrite(Buffer::Instance&, bool end_stream) override;
7274

75+
// Network::ConnectionCallbacks
76+
void onEvent(Network::ConnectionEvent event) override;
77+
void onAboveWriteBufferHighWatermark() override {}
78+
void onBelowWriteBufferLowWatermark() override {}
79+
7380
private:
7481
// helper to be used either directly from onNewConnection (no L7 LB),
7582
// or from upstream callback (l7 lb)

0 commit comments

Comments
 (0)