From patchwork Tue Apr 8 11:25:00 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 14042867 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5C12AC369A1 for ; Tue, 8 Apr 2025 11:27:22 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u275a-0007WQ-Sp; Tue, 08 Apr 2025 07:25:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u275Y-0007WC-AO for qemu-devel@nongnu.org; Tue, 08 Apr 2025 07:25:56 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u275W-0006NG-H0 for qemu-devel@nongnu.org; Tue, 08 Apr 2025 07:25:55 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744111553; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cZYjj3TSQknbpghdbxSdQf+QPw46EKUTI+qxJHOAmRg=; b=VRM3ezGE8zEKtMeVdeyVCpwaMEfbbTSQLAYZt7EBsF/24avj8yvMbojRbwaUxP4tXB59Sl z6telflKgu5heWi7hWLZhTrJFMBeNTZxAfZX3cVIyA0vwjUKLpvQxm6SYlys35S91HEN9S KRQPpGjGAFUnH5Si/yoOQfTS0YX0IWk= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-504-KFGmRhtJM0-UIAUkiu1m4g-1; Tue, 08 Apr 2025 07:25:48 -0400 X-MC-Unique: KFGmRhtJM0-UIAUkiu1m4g-1 X-Mimecast-MFC-AGG-ID: KFGmRhtJM0-UIAUkiu1m4g_1744111547 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E197818001FA; Tue, 8 Apr 2025 11:25:46 +0000 (UTC) Received: from rh-jmarcin.redhat.com (unknown [10.44.34.27]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D0E7719560AD; Tue, 8 Apr 2025 11:25:44 +0000 (UTC) From: Juraj Marcin To: qemu-devel@nongnu.org Cc: Juraj Marcin , vsementsov@yandex-team.ru, =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Paolo Bonzini Subject: [PATCH v3 1/5] io: Fix partial struct copy in qio_dns_resolver_lookup_sync_inet() Date: Tue, 8 Apr 2025 13:25:00 +0200 Message-ID: <20250408112508.1638722-2-jmarcin@redhat.com> In-Reply-To: <20250408112508.1638722-1-jmarcin@redhat.com> References: <20250408112508.1638722-1-jmarcin@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass client-ip=170.10.133.124; envelope-from=jmarcin@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.845, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Juraj Marcin Commit aec21d3175 (qapi: Add InetSocketAddress member keep-alive) introduces the keep-alive flag, but this flag is not copied together with other options in qio_dns_resolver_lookup_sync_inet(). This patch fixes this issue and also prevents future ones by copying the entire structure first and only then overriding a few attributes that need to be different. Fixes: aec21d31756c (qapi: Add InetSocketAddress member keep-alive) Signed-off-by: Juraj Marcin Reviewed-by: Daniel P. Berrangé --- io/dns-resolver.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/io/dns-resolver.c b/io/dns-resolver.c index 53b0e8407a..3712438f82 100644 --- a/io/dns-resolver.c +++ b/io/dns-resolver.c @@ -111,22 +111,11 @@ static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver, uaddr, INET6_ADDRSTRLEN, uport, 32, NI_NUMERICHOST | NI_NUMERICSERV); - newaddr->u.inet = (InetSocketAddress){ - .host = g_strdup(uaddr), - .port = g_strdup(uport), - .has_numeric = true, - .numeric = true, - .has_to = iaddr->has_to, - .to = iaddr->to, - .has_ipv4 = iaddr->has_ipv4, - .ipv4 = iaddr->ipv4, - .has_ipv6 = iaddr->has_ipv6, - .ipv6 = iaddr->ipv6, -#ifdef HAVE_IPPROTO_MPTCP - .has_mptcp = iaddr->has_mptcp, - .mptcp = iaddr->mptcp, -#endif - }; + newaddr->u.inet = *iaddr; + newaddr->u.inet.host = g_strdup(uaddr), + newaddr->u.inet.port = g_strdup(uport), + newaddr->u.inet.has_numeric = true, + newaddr->u.inet.numeric = true, (*addrs)[i] = newaddr; } From patchwork Tue Apr 8 11:25:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 14042866 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1CEDCC3600C for ; Tue, 8 Apr 2025 11:27:21 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u275e-0007Xu-Ml; Tue, 08 Apr 2025 07:26:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u275a-0007WR-TX for qemu-devel@nongnu.org; Tue, 08 Apr 2025 07:25:59 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u275Z-0006NU-B4 for qemu-devel@nongnu.org; Tue, 08 Apr 2025 07:25:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744111556; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=y0qFSq+Nz5Tjs3h45eynnba7uyQWzWhoqTJ7eq5wvpo=; b=ISTKAH5Z6VjLKAKLb9YZBy4Gw9IQ8ublWx1ECry7fBQEl4s8tAraxtXZT/q2Kh8MYv85G6 kNte5OK7YEGDud2v6PGbjIT4TXO7MjIbBFuS4QKrcDkB4X5Q2qceleo4gxIWdB9cV3iC0b wbP6+8nehmTfflgxQpKaZi3rqI4p5fU= 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-552-_IJfgG6hPFeF3vW94NsNRg-1; Tue, 08 Apr 2025 07:25:53 -0400 X-MC-Unique: _IJfgG6hPFeF3vW94NsNRg-1 X-Mimecast-MFC-AGG-ID: _IJfgG6hPFeF3vW94NsNRg_1744111552 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 BA8DD19560B8; Tue, 8 Apr 2025 11:25:52 +0000 (UTC) Received: from rh-jmarcin.redhat.com (unknown [10.44.34.27]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BACEE19541A6; Tue, 8 Apr 2025 11:25:50 +0000 (UTC) From: Juraj Marcin To: qemu-devel@nongnu.org Cc: Juraj Marcin , vsementsov@yandex-team.ru, =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Paolo Bonzini Subject: [PATCH v3 2/5] util/qemu-sockets: Refactor setting client sockopts into a separate function Date: Tue, 8 Apr 2025 13:25:01 +0200 Message-ID: <20250408112508.1638722-3-jmarcin@redhat.com> In-Reply-To: <20250408112508.1638722-1-jmarcin@redhat.com> References: <20250408112508.1638722-1-jmarcin@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass client-ip=170.10.133.124; envelope-from=jmarcin@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.845, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Juraj Marcin This is done in preparation for enabling the SO_KEEPALIVE support for server sockets and adding settings for more TCP keep-alive socket options. Signed-off-by: Juraj Marcin --- util/qemu-sockets.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 77477c1cd5..d15f6aa4b0 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -205,6 +205,22 @@ static int try_bind(int socket, InetSocketAddress *saddr, struct addrinfo *e) #endif } +static int inet_set_sockopts(int sock, InetSocketAddress *saddr, Error **errp) +{ + if (saddr->keep_alive) { + int keep_alive = 1; + int ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + &keep_alive, sizeof(keep_alive)); + + if (ret < 0) { + error_setg_errno(errp, errno, + "Unable to set keep-alive option on socket"); + return -1; + } + } + return 0; +} + static int inet_listen_saddr(InetSocketAddress *saddr, int port_offset, int num, @@ -475,16 +491,9 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp) return sock; } - if (saddr->keep_alive) { - int val = 1; - int ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, - &val, sizeof(val)); - - if (ret < 0) { - error_setg_errno(errp, errno, "Unable to set KEEPALIVE"); - close(sock); - return -1; - } + if (inet_set_sockopts(sock, saddr, errp)) { + close(sock); + return -1; } return sock; From patchwork Tue Apr 8 11:25:02 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 14042865 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id AD948C369A1 for ; Tue, 8 Apr 2025 11:27:03 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u275k-0007ZX-HA; Tue, 08 Apr 2025 07:26:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u275h-0007Yz-Qh for qemu-devel@nongnu.org; Tue, 08 Apr 2025 07:26:06 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u275f-0006Ns-MG for qemu-devel@nongnu.org; Tue, 08 Apr 2025 07:26:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744111562; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=em7HfNjXXY6KBwR8Ua+OaLCAcJ3v3oH/N9KXm3dHXdI=; b=fbLF7Sm6GMgHwHQpnOPFctqKKGNRcyONBqUJNRf1fu0iovJRpLxexxJNCm0U0AKhFvf5VY q9IaBZ3rOZoMRWk7q0yJaonnIEhRrmUWYQJMrsHFTvsNoYk4sxRgSokF1wUHd9Dk1rbW08 pArWy28TekcqUrmQNm+/mYe+5/v4/lI= Received: from mx-prod-mc-04.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-613-chc3xaDVP1iR8SFq67SDWg-1; Tue, 08 Apr 2025 07:25:58 -0400 X-MC-Unique: chc3xaDVP1iR8SFq67SDWg-1 X-Mimecast-MFC-AGG-ID: chc3xaDVP1iR8SFq67SDWg_1744111558 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id F02D01955DCD; Tue, 8 Apr 2025 11:25:57 +0000 (UTC) Received: from rh-jmarcin.redhat.com (unknown [10.44.34.27]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id C558819560AD; Tue, 8 Apr 2025 11:25:55 +0000 (UTC) From: Juraj Marcin To: qemu-devel@nongnu.org Cc: Juraj Marcin , vsementsov@yandex-team.ru, =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Paolo Bonzini Subject: [PATCH v3 3/5] util/qemu-sockets: Refactor success and failure paths in inet_listen_saddr() Date: Tue, 8 Apr 2025 13:25:02 +0200 Message-ID: <20250408112508.1638722-4-jmarcin@redhat.com> In-Reply-To: <20250408112508.1638722-1-jmarcin@redhat.com> References: <20250408112508.1638722-1-jmarcin@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass client-ip=170.10.129.124; envelope-from=jmarcin@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.845, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Juraj Marcin To get a listening socket, we need to first create a socket, try binding it to a certain port, and lastly starting listening to it. Each of these operations can fail due to various reasons, one of them being that the requested address/port is already in use. In such case, the function tries the same process with a new port number. This patch refactors the port number loop, so the success path is no longer buried inside the 'if' statements in the middle of the loop. Now, the success path is not nested and ends at the end of the iteration after successful socket creation, binding, and listening. In case any of the operations fails, it either continues to the next iteration (and the next port) or jumps out of the loop to handle the error and exits the function. Signed-off-by: Juraj Marcin Reviewed-by: Daniel P. Berrangé --- util/qemu-sockets.c | 51 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index d15f6aa4b0..a86964786a 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -303,11 +303,20 @@ static int inet_listen_saddr(InetSocketAddress *saddr, port_min = inet_getport(e); port_max = saddr->has_to ? saddr->to + port_offset : port_min; for (p = port_min; p <= port_max; p++) { + if (slisten >= 0) { + /* + * We have a socket we tried with the previous port. It cannot + * be rebound, we need to close it and create a new one. + */ + close(slisten); + slisten = -1; + } inet_setport(e, p); slisten = create_fast_reuse_socket(e); if (slisten < 0) { - /* First time we expect we might fail to create the socket + /* + * First time we expect we might fail to create the socket * eg if 'e' has AF_INET6 but ipv6 kmod is not loaded. * Later iterations should always succeed if first iteration * worked though, so treat that as fatal. @@ -317,40 +326,38 @@ static int inet_listen_saddr(InetSocketAddress *saddr, } else { error_setg_errno(errp, errno, "Failed to recreate failed listening socket"); - goto listen_failed; + goto fail; } } socket_created = true; rc = try_bind(slisten, saddr, e); if (rc < 0) { - if (errno != EADDRINUSE) { - error_setg_errno(errp, errno, "Failed to bind socket"); - goto listen_failed; + if (errno == EADDRINUSE) { + /* This port is already used, try the next one */ + continue; } - } else { - if (!listen(slisten, num)) { - goto listen_ok; - } - if (errno != EADDRINUSE) { - error_setg_errno(errp, errno, "Failed to listen on socket"); - goto listen_failed; + error_setg_errno(errp, errno, "Failed to bind socket"); + goto fail; + } + if (listen(slisten, num)) { + if (errno == EADDRINUSE) { + /* This port is already used, try the next one */ + continue; } + error_setg_errno(errp, errno, "Failed to listen on socket"); + goto fail; } - /* Someone else managed to bind to the same port and beat us - * to listen on it! Socket semantics does not allow us to - * recover from this situation, so we need to recreate the - * socket to allow bind attempts for subsequent ports: - */ - close(slisten); - slisten = -1; + /* We have a listening socket */ + freeaddrinfo(res); + return slisten; } } error_setg_errno(errp, errno, socket_created ? "Failed to find an available port" : "Failed to create a socket"); -listen_failed: +fail: saved_errno = errno; if (slisten >= 0) { close(slisten); @@ -358,10 +365,6 @@ listen_failed: freeaddrinfo(res); errno = saved_errno; return -1; - -listen_ok: - freeaddrinfo(res); - return slisten; } #ifdef _WIN32 From patchwork Tue Apr 8 11:25:03 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 14042869 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BB0E0C369A4 for ; Tue, 8 Apr 2025 11:27:32 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u275o-0007aB-0T; Tue, 08 Apr 2025 07:26:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u275l-0007Zr-QA for qemu-devel@nongnu.org; Tue, 08 Apr 2025 07:26:10 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u275j-0006OH-VR for qemu-devel@nongnu.org; Tue, 08 Apr 2025 07:26:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744111567; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ExzazHutwHcMdtek0Bh0IzwUbsdsm4bkTxcjrWo+zao=; b=jFJF6YB5WB424biD6VqjRJLnKoBagvf7M3TbyvJraJQqDkcQesKlr8HxwZLQFPtAFElQBK qKJMnQv6IY536O2PSxXoQguxfOvBil+5ssJmq9pwKHG4kAiSqugnDXBBAHKjuX08EsROGA NyRCpVwfTPf6gLPL4KaaAKSw54JPdsw= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-682-nOJO2SmIOne_jM9hxVq1Uw-1; Tue, 08 Apr 2025 07:26:03 -0400 X-MC-Unique: nOJO2SmIOne_jM9hxVq1Uw-1 X-Mimecast-MFC-AGG-ID: nOJO2SmIOne_jM9hxVq1Uw_1744111563 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id DBB42180AF72; Tue, 8 Apr 2025 11:26:02 +0000 (UTC) Received: from rh-jmarcin.redhat.com (unknown [10.44.34.27]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B05EF19560AD; Tue, 8 Apr 2025 11:26:00 +0000 (UTC) From: Juraj Marcin To: qemu-devel@nongnu.org Cc: Juraj Marcin , vsementsov@yandex-team.ru, =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Paolo Bonzini Subject: [PATCH v3 4/5] util/qemu-sockets: Add support for keep-alive flag to passive sockets Date: Tue, 8 Apr 2025 13:25:03 +0200 Message-ID: <20250408112508.1638722-5-jmarcin@redhat.com> In-Reply-To: <20250408112508.1638722-1-jmarcin@redhat.com> References: <20250408112508.1638722-1-jmarcin@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass client-ip=170.10.133.124; envelope-from=jmarcin@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.845, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Juraj Marcin Commit aec21d3175 (qapi: Add InetSocketAddress member keep-alive) introduces the keep-alive flag, which enables the SO_KEEPALIVE socket option, but only on client-side sockets. However, this option is also useful for server-side sockets, so they can check if a client is still reachable or drop the connection otherwise. This patch enables the SO_KEEPALIVE socket option on passive server-side sockets if the keep-alive flag is enabled. This socket option is then inherited by active server-side sockets communicating with connected clients. Signed-off-by: Juraj Marcin Reviewed-by: Daniel P. Berrangé --- qapi/sockets.json | 4 ++-- util/qemu-sockets.c | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/qapi/sockets.json b/qapi/sockets.json index 6a95023315..62797cd027 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -56,8 +56,8 @@ # @ipv6: whether to accept IPv6 addresses, default try both IPv4 and # IPv6 # -# @keep-alive: enable keep-alive when connecting to this socket. Not -# supported for passive sockets. (Since 4.2) +# @keep-alive: enable keep-alive when connecting to/listening on this socket. +# (Since 4.2, not supported for listening sockets until 10.1) # # @mptcp: enable multi-path TCP. (Since 6.1) # diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index a86964786a..fed17a1ffb 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -236,12 +236,6 @@ static int inet_listen_saddr(InetSocketAddress *saddr, int saved_errno = 0; bool socket_created = false; - if (saddr->keep_alive) { - error_setg(errp, "keep-alive option is not supported for passive " - "sockets"); - return -1; - } - memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; if (saddr->has_numeric && saddr->numeric) { @@ -349,6 +343,9 @@ static int inet_listen_saddr(InetSocketAddress *saddr, goto fail; } /* We have a listening socket */ + if (inet_set_sockopts(slisten, saddr, errp)) { + goto fail; + } freeaddrinfo(res); return slisten; } From patchwork Tue Apr 8 11:25:04 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 14042870 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 99576C369A1 for ; Tue, 8 Apr 2025 11:27:55 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1u275s-0007b9-Fb; Tue, 08 Apr 2025 07:26:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u275p-0007aZ-Nz for qemu-devel@nongnu.org; Tue, 08 Apr 2025 07:26:14 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1u275n-0006OZ-Pv for qemu-devel@nongnu.org; Tue, 08 Apr 2025 07:26:13 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744111571; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Yq+SSWaeQzXTk76xvI7u2atw8L3iFrBBMkDgz0BDY5k=; b=AV7Gi/VoZ/rgumToQwvB69nPvnFcqG6Oyt/c/xG0FaGM8kLFlYTkvUmvc7L6a5XceGg4OE tte4ocvtkjIi/xL/nPDQO90qQ0Hs0zLonpameoFEng/yS2r6TuVfDAF5Cb/bF4h0krWB03 SEYaFxFRuMnUKRyGVbrzdcAFDociyIc= Received: from mx-prod-mc-02.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-198-oqIzsSJPM3qH1lzLqmJ_Yw-1; Tue, 08 Apr 2025 07:26:09 -0400 X-MC-Unique: oqIzsSJPM3qH1lzLqmJ_Yw-1 X-Mimecast-MFC-AGG-ID: oqIzsSJPM3qH1lzLqmJ_Yw_1744111568 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B42A419560AB; Tue, 8 Apr 2025 11:26:08 +0000 (UTC) Received: from rh-jmarcin.redhat.com (unknown [10.44.34.27]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 6D9AB195DF84; Tue, 8 Apr 2025 11:26:05 +0000 (UTC) From: Juraj Marcin To: qemu-devel@nongnu.org Cc: Juraj Marcin , vsementsov@yandex-team.ru, =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Paolo Bonzini Subject: [PATCH v3 5/5] utils/qemu-sockets: Introduce inet socket options controlling TCP keep-alive Date: Tue, 8 Apr 2025 13:25:04 +0200 Message-ID: <20250408112508.1638722-6-jmarcin@redhat.com> In-Reply-To: <20250408112508.1638722-1-jmarcin@redhat.com> References: <20250408112508.1638722-1-jmarcin@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass client-ip=170.10.133.124; envelope-from=jmarcin@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.845, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Juraj Marcin With the default TCP stack configuration, it could be even 2 hours before the connection times out due to the other side not being reachable. However, in some cases, the application needs to be aware of a connection issue much sooner. This is the case, for example, for postcopy live migration. If there is no traffic from the migration destination guest (server-side) to the migration source guest (client-side), the destination keeps waiting for pages indefinitely and does not switch to the postcopy-paused state. This can happen, for example, if the destination QEMU instance is started with the '-S' command line option and the machine is not started yet, or if the machine is idle and produces no new page faults for not-yet-migrated pages. This patch introduces new inet socket parameters that control count, idle period, and interval of TCP keep-alive packets before the connection is considered broken. These parameters are available on systems where the respective TCP socket options are defined (TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL). The default value for all is 0, which means the system configuration is used. Signed-off-by: Juraj Marcin --- meson.build | 6 ++++ qapi/sockets.json | 15 ++++++++ util/qemu-sockets.c | 88 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) diff --git a/meson.build b/meson.build index 41f68d3806..680f47cf42 100644 --- a/meson.build +++ b/meson.build @@ -2734,6 +2734,12 @@ if linux_io_uring.found() config_host_data.set('HAVE_IO_URING_PREP_WRITEV2', cc.has_header_symbol('liburing.h', 'io_uring_prep_writev2')) endif +config_host_data.set('HAVE_TCP_KEEPCNT', + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPCNT')) +config_host_data.set('HAVE_TCP_KEEPIDLE', + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPIDLE')) +config_host_data.set('HAVE_TCP_KEEPINTVL', + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPINTVL')) # has_member config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID', diff --git a/qapi/sockets.json b/qapi/sockets.json index 62797cd027..bb9d298635 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -59,6 +59,18 @@ # @keep-alive: enable keep-alive when connecting to/listening on this socket. # (Since 4.2, not supported for listening sockets until 10.1) # +# @keep-alive-count: number of keep-alive packets sent before the connection is +# closed. Only supported for TCP sockets on systems where TCP_KEEPCNT +# socket option is defined. (Since 10.1) +# +# @keep-alive-idle: time in seconds the connection needs to be idle before +# sending a keepalive packet. Only supported for TCP sockets on systems +# where TCP_KEEPIDLE socket option is defined. (Since 10.1) +# +# @keep-alive-interval: time in secods between keep-alive packets. Only +# supported for TCP sockets on systems where TCP_KEEPINTVL is defined. +# (Since 10.1) +# # @mptcp: enable multi-path TCP. (Since 6.1) # # Since: 1.3 @@ -71,6 +83,9 @@ '*ipv4': 'bool', '*ipv6': 'bool', '*keep-alive': 'bool', + '*keep-alive-count': { 'type': 'uint32', 'if': 'HAVE_TCP_KEEPCNT' }, + '*keep-alive-idle': { 'type': 'uint32', 'if': 'HAVE_TCP_KEEPIDLE' }, + '*keep-alive-interval': { 'type': 'uint32', 'if': 'HAVE_TCP_KEEPINTVL' }, '*mptcp': { 'type': 'bool', 'if': 'HAVE_IPPROTO_MPTCP' } } } ## diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index fed17a1ffb..8e355b097c 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -217,6 +217,45 @@ static int inet_set_sockopts(int sock, InetSocketAddress *saddr, Error **errp) "Unable to set keep-alive option on socket"); return -1; } +#ifdef HAVE_TCP_KEEPCNT + if (saddr->has_keep_alive_count && + saddr->keep_alive_count) { + int keep_count = saddr->has_keep_alive_count; + ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keep_count, + sizeof(keep_count)); + if (ret < 0) { + error_setg_errno(errp, errno, + "Unable to set TCP keep-alive count option on socket"); + return -1; + } + } +#endif +#ifdef HAVE_TCP_KEEPIDLE + if (saddr->has_keep_alive_idle && + saddr->keep_alive_idle) { + int keep_idle = saddr->has_keep_alive_idle; + ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keep_idle, + sizeof(keep_idle)); + if (ret < 0) { + error_setg_errno(errp, errno, + "Unable to set TCP keep-alive idle option on socket"); + return -1; + } + } +#endif +#ifdef HAVE_TCP_KEEPINTVL + if (saddr->has_keep_alive_interval && + saddr->keep_alive_interval) { + int keep_interval = saddr->has_keep_alive_interval; + ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keep_interval, + sizeof(keep_interval)); + if (ret < 0) { + error_setg_errno(errp, errno, + "Unable to set TCP keep-alive interval option on socket"); + return -1; + } + } +#endif } return 0; } @@ -628,6 +667,22 @@ static int inet_parse_flag(const char *flagname, const char *optstr, bool *val, return 0; } +static int inet_parse_u32(const char *optname, const char *optstr, + uint32_t max, uint32_t *val, Error **errp) +{ + int pos; + if (sscanf(optstr, "%" PRIu32 "%n", val, &pos) != 1 || + (optstr[pos] != '\0' && optstr[pos] != ',')) { + error_setg(errp, "error parsing %s argument", optname); + return -1; + } + if (*val > max) { + error_setg(errp, "%s is too large", optname); + return -1; + } + return 0; +} + int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) { const char *optstr, *h; @@ -700,6 +755,39 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) } addr->has_keep_alive = true; } +#ifdef HAVE_TCP_KEEPCNT + begin = strstr(optstr, ",keep-alive-count="); + if (begin) { + if (inet_parse_u32("keep-alive-count", + begin + strlen(",keep-alive-count="), INT_MAX, + &addr->keep_alive_count, errp)) { + return -1; + } + addr->has_keep_alive_count = true; + } +#endif +#ifdef HAVE_TCP_KEEPIDLE + begin = strstr(optstr, ",keep-alive-idle="); + if (begin) { + if (inet_parse_u32("keep-alive-idle", + begin + strlen(",keep-alive-idle="), INT_MAX, + &addr->keep_alive_idle, errp)) { + return -1; + } + addr->has_keep_alive_idle = true; + } +#endif +#ifdef HAVE_TCP_KEEPINTVL + begin = strstr(optstr, ",keep-alive-interval="); + if (begin) { + if (inet_parse_u32("keep-alive-interval", + begin + strlen(",keep-alive-interval="), INT_MAX, + &addr->keep_alive_interval, errp)) { + return -1; + } + addr->has_keep_alive_interval = true; + } +#endif #ifdef HAVE_IPPROTO_MPTCP begin = strstr(optstr, ",mptcp"); if (begin) {