* [PATCH 0/5] socket: add TCP_USER_TIMEOUT, fix -netdev stream option docs
@ 2026-05-24 7:34 Mitsuru Kariya
2026-05-24 7:34 ` [PATCH 1/5] qemu-options: fix missing addr. prefix on -netdev stream inet/unix options Mitsuru Kariya
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Mitsuru Kariya @ 2026-05-24 7:34 UTC (permalink / raw)
To: qemu-devel
Cc: Daniel P. Berrangé, Paolo Bonzini, Marc-André Lureau,
Philippe Mathieu-Daudé, Pierrick Bouvier, Eric Blake,
Markus Armbruster, Fabiano Rosas, Laurent Vivier, Peter Xu,
Jason Wang
The default Linux TCP retransmission timeout for unacknowledged segments
is on the order of 15+ minutes and can stretch well past an hour with
exponential backoff. For QEMU live migration over TCP that means a
silently disconnected peer (cable pulled, peer host crashed, NAT idle
flush, firewall reset) can leave the source QEMU "migrating" for many
minutes with no diagnosis.
TCP keep-alive options already help, but they only trigger on idle
connections; they do nothing when the connection has unacknowledged
in-flight data, which is the common case during a live migration push.
The Linux TCP_USER_TIMEOUT socket option bounds this: the kernel
forcibly closes the connection and returns ETIMEDOUT after the
configured number of milliseconds of unacknowledged data, regardless of
keep-alive state.
This series adds TCP_USER_TIMEOUT as a new optional InetSocketAddress
member. Two parsing paths feed into InetSocketAddress in QEMU, and
both need separate plumbing to accept a new option:
- the QAPI keyval visitor used by modern syntax such as
-netdev stream, -chardev socket, -incoming <channel>, and any
QMP command that takes a SocketAddress argument. This path
automatically picks up the new member once it is declared in
qapi/sockets.json.
- the legacy URI parser (socket_parse() -> inet_parse()) used by
-incoming tcp:, migrate tcp:, and HMP nbd_server_start, which
has its own option table (inet_opts) and needs an explicit entry
plus a copy into the QAPI struct.
This series adds the qapi/sockets.json declaration and the inet_opts /
inet_parse() plumbing so that user-timeout is available through both
paths.
While preparing it I noticed two pre-existing qemu-options.hx issues
that had never been caught because nothing tested those options'
acceptance through the QAPI path:
- The -netdev stream synopsis listed several InetSocketAddress and
UnixSocketAddress members without the required "addr." prefix
(to, numeric, keep-alive, mptcp, ipv4, ipv6, abstract, tight).
These names are actually rejected by the QAPI input visitor with
"Parameter '...' is unexpected". Broken since bb1326abd9df ("net:
update netdev stream/dgram man page", 2024-07).
- keep-alive-count/idle/interval (added to InetSocketAddress in 10.1)
and keep-alive/numeric/mptcp (older) were never documented in the
-incoming tcp: synopsis, despite inet_opts accepting them.
The series is therefore split into:
1/5 bug-fix only: add the missing "addr." prefix to -netdev stream
inet/unix option docs (separated so it can be considered for
stable backport)
2/5 pure docs: keep-alive-count/idle/interval for -netdev stream
3/5 pure docs: keep-alive*/numeric/mptcp for -incoming tcp:
4/5 the feature itself: meson HAVE_TCP_USER_TIMEOUT check,
qapi/sockets.json schema addition, inet_set_sockopts() and
inet_parse() plumbing, qemu-options.hx user-timeout entries for
both -netdev stream (addr.user-timeout=...) and -incoming tcp:
(user-timeout=...), and test_inet_parse_all_options_good
extension
5/5 new qtest /netdev/stream/inet/options that smoke-tests the
complete optional InetSocketAddress member set on the QAPI
keyval parsing path; catches the class of schema/synopsis drift
described above
Each commit builds and passes test-util-sockets and
qtest-x86_64/netdev-socket independently, verified with
git rebase --exec. checkpatch reports 0 errors / 0 warnings for every
patch.
A companion libvirt change to expose this option through the QEMU
driver's migration parameters is in preparation.
Mitsuru Kariya (5):
qemu-options: fix missing addr. prefix on -netdev stream inet/unix
options
qemu-options: document keep-alive-count/idle/interval for -netdev
stream
qemu-options: document keep-alive*/numeric/mptcp for -incoming tcp:
util/qemu-sockets: add TCP_USER_TIMEOUT support
tests/qtest/netdev-socket: smoke test -netdev stream inet option set
meson.build | 2 +
qapi/sockets.json | 7 ++++
qemu-options.hx | 47 +++++++++++++++-------
tests/qtest/netdev-socket.c | 71 ++++++++++++++++++++++++++++++++++
tests/unit/test-util-sockets.c | 13 +++++++
util/qemu-sockets.c | 24 ++++++++++++
6 files changed, 149 insertions(+), 15 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/5] qemu-options: fix missing addr. prefix on -netdev stream inet/unix options
2026-05-24 7:34 [PATCH 0/5] socket: add TCP_USER_TIMEOUT, fix -netdev stream option docs Mitsuru Kariya
@ 2026-05-24 7:34 ` Mitsuru Kariya
2026-06-02 4:33 ` Markus Armbruster
2026-05-24 7:34 ` [PATCH 2/5] qemu-options: document keep-alive-count/idle/interval for -netdev stream Mitsuru Kariya
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Mitsuru Kariya @ 2026-05-24 7:34 UTC (permalink / raw)
To: qemu-devel
Cc: Daniel P. Berrangé, Paolo Bonzini, Marc-André Lureau,
Philippe Mathieu-Daudé, Pierrick Bouvier, Eric Blake,
Markus Armbruster, Fabiano Rosas, Laurent Vivier, Peter Xu,
Jason Wang, qemu-stable
-netdev stream uses modern syntax parsed by netdev_parse_modern() which
goes through the QAPI keyval visitor (qobject_input_visitor_new_str() ->
keyval_parse() -> qobject_input_visitor_new_keyval() -> visit_type_Netdev()).
Options nested under addr (of type SocketAddress) must therefore be
written with the "addr." prefix: a top-level "keep-alive=on" is rejected
by the QAPI input visitor with "Parameter 'keep-alive' is unexpected",
because NetdevStreamOptions has no such member.
The documentation listed several InetSocketAddress members (to, numeric,
keep-alive, mptcp, ipv4, ipv6) and UnixSocketAddress members (abstract,
tight) without the prefix, which never actually worked. Only
addr.type/addr.host/addr.port/addr.path/addr.str were spelled correctly
in the synopsis.
Add the missing addr. prefix to all affected option names.
Fixes: bb1326abd9df ("net: update netdev stream/dgram man page")
Cc: qemu-stable@nongnu.org
Signed-off-by: Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com>
---
qemu-options.hx | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/qemu-options.hx b/qemu-options.hx
index 96ae41f787..527fc12494 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3034,8 +3034,8 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
"-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
" configure a network backend to connect to another network\n"
" using an UDP tunnel\n"
- "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
- "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect-ms=milliseconds]\n"
+ "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
+ "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,addr.abstract=on|off][,addr.tight=on|off][,reconnect-ms=milliseconds]\n"
"-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect-ms=milliseconds]\n"
" configure a network backend to connect to another network\n"
" using a socket connection in stream mode.\n"
@@ -3640,7 +3640,7 @@ SRST
-device e1000,netdev=n1,mac=52:54:00:12:34:56 \\
-netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4
-``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
+``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
Configure a network backend to connect to another QEMU virtual machine or a proxy using a TCP/IP socket.
``server=on|off``
@@ -3649,22 +3649,22 @@ SRST
``addr.host=host,addr.port=port``
socket address to listen on (server=on) or connect to (server=off)
- ``to=maxport``
+ ``addr.to=maxport``
if present, this is range of possible addresses, with port between ``port`` and ``maxport``.
- ``numeric=on|off``
+ ``addr.numeric=on|off``
if ``on`` ``host`` and ``port`` are guaranteed to be numeric, otherwise a name resolution should be attempted (default: ``off``)
- ``keep-alive=on|off``
+ ``addr.keep-alive=on|off``
enable keep-alive when connecting to this socket. Not supported for passive sockets.
- ``mptcp=on|off``
+ ``addr.mptcp=on|off``
enable multipath TCP
- ``ipv4=on|off``
+ ``addr.ipv4=on|off``
whether to accept IPv4 addresses, default to try both IPv4 and IPv6
- ``ipv6=on|off``
+ ``addr.ipv6=on|off``
whether to accept IPv6 addresses, default to try both IPv4 and IPv6
``reconnect-ms=milliseconds``
@@ -3684,7 +3684,7 @@ SRST
-device virtio-net,netdev=net0,mac=52:54:00:12:34:57 \\
-netdev stream,id=net0,server=off,addr.type=inet,addr.host=localhost,addr.port=1234,reconnect-ms=5000
-``-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect-ms=milliseconds]``
+``-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,addr.abstract=on|off][,addr.tight=on|off][,reconnect-ms=milliseconds]``
Configure a network backend to connect to another QEMU virtual machine or a proxy using a stream oriented unix domain socket.
``server=on|off``
@@ -3693,10 +3693,10 @@ SRST
``addr.path=path``
filesystem path to use
- ``abstract=on|off``
+ ``addr.abstract=on|off``
if ``on``, this is a Linux abstract socket address.
- ``tight=on|off``
+ ``addr.tight=on|off``
if false, pad an abstract socket address with enough null bytes to make it fill struct sockaddr_un member sun_path.
``reconnect-ms=milliseconds``
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/5] qemu-options: document keep-alive-count/idle/interval for -netdev stream
2026-05-24 7:34 [PATCH 0/5] socket: add TCP_USER_TIMEOUT, fix -netdev stream option docs Mitsuru Kariya
2026-05-24 7:34 ` [PATCH 1/5] qemu-options: fix missing addr. prefix on -netdev stream inet/unix options Mitsuru Kariya
@ 2026-05-24 7:34 ` Mitsuru Kariya
2026-06-02 4:38 ` Markus Armbruster
2026-05-24 7:34 ` [PATCH 3/5] qemu-options: document keep-alive*/numeric/mptcp for -incoming tcp: Mitsuru Kariya
` (2 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Mitsuru Kariya @ 2026-05-24 7:34 UTC (permalink / raw)
To: qemu-devel
Cc: Daniel P. Berrangé, Paolo Bonzini, Marc-André Lureau,
Philippe Mathieu-Daudé, Pierrick Bouvier, Eric Blake,
Markus Armbruster, Fabiano Rosas, Laurent Vivier, Peter Xu,
Jason Wang
The keep-alive-count, keep-alive-idle and keep-alive-interval members of
InetSocketAddress have been available for -netdev stream (and every
other QAPI SocketAddress consumer) since the qemu-sockets keep-alive
options were extended in 10.1, but were never documented in
qemu-options.hx.
Add their descriptions, and drop the "Not supported for passive sockets"
remark from addr.keep-alive=on|off: as of 10.1 keep-alive on listening
sockets is also supported (see the SocketAddress @keep-alive QAPI doc
comment, which records "(Since 4.2, not supported for listening sockets
until 10.1)").
Signed-off-by: Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com>
---
qemu-options.hx | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/qemu-options.hx b/qemu-options.hx
index 527fc12494..7432b77571 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3034,7 +3034,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
"-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
" configure a network backend to connect to another network\n"
" using an UDP tunnel\n"
- "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
+ "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
"-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,addr.abstract=on|off][,addr.tight=on|off][,reconnect-ms=milliseconds]\n"
"-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect-ms=milliseconds]\n"
" configure a network backend to connect to another network\n"
@@ -3640,7 +3640,7 @@ SRST
-device e1000,netdev=n1,mac=52:54:00:12:34:56 \\
-netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4
-``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
+``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
Configure a network backend to connect to another QEMU virtual machine or a proxy using a TCP/IP socket.
``server=on|off``
@@ -3656,7 +3656,19 @@ SRST
if ``on`` ``host`` and ``port`` are guaranteed to be numeric, otherwise a name resolution should be attempted (default: ``off``)
``addr.keep-alive=on|off``
- enable keep-alive when connecting to this socket. Not supported for passive sockets.
+ enable keep-alive when connecting to this socket.
+
+ ``addr.keep-alive-count=count``
+ number of keep-alive packets to send before dropping the connection.
+ Set to 0 to use the system default. (default: 0)
+
+ ``addr.keep-alive-idle=idle``
+ time in seconds the connection needs to be idle before sending keep-alive packets.
+ Set to 0 to use the system default. (default: 0)
+
+ ``addr.keep-alive-interval=interval``
+ time in seconds between individual keep-alive packets.
+ Set to 0 to use the system default. (default: 0)
``addr.mptcp=on|off``
enable multipath TCP
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/5] qemu-options: document keep-alive*/numeric/mptcp for -incoming tcp:
2026-05-24 7:34 [PATCH 0/5] socket: add TCP_USER_TIMEOUT, fix -netdev stream option docs Mitsuru Kariya
2026-05-24 7:34 ` [PATCH 1/5] qemu-options: fix missing addr. prefix on -netdev stream inet/unix options Mitsuru Kariya
2026-05-24 7:34 ` [PATCH 2/5] qemu-options: document keep-alive-count/idle/interval for -netdev stream Mitsuru Kariya
@ 2026-05-24 7:34 ` Mitsuru Kariya
2026-05-24 7:34 ` [PATCH 4/5] util/qemu-sockets: add TCP_USER_TIMEOUT support Mitsuru Kariya
2026-05-24 7:34 ` [PATCH 5/5] tests/qtest/netdev-socket: smoke test -netdev stream inet option set Mitsuru Kariya
4 siblings, 0 replies; 9+ messages in thread
From: Mitsuru Kariya @ 2026-05-24 7:34 UTC (permalink / raw)
To: qemu-devel
Cc: Daniel P. Berrangé, Paolo Bonzini, Marc-André Lureau,
Philippe Mathieu-Daudé, Pierrick Bouvier, Eric Blake,
Markus Armbruster, Fabiano Rosas, Laurent Vivier, Peter Xu,
Jason Wang
-incoming tcp: and migrate tcp: parse their URIs through
socket_parse() -> inet_parse(), which uses the inet_opts QemuOptsList
(util/qemu-sockets.c). That table has long accepted numeric, keep-alive
and (when supported by the host) keep-alive-count, keep-alive-idle,
keep-alive-interval and mptcp, but the -incoming synopsis only listed
to/ipv4/ipv6.
List the other accepted options too, so the documentation matches what
the parser actually supports.
Signed-off-by: Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com>
---
qemu-options.hx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/qemu-options.hx b/qemu-options.hx
index 7432b77571..d2b816e16f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -5365,7 +5365,7 @@ SRST
ERST
DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \
- "-incoming tcp:[host]:port[,to=maxport][,ipv4=on|off][,ipv6=on|off]\n" \
+ "-incoming tcp:[host]:port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,keep-alive-count=count][,keep-alive-idle=idle][,keep-alive-interval=interval][,mptcp=on|off][,ipv4=on|off][,ipv6=on|off]\n" \
"-incoming rdma:host:port[,ipv4=on|off][,ipv6=on|off]\n" \
"-incoming unix:socketpath\n" \
" prepare for incoming migration, listen on\n" \
@@ -5387,7 +5387,7 @@ migration channel types. The channel type is specified in <channel>,
or is 'main' for all other forms of -incoming. If multiple -incoming
options are specified for a channel type, the last one takes precedence.
-``-incoming tcp:[host]:port[,to=maxport][,ipv4=on|off][,ipv6=on|off]``
+``-incoming tcp:[host]:port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,keep-alive-count=count][,keep-alive-idle=idle][,keep-alive-interval=interval][,mptcp=on|off][,ipv4=on|off][,ipv6=on|off]``
\
``-incoming rdma:host:port[,ipv4=on|off][,ipv6=on|off]``
Prepare for incoming migration, listen on a given tcp port.
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/5] util/qemu-sockets: add TCP_USER_TIMEOUT support
2026-05-24 7:34 [PATCH 0/5] socket: add TCP_USER_TIMEOUT, fix -netdev stream option docs Mitsuru Kariya
` (2 preceding siblings ...)
2026-05-24 7:34 ` [PATCH 3/5] qemu-options: document keep-alive*/numeric/mptcp for -incoming tcp: Mitsuru Kariya
@ 2026-05-24 7:34 ` Mitsuru Kariya
2026-06-02 4:54 ` Markus Armbruster
2026-05-24 7:34 ` [PATCH 5/5] tests/qtest/netdev-socket: smoke test -netdev stream inet option set Mitsuru Kariya
4 siblings, 1 reply; 9+ messages in thread
From: Mitsuru Kariya @ 2026-05-24 7:34 UTC (permalink / raw)
To: qemu-devel
Cc: Daniel P. Berrangé, Paolo Bonzini, Marc-André Lureau,
Philippe Mathieu-Daudé, Pierrick Bouvier, Eric Blake,
Markus Armbruster, Fabiano Rosas, Laurent Vivier, Peter Xu,
Jason Wang
The TCP_USER_TIMEOUT socket option (Linux-only) specifies the maximum
amount of time in milliseconds that transmitted data may remain
unacknowledged, or buffered data may remain untransmitted, before TCP
forcibly closes the connection and returns ETIMEDOUT to the
application. Without it, a peer that becomes silently unreachable can
take well over an hour to be noticed (the kernel default), which is
particularly painful for use cases like QEMU live migration.
Expose user-timeout as a new optional InetSocketAddress member, gated
on a new HAVE_TCP_USER_TIMEOUT meson check, and apply it in
inet_set_sockopts() alongside the existing keep-alive options. Plumb
the same option through the legacy QemuOpts-based inet_parse() path so
that URI-style users (-incoming tcp:, migrate tcp:, HMP
nbd_server_start, ...) can set it too.
Update the documentation for -netdev stream (addr.user-timeout=N) and
-incoming tcp: (user-timeout=N, flat key as for the other inet_opts
entries), and extend test_inet_parse_all_options_good accordingly.
Signed-off-by: Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com>
---
meson.build | 2 ++
qapi/sockets.json | 7 +++++++
qemu-options.hx | 13 +++++++++----
tests/unit/test-util-sockets.c | 13 +++++++++++++
util/qemu-sockets.c | 24 ++++++++++++++++++++++++
5 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/meson.build b/meson.build
index eb07491819..c5afe8754d 100644
--- a/meson.build
+++ b/meson.build
@@ -2726,6 +2726,8 @@ config_host_data.set('HAVE_TCP_KEEPINTVL',
#endif
int main(void) { return 0; }''',
name: 'Win32 TCP_KEEPINTVL'))
+config_host_data.set('HAVE_TCP_USER_TIMEOUT',
+ cc.has_header_symbol('netinet/tcp.h', 'TCP_USER_TIMEOUT'))
# has_member
config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID',
diff --git a/qapi/sockets.json b/qapi/sockets.json
index 473be2ac58..543689a2c7 100644
--- a/qapi/sockets.json
+++ b/qapi/sockets.json
@@ -79,6 +79,12 @@
# defined (this includes Linux, Windows, macOS, FreeBSD, but not
# OpenBSD). When set to 0, system setting is used. (Since 10.1)
#
+# @user-timeout: time in milliseconds that transmitted data may remain
+# unacknowledged before the connection is closed. Only supported
+# for TCP sockets on systems where TCP_USER_TIMEOUT socket option
+# is defined (Linux only). When set to 0, system setting is used.
+# (Since 11.1)
+#
# @mptcp: enable multi-path TCP. (Since 6.1)
#
# Since: 1.3
@@ -94,6 +100,7 @@
'*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' },
+ '*user-timeout': { 'type': 'uint32', 'if': 'HAVE_TCP_USER_TIMEOUT' },
'*mptcp': { 'type': 'bool', 'if': 'HAVE_IPPROTO_MPTCP' } } }
##
diff --git a/qemu-options.hx b/qemu-options.hx
index d2b816e16f..63587cccd3 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3034,7 +3034,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
"-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
" configure a network backend to connect to another network\n"
" using an UDP tunnel\n"
- "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
+ "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.user-timeout=timeout][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
"-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,addr.abstract=on|off][,addr.tight=on|off][,reconnect-ms=milliseconds]\n"
"-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect-ms=milliseconds]\n"
" configure a network backend to connect to another network\n"
@@ -3640,7 +3640,7 @@ SRST
-device e1000,netdev=n1,mac=52:54:00:12:34:56 \\
-netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4
-``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
+``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.user-timeout=timeout][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
Configure a network backend to connect to another QEMU virtual machine or a proxy using a TCP/IP socket.
``server=on|off``
@@ -3670,6 +3670,11 @@ SRST
time in seconds between individual keep-alive packets.
Set to 0 to use the system default. (default: 0)
+ ``addr.user-timeout=timeout``
+ time in milliseconds that transmitted data may remain unacknowledged
+ before the connection is forcibly closed.
+ Set to 0 to use the system default. (default: 0)
+
``addr.mptcp=on|off``
enable multipath TCP
@@ -5365,7 +5370,7 @@ SRST
ERST
DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \
- "-incoming tcp:[host]:port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,keep-alive-count=count][,keep-alive-idle=idle][,keep-alive-interval=interval][,mptcp=on|off][,ipv4=on|off][,ipv6=on|off]\n" \
+ "-incoming tcp:[host]:port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,keep-alive-count=count][,keep-alive-idle=idle][,keep-alive-interval=interval][,user-timeout=timeout][,mptcp=on|off][,ipv4=on|off][,ipv6=on|off]\n" \
"-incoming rdma:host:port[,ipv4=on|off][,ipv6=on|off]\n" \
"-incoming unix:socketpath\n" \
" prepare for incoming migration, listen on\n" \
@@ -5387,7 +5392,7 @@ migration channel types. The channel type is specified in <channel>,
or is 'main' for all other forms of -incoming. If multiple -incoming
options are specified for a channel type, the last one takes precedence.
-``-incoming tcp:[host]:port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,keep-alive-count=count][,keep-alive-idle=idle][,keep-alive-interval=interval][,mptcp=on|off][,ipv4=on|off][,ipv6=on|off]``
+``-incoming tcp:[host]:port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,keep-alive-count=count][,keep-alive-idle=idle][,keep-alive-interval=interval][,user-timeout=timeout][,mptcp=on|off][,ipv4=on|off][,ipv6=on|off]``
\
``-incoming rdma:host:port[,ipv4=on|off][,ipv6=on|off]``
Prepare for incoming migration, listen on a given tcp port.
diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c
index b9f2453e29..a56efc1b83 100644
--- a/tests/unit/test-util-sockets.c
+++ b/tests/unit/test-util-sockets.c
@@ -382,6 +382,12 @@ static void inet_parse_test_helper(const char *str,
g_assert_cmpint(addr.keep_alive_interval, ==,
exp_addr->keep_alive_interval);
#endif
+#ifdef HAVE_TCP_USER_TIMEOUT
+ g_assert_cmpint(addr.has_user_timeout, ==,
+ exp_addr->has_user_timeout);
+ g_assert_cmpint(addr.user_timeout, ==,
+ exp_addr->user_timeout);
+#endif
#ifdef HAVE_IPPROTO_MPTCP
g_assert_cmpint(addr.has_mptcp, ==, exp_addr->has_mptcp);
g_assert_cmpint(addr.mptcp, ==, exp_addr->mptcp);
@@ -495,6 +501,10 @@ static void test_inet_parse_all_options_good(void)
.has_keep_alive_interval = true,
.keep_alive_interval = 30,
#endif
+#ifdef HAVE_TCP_USER_TIMEOUT
+ .has_user_timeout = true,
+ .user_timeout = 10000,
+#endif
#ifdef HAVE_IPPROTO_MPTCP
.has_mptcp = true,
.mptcp = false,
@@ -511,6 +521,9 @@ static void test_inet_parse_all_options_good(void)
#ifdef HAVE_TCP_KEEPINTVL
",keep-alive-interval=30"
#endif
+#ifdef HAVE_TCP_USER_TIMEOUT
+ ",user-timeout=10000"
+#endif
#ifdef HAVE_IPPROTO_MPTCP
",mptcp=off"
#endif
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 4773755fd5..f16f9b007c 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -263,6 +263,18 @@ static int inet_set_sockopts(int sock, InetSocketAddress *saddr, Error **errp)
}
#endif
}
+#ifdef HAVE_TCP_USER_TIMEOUT
+ if (saddr->has_user_timeout && saddr->user_timeout) {
+ int user_timeout = saddr->user_timeout;
+ int ret = setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout,
+ sizeof(user_timeout));
+ if (ret < 0) {
+ error_setg_errno(errp, errno,
+ "Unable to set TCP user timeout option on socket");
+ return -1;
+ }
+ }
+#endif
return 0;
}
@@ -692,6 +704,12 @@ static QemuOptsList inet_opts = {
.type = QEMU_OPT_NUMBER,
},
#endif
+#ifdef HAVE_TCP_USER_TIMEOUT
+ {
+ .name = "user-timeout",
+ .type = QEMU_OPT_NUMBER,
+ },
+#endif
#ifdef HAVE_IPPROTO_MPTCP
{
.name = "mptcp",
@@ -775,6 +793,12 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
addr->keep_alive_interval = qemu_opt_get_number(opts, "keep-alive-interval", 0);
}
#endif
+#ifdef HAVE_TCP_USER_TIMEOUT
+ if (qemu_opt_find(opts, "user-timeout")) {
+ addr->has_user_timeout = true;
+ addr->user_timeout = qemu_opt_get_number(opts, "user-timeout", 0);
+ }
+#endif
#ifdef HAVE_IPPROTO_MPTCP
if (qemu_opt_find(opts, "mptcp")) {
addr->has_mptcp = true;
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/5] tests/qtest/netdev-socket: smoke test -netdev stream inet option set
2026-05-24 7:34 [PATCH 0/5] socket: add TCP_USER_TIMEOUT, fix -netdev stream option docs Mitsuru Kariya
` (3 preceding siblings ...)
2026-05-24 7:34 ` [PATCH 4/5] util/qemu-sockets: add TCP_USER_TIMEOUT support Mitsuru Kariya
@ 2026-05-24 7:34 ` Mitsuru Kariya
4 siblings, 0 replies; 9+ messages in thread
From: Mitsuru Kariya @ 2026-05-24 7:34 UTC (permalink / raw)
To: qemu-devel
Cc: Daniel P. Berrangé, Paolo Bonzini, Marc-André Lureau,
Philippe Mathieu-Daudé, Pierrick Bouvier, Eric Blake,
Markus Armbruster, Fabiano Rosas, Laurent Vivier, Peter Xu,
Jason Wang
The existing /netdev/stream/inet/ipv4 and /ipv6 tests only exercise
addr.type, addr.host, addr.port and addr.ipv4/ipv6. None of the other
optional InetSocketAddress members (numeric, to, keep-alive,
keep-alive-count, keep-alive-idle, keep-alive-interval, user-timeout,
mptcp) have any test coverage on the QAPI keyval parsing path used by
netdev_parse_modern(). That gap let the qemu-options.hx synopsis drift
out of sync with reality (multiple options were documented without the
required "addr." prefix, which the QAPI input visitor would have
rejected).
Add /netdev/stream/inet/options that sets all those options on the
server and client -netdev stream invocations. The options conditionally
compiled by HAVE_TCP_KEEP*/HAVE_TCP_USER_TIMEOUT/HAVE_IPPROTO_MPTCP are
gated the same way here, mirroring inet_set_sockopts() and the QAPI
schema.
This is a smoke test: it verifies QEMU accepts the options and the
netdev reaches "listening"/"tcp:..." state. It does not read the
options back from the kernel; that path is already covered indirectly
by test_inet_parse_all_options_good which exercises inet_set_sockopts()
through the QemuOpts inet_parse() path.
Signed-off-by: Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com>
---
tests/qtest/netdev-socket.c | 71 +++++++++++++++++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c
index b731af0ad9..d1718813eb 100644
--- a/tests/qtest/netdev-socket.c
+++ b/tests/qtest/netdev-socket.c
@@ -146,6 +146,76 @@ static void test_stream_inet_ipv4(void)
qtest_quit(qts0);
}
+/*
+ * Smoke test that -netdev stream accepts all optional InetSocketAddress
+ * members (numeric, to, keep-alive*, user-timeout, mptcp). Catches
+ * regressions in the QAPI schema, the keyval parsing path, and the
+ * synopsis spelling in qemu-options.hx.
+ */
+static void test_stream_inet_options(void)
+{
+ QTestState *qts0, *qts1;
+ char *expect;
+ int port;
+
+ port = inet_get_free_port(false);
+ qts0 = qtest_initf("-nodefaults -M none "
+ "-netdev stream,id=st0,server=true,addr.type=inet,"
+ "addr.ipv4=on,addr.ipv6=off,addr.numeric=on,"
+ "addr.host=127.0.0.1,addr.port=%d,addr.to=%d,"
+ "addr.keep-alive=on"
+#ifdef HAVE_TCP_KEEPCNT
+ ",addr.keep-alive-count=3"
+#endif
+#ifdef HAVE_TCP_KEEPIDLE
+ ",addr.keep-alive-idle=10"
+#endif
+#ifdef HAVE_TCP_KEEPINTVL
+ ",addr.keep-alive-interval=5"
+#endif
+#ifdef HAVE_TCP_USER_TIMEOUT
+ ",addr.user-timeout=10000"
+#endif
+#ifdef HAVE_IPPROTO_MPTCP
+ ",addr.mptcp=off"
+#endif
+ , port, port);
+
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,listening\r\n", 0);
+
+ qts1 = qtest_initf("-nodefaults -M none "
+ "-netdev stream,server=false,id=st0,addr.type=inet,"
+ "addr.ipv4=on,addr.ipv6=off,addr.numeric=on,"
+ "addr.host=127.0.0.1,addr.port=%d,"
+ "addr.keep-alive=on"
+#ifdef HAVE_TCP_KEEPCNT
+ ",addr.keep-alive-count=3"
+#endif
+#ifdef HAVE_TCP_KEEPIDLE
+ ",addr.keep-alive-idle=10"
+#endif
+#ifdef HAVE_TCP_KEEPINTVL
+ ",addr.keep-alive-interval=5"
+#endif
+#ifdef HAVE_TCP_USER_TIMEOUT
+ ",addr.user-timeout=10000"
+#endif
+#ifdef HAVE_IPPROTO_MPTCP
+ ",addr.mptcp=off"
+#endif
+ , port);
+
+ expect = g_strdup_printf("st0: index=0,type=stream,tcp:127.0.0.1:%d\r\n",
+ port);
+ EXPECT_STATE(qts1, expect, 0);
+ g_free(expect);
+
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:127.0.0.1", ':');
+
+ qtest_quit(qts1);
+ qtest_quit(qts0);
+}
+
static void wait_stream_connected(QTestState *qts, const char *id,
SocketAddress **addr)
{
@@ -512,6 +582,7 @@ int main(int argc, char **argv)
if (has_ipv4) {
qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4);
+ qtest_add_func("/netdev/stream/inet/options", test_stream_inet_options);
qtest_add_func("/netdev/dgram/inet", test_dgram_inet);
#if !defined(_WIN32) && !defined(CONFIG_DARWIN)
qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 1/5] qemu-options: fix missing addr. prefix on -netdev stream inet/unix options
2026-05-24 7:34 ` [PATCH 1/5] qemu-options: fix missing addr. prefix on -netdev stream inet/unix options Mitsuru Kariya
@ 2026-06-02 4:33 ` Markus Armbruster
0 siblings, 0 replies; 9+ messages in thread
From: Markus Armbruster @ 2026-06-02 4:33 UTC (permalink / raw)
To: Mitsuru Kariya
Cc: qemu-devel, Daniel P. Berrangé, Paolo Bonzini,
Marc-André Lureau, Philippe Mathieu-Daudé,
Pierrick Bouvier, Eric Blake, Fabiano Rosas, Laurent Vivier,
Peter Xu, Jason Wang, qemu-stable
Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com> writes:
> -netdev stream uses modern syntax parsed by netdev_parse_modern() which
> goes through the QAPI keyval visitor (qobject_input_visitor_new_str() ->
> keyval_parse() -> qobject_input_visitor_new_keyval() -> visit_type_Netdev()).
> Options nested under addr (of type SocketAddress) must therefore be
> written with the "addr." prefix: a top-level "keep-alive=on" is rejected
> by the QAPI input visitor with "Parameter 'keep-alive' is unexpected",
> because NetdevStreamOptions has no such member.
>
> The documentation listed several InetSocketAddress members (to, numeric,
> keep-alive, mptcp, ipv4, ipv6) and UnixSocketAddress members (abstract,
> tight) without the prefix, which never actually worked. Only
> addr.type/addr.host/addr.port/addr.path/addr.str were spelled correctly
> in the synopsis.
>
> Add the missing addr. prefix to all affected option names.
>
> Fixes: bb1326abd9df ("net: update netdev stream/dgram man page")
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/5] qemu-options: document keep-alive-count/idle/interval for -netdev stream
2026-05-24 7:34 ` [PATCH 2/5] qemu-options: document keep-alive-count/idle/interval for -netdev stream Mitsuru Kariya
@ 2026-06-02 4:38 ` Markus Armbruster
0 siblings, 0 replies; 9+ messages in thread
From: Markus Armbruster @ 2026-06-02 4:38 UTC (permalink / raw)
To: Mitsuru Kariya
Cc: qemu-devel, Daniel P. Berrangé, Paolo Bonzini,
Marc-André Lureau, Philippe Mathieu-Daudé,
Pierrick Bouvier, Eric Blake, Fabiano Rosas, Laurent Vivier,
Peter Xu, Jason Wang
Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com> writes:
> The keep-alive-count, keep-alive-idle and keep-alive-interval members of
> InetSocketAddress have been available for -netdev stream (and every
> other QAPI SocketAddress consumer) since the qemu-sockets keep-alive
> options were extended in 10.1, but were never documented in
> qemu-options.hx.
>
> Add their descriptions, and drop the "Not supported for passive sockets"
> remark from addr.keep-alive=on|off: as of 10.1 keep-alive on listening
> sockets is also supported (see the SocketAddress @keep-alive QAPI doc
> comment, which records "(Since 4.2, not supported for listening sockets
> until 10.1)").
>
> Signed-off-by: Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com>
> ---
> qemu-options.hx | 18 +++++++++++++++---
> 1 file changed, 15 insertions(+), 3 deletions(-)
>
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 527fc12494..7432b77571 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -3034,7 +3034,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
> "-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
> " configure a network backend to connect to another network\n"
> " using an UDP tunnel\n"
> - "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
> + "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
> "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,addr.abstract=on|off][,addr.tight=on|off][,reconnect-ms=milliseconds]\n"
> "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect-ms=milliseconds]\n"
> " configure a network backend to connect to another network\n"
> @@ -3640,7 +3640,7 @@ SRST
> -device e1000,netdev=n1,mac=52:54:00:12:34:56 \\
> -netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4
>
> -``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
> +``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
> Configure a network backend to connect to another QEMU virtual machine or a proxy using a TCP/IP socket.
>
> ``server=on|off``
> @@ -3656,7 +3656,19 @@ SRST
> if ``on`` ``host`` and ``port`` are guaranteed to be numeric, otherwise a name resolution should be attempted (default: ``off``)
>
> ``addr.keep-alive=on|off``
> - enable keep-alive when connecting to this socket. Not supported for passive sockets.
> + enable keep-alive when connecting to this socket.
> +
> + ``addr.keep-alive-count=count``
> + number of keep-alive packets to send before dropping the connection.
> + Set to 0 to use the system default. (default: 0)
> +
> + ``addr.keep-alive-idle=idle``
> + time in seconds the connection needs to be idle before sending keep-alive packets.
> + Set to 0 to use the system default. (default: 0)
> +
> + ``addr.keep-alive-interval=interval``
> + time in seconds between individual keep-alive packets.
> + Set to 0 to use the system default. (default: 0)
>
> ``addr.mptcp=on|off``
> enable multipath TCP
You document these options only for -netdev stream. They also work for
-netdev dgram, possibly more (didn't check). Shouldn't we document them
every where they work?
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 4/5] util/qemu-sockets: add TCP_USER_TIMEOUT support
2026-05-24 7:34 ` [PATCH 4/5] util/qemu-sockets: add TCP_USER_TIMEOUT support Mitsuru Kariya
@ 2026-06-02 4:54 ` Markus Armbruster
0 siblings, 0 replies; 9+ messages in thread
From: Markus Armbruster @ 2026-06-02 4:54 UTC (permalink / raw)
To: Mitsuru Kariya
Cc: qemu-devel, Daniel P. Berrangé, Paolo Bonzini,
Marc-André Lureau, Philippe Mathieu-Daudé,
Pierrick Bouvier, Eric Blake, Fabiano Rosas, Laurent Vivier,
Peter Xu, Jason Wang
Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com> writes:
> The TCP_USER_TIMEOUT socket option (Linux-only) specifies the maximum
> amount of time in milliseconds that transmitted data may remain
> unacknowledged, or buffered data may remain untransmitted, before TCP
> forcibly closes the connection and returns ETIMEDOUT to the
> application. Without it, a peer that becomes silently unreachable can
> take well over an hour to be noticed (the kernel default), which is
> particularly painful for use cases like QEMU live migration.
>
> Expose user-timeout as a new optional InetSocketAddress member, gated
> on a new HAVE_TCP_USER_TIMEOUT meson check, and apply it in
> inet_set_sockopts() alongside the existing keep-alive options. Plumb
> the same option through the legacy QemuOpts-based inet_parse() path so
> that URI-style users (-incoming tcp:, migrate tcp:, HMP
> nbd_server_start, ...) can set it too.
>
> Update the documentation for -netdev stream (addr.user-timeout=N) and
> -incoming tcp: (user-timeout=N, flat key as for the other inet_opts
> entries), and extend test_inet_parse_all_options_good accordingly.
>
> Signed-off-by: Mitsuru Kariya <Mitsuru.Kariya@oss.nttdata.com>
> ---
> meson.build | 2 ++
> qapi/sockets.json | 7 +++++++
> qemu-options.hx | 13 +++++++++----
> tests/unit/test-util-sockets.c | 13 +++++++++++++
> util/qemu-sockets.c | 24 ++++++++++++++++++++++++
> 5 files changed, 55 insertions(+), 4 deletions(-)
>
> diff --git a/meson.build b/meson.build
> index eb07491819..c5afe8754d 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -2726,6 +2726,8 @@ config_host_data.set('HAVE_TCP_KEEPINTVL',
> #endif
> int main(void) { return 0; }''',
> name: 'Win32 TCP_KEEPINTVL'))
> +config_host_data.set('HAVE_TCP_USER_TIMEOUT',
> + cc.has_header_symbol('netinet/tcp.h', 'TCP_USER_TIMEOUT'))
>
> # has_member
> config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID',
> diff --git a/qapi/sockets.json b/qapi/sockets.json
> index 473be2ac58..543689a2c7 100644
> --- a/qapi/sockets.json
> +++ b/qapi/sockets.json
> @@ -79,6 +79,12 @@
> # defined (this includes Linux, Windows, macOS, FreeBSD, but not
> # OpenBSD). When set to 0, system setting is used. (Since 10.1)
> #
> +# @user-timeout: time in milliseconds that transmitted data may remain
> +# unacknowledged before the connection is closed. Only supported
> +# for TCP sockets on systems where TCP_USER_TIMEOUT socket option
> +# is defined (Linux only). When set to 0, system setting is used.
> +# (Since 11.1)
> +#
Actually, it's "transmitted data may remain unacknowledged, or buffered
data may remain untransmitted". Moreover, the interaction with
@keep-alive is not mentioned. We want to keep the description
reasonably short, though. Have it point to tcp(7) for details?
Perhaps something like
# @user-timeout: time in milliseconds that transmitted data may remain
# unacknowledged, or buffered data may remain untransmitted before
# the connection is closed. See tcp(7) for details. Only
# supported when the host provides socket option TCP_USER_TIMEOUT
# (Linux). 0 means system default. (default 0) (since 11.1)
What do you think?
> # @mptcp: enable multi-path TCP. (Since 6.1)
> #
> # Since: 1.3
> @@ -94,6 +100,7 @@
> '*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' },
> + '*user-timeout': { 'type': 'uint32', 'if': 'HAVE_TCP_USER_TIMEOUT' },
> '*mptcp': { 'type': 'bool', 'if': 'HAVE_IPPROTO_MPTCP' } } }
>
> ##
> diff --git a/qemu-options.hx b/qemu-options.hx
> index d2b816e16f..63587cccd3 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -3034,7 +3034,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
> "-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
> " configure a network backend to connect to another network\n"
> " using an UDP tunnel\n"
> - "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
> + "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.user-timeout=timeout][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]\n"
> "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,addr.abstract=on|off][,addr.tight=on|off][,reconnect-ms=milliseconds]\n"
> "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect-ms=milliseconds]\n"
> " configure a network backend to connect to another network\n"
> @@ -3640,7 +3640,7 @@ SRST
> -device e1000,netdev=n1,mac=52:54:00:12:34:56 \\
> -netdev socket,id=n1,mcast=239.192.168.1:1102,localaddr=1.2.3.4
>
> -``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
> +``-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,addr.to=maxport][,addr.numeric=on|off][,addr.keep-alive=on|off][,addr.keep-alive-count=count][,addr.keep-alive-idle=idle][,addr.keep-alive-interval=interval][,addr.user-timeout=timeout][,addr.mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect-ms=milliseconds]``
> Configure a network backend to connect to another QEMU virtual machine or a proxy using a TCP/IP socket.
>
> ``server=on|off``
> @@ -3670,6 +3670,11 @@ SRST
> time in seconds between individual keep-alive packets.
> Set to 0 to use the system default. (default: 0)
>
> + ``addr.user-timeout=timeout``
> + time in milliseconds that transmitted data may remain unacknowledged
> + before the connection is forcibly closed.
> + Set to 0 to use the system default. (default: 0)
> +
If you improve the description in net.json, update this one to match it.
> ``addr.mptcp=on|off``
> enable multipath TCP
>
> @@ -5365,7 +5370,7 @@ SRST
> ERST
>
> DEF("incoming", HAS_ARG, QEMU_OPTION_incoming, \
> - "-incoming tcp:[host]:port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,keep-alive-count=count][,keep-alive-idle=idle][,keep-alive-interval=interval][,mptcp=on|off][,ipv4=on|off][,ipv6=on|off]\n" \
> + "-incoming tcp:[host]:port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,keep-alive-count=count][,keep-alive-idle=idle][,keep-alive-interval=interval][,user-timeout=timeout][,mptcp=on|off][,ipv4=on|off][,ipv6=on|off]\n" \
> "-incoming rdma:host:port[,ipv4=on|off][,ipv6=on|off]\n" \
> "-incoming unix:socketpath\n" \
> " prepare for incoming migration, listen on\n" \
> @@ -5387,7 +5392,7 @@ migration channel types. The channel type is specified in <channel>,
> or is 'main' for all other forms of -incoming. If multiple -incoming
> options are specified for a channel type, the last one takes precedence.
>
> -``-incoming tcp:[host]:port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,keep-alive-count=count][,keep-alive-idle=idle][,keep-alive-interval=interval][,mptcp=on|off][,ipv4=on|off][,ipv6=on|off]``
> +``-incoming tcp:[host]:port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,keep-alive-count=count][,keep-alive-idle=idle][,keep-alive-interval=interval][,user-timeout=timeout][,mptcp=on|off][,ipv4=on|off][,ipv6=on|off]``
> \
> ``-incoming rdma:host:port[,ipv4=on|off][,ipv6=on|off]``
> Prepare for incoming migration, listen on a given tcp port.
[...]
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-06-02 4:55 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-24 7:34 [PATCH 0/5] socket: add TCP_USER_TIMEOUT, fix -netdev stream option docs Mitsuru Kariya
2026-05-24 7:34 ` [PATCH 1/5] qemu-options: fix missing addr. prefix on -netdev stream inet/unix options Mitsuru Kariya
2026-06-02 4:33 ` Markus Armbruster
2026-05-24 7:34 ` [PATCH 2/5] qemu-options: document keep-alive-count/idle/interval for -netdev stream Mitsuru Kariya
2026-06-02 4:38 ` Markus Armbruster
2026-05-24 7:34 ` [PATCH 3/5] qemu-options: document keep-alive*/numeric/mptcp for -incoming tcp: Mitsuru Kariya
2026-05-24 7:34 ` [PATCH 4/5] util/qemu-sockets: add TCP_USER_TIMEOUT support Mitsuru Kariya
2026-06-02 4:54 ` Markus Armbruster
2026-05-24 7:34 ` [PATCH 5/5] tests/qtest/netdev-socket: smoke test -netdev stream inet option set Mitsuru Kariya
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.