- kvm-s390x-Fix-leak-in-machine_set_loadparm.patch [RHEL-98554] - kvm-hw-s390x-ccw-device-Fix-memory-leak-in-loadparm-sett.patch [RHEL-98554] - kvm-amd_iommu-Rename-variable-mmio-to-mr_mmio.patch [RHEL-66202] - kvm-amd_iommu-Add-support-for-pass-though-mode.patch [RHEL-66202] - kvm-amd_iommu-Use-shared-memory-region-for-Interrupt-Rem.patch [RHEL-66202] - kvm-amd_iommu-Send-notification-when-invalidate-interrup.patch [RHEL-66202] - kvm-amd_iommu-Check-APIC-ID-255-for-XTSup.patch [RHEL-66202] - kvm-io-Fix-partial-struct-copy-in-qio_dns_resolver_looku.patch [RHEL-67104] - kvm-util-qemu-sockets-Refactor-setting-client-sockopts-i.patch [RHEL-67104] - kvm-util-qemu-sockets-Refactor-success-and-failure-paths.patch [RHEL-67104] - kvm-util-qemu-sockets-Add-support-for-keep-alive-flag-to.patch [RHEL-67104] - kvm-util-qemu-sockets-Refactor-inet_parse-to-use-QemuOpt.patch [RHEL-67104] - kvm-util-qemu-sockets-Introduce-inet-socket-options-cont.patch [RHEL-67104] - kvm-tests-unit-test-util-sockets-fix-mem-leak-on-error-o.patch [RHEL-67104] - kvm-target-i386-Expose-bits-related-to-SRSO-vulnerabilit.patch [RHEL-52649] - kvm-target-i386-Add-PerfMonV2-feature-bit.patch [RHEL-52649] - kvm-target-i386-Update-EPYC-CPU-model-for-Cache-property.patch [RHEL-52649] - kvm-target-i386-Update-EPYC-Rome-CPU-model-for-Cache-pro.patch [RHEL-52649] - kvm-target-i386-Update-EPYC-Milan-CPU-model-for-Cache-pr.patch [RHEL-52649] - kvm-target-i386-Add-couple-of-feature-bits-in-CPUID_Fn80.patch [RHEL-52649] - kvm-target-i386-Update-EPYC-Genoa-for-Cache-property-per.patch [RHEL-52649] - kvm-target-i386-Add-support-for-EPYC-Turin-model.patch [RHEL-52649] - kvm-hw-i386-amd_iommu-Assign-pci-id-0x1419-for-the-AMD-I.patch [RHEL-70926] - kvm-hw-i386-amd_iommu-Isolate-AMDVI-PCI-from-amd-iommu-d.patch [RHEL-70925] - kvm-hw-i386-amd_iommu-Allow-migration-when-explicitly-cr.patch [RHEL-70925] - kvm-Enable-amd-iommu-device.patch [RHEL-70925] - kvm-include-qemu-compiler-add-QEMU_UNINITIALIZED-attribu.patch [RHEL-99888] - kvm-hw-virtio-virtio-avoid-cost-of-ftrivial-auto-var-ini.patch [RHEL-99888] - kvm-block-skip-automatic-zero-init-of-large-array-in-ioq.patch [RHEL-99888] - kvm-chardev-char-fd-skip-automatic-zero-init-of-large-ar.patch [RHEL-99888] - kvm-chardev-char-pty-skip-automatic-zero-init-of-large-a.patch [RHEL-99888] - kvm-chardev-char-socket-skip-automatic-zero-init-of-larg.patch [RHEL-99888] - kvm-hw-audio-ac97-skip-automatic-zero-init-of-large-arra.patch [RHEL-99888] - kvm-hw-audio-cs4231a-skip-automatic-zero-init-of-large-a.patch [RHEL-99888] - kvm-hw-audio-es1370-skip-automatic-zero-init-of-large-ar.patch [RHEL-99888] - kvm-hw-audio-gus-skip-automatic-zero-init-of-large-array.patch [RHEL-99888] - kvm-hw-audio-marvell_88w8618-skip-automatic-zero-init-of.patch [RHEL-99888] - kvm-hw-audio-sb16-skip-automatic-zero-init-of-large-arra.patch [RHEL-99888] - kvm-hw-audio-via-ac97-skip-automatic-zero-init-of-large-.patch [RHEL-99888] - kvm-hw-char-sclpconsole-lm-skip-automatic-zero-init-of-l.patch [RHEL-99888] - kvm-hw-dma-xlnx_csu_dma-skip-automatic-zero-init-of-larg.patch [RHEL-99888] - kvm-hw-display-vmware_vga-skip-automatic-zero-init-of-la.patch [RHEL-99888] - kvm-hw-hyperv-syndbg-skip-automatic-zero-init-of-large-a.patch [RHEL-99888] - kvm-hw-misc-aspeed_hace-skip-automatic-zero-init-of-larg.patch [RHEL-99888] - kvm-hw-net-rtl8139-skip-automatic-zero-init-of-large-arr.patch [RHEL-99888] - kvm-hw-net-tulip-skip-automatic-zero-init-of-large-array.patch [RHEL-99888] - kvm-hw-net-virtio-net-skip-automatic-zero-init-of-large-.patch [RHEL-99888] - kvm-hw-net-xgamc-skip-automatic-zero-init-of-large-array.patch [RHEL-99888] - kvm-hw-nvme-ctrl-skip-automatic-zero-init-of-large-array.patch [RHEL-99888] - kvm-hw-ppc-spapr_tpm_proxy-skip-automatic-zero-init-of-l.patch [RHEL-99888] - kvm-hw-usb-hcd-ohci-skip-automatic-zero-init-of-large-ar.patch [RHEL-99888] - kvm-hw-scsi-lsi53c895a-skip-automatic-zero-init-of-large.patch [RHEL-99888] - kvm-hw-scsi-megasas-skip-automatic-zero-init-of-large-ar.patch [RHEL-99888] - kvm-hw-ufs-lu-skip-automatic-zero-init-of-large-array.patch [RHEL-99888] - kvm-net-socket-skip-automatic-zero-init-of-large-array.patch [RHEL-99888] - kvm-net-stream-skip-automatic-zero-init-of-large-array.patch [RHEL-99888] - kvm-ui-vnc-Update-display-update-interval-when-VM-state-.patch [RHEL-100741] - Resolves: RHEL-98554 ([s390x][RHEL9.7.0][virtio_block] there would be memory leak with virtio_blk disks) - Resolves: RHEL-66202 ([AMDSERVER 9.6 Feature] qemu: Interrupt Remap support for emulated amd viommu) - Resolves: RHEL-67104 (postcopy on the destination host can't switch into pause status under the network issue if boot VM with '-S') - Resolves: RHEL-52649 ([AMDSERVER 9.6 Feature] Turin: Qemu EPYC-Turin Model) - Resolves: RHEL-70926 (Qemu/amd-iommu: Advertise a suitable device id) - Resolves: RHEL-70925 (Qemu/amd-iommu: Add ability to manually specify the AMDVI-PCI device) - Resolves: RHEL-99888 (-ftrivial-auto-var-init=zero reduced performance [rhel-9]) - Resolves: RHEL-100741 (Video stuck after switchover phase when play one video during migration [rhel-9])
315 lines
12 KiB
Diff
315 lines
12 KiB
Diff
From 3e9458cd71f909474c1dd051f43fd3fbef8d53fd Mon Sep 17 00:00:00 2001
|
|
From: Juraj Marcin <jmarcin@redhat.com>
|
|
Date: Wed, 21 May 2025 15:52:35 +0200
|
|
Subject: [PATCH 13/57] util/qemu-sockets: Introduce inet socket options
|
|
controlling TCP keep-alive
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
RH-Author: Juraj Marcin <None>
|
|
RH-MergeRequest: 369: util/qemu-sockets: Introduce inet socket options controlling TCP keep-alive
|
|
RH-Jira: RHEL-67104
|
|
RH-Acked-by: Peter Xu <peterx@redhat.com>
|
|
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
RH-Commit: [6/7] 3861e7874d5952c53a5020c123b3b2e632149008 (JurajMarcin/centos-src-qemu-kvm)
|
|
|
|
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, that
|
|
includes Linux, Windows, macOS, but not OpenBSD. Additionally, macOS
|
|
defines TCP_KEEPIDLE as TCP_KEEPALIVE instead, so the patch supplies its
|
|
own definition.
|
|
|
|
The default value for all is 0, which means the system configuration is
|
|
used.
|
|
|
|
Signed-off-by: Juraj Marcin <jmarcin@redhat.com>
|
|
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
|
|
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
|
|
|
(cherry picked from commit 1bd4237cb1095d71c16afad3ce93b4a1e453173e)
|
|
|
|
JIRA: https://issues.redhat.com/browse/RHEL-67104
|
|
|
|
Signed-off-by: Juraj Marcin <jmarcin@redhat.com>
|
|
---
|
|
meson.build | 30 +++++++++++++
|
|
qapi/sockets.json | 19 ++++++++
|
|
tests/unit/test-util-sockets.c | 39 +++++++++++++++++
|
|
util/qemu-sockets.c | 80 ++++++++++++++++++++++++++++++++++
|
|
4 files changed, 168 insertions(+)
|
|
|
|
diff --git a/meson.build b/meson.build
|
|
index 5bb2b757c3..c4539b66c5 100644
|
|
--- a/meson.build
|
|
+++ b/meson.build
|
|
@@ -2581,6 +2581,36 @@ config_host_data.set('HAVE_OPTRESET',
|
|
cc.has_header_symbol('getopt.h', 'optreset'))
|
|
config_host_data.set('HAVE_IPPROTO_MPTCP',
|
|
cc.has_header_symbol('netinet/in.h', 'IPPROTO_MPTCP'))
|
|
+config_host_data.set('HAVE_TCP_KEEPCNT',
|
|
+ cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPCNT') or
|
|
+ cc.compiles('''
|
|
+ #include <ws2tcpip.h>
|
|
+ #ifndef TCP_KEEPCNT
|
|
+ #error
|
|
+ #endif
|
|
+ int main(void) { return 0; }''',
|
|
+ name: 'Win32 TCP_KEEPCNT'))
|
|
+# On Darwin TCP_KEEPIDLE is available under different name, TCP_KEEPALIVE.
|
|
+# https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/man/man4/tcp.4#L172
|
|
+config_host_data.set('HAVE_TCP_KEEPIDLE',
|
|
+ cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPIDLE') or
|
|
+ cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPALIVE') or
|
|
+ cc.compiles('''
|
|
+ #include <ws2tcpip.h>
|
|
+ #ifndef TCP_KEEPIDLE
|
|
+ #error
|
|
+ #endif
|
|
+ int main(void) { return 0; }''',
|
|
+ name: 'Win32 TCP_KEEPIDLE'))
|
|
+config_host_data.set('HAVE_TCP_KEEPINTVL',
|
|
+ cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPINTVL') or
|
|
+ cc.compiles('''
|
|
+ #include <ws2tcpip.h>
|
|
+ #ifndef TCP_KEEPINTVL
|
|
+ #error
|
|
+ #endif
|
|
+ int main(void) { return 0; }''',
|
|
+ name: 'Win32 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..f9f559daba 100644
|
|
--- a/qapi/sockets.json
|
|
+++ b/qapi/sockets.json
|
|
@@ -59,6 +59,22 @@
|
|
# @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 (this includes Linux, Windows, macOS, FreeBSD,
|
|
+# but not OpenBSD). When set to 0, system setting is used. (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 (this includes Linux,
|
|
+# Windows, macOS, FreeBSD, but not OpenBSD). When set to 0, system setting
|
|
+# is used. (Since 10.1)
|
|
+#
|
|
+# @keep-alive-interval: time in seconds between keep-alive packets. Only
|
|
+# supported for TCP sockets on systems where TCP_KEEPINTVL is defined (this
|
|
+# includes Linux, Windows, macOS, FreeBSD, but not OpenBSD). When set to
|
|
+# 0, system setting is used. (Since 10.1)
|
|
+#
|
|
# @mptcp: enable multi-path TCP. (Since 6.1)
|
|
#
|
|
# Since: 1.3
|
|
@@ -71,6 +87,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/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c
|
|
index 9e39b92e7c..8492f4d68f 100644
|
|
--- a/tests/unit/test-util-sockets.c
|
|
+++ b/tests/unit/test-util-sockets.c
|
|
@@ -359,6 +359,24 @@ static void inet_parse_test_helper(const char *str,
|
|
g_assert_cmpint(addr.ipv6, ==, exp_addr->ipv6);
|
|
g_assert_cmpint(addr.has_keep_alive, ==, exp_addr->has_keep_alive);
|
|
g_assert_cmpint(addr.keep_alive, ==, exp_addr->keep_alive);
|
|
+#ifdef HAVE_TCP_KEEPCNT
|
|
+ g_assert_cmpint(addr.has_keep_alive_count, ==,
|
|
+ exp_addr->has_keep_alive_count);
|
|
+ g_assert_cmpint(addr.keep_alive_count, ==,
|
|
+ exp_addr->keep_alive_count);
|
|
+#endif
|
|
+#ifdef HAVE_TCP_KEEPIDLE
|
|
+ g_assert_cmpint(addr.has_keep_alive_idle, ==,
|
|
+ exp_addr->has_keep_alive_idle);
|
|
+ g_assert_cmpint(addr.keep_alive_idle, ==,
|
|
+ exp_addr->keep_alive_idle);
|
|
+#endif
|
|
+#ifdef HAVE_TCP_KEEPINTVL
|
|
+ g_assert_cmpint(addr.has_keep_alive_interval, ==,
|
|
+ exp_addr->has_keep_alive_interval);
|
|
+ g_assert_cmpint(addr.keep_alive_interval, ==,
|
|
+ exp_addr->keep_alive_interval);
|
|
+#endif
|
|
#ifdef HAVE_IPPROTO_MPTCP
|
|
g_assert_cmpint(addr.has_mptcp, ==, exp_addr->has_mptcp);
|
|
g_assert_cmpint(addr.mptcp, ==, exp_addr->mptcp);
|
|
@@ -460,6 +478,18 @@ static void test_inet_parse_all_options_good(void)
|
|
.ipv6 = true,
|
|
.has_keep_alive = true,
|
|
.keep_alive = true,
|
|
+#ifdef HAVE_TCP_KEEPCNT
|
|
+ .has_keep_alive_count = true,
|
|
+ .keep_alive_count = 10,
|
|
+#endif
|
|
+#ifdef HAVE_TCP_KEEPIDLE
|
|
+ .has_keep_alive_idle = true,
|
|
+ .keep_alive_idle = 60,
|
|
+#endif
|
|
+#ifdef HAVE_TCP_KEEPINTVL
|
|
+ .has_keep_alive_interval = true,
|
|
+ .keep_alive_interval = 30,
|
|
+#endif
|
|
#ifdef HAVE_IPPROTO_MPTCP
|
|
.has_mptcp = true,
|
|
.mptcp = false,
|
|
@@ -467,6 +497,15 @@ static void test_inet_parse_all_options_good(void)
|
|
};
|
|
inet_parse_test_helper(
|
|
"[::1]:5000,numeric=on,to=5006,ipv4=off,ipv6=on,keep-alive=on"
|
|
+#ifdef HAVE_TCP_KEEPCNT
|
|
+ ",keep-alive-count=10"
|
|
+#endif
|
|
+#ifdef HAVE_TCP_KEEPIDLE
|
|
+ ",keep-alive-idle=60"
|
|
+#endif
|
|
+#ifdef HAVE_TCP_KEEPINTVL
|
|
+ ",keep-alive-interval=30"
|
|
+#endif
|
|
#ifdef HAVE_IPPROTO_MPTCP
|
|
",mptcp=off"
|
|
#endif
|
|
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
|
|
index 8017124c74..ef0a137bd2 100644
|
|
--- a/util/qemu-sockets.c
|
|
+++ b/util/qemu-sockets.c
|
|
@@ -45,6 +45,14 @@
|
|
# define AI_NUMERICSERV 0
|
|
#endif
|
|
|
|
+/*
|
|
+ * On macOS TCP_KEEPIDLE is available under a different name, TCP_KEEPALIVE.
|
|
+ * https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/man/man4/tcp.4#L172
|
|
+ */
|
|
+#if defined(TCP_KEEPALIVE) && !defined(TCP_KEEPIDLE)
|
|
+# define TCP_KEEPIDLE TCP_KEEPALIVE
|
|
+#endif
|
|
+
|
|
|
|
static int inet_getport(struct addrinfo *e)
|
|
{
|
|
@@ -218,6 +226,42 @@ 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->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->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->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;
|
|
}
|
|
@@ -631,6 +675,24 @@ static QemuOptsList inet_opts = {
|
|
.name = "keep-alive",
|
|
.type = QEMU_OPT_BOOL,
|
|
},
|
|
+#ifdef HAVE_TCP_KEEPCNT
|
|
+ {
|
|
+ .name = "keep-alive-count",
|
|
+ .type = QEMU_OPT_NUMBER,
|
|
+ },
|
|
+#endif
|
|
+#ifdef HAVE_TCP_KEEPIDLE
|
|
+ {
|
|
+ .name = "keep-alive-idle",
|
|
+ .type = QEMU_OPT_NUMBER,
|
|
+ },
|
|
+#endif
|
|
+#ifdef HAVE_TCP_KEEPINTVL
|
|
+ {
|
|
+ .name = "keep-alive-interval",
|
|
+ .type = QEMU_OPT_NUMBER,
|
|
+ },
|
|
+#endif
|
|
#ifdef HAVE_IPPROTO_MPTCP
|
|
{
|
|
.name = "mptcp",
|
|
@@ -696,6 +758,24 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
|
|
addr->has_keep_alive = true;
|
|
addr->keep_alive = qemu_opt_get_bool(opts, "keep-alive", false);
|
|
}
|
|
+#ifdef HAVE_TCP_KEEPCNT
|
|
+ if (qemu_opt_find(opts, "keep-alive-count")) {
|
|
+ addr->has_keep_alive_count = true;
|
|
+ addr->keep_alive_count = qemu_opt_get_number(opts, "keep-alive-count", 0);
|
|
+ }
|
|
+#endif
|
|
+#ifdef HAVE_TCP_KEEPIDLE
|
|
+ if (qemu_opt_find(opts, "keep-alive-idle")) {
|
|
+ addr->has_keep_alive_idle = true;
|
|
+ addr->keep_alive_idle = qemu_opt_get_number(opts, "keep-alive-idle", 0);
|
|
+ }
|
|
+#endif
|
|
+#ifdef HAVE_TCP_KEEPINTVL
|
|
+ if (qemu_opt_find(opts, "keep-alive-interval")) {
|
|
+ addr->has_keep_alive_interval = true;
|
|
+ addr->keep_alive_interval = qemu_opt_get_number(opts, "keep-alive-interval", 0);
|
|
+ }
|
|
+#endif
|
|
#ifdef HAVE_IPPROTO_MPTCP
|
|
if (qemu_opt_find(opts, "mptcp")) {
|
|
addr->has_mptcp = true;
|
|
--
|
|
2.39.3
|
|
|