qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
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



  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).