From: Eric Blake <eblake@redhat.com>
To: Markus Armbruster <armbru@redhat.com>, qemu-devel@nongnu.org
Cc: kwolf@redhat.com, marcandre.lureau@redhat.com,
qemu-block@nongnu.org, pbonzini@redhat.com
Subject: Re: [PATCH 3/4] char: Flat alternative to overly nested chardev-add arguments
Date: Tue, 27 Oct 2020 13:23:13 -0500 [thread overview]
Message-ID: <df6a32e6-3b4c-d9d7-b473-9bdd7c674843@redhat.com> (raw)
In-Reply-To: <20201026101005.2940615-4-armbru@redhat.com>
On 10/26/20 5:10 AM, Markus Armbruster wrote:
> chardev-add's arguments use an annoying amount of nesting. Example:
>
> {"execute": "chardev-add",
> "arguments": {
> "id":"sock0",
> "backend": {
> "type": "socket",
> "data": {
> "addr": {
> "type": "inet",
> "data": {
> "host": "0.0.0.0",
> "port": "2445"}}}}}}
>
> This is because chardev-add predates QAPI features that enable flatter
> data structures, both on the wire and in C: base types, flat unions,
> commands taking a union or alternate as 'data'.
>
> The nesting would be even more annoying in dotted key syntax:
>
> id=sock0,\
> backend.type=socket,\
> backend.data.addr.type=inet,\
> backend.data.addr.data.host=0.0.0.0,\
> backend.data.addr.data.port=2445
>
> Relevant, because the next commit will QAPIfy qemu-storage-daemon
> --chardev. We really want this instead:
>
> --chardev socket,id=sock0,\
> addr.type=inet,\
> addr.host=0.0.0.0,\
> addr.port=2445
>
> To get it, define a new QAPI type ChardevOptions that is the flat
> equivalent to chardev-add's arguments.
>
> What we should do now is convert the internal interfaces to take this
> new type, and limit the nested old type to the external interface,
> similar to what commit bd269ebc82 "sockets: Limit SocketAddressLegacy
> to external interfaces" did. But we're too close to the freeze to
> pull that off safely.
>
> What I can do now is convert the new type to the old nested type, and
> promise to replace this by what should be done in the next development
> cycle.
Nice evaluation of the trade-off.
>
> In more detail:
>
> * Flat union ChardevOptions corresponds to chardev-add's implicit
> arguments type. It flattens a struct containing a simple union into
> a flat union.
>
> * The flat union's discriminator is named @backend, not @type. This
> avoids clashing with member @type of ChardevSpiceChannel. For what
> it's worth, -chardev also uses this name.
>
> * Its branches @socket, @udp use ChardevSocketFlat, ChardevUdpFlat
> instead of ChardevSocket, ChardevUdp. This flattens simple union
> SocketAddressLegacy members to flat union SocketAddress members.
>
> * New chardev_options_crumple() converts ChardevOptions to
> chardev-add's implict arguments type.
implicit
>
> Only one existing QAPI definition is affected: some of ChardevSocket's
> members get moved to a new base type ChardevSocketBase, to reduce
> duplication. No change to the generated C type and the wire format.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
> qapi/char.json | 106 ++++++++++++++++++++++++++++---
> include/chardev/char.h | 5 ++
> include/qemu/sockets.h | 3 +
> chardev/char-legacy.c | 140 +++++++++++++++++++++++++++++++++++++++++
> chardev/char-socket.c | 3 +-
> util/qemu-sockets.c | 38 +++++++++++
> chardev/meson.build | 1 +
> 7 files changed, 287 insertions(+), 9 deletions(-)
> create mode 100644 chardev/char-legacy.c
Big but worth it. I'm liking the simplicity of this alternative over
Kevin's proposal, especially if we're aiming to get this in 5.2 soft freeze.
>
> diff --git a/qapi/char.json b/qapi/char.json
> index 43486d1daa..31b693bbb2 100644
> --- a/qapi/char.json
> +++ b/qapi/char.json
> @@ -244,12 +244,8 @@
> 'base': 'ChardevCommon' }
>
> ##
> -# @ChardevSocket:
> +# @ChardevSocketBase:
> #
> -# Configuration info for (stream) socket chardevs.
> -#
> -# @addr: socket address to listen on (server=true)
> -# or connect to (server=false)
> # @tls-creds: the ID of the TLS credentials object (since 2.6)
> # @tls-authz: the ID of the QAuthZ authorization object against which
> # the client's x509 distinguished name will be validated. This
> @@ -274,9 +270,8 @@
> #
> # Since: 1.4
> ##
> -{ 'struct': 'ChardevSocket',
> - 'data': { 'addr': 'SocketAddressLegacy',
> - '*tls-creds': 'str',
> +{ 'struct': 'ChardevSocketBase',
> + 'data': { '*tls-creds': 'str',
> '*tls-authz' : 'str',
> '*server': 'bool',
> '*wait': 'bool',
> @@ -287,6 +282,35 @@
> '*reconnect': 'int' },
> 'base': 'ChardevCommon' }
Here we are subdividing ChardevSocket into everything that is already
flat, and excluding the awkward 'addr'...
>
> +##
> +# @ChardevSocket:
> +#
> +# Configuration info for (stream) socket chardevs.
> +#
> +# @addr: socket address to listen on (server=true)
> +# or connect to (server=false)
> +#
> +# Since: 1.4
> +##
> +{ 'struct': 'ChardevSocket',
> + # Do not add to 'data', it breaks chardev_options_crumple()! Add to
> + # ChardevSocketBase's 'data' instead.
> + 'data': { 'addr': 'SocketAddressLegacy' },
> + 'base': 'ChardevSocketBase' }
...legacy use pulls in the legacy 'addr'...
> +
> +##
> +# @ChardevSocketFlat:
> +#
> +# Note: This type should eventually replace ChardevSocket. The
> +# difference between the two: ChardevSocketFlat uses
> +# SocketAddressLegacy, ChardevSocket uses SocketAddress.
> +##
Missing a 'Since: 5.2' tag, if you want one.
> +{ 'struct': 'ChardevSocketFlat',
> + # Do not add to 'data', it breaks chardev_options_crumple()! Add to
> + # ChardevSocketBase's 'data' instead.
> + 'data': { 'addr': 'SocketAddress' },
> + 'base': 'ChardevSocketBase' }
> +
...and this is the new type with a saner 'addr'. Works for me so far.
> ##
> # @ChardevUdp:
> #
> @@ -298,10 +322,26 @@
> # Since: 1.5
> ##
> { 'struct': 'ChardevUdp',
> + # Do not add to 'data', it breaks chardev_options_crumple()! Create
> + # ChardevUdpBase instead, similar to ChardevSocketBase.
> 'data': { 'remote': 'SocketAddressLegacy',
> '*local': 'SocketAddressLegacy' },
> 'base': 'ChardevCommon' }
>
> +##
> +# @ChardevUdpFlat:
> +#
> +# Note: This type should eventually replace ChardevUdp. The
> +# difference between the two: ChardevUdpFlat uses
> +# SocketAddressLegacy, ChardevUdp uses SocketAddress.
> +##
Another missing 'Since: 5.2'
> +{ 'struct': 'ChardevUdpFlat',
> + # Do not add to 'data', it breaks chardev_options_crumple()! Create
> + # ChardevUdpBase instead, similar to ChardevSocketBase.
> + 'data': { 'remote': 'SocketAddress',
> + '*local': 'SocketAddress' },
> + 'base': 'ChardevCommon' }
> +
> ##
> # @ChardevMux:
> #
> @@ -422,6 +462,56 @@
> # next one is just for compatibility
> 'memory': 'ChardevRingbuf' } }
>
> +##
> +# @ChardevBackendType:
> +#
> +# Since: 5.2
> +##
> +{ 'enum': 'ChardevBackendType',
> +
> + 'data': [ 'file', 'serial', 'parallel', 'pipe', 'socket', 'udp',
> + 'pty', 'null', 'mux', 'msmouse', 'wctablet', 'braille',
> + 'testdev', 'stdio', 'console', 'spicevmc', 'spiceport',
> + 'vc', 'ringbuf' ] }
> +
> +##
> +# @ChardevOptions:
> +#
> +# Note: This type should eventually replace the implicit arguments
> +# type of chardev-add and chardev-chardev. The differences
> +# between the two: 1. ChardevSocketOptions is a flat union
> +# rather than a struct with a simple union member, and 2. it
> +# uses SocketAddress instead of SocketAddressLegacy. This
> +# avoids nesting on the wire, i.e. we need fewer {}.
> +#
> +# Since: 5.2
> +##
> +{ 'union': 'ChardevOptions',
> + 'base': { 'backend': 'ChardevBackendType',
> + 'id': 'str' },
> + 'discriminator': 'backend',
> + 'data': { 'file': 'ChardevFile',
> + 'serial': 'ChardevHostdev',
> + 'parallel': 'ChardevHostdev',
> + 'pipe': 'ChardevHostdev',
> + 'socket': 'ChardevSocketFlat',
> + 'udp': 'ChardevUdpFlat',
> + 'pty': 'ChardevCommon',
> + 'null': 'ChardevCommon',
> + 'mux': 'ChardevMux',
> + 'msmouse': 'ChardevCommon',
> + 'wctablet': 'ChardevCommon',
> + 'braille': 'ChardevCommon',
> + 'testdev': 'ChardevCommon',
> + 'stdio': 'ChardevStdio',
> + 'console': 'ChardevCommon',
> + 'spicevmc': { 'type': 'ChardevSpiceChannel',
> + 'if': 'defined(CONFIG_SPICE)' },
> + 'spiceport': { 'type': 'ChardevSpicePort',
> + 'if': 'defined(CONFIG_SPICE)' },
> + 'vc': 'ChardevVC',
> + 'ringbuf': 'ChardevRingbuf' } }
Looks good from the QAPI point of view.
> +/*
> + * TODO Convert internal interfaces to ChardevOptions, replace this
> + * function by one that flattens (const char *str, ChardevBackend
> + * *backend) -> ChardevOptions.
> + */
> +q_obj_chardev_add_arg *chardev_options_crumple(ChardevOptions *chr)
> +{
> + q_obj_chardev_add_arg *arg;
> + ChardevBackend *be;
> +
> + if (!chr) {
> + return NULL;
> + }
> +
> + arg = g_malloc(sizeof(*arg));
> + arg->id = g_strdup(chr->id);
> + arg->backend = be = g_malloc(sizeof(*be));
> +
> + switch (chr->backend) {
> + case CHARDEV_BACKEND_TYPE_FILE:
> + be->type = CHARDEV_BACKEND_KIND_FILE;
> + be->u.file.data = QAPI_CLONE(ChardevFile, &chr->u.file);
> + break;
Most branches are straightforward,...
> + case CHARDEV_BACKEND_TYPE_SOCKET:
> + be->type = CHARDEV_BACKEND_KIND_SOCKET;
> + /*
> + * Clone with SocketAddress crumpled to SocketAddressLegacy.
> + * All other members are in the base type.
> + */
> + be->u.socket.data = g_memdup(&chr->u.socket, sizeof(chr->u.socket));
> + QAPI_CLONE_MEMBERS(ChardevSocketBase,
> + qapi_ChardevSocket_base(be->u.socket.data),
> + qapi_ChardevSocketFlat_base(&chr->u.socket));
> + be->u.socket.data->addr = socket_address_crumple(chr->u.socket.addr);
> + break;
...and this looks correct as well.
> +++ b/chardev/char-socket.c
> @@ -1404,7 +1404,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
>
> backend->type = CHARDEV_BACKEND_KIND_SOCKET;
> sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
> - qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
> + qemu_chr_parse_common(opts,
> + qapi_ChardevSocketBase_base(qapi_ChardevSocket_base(sock)));
The double function call (for a double cast) looks unusual, but I don't
see any shorter expression, so it is fine.
Reviewed-by: Eric Blake <eblake@redhat.com>
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
next prev parent reply other threads:[~2020-10-27 18:37 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-10-26 10:10 [PATCH 0/4] qemu-storage-daemon: QAPIfy --chardev the stupid way Markus Armbruster
2020-10-26 10:10 ` [PATCH 1/4] char/stdio: Fix QMP default for 'signal' Markus Armbruster
2020-10-26 10:10 ` [PATCH 2/4] char: Factor out qemu_chr_print_types() Markus Armbruster
2020-10-26 10:10 ` [PATCH 3/4] char: Flat alternative to overly nested chardev-add arguments Markus Armbruster
2020-10-27 18:23 ` Eric Blake [this message]
2020-10-28 7:33 ` Markus Armbruster
2020-10-26 10:10 ` [PATCH 4/4] qemu-storage-daemon: QAPIfy --chardev Markus Armbruster
2020-10-27 18:59 ` Eric Blake
2020-10-28 7:42 ` Markus Armbruster
2020-10-28 9:18 ` Markus Armbruster
2020-10-27 18:36 ` [PATCH 0/4] qemu-storage-daemon: QAPIfy --chardev the stupid way Paolo Bonzini
2020-10-28 7:01 ` Markus Armbruster
2020-10-28 11:46 ` Kevin Wolf
2020-10-28 14:39 ` Paolo Bonzini
2020-10-28 14:59 ` Kevin Wolf
2020-10-28 15:09 ` Paolo Bonzini
2020-10-28 15:39 ` Kevin Wolf
2020-10-28 16:01 ` Paolo Bonzini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=df6a32e6-3b4c-d9d7-b473-9bdd7c674843@redhat.com \
--to=eblake@redhat.com \
--cc=armbru@redhat.com \
--cc=kwolf@redhat.com \
--cc=marcandre.lureau@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).