From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202512 header.b=bxOqklW7; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id 496075A0624 for ; Fri, 30 Jan 2026 05:41:10 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202512; t=1769748065; bh=JOBzcnpSM+YMHoP04DHGyLGm5wKhSMd22zXenhyww4k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bxOqklW7OiiZlYj2b669It+9dmatIKa7OmMi46AsfwaUtvWHYG4EpLTUKwqkATJSa jSYrICuEvdS3QEOQvWJfdo67aQDRSPnO7bLLArALV+l4/Svfl8ZdJrynfNfHLCNT1u 7oJT0eWP+sXrAtLhUFSkzt8MBxLj8vTDpwluQt3zLNvC2tOsCHNZ9+eXhc3Q17CbCb KY9GAgWSKQyFm3eQwIIEBsE6Sg8ZCIx/CUSchlV7cD9KypVZWZr3MIa4awyjARviTT cl6CO2tTDvcPJTjYTulV/wQqhCJ+dGIFJs7240gmd1VYBCiOkXdWMYJvBGAPDKygf9 Av/GLtaZeIqEA== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4f2Ncd4R7qz4wDK; Fri, 30 Jan 2026 15:41:05 +1100 (AEDT) From: David Gibson To: passt-dev@passt.top, Stefano Brivio Subject: [PATCH v2 2/3] tcp: Eliminate FIN_TIMEOUT Date: Fri, 30 Jan 2026 15:41:03 +1100 Message-ID: <20260130044104.1793253-3-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260130044104.1793253-1-david@gibson.dropbear.id.au> References: <20260130044104.1793253-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: TA4VOV5IB3Z4V7IX5UJUMBMIB5CSLD2H X-Message-ID-Hash: TA4VOV5IB3Z4V7IX5UJUMBMIB5CSLD2H X-MailFrom: dgibson@gandalf.ozlabs.org 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 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: Despite the name and its value of 60s, FIN_TIMEOUT is not related to the kernel's net.ipv4.tcp_fin_timeout sysctl. Indeed, we can't make an equivalent to that, since it relies on information that endpoint kernels have, but we do not. Neither is it simply the time to wait for an ACK to a FIN. It may have been intended as that at some point, but the implementation has not matched that for some time. In any case RFC9293 makes no distinction between ACKs to FIN segments and ACKs to data segments, so we now implement handling of ACKs to FINs with the same code path as ACKs to data segments. The theory of operation describes FIN_TIMEOUT thus: - FIN_TIMEOUT: if a FIN segment was acknowledged by tap/guest and a FIN segment (write shutdown) was sent via socket (events SOCK_FIN_SENT and TAP_FIN_ACKED), but no socket activity is detected from the socket within this time, reset the connection In other words, it's attempting to handle the case that we shutdown(SHUT_WR) on the socket side (causing the kernel to send a FIN), but the kernel never responds with an EPOLLHUP event indicating the peer has acked the FIN. The description doesn't match what the code does: in tcp_timer_ctl() we only set FIN_TIMEOUT on our timer when when ACK_FROM_TAP_DUE is unset, but we only act on the FIN_TIMEOUT if ACK_FROM_TAP_DUE *is* (also) set. In fact, there's no need to handle this case. Once we've called shutdown(SHUT_WR), it's the kernel's responsibility to resend FINs as needed (and reset the connection if that times out). Therefore, entirely remove the FIN_TIMEOUT related logic. Signed-off-by: David Gibson --- tcp.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tcp.c b/tcp.c index dbfde2e0..0be871a4 100644 --- a/tcp.c +++ b/tcp.c @@ -190,11 +190,6 @@ * - RTO_INIT_AFTER_SYN_RETRIES: if SYN retries happened during handshake and * RTO is less than this, re-initialise RTO to this for data retransmissions * - * - FIN_TIMEOUT: if a FIN segment was acknowledged by tap/guest and a FIN - * segment (write shutdown) was sent via socket (events SOCK_FIN_SENT and - * TAP_FIN_ACKED), but no socket activity is detected from the socket within - * this time, reset the connection - * * - ACT_TIMEOUT, in the presence of any event: if no activity is detected on * either side, the connection is reset * @@ -341,7 +336,6 @@ enum { #define RTO_INIT 1 /* s, RFC 6298 */ #define RTO_INIT_AFTER_SYN_RETRIES 3 /* s, RFC 6298 */ -#define FIN_TIMEOUT 60 #define ACT_TIMEOUT 7200 #define LOW_RTT_TABLE_SIZE 8 @@ -594,8 +588,6 @@ static void tcp_timer_ctl(const struct ctx *c, struct tcp_tap_conn *conn) timeout = MAX(timeout, RTO_INIT_AFTER_SYN_RETRIES); timeout <<= MAX(exp, 0); it.it_value.tv_sec = MIN(timeout, c->tcp.rto_max); - } else if (CONN_HAS(conn, SOCK_FIN_SENT | TAP_FIN_ACKED)) { - it.it_value.tv_sec = FIN_TIMEOUT; } else { it.it_value.tv_sec = ACT_TIMEOUT; } @@ -715,9 +707,6 @@ void conn_event_do(const struct ctx *c, struct tcp_tap_conn *conn, flow_hash_remove(c, TAP_SIDX(conn)); tcp_epoll_ctl(conn); } - - if (CONN_HAS(conn, SOCK_FIN_SENT | TAP_FIN_ACKED)) - tcp_timer_ctl(c, conn); } /** @@ -2590,9 +2579,6 @@ void tcp_timer_handler(const struct ctx *c, union epoll_ref ref) conn_flag(c, conn, SYN_RETRIED); 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); } else if (conn->retries == TCP_MAX_RETRIES) { flow_dbg(conn, "retransmissions count exceeded"); tcp_rst(c, conn); -- 2.52.0