util/qemu-sockets: Introduce inet socket options controlling TCP keep-alive

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>
This commit is contained in:
Juraj Marcin 2025-05-21 15:52:35 +02:00 committed by Daniel P. Berrangé
parent 316e8ee8d6
commit 1bd4237cb1
4 changed files with 168 additions and 0 deletions

View file

@ -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