From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: passt.top; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=fj+AskLw; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by passt.top (Postfix) with ESMTPS id 8DE265A061D for ; Fri, 10 Oct 2025 09:47:26 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1760082445; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Gg7kQw3uYgpFNkRhqTFap1BZrUFfYkbmPlawK2q68L0=; b=fj+AskLwkZNsIO1ude0/kVN43FWLvQ2F9Pz71YNCVSp1KkXd0M4WnDDSoSXTYvqcm1ugiV A6hvJtQVm4kwU2f/0MdXhC+X2qY/2vYs5gqo+PoHe0uSOWjN2UJ1UKsvvp4YqCc79Hr1Ub K7Zi/8cMNOlGi8A91nMfHnzIR2BMcn0= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-203-Wpc6Dt6LPD67GanQUHhNOQ-1; Fri, 10 Oct 2025 03:47:23 -0400 X-MC-Unique: Wpc6Dt6LPD67GanQUHhNOQ-1 X-Mimecast-MFC-AGG-ID: Wpc6Dt6LPD67GanQUHhNOQ_1760082442 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 84037195608C; Fri, 10 Oct 2025 07:47:21 +0000 (UTC) Received: from fedora.redhat.com (unknown [10.72.112.91]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 668BC3000387; Fri, 10 Oct 2025 07:47:17 +0000 (UTC) From: Yumei Huang To: passt-dev@passt.top, sbrivio@redhat.com Subject: [PATCH v2 2/3] tcp: Resend SYN for inbound connections Date: Fri, 10 Oct 2025 15:46:59 +0800 Message-ID: <20251010074700.22177-3-yuhuang@redhat.com> In-Reply-To: <20251010074700.22177-1-yuhuang@redhat.com> References: <20251010074700.22177-1-yuhuang@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.4 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: cmZ5XgIJyzKmoCTnwLNIuNhAIHa6hm16WtjMrY8NGX4_1760082442 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true Message-ID-Hash: WAVFBPAH5HD5HFAAIRJEAT4WTF25PNTS X-Message-ID-Hash: WAVFBPAH5HD5HFAAIRJEAT4WTF25PNTS X-MailFrom: yuhuang@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: david@gibson.dropbear.id.au, yuhuang@redhat.com X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: If a client connects while guest is not connected or ready yet, resend SYN instead of just resetting connection after 10 seconds. Use the same backoff calculation for the timeout as linux kernel. Signed-off-by: Yumei Huang --- tcp.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- tcp.h | 2 ++ 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/tcp.c b/tcp.c index 2ec4b0c..85bbdac 100644 --- a/tcp.c +++ b/tcp.c @@ -179,9 +179,11 @@ * * Timeouts are implemented by means of timerfd timers, set based on flags: * - * - SYN_TIMEOUT: if no ACK is received from tap/guest during handshake (flag - * ACK_FROM_TAP_DUE without ESTABLISHED event) within this time, reset the - * connection + * - SYN_TIMEOUT_INIT: if no ACK is received from tap/guest during handshake + * (flag ACK_FROM_TAP_DUE without ESTABLISHED event) within this time, resend + * SYN. It's the starting timeout for the first SYN retry. If this persists + * for more than TCP_MAX_RETRIES or (tcp_syn_retries + + * tcp_syn_linear_timeouts) times in a row, reset the connection * * - ACK_TIMEOUT: if no ACK segment was received from tap/guest, after sending * data (flag ACK_FROM_TAP_DUE with ESTABLISHED event), re-send data from the @@ -309,6 +311,7 @@ #include "tcp_internal.h" #include "tcp_buf.h" #include "tcp_vu.h" +#include "lineread.h" /* * The size of TCP header (including options) is given by doff (Data Offset) @@ -340,7 +343,7 @@ enum { #define WINDOW_DEFAULT 14600 /* RFC 6928 */ #define ACK_INTERVAL 10 /* ms */ -#define SYN_TIMEOUT 10 /* s */ +#define SYN_TIMEOUT_INIT 1 /* s */ #define ACK_TIMEOUT 2 #define FIN_TIMEOUT 60 #define ACT_TIMEOUT 7200 @@ -365,6 +368,10 @@ uint8_t tcp_migrate_rcv_queue [TCP_MIGRATE_RCV_QUEUE_MAX]; #define TCP_MIGRATE_RESTORE_CHUNK_MIN 1024 /* Try smaller when above this */ +#define TCP_SYN_RETRIES_SYSCTL "/proc/sys/net/ipv4/tcp_syn_retries" +#define TCP_SYN_LINEAR_TIMEOUTS_SYSCTL \ + "/proc/sys/net/ipv4/tcp_syn_linear_timeouts" + /* "Extended" data (not stored in the flow table) for TCP flow migration */ static struct tcp_tap_transfer_ext migrate_ext[FLOW_MAX]; @@ -581,8 +588,13 @@ static void tcp_timer_ctl(const struct ctx *c, struct tcp_tap_conn *conn) if (conn->flags & ACK_TO_TAP_DUE) { it.it_value.tv_nsec = (long)ACK_INTERVAL * 1000 * 1000; } else if (conn->flags & ACK_FROM_TAP_DUE) { - if (!(conn->events & ESTABLISHED)) - it.it_value.tv_sec = SYN_TIMEOUT; + if (!(conn->events & ESTABLISHED)) { + if (conn->retries < c->tcp.syn_linear_timeouts) + it.it_value.tv_sec = SYN_TIMEOUT_INIT; + else + it.it_value.tv_sec = SYN_TIMEOUT_INIT << + (conn->retries - c->tcp.syn_linear_timeouts); + } else it.it_value.tv_sec = ACK_TIMEOUT; } else if (CONN_HAS(conn, SOCK_FIN_SENT | TAP_FIN_ACKED)) { @@ -1961,6 +1973,7 @@ static void tcp_conn_from_sock_finish(const struct ctx *c, } tcp_send_flag(c, conn, ACK); + conn->retries = 0; /* The client might have sent data already, which we didn't * dequeue waiting for SYN,ACK from tap -- check now. @@ -2409,8 +2422,16 @@ void tcp_timer_handler(const struct ctx *c, union epoll_ref ref) tcp_timer_ctl(c, conn); } else if (conn->flags & ACK_FROM_TAP_DUE) { if (!(conn->events & ESTABLISHED)) { - flow_dbg(conn, "handshake timeout"); - tcp_rst(c, conn); + if (conn->retries == MIN(TCP_MAX_RETRIES, + (c->tcp.tcp_syn_retries + c->tcp.tcp_syn_retries))) { + flow_dbg(conn, "handshake timeout"); + tcp_rst(c, conn); + } else { + flow_dbg(conn, "SYN timeout, retry"); + tcp_send_flag(c, conn, SYN); + conn->retries++; + tcp_timer_ctl(c, conn); + } } else if (CONN_HAS(conn, SOCK_FIN_SENT | TAP_FIN_ACKED)) { flow_dbg(conn, "FIN timeout"); tcp_rst(c, conn); @@ -2766,6 +2787,62 @@ static socklen_t tcp_probe_tcp_info(void) return sl; } +/** + * get_tcp_syn_param() - Read SYN parameters from /proc/sys + * @path: Path to the sysctl file + * @fallback: Default value if file can't be read + * + * Return: Parameter value, fallback on failure +*/ +int get_tcp_syn_param(const char *path, int fallback) +{ + char *line, *end; + struct lineread lr; + long value; + ssize_t len; + int fd; + + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + debug("Unable to open %s", path); + return fallback; + } + + lineread_init(&lr, fd); + len = lineread_get(&lr, &line); + close(fd); + + if (len < 0) { + debug("Unable to read %s", path); + return fallback; + } + + errno = 0; + value = strtol(line, &end, 10); + if (*end && *end != '\n') { + debug("Invalid format in %s", path); + return fallback; + } + if (errno || value < 0 || value > INT_MAX) { + debug("Invalid value in %s: %ld", path, value); + return fallback; + } + return (int)value; +} + +/** + * tcp_syn_params_init() - Get initial syn params for inbound connection + * @c: Execution context +*/ +void tcp_syn_params_init(struct ctx *c) +{ + c->tcp.tcp_syn_retries = get_tcp_syn_param(TCP_SYN_RETRIES_SYSCTL, 8); + c->tcp.syn_linear_timeouts = + get_tcp_syn_param(TCP_SYN_LINEAR_TIMEOUTS_SYSCTL, 1); + debug("TCP SYN parameters: retries=%d, linear_timeouts=%d", + c->tcp.tcp_syn_retries, c->tcp.syn_linear_timeouts); +} + /** * tcp_init() - Get initial sequence, hash secret, initialise per-socket data * @c: Execution context @@ -2776,6 +2853,8 @@ int tcp_init(struct ctx *c) { ASSERT(!c->no_tcp); + tcp_syn_params_init(c); + tcp_sock_iov_init(c); memset(init_sock_pool4, 0xff, sizeof(init_sock_pool4)); diff --git a/tcp.h b/tcp.h index 234a803..df699a4 100644 --- a/tcp.h +++ b/tcp.h @@ -65,6 +65,8 @@ struct tcp_ctx { struct fwd_ports fwd_out; struct timespec timer_run; size_t pipe_size; + uint8_t tcp_syn_retries; + uint8_t syn_linear_timeouts; }; #endif /* TCP_H */ -- 2.47.0