From: Laurent Vivier <lvivier@redhat.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: qemu-devel@nongnu.org, "Eric Blake" <eblake@redhat.com>,
"Dr. David Alan Gilbert" <dgilbert@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Daniel P. Berrangé" <berrange@redhat.com>,
"Jason Wang" <jasowang@redhat.com>
Subject: Re: [RFC PATCH v3 03/11] qapi: net: introduce a way to bypass qemu_opts_parse_noisily()
Date: Mon, 20 Jun 2022 15:46:29 +0200 [thread overview]
Message-ID: <e6bed870-8b6f-48a7-dd59-0e2477738319@redhat.com> (raw)
In-Reply-To: <87ilov1p54.fsf@pond.sub.org>
On 20/06/2022 14:43, Markus Armbruster wrote:
> Laurent Vivier <lvivier@redhat.com> writes:
>
>> As qemu_opts_parse_noisily() flattens the QAPI structures ("type" field
>> of Netdev structure can collides with "type" field of SocketAddress),
>> we introduce a way to bypass qemu_opts_parse_noisily() and use directly
>> visit_type_Netdev() to parse the backend parameters.
>>
>> More details from Markus:
>>
>> qemu_init() passes the argument of -netdev, -nic, and -net to
>> net_client_parse().
>>
>> net_client_parse() parses with qemu_opts_parse_noisily(), passing
>> QemuOptsList qemu_netdev_opts for -netdev, qemu_nic_opts for -nic, and
>> qemu_net_opts for -net. Their desc[] are all empty, which means any
>> keys are accepted. The result of the parse (a QemuOpts) is stored in
>> the QemuOptsList.
>>
>> Note that QemuOpts is flat by design. In some places, we layer non-flat
>> on top using dotted keys convention, but not here.
>>
>> net_init_clients() iterates over the stored QemuOpts, and passes them to
>> net_init_netdev(), net_param_nic(), or net_init_client(), respectively.
>>
>> These functions pass the QemuOpts to net_client_init(). They also do
>> other things with the QemuOpts, which we can ignore here.
>>
>> net_client_init() uses the opts visitor to convert the (flat) QemOpts to
>> a (non-flat) QAPI object Netdev. Netdev is also the argument of QMP
>> command netdev_add.
>>
>> The opts visitor was an early attempt to support QAPI in
>> (QemuOpts-based) CLI. It restricts QAPI types to a certain shape; see
>> commit eb7ee2cbeb "qapi: introduce OptsVisitor".
>>
>> A more modern way to support QAPI is qobject_input_visitor_new_str().
>> It uses keyval_parse() instead of QemuOpts for KEY=VALUE,... syntax, and
>> it also supports JSON syntax. The former isn't quite as expressive as
>> JSON, but it's a lot closer than QemuOpts + opts visitor.
>>
>> This commit paves the way to use of the modern way instead.
>>
>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
>> ---
>> include/net/net.h | 1 +
>> net/net.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++
>> softmmu/vl.c | 3 ++-
>> 3 files changed, 63 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/net/net.h b/include/net/net.h
>> index c53c64ac18c4..4ae8ed480f73 100644
>> --- a/include/net/net.h
>> +++ b/include/net/net.h
>> @@ -214,6 +214,7 @@ extern NICInfo nd_table[MAX_NICS];
>> extern const char *host_net_devices[];
>>
>> /* from net.c */
>> +int netdev_parse_modern(const char *optarg);
>> int net_client_parse(QemuOptsList *opts_list, const char *str);
>> void show_netdevs(void);
>> void net_init_clients(void);
>> diff --git a/net/net.c b/net/net.c
>> index 15958f881776..c337d3d753fe 100644
>> --- a/net/net.c
>> +++ b/net/net.c
>> @@ -54,6 +54,7 @@
>> #include "net/colo-compare.h"
>> #include "net/filter.h"
>> #include "qapi/string-output-visitor.h"
>> +#include "qapi/qobject-input-visitor.h"
>>
>> /* Net bridge is currently not supported for W32. */
>> #if !defined(_WIN32)
>> @@ -63,6 +64,16 @@
>> static VMChangeStateEntry *net_change_state_entry;
>> static QTAILQ_HEAD(, NetClientState) net_clients;
>>
>> +typedef struct NetdevQueueEntry {
>> + Netdev *nd;
>> + Location loc;
>> + QSIMPLEQ_ENTRY(NetdevQueueEntry) entry;
>> +} NetdevQueueEntry;
>> +
>> +typedef QSIMPLEQ_HEAD(, NetdevQueueEntry) NetdevQueue;
>> +
>> +static NetdevQueue nd_queue = QSIMPLEQ_HEAD_INITIALIZER(nd_queue);
>> +
>> /***********************************************************/
>> /* network device redirectors */
>>
>> @@ -1562,6 +1573,20 @@ out:
>> return ret;
>> }
>>
>> +static void netdev_init_modern(void)
>> +{
>> + while (!QSIMPLEQ_EMPTY(&nd_queue)) {
>> + NetdevQueueEntry *nd = QSIMPLEQ_FIRST(&nd_queue);
>> +
>> + QSIMPLEQ_REMOVE_HEAD(&nd_queue, entry);
>> + loc_push_restore(&nd->loc);
>> + net_client_init1(nd->nd, true, &error_fatal);
>> + loc_pop(&nd->loc);
>> + qapi_free_Netdev(nd->nd);
>> + g_free(nd);
>> + }
>> +}
>> +
>> void net_init_clients(void)
>> {
>> net_change_state_entry =
>> @@ -1569,6 +1594,8 @@ void net_init_clients(void)
>>
>> QTAILQ_INIT(&net_clients);
>>
>> + netdev_init_modern();
>> +
>> qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL,
>> &error_fatal);
>>
>> @@ -1579,6 +1606,39 @@ void net_init_clients(void)
>> &error_fatal);
>> }
>>
>> +/*
>> + * netdev_is_modern() returns true when the backend needs to bypass
>> + * qemu_opts_parse_noisily()
>> + */
>> +static bool netdev_is_modern(const char *optarg)
>> +{
>> + return false;
>> +}
>> +
>> +/*
>> + * netdev_parse_modern() uses modern, more expressive syntax than
>> + * net_client_parse(), supports only the netdev option.
>> + */
>> +int netdev_parse_modern(const char *optarg)
>> +{
>> + Visitor *v;
>> + NetdevQueueEntry *nd;
>> +
>> + if (!netdev_is_modern(optarg)) {
>> + return -1;
>> + }
>> +
>> + v = qobject_input_visitor_new_str(optarg, "type", &error_fatal);
>> + nd = g_new(NetdevQueueEntry, 1);
>> + visit_type_Netdev(v, NULL, &nd->nd, &error_fatal);
>> + visit_free(v);
>> + loc_save(&nd->loc);
>> +
>> + QSIMPLEQ_INSERT_TAIL(&nd_queue, nd, entry);
>> +
>> + return 0;
>> +}
>> +
>> int net_client_parse(QemuOptsList *opts_list, const char *optarg)
>> {
>> if (!qemu_opts_parse_noisily(opts_list, optarg, true)) {
>> diff --git a/softmmu/vl.c b/softmmu/vl.c
>> index 8eed0f31c073..838f5b48c447 100644
>> --- a/softmmu/vl.c
>> +++ b/softmmu/vl.c
>> @@ -2839,7 +2839,8 @@ void qemu_init(int argc, char **argv, char **envp)
>> break;
>> case QEMU_OPTION_netdev:
>> default_net = 0;
>> - if (net_client_parse(qemu_find_opts("netdev"), optarg) == -1) {
>> + if (netdev_parse_modern(optarg) == -1 &&
>> + net_client_parse(qemu_find_opts("netdev"), optarg) == -1) {
>> exit(1);
>> }
>> break;
>
> To make this work, netdev_parse_modern() must
>
> * either succeeed, or
>
> * fail without reporting an error, or
>
> * report an error and exit()
>
> Recommend to spell that out in its function comment.
>
> Alternatively:
>
> if (netdev_is_modern(optarg)) {
> netdev_parse_modern(optarg);
> } else {
> if (net_client_parse(qemu_find_opts("netdev"), optarg) == -1) {
> exit(1);
> }
> }
>
> netdev_is_modern() needs external linkage, and netdev_parse_modern()
> loses its return value.
>
> Note that all callers net_client_parse() handle failure exactly the same
> way. If we let net_client_parse() exit(), then this becomes
>
> if (netdev_is_modern(optarg)) {
> netdev_parse_modern(optarg);
> } else {
> net_client_parse(qemu_find_opts("netdev"), optarg);
> }
>
> I like this one best. What do you think?
>
Me too.
I wanted to have only entry point in net.c it's why I didn't export netdev_is_modern() but
I think it's better to export it not to mix error return (parse has failed) and checking
result (is modern or not).
And I agree it's more consistent to have both parse functions behaving in the same way
(exit or not exit...).
I update the patch in that way.
Thanks,
Laurent
next prev parent reply other threads:[~2022-06-20 13:48 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-06-20 10:18 [RFC PATCH v3 00/11] qapi: net: add unix socket type support to netdev backend Laurent Vivier
2022-06-20 10:18 ` [RFC PATCH v3 01/11] net: introduce convert_host_port() Laurent Vivier
2022-06-20 10:18 ` [RFC PATCH v3 02/11] net: remove the @errp argument of net_client_inits() Laurent Vivier
2022-06-20 11:39 ` Markus Armbruster
2022-06-20 10:18 ` [RFC PATCH v3 03/11] qapi: net: introduce a way to bypass qemu_opts_parse_noisily() Laurent Vivier
2022-06-20 12:43 ` Markus Armbruster
2022-06-20 13:46 ` Laurent Vivier [this message]
2022-06-22 8:00 ` Markus Armbruster
2022-06-20 10:18 ` [RFC PATCH v3 04/11] qapi: net: add stream and dgram netdevs Laurent Vivier
2022-06-20 15:21 ` Markus Armbruster
2022-06-20 17:52 ` Laurent Vivier
2022-06-21 8:49 ` Markus Armbruster
2022-06-21 19:27 ` Laurent Vivier
2022-06-22 11:47 ` Markus Armbruster
2022-06-22 16:18 ` Laurent Vivier
2022-06-23 12:49 ` Markus Armbruster
2022-06-20 10:18 ` [RFC PATCH v3 05/11] net: stream: Don't ignore EINVAL on netdev socket connection Laurent Vivier
2022-06-20 10:18 ` [RFC PATCH v3 06/11] net: stream: add unix socket Laurent Vivier
2022-06-20 10:18 ` [RFC PATCH v3 07/11] net: dgram: make dgram_dst generic Laurent Vivier
2022-06-20 10:18 ` [RFC PATCH v3 08/11] net: dgram: move mcast specific code from net_socket_fd_init_dgram() Laurent Vivier
2022-06-20 10:18 ` [RFC PATCH v3 09/11] net: dgram: add unix socket Laurent Vivier
2022-06-20 10:18 ` [RFC PATCH v3 10/11] qemu-sockets: introduce socket_uri() Laurent Vivier
2022-06-20 10:18 ` [RFC PATCH v3 11/11] net: stream: move to QIO Laurent Vivier
2022-06-20 18:24 ` [RFC PATCH v3 00/11] qapi: net: add unix socket type support to netdev backend Dr. David Alan Gilbert
2022-06-21 9:51 ` Laurent Vivier
2022-06-21 10:31 ` Dr. David Alan Gilbert
2022-06-21 10:54 ` Daniel P. Berrangé
2022-06-21 12:16 ` Dr. David Alan Gilbert
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=e6bed870-8b6f-48a7-dd59-0e2477738319@redhat.com \
--to=lvivier@redhat.com \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=dgilbert@redhat.com \
--cc=eblake@redhat.com \
--cc=jasowang@redhat.com \
--cc=pbonzini@redhat.com \
--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).