From e8410b230204077a8242d9b0ae48bd01c09be308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 5 Jun 2026 16:37:12 +0100 Subject: [PATCH] feat: disable Nagle's algorithm for LP between nym-nodes (#6857) --- .../src/node/lp/control/ingress/client_handler.rs | 12 +++++++++++- nym-node/src/node/lp/control/ingress/listener.rs | 8 ++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/nym-node/src/node/lp/control/ingress/client_handler.rs b/nym-node/src/node/lp/control/ingress/client_handler.rs index 1613795601..aad0ce88b8 100644 --- a/nym-node/src/node/lp/control/ingress/client_handler.rs +++ b/nym-node/src/node/lp/control/ingress/client_handler.rs @@ -404,7 +404,7 @@ where }; // Connect to target gateway with timeout - let stream = match timeout(Duration::from_secs(5), S::connect(target_addr)).await { + let mut stream = match timeout(Duration::from_secs(5), S::connect(target_addr)).await { Ok(Ok(stream)) => stream, Ok(Err(e)) => { inc!("lp_forward_failed"); @@ -422,6 +422,16 @@ where } }; + // Disable Nagle's algorithm: the forward stream carries small request/response + // handshake packets, so we want them sent immediately rather than coalesced. + if let Err(e) = stream.set_no_delay(true) { + inc!("lp_forward_failed"); + return Err(LpHandlerError::ConnectionFailure { + egress: target_addr, + reason: format!("failed to set TCP_NODELAY: {e}"), + }); + } + debug!("Opened persistent exit connection to {target_addr} for forwarding"); self.exit_stream = Some((stream, target_addr)); diff --git a/nym-node/src/node/lp/control/ingress/listener.rs b/nym-node/src/node/lp/control/ingress/listener.rs index 3d038abebe..15377a546f 100644 --- a/nym-node/src/node/lp/control/ingress/listener.rs +++ b/nym-node/src/node/lp/control/ingress/listener.rs @@ -171,6 +171,14 @@ impl LpControlListener { } fn handle_connection(&self, stream: tokio::net::TcpStream, remote_addr: SocketAddr) { + // Disable Nagle's algorithm on the accepted socket so our responses are flushed + // immediately rather than coalesced. This is the write side of every reply we send, + // including handshake replies forwarded back to an entry gateway. Non-fatal: a valid + // connection should still be served if the option can't be set. + if let Err(e) = stream.set_nodelay(true) { + warn!("failed to set TCP_NODELAY on accepted LP connection from {remote_addr}: {e}"); + } + if let Some(initiator_details) = self .nodes_handler_state .nodes