qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F)
@ 2015-12-23 20:55 Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 01/16] net: use Netdev instead of NetClientOptions in client init Eric Blake
                   ` (16 more replies)
  0 siblings, 17 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru

Prerequisites:
+ my qapi cleanups subset E v8:
https://lists.gnu.org/archive/html/qemu-devel/2015-12/msg03863.html

This is the final subset of my original cleanups series v5.
The focus here is adding a 'box':true parameter and anonymous
flat union base syntax, so that we can finally represent
netdev_add as a full-fledged qapi command that shows up in
introspection rather than as a magic command with undocumented
arguments.

v6 notes:
Rebase, since there are several other series that want features
from this subset.

Backport diffstat:

001/16:[0096] [FC] 'net: use Netdev instead of NetClientOptions in client init'
002/16:[0021] [FC] 'qapi: Avoid use of 'data' member of qapi unions'
003/16:[0010] [FC] 'qapi: Forbid empty unions and useless alternates'
004/16:[0014] [FC] 'qapi: Drop useless 'data' member of unions'
005/16:[0017] [FC] 'qapi: Hide tag_name data member of variants'
006/16:[0049] [FC] 'qapi: Plumb in 'box' to qapi generator lower levels'
007/16:[down] 'qapi: Implement boxed types for commands/events'
008/16:[0008] [FC] 'qapi: support implicit structs in OptsVisitor'
009/16:[0092] [FC] 'qapi: Change Netdev into a flat union'
010/16:[----] [-C] 'net: Use correct type for bool flag'
011/16:[0023] [FC] 'net: Complete qapi-fication of netdev_add'
012/16:[0049] [FC] 'qapi: Allow anonymous base for flat union'
013/16:[down] 'qapi: Use anonymous base in SchemaInfo'
014/16:[down] 'qapi: Use anonymous base in Netdev'
015/16:[down] 'qapi: Use anonymous base in CpuInfo'
016/16:[down] 'qapi: Populate info['name'] for each entity'

v5 notes:
https://lists.gnu.org/archive/html/qemu-devel/2015-09/msg05410.html
see the archives for more

Eric Blake (13):
  qapi: Avoid use of 'data' member of qapi unions
  qapi: Forbid empty unions and useless alternates
  qapi: Drop useless 'data' member of unions
  qapi: Hide tag_name data member of variants
  qapi: Plumb in 'box' to qapi generator lower levels
  qapi: Implement boxed types for commands/events
  net: Use correct type for bool flag
  net: Complete qapi-fication of netdev_add
  qapi: Allow anonymous base for flat union
  qapi: Use anonymous base in SchemaInfo
  qapi: Use anonymous base in Netdev
  qapi: Use anonymous base in CpuInfo
  qapi: Populate info['name'] for each entity

Kővágó, Zoltán (3):
  net: use Netdev instead of NetClientOptions in client init
  qapi: support implicit structs in OptsVisitor
  qapi: Change Netdev into a flat union

 blockdev.c                                         |  31 ++--
 docs/qapi-code-gen.txt                             |  67 ++++++---
 hw/arm/musicpal.c                                  |   2 +-
 hw/core/qdev-properties-system.c                   |   2 +-
 hw/net/allwinner_emac.c                            |   2 +-
 hw/net/cadence_gem.c                               |   2 +-
 hw/net/dp8393x.c                                   |   2 +-
 hw/net/e1000.c                                     |   2 +-
 hw/net/eepro100.c                                  |   2 +-
 hw/net/etraxfs_eth.c                               |   2 +-
 hw/net/fsl_etsec/etsec.c                           |   2 +-
 hw/net/imx_fec.c                                   |   2 +-
 hw/net/lan9118.c                                   |   2 +-
 hw/net/lance.c                                     |   2 +-
 hw/net/mcf_fec.c                                   |   2 +-
 hw/net/milkymist-minimac2.c                        |   2 +-
 hw/net/mipsnet.c                                   |   2 +-
 hw/net/ne2000-isa.c                                |   2 +-
 hw/net/ne2000.c                                    |   2 +-
 hw/net/opencores_eth.c                             |   2 +-
 hw/net/pcnet-pci.c                                 |   2 +-
 hw/net/rocker/rocker_fp.c                          |   2 +-
 hw/net/rtl8139.c                                   |   2 +-
 hw/net/smc91c111.c                                 |   2 +-
 hw/net/spapr_llan.c                                |   2 +-
 hw/net/stellaris_enet.c                            |   2 +-
 hw/net/vhost_net.c                                 |  16 +-
 hw/net/virtio-net.c                                |  10 +-
 hw/net/vmxnet3.c                                   |   2 +-
 hw/net/xen_nic.c                                   |   2 +-
 hw/net/xgmac.c                                     |   2 +-
 hw/net/xilinx_axienet.c                            |   2 +-
 hw/net/xilinx_ethlite.c                            |   2 +-
 hw/usb/dev-network.c                               |   4 +-
 include/net/net.h                                  |   7 +-
 monitor.c                                          |  14 +-
 net/clients.h                                      |  20 +--
 net/dump.c                                         |   8 +-
 net/hub.c                                          |  24 +--
 net/l2tpv3.c                                       |   8 +-
 net/net.c                                          | 161 +++++++++++++--------
 net/netmap.c                                       |   6 +-
 net/slirp.c                                        |   8 +-
 net/socket.c                                       |  10 +-
 net/tap-win32.c                                    |   8 +-
 net/tap.c                                          |  28 ++--
 net/vde.c                                          |   8 +-
 net/vhost-user.c                                   |  20 +--
 qapi-schema.json                                   |  82 ++++++-----
 qapi/introspect.json                               |  12 +-
 qapi/opts-visitor.c                                |  15 ++
 qmp-commands.hx                                    |   2 +-
 scripts/qapi-commands.py                           |  75 ++++++----
 scripts/qapi-event.py                              |  43 ++++--
 scripts/qapi-introspect.py                         |   4 +-
 scripts/qapi-types.py                              |  17 +--
 scripts/qapi-visit.py                              |  10 +-
 scripts/qapi.py                                    | 116 ++++++++++-----
 tests/Makefile                                     |   4 +-
 tests/qapi-schema/alternate-empty.err              |   1 +
 tests/qapi-schema/alternate-empty.exit             |   2 +-
 tests/qapi-schema/alternate-empty.json             |   2 +-
 tests/qapi-schema/alternate-empty.out              |   5 -
 tests/qapi-schema/args-bad-box.err                 |   1 +
 ...{flat-union-bad-base.exit => args-bad-box.exit} |   0
 tests/qapi-schema/args-bad-box.json                |   2 +
 .../{union-clash-data.err => args-bad-box.out}     |   0
 tests/qapi-schema/args-box-anon.err                |   1 +
 tests/qapi-schema/args-box-anon.exit               |   1 +
 tests/qapi-schema/args-box-anon.json               |   2 +
 .../{flat-union-bad-base.out => args-box-anon.out} |   0
 tests/qapi-schema/args-union.err                   |   2 +-
 tests/qapi-schema/args-union.json                  |   3 +-
 tests/qapi-schema/event-case.out                   |   1 +
 tests/qapi-schema/flat-union-bad-base.err          |   1 -
 tests/qapi-schema/flat-union-bad-base.json         |  13 --
 tests/qapi-schema/flat-union-empty.err             |   1 +
 tests/qapi-schema/flat-union-empty.exit            |   2 +-
 tests/qapi-schema/flat-union-empty.json            |   2 +-
 tests/qapi-schema/flat-union-empty.out             |  10 --
 tests/qapi-schema/ident-with-escape.out            |   2 +-
 tests/qapi-schema/indented-expr.out                |   4 +-
 tests/qapi-schema/qapi-schema-test.json            |  10 +-
 tests/qapi-schema/qapi-schema-test.out             |  47 ++++--
 tests/qapi-schema/test-qapi.py                     |  11 +-
 tests/qapi-schema/union-clash-data.exit            |   1 -
 tests/qapi-schema/union-clash-data.json            |   7 -
 tests/qapi-schema/union-clash-data.out             |  11 --
 tests/qapi-schema/union-empty.err                  |   1 +
 tests/qapi-schema/union-empty.exit                 |   2 +-
 tests/qapi-schema/union-empty.json                 |   2 +-
 tests/qapi-schema/union-empty.out                  |   7 -
 tests/test-qmp-commands.c                          |  12 ++
 ui/input.c                                         |   2 +-
 94 files changed, 604 insertions(+), 463 deletions(-)
 create mode 100644 tests/qapi-schema/args-bad-box.err
 rename tests/qapi-schema/{flat-union-bad-base.exit => args-bad-box.exit} (100%)
 create mode 100644 tests/qapi-schema/args-bad-box.json
 rename tests/qapi-schema/{union-clash-data.err => args-bad-box.out} (100%)
 create mode 100644 tests/qapi-schema/args-box-anon.err
 create mode 100644 tests/qapi-schema/args-box-anon.exit
 create mode 100644 tests/qapi-schema/args-box-anon.json
 rename tests/qapi-schema/{flat-union-bad-base.out => args-box-anon.out} (100%)
 delete mode 100644 tests/qapi-schema/flat-union-bad-base.err
 delete mode 100644 tests/qapi-schema/flat-union-bad-base.json
 delete mode 100644 tests/qapi-schema/union-clash-data.exit
 delete mode 100644 tests/qapi-schema/union-clash-data.json
 delete mode 100644 tests/qapi-schema/union-clash-data.out

-- 
2.4.3

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 01/16] net: use Netdev instead of NetClientOptions in client init
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 02/16] qapi: Avoid use of 'data' member of qapi unions Eric Blake
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel
  Cc: Michael S. Tsirkin, Jason Wang, armbru, Vincenzo Maffione,
	Kővágó, Zoltán, Giuseppe Lettieri,
	Luigi Rizzo

From: Kővágó, Zoltán <dirty.ice.hu@gmail.com>

This way we no longer need NetClientOptions and can convert Netdev
into a flat union.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <93ffdfed7054529635e6acb935150d95dc173a12.1441627176.git.DirtY.iCE.hu@gmail.com>

[rework net_client_init1() to pass Netdev by copying from NetdevLegacy,
rather than merging the two types; rebase to qapi changes]
Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: rebase
---
 net/clients.h    | 20 ++++++++++----------
 net/dump.c       |  6 +++---
 net/hub.c        |  6 +++---
 net/l2tpv3.c     |  6 +++---
 net/net.c        | 18 +++++++++++-------
 net/netmap.c     |  4 ++--
 net/slirp.c      |  6 +++---
 net/socket.c     |  6 +++---
 net/tap-win32.c  |  6 +++---
 net/tap.c        | 12 ++++++------
 net/vde.c        |  6 +++---
 net/vhost-user.c |  6 +++---
 12 files changed, 53 insertions(+), 49 deletions(-)

diff --git a/net/clients.h b/net/clients.h
index d47530e..5cae479 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -27,39 +27,39 @@
 #include "net/net.h"
 #include "qapi-types.h"

-int net_init_dump(const NetClientOptions *opts, const char *name,
+int net_init_dump(const Netdev *netdev, const char *name,
                   NetClientState *peer, Error **errp);

 #ifdef CONFIG_SLIRP
-int net_init_slirp(const NetClientOptions *opts, const char *name,
+int net_init_slirp(const Netdev *netdev, const char *name,
                    NetClientState *peer, Error **errp);
 #endif

-int net_init_hubport(const NetClientOptions *opts, const char *name,
+int net_init_hubport(const Netdev *netdev, const char *name,
                      NetClientState *peer, Error **errp);

-int net_init_socket(const NetClientOptions *opts, const char *name,
+int net_init_socket(const Netdev *netdev, const char *name,
                     NetClientState *peer, Error **errp);

-int net_init_tap(const NetClientOptions *opts, const char *name,
+int net_init_tap(const Netdev *netdev, const char *name,
                  NetClientState *peer, Error **errp);

-int net_init_bridge(const NetClientOptions *opts, const char *name,
+int net_init_bridge(const Netdev *netdev, const char *name,
                     NetClientState *peer, Error **errp);

-int net_init_l2tpv3(const NetClientOptions *opts, const char *name,
+int net_init_l2tpv3(const Netdev *netdev, const char *name,
                     NetClientState *peer, Error **errp);
 #ifdef CONFIG_VDE
-int net_init_vde(const NetClientOptions *opts, const char *name,
+int net_init_vde(const Netdev *netdev, const char *name,
                  NetClientState *peer, Error **errp);
 #endif

 #ifdef CONFIG_NETMAP
-int net_init_netmap(const NetClientOptions *opts, const char *name,
+int net_init_netmap(const Netdev *netdev, const char *name,
                     NetClientState *peer, Error **errp);
 #endif

-int net_init_vhost_user(const NetClientOptions *opts, const char *name,
+int net_init_vhost_user(const Netdev *netdev, const char *name,
                         NetClientState *peer, Error **errp);

 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/dump.c b/net/dump.c
index 3764a7c..b75b49a 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -177,7 +177,7 @@ static NetClientInfo net_dump_info = {
     .cleanup = dumpclient_cleanup,
 };

-int net_init_dump(const NetClientOptions *opts, const char *name,
+int net_init_dump(const Netdev *netdev, const char *name,
                   NetClientState *peer, Error **errp)
 {
     int len, rc;
@@ -187,8 +187,8 @@ int net_init_dump(const NetClientOptions *opts, const char *name,
     NetClientState *nc;
     DumpNetClient *dnc;

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_DUMP);
-    dump = opts->u.dump;
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_DUMP);
+    dump = netdev->opts->u.dump;

     assert(peer);

diff --git a/net/hub.c b/net/hub.c
index 9ae9f01..9a57905 100644
--- a/net/hub.c
+++ b/net/hub.c
@@ -280,14 +280,14 @@ int net_hub_id_for_client(NetClientState *nc, int *id)
     return 0;
 }

-int net_init_hubport(const NetClientOptions *opts, const char *name,
+int net_init_hubport(const Netdev *netdev, const char *name,
                      NetClientState *peer, Error **errp)
 {
     const NetdevHubPortOptions *hubport;

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT);
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT);
     assert(!peer);
-    hubport = opts->u.hubport;
+    hubport = netdev->opts->u.hubport;

     net_hub_add_port(hubport->hubid, name);
     return 0;
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
index 8e68e54..c3511d7 100644
--- a/net/l2tpv3.c
+++ b/net/l2tpv3.c
@@ -524,7 +524,7 @@ static NetClientInfo net_l2tpv3_info = {
     .cleanup = net_l2tpv3_cleanup,
 };

-int net_init_l2tpv3(const NetClientOptions *opts,
+int net_init_l2tpv3(const Netdev *netdev,
                     const char *name,
                     NetClientState *peer, Error **errp)
 {
@@ -545,8 +545,8 @@ int net_init_l2tpv3(const NetClientOptions *opts,
     s->queue_tail = 0;
     s->header_mismatch = false;

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_L2TPV3);
-    l2tpv3 = opts->u.l2tpv3;
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_L2TPV3);
+    l2tpv3 = netdev->opts->u.l2tpv3;

     if (l2tpv3->has_ipv6 && l2tpv3->ipv6) {
         s->ipv6 = l2tpv3->ipv6;
diff --git a/net/net.c b/net/net.c
index 428636a..0902ed2 100644
--- a/net/net.c
+++ b/net/net.c
@@ -875,15 +875,15 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models,
     return -1;
 }

-static int net_init_nic(const NetClientOptions *opts, const char *name,
+static int net_init_nic(const Netdev *netdev, const char *name,
                         NetClientState *peer, Error **errp)
 {
     int idx;
     NICInfo *nd;
     const NetLegacyNicOptions *nic;

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_NIC);
-    nic = opts->u.nic;
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_NIC);
+    nic = netdev->opts->u.nic;

     idx = nic_get_free_idx();
     if (idx == -1 || nb_nics >= MAX_NICS) {
@@ -944,7 +944,7 @@ static int net_init_nic(const NetClientOptions *opts, const char *name,


 static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND__MAX])(
-    const NetClientOptions *opts,
+    const Netdev *netdev,
     const char *name,
     NetClientState *peer, Error **errp) = {
         [NET_CLIENT_OPTIONS_KIND_NIC]       = net_init_nic,
@@ -976,11 +976,13 @@ static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND__MAX])(
 static int net_client_init1(const void *object, int is_netdev, Error **errp)
 {
     const NetClientOptions *opts;
+    Netdev legacy = {0};
+    const Netdev *netdev;
     const char *name;
     NetClientState *peer = NULL;

     if (is_netdev) {
-        const Netdev *netdev = object;
+        netdev = object;
         opts = netdev->opts;
         name = netdev->id;

@@ -993,7 +995,9 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
         }
     } else {
         const NetLegacy *net = object;
-        opts = net->opts;
+        legacy.id = net->id;
+        opts = legacy.opts = net->opts;
+        netdev = &legacy;
         /* missing optional values have been initialized to "all bits zero" */
         name = net->has_id ? net->id : net->name;

@@ -1020,7 +1024,7 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
         }
     }

-    if (net_client_init_fun[opts->type](opts, name, peer, errp) < 0) {
+    if (net_client_init_fun[opts->type](netdev, name, peer, errp) < 0) {
         /* FIXME drop when all init functions store an Error */
         if (errp && !*errp) {
             error_setg(errp, QERR_DEVICE_INIT_FAILED,
diff --git a/net/netmap.c b/net/netmap.c
index 5558368..89419c1 100644
--- a/net/netmap.c
+++ b/net/netmap.c
@@ -433,10 +433,10 @@ static NetClientInfo net_netmap_info = {
  *
  * ... -net netmap,ifname="..."
  */
-int net_init_netmap(const NetClientOptions *opts,
+int net_init_netmap(const Netdev *netdev,
                     const char *name, NetClientState *peer, Error **errp)
 {
-    const NetdevNetmapOptions *netmap_opts = opts->u.netmap;
+    const NetdevNetmapOptions *netmap_opts = netdev->opts->u.netmap;
     NetClientState *nc;
     Error *err = NULL;
     NetmapPriv me;
diff --git a/net/slirp.c b/net/slirp.c
index f505570..a3c40d9 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -736,7 +736,7 @@ static const char **slirp_dnssearch(const StringList *dnsname)
     return ret;
 }

-int net_init_slirp(const NetClientOptions *opts, const char *name,
+int net_init_slirp(const Netdev *netdev, const char *name,
                    NetClientState *peer, Error **errp)
 {
     /* FIXME error_setg(errp, ...) on failure */
@@ -746,8 +746,8 @@ int net_init_slirp(const NetClientOptions *opts, const char *name,
     const NetdevUserOptions *user;
     const char **dnssearch;

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_USER);
-    user = opts->u.user;
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_USER);
+    user = netdev->opts->u.user;

     vnet = user->has_net ? g_strdup(user->net) :
            user->has_ip  ? g_strdup_printf("%s/24", user->ip) :
diff --git a/net/socket.c b/net/socket.c
index e8605d4..0098896 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -699,15 +699,15 @@ static int net_socket_udp_init(NetClientState *peer,
     return 0;
 }

-int net_init_socket(const NetClientOptions *opts, const char *name,
+int net_init_socket(const Netdev *netdev, const char *name,
                     NetClientState *peer, Error **errp)
 {
     /* FIXME error_setg(errp, ...) on failure */
     Error *err = NULL;
     const NetdevSocketOptions *sock;

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET);
-    sock = opts->u.socket;
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET);
+    sock = netdev->opts->u.socket;

     if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast +
         sock->has_udp != 1) {
diff --git a/net/tap-win32.c b/net/tap-win32.c
index 7fddb20..e442727 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -788,14 +788,14 @@ static int tap_win32_init(NetClientState *peer, const char *model,
     return 0;
 }

-int net_init_tap(const NetClientOptions *opts, const char *name,
+int net_init_tap(const Netdev *netdev, const char *name,
                  NetClientState *peer, Error **errp)
 {
     /* FIXME error_setg(errp, ...) on failure */
     const NetdevTapOptions *tap;

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
-    tap = opts->u.tap;
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    tap = netdev->opts->u.tap;

     if (!tap->has_ifname) {
         error_report("tap: no interface name");
diff --git a/net/tap.c b/net/tap.c
index 85c4142..b218913 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -557,7 +557,7 @@ static int net_bridge_run_helper(const char *helper, const char *bridge,
     }
 }

-int net_init_bridge(const NetClientOptions *opts, const char *name,
+int net_init_bridge(const Netdev *netdev, const char *name,
                     NetClientState *peer, Error **errp)
 {
     const NetdevBridgeOptions *bridge;
@@ -565,8 +565,8 @@ int net_init_bridge(const NetClientOptions *opts, const char *name,
     TAPState *s;
     int fd, vnet_hdr;

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_BRIDGE);
-    bridge = opts->u.bridge;
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_BRIDGE);
+    bridge = netdev->opts->u.bridge;

     helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER;
     br     = bridge->has_br     ? bridge->br     : DEFAULT_BRIDGE_INTERFACE;
@@ -716,7 +716,7 @@ static int get_fds(char *str, char *fds[], int max)
     return i;
 }

-int net_init_tap(const NetClientOptions *opts, const char *name,
+int net_init_tap(const Netdev *netdev, const char *name,
                  NetClientState *peer, Error **errp)
 {
     const NetdevTapOptions *tap;
@@ -728,8 +728,8 @@ int net_init_tap(const NetClientOptions *opts, const char *name,
     const char *vhostfdname;
     char ifname[128];

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
-    tap = opts->u.tap;
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    tap = netdev->opts->u.tap;
     queues = tap->has_queues ? tap->queues : 1;
     vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;

diff --git a/net/vde.c b/net/vde.c
index 4475d92..23834d7 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -109,14 +109,14 @@ static int net_vde_init(NetClientState *peer, const char *model,
     return 0;
 }

-int net_init_vde(const NetClientOptions *opts, const char *name,
+int net_init_vde(const Netdev *netdev, const char *name,
                  NetClientState *peer, Error **errp)
 {
     /* FIXME error_setg(errp, ...) on failure */
     const NetdevVdeOptions *vde;

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_VDE);
-    vde = opts->u.vde;
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_VDE);
+    vde = netdev->opts->u.vde;

     /* missing optional values have been initialized to "all bits zero" */
     if (net_vde_init(peer, "vde", name, vde->sock, vde->port, vde->group,
diff --git a/net/vhost-user.c b/net/vhost-user.c
index b368a90..506398e 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -294,15 +294,15 @@ static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
     return 0;
 }

-int net_init_vhost_user(const NetClientOptions *opts, const char *name,
+int net_init_vhost_user(const Netdev *netdev, const char *name,
                         NetClientState *peer, Error **errp)
 {
     int queues;
     const NetdevVhostUserOptions *vhost_user_opts;
     CharDriverState *chr;

-    assert(opts->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
-    vhost_user_opts = opts->u.vhost_user;
+    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
+    vhost_user_opts = netdev->opts->u.vhost_user;

     chr = net_vhost_parse_chardev(vhost_user_opts, errp);
     if (!chr) {
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 02/16] qapi: Avoid use of 'data' member of qapi unions
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 01/16] net: use Netdev instead of NetClientOptions in client init Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 03/16] qapi: Forbid empty unions and useless alternates Eric Blake
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, armbru, open list:Block layer core, Gerd Hoffmann

qapi code generators currently create a 'void *data' member as
part of the anonymous union embedded in the C struct corresponding
to a qapi union.  However, directly assigning to this member of
the union feels a bit fishy, when we can directly use the rest
of the struct instead.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: rebase to latest
---
 blockdev.c | 31 +++++++++++++++++--------------
 ui/input.c |  2 +-
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index b6c710a..7c9430c 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1186,15 +1186,11 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
     }
 }

-static void blockdev_do_action(TransactionActionKind type, void *data,
-                               Error **errp)
+static void blockdev_do_action(TransactionAction *action, Error **errp)
 {
-    TransactionAction action;
     TransactionActionList list;

-    action.type = type;
-    action.u.data = data;
-    list.value = &action;
+    list.value = action;
     list.next = NULL;
     qmp_transaction(&list, false, NULL, errp);
 }
@@ -1220,8 +1216,11 @@ void qmp_blockdev_snapshot_sync(bool has_device, const char *device,
         .has_mode = has_mode,
         .mode = mode,
     };
-    blockdev_do_action(TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC,
-                       &snapshot, errp);
+    TransactionAction action = {
+        .type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC,
+        .u.blockdev_snapshot_sync = &snapshot,
+    };
+    blockdev_do_action(&action, errp);
 }

 void qmp_blockdev_snapshot(const char *node, const char *overlay,
@@ -1231,9 +1230,11 @@ void qmp_blockdev_snapshot(const char *node, const char *overlay,
         .node = (char *) node,
         .overlay = (char *) overlay
     };
-
-    blockdev_do_action(TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT,
-                       &snapshot_data, errp);
+    TransactionAction action = {
+        .type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT,
+        .u.blockdev_snapshot = &snapshot_data,
+    };
+    blockdev_do_action(&action, errp);
 }

 void qmp_blockdev_snapshot_internal_sync(const char *device,
@@ -1244,9 +1245,11 @@ void qmp_blockdev_snapshot_internal_sync(const char *device,
         .device = (char *) device,
         .name = (char *) name
     };
-
-    blockdev_do_action(TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC,
-                       &snapshot, errp);
+    TransactionAction action = {
+        .type = TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC,
+        .u.blockdev_snapshot_internal_sync = &snapshot,
+    };
+    blockdev_do_action(&action, errp);
 }

 SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
diff --git a/ui/input.c b/ui/input.c
index 006667b..a12ac71 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -463,7 +463,7 @@ InputEvent *qemu_input_event_new_move(InputEventKind kind,
     InputMoveEvent *move = g_new0(InputMoveEvent, 1);

     evt->type = kind;
-    evt->u.data = move;
+    evt->u.rel = move; /* also would work as evt->u.abs */
     move->axis = axis;
     move->value = value;
     return evt;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 03/16] qapi: Forbid empty unions and useless alternates
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 01/16] net: use Netdev instead of NetClientOptions in client init Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 02/16] qapi: Avoid use of 'data' member of qapi unions Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 04/16] qapi: Drop useless 'data' member of unions Eric Blake
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Empty unions serve no purpose, and while we compile with gcc
which permits them, strict C99 forbids them.  We could inject
a dummy member (and in fact, we do for empty structs), but while
empty structs make sense in qapi, empty unions don't add any
expressiveness to the QMP language.  So prohibit them at parse
time.  Update the documentation and testsuite to match.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: rebase to earlier qapi.py cleanups
---
 docs/qapi-code-gen.txt                  | 15 ++++++++-------
 scripts/qapi.py                         | 12 ++++++++++--
 tests/qapi-schema/alternate-empty.err   |  1 +
 tests/qapi-schema/alternate-empty.exit  |  2 +-
 tests/qapi-schema/alternate-empty.json  |  2 +-
 tests/qapi-schema/alternate-empty.out   |  5 -----
 tests/qapi-schema/flat-union-empty.err  |  1 +
 tests/qapi-schema/flat-union-empty.exit |  2 +-
 tests/qapi-schema/flat-union-empty.json |  2 +-
 tests/qapi-schema/flat-union-empty.out  | 10 ----------
 tests/qapi-schema/union-empty.err       |  1 +
 tests/qapi-schema/union-empty.exit      |  2 +-
 tests/qapi-schema/union-empty.json      |  2 +-
 tests/qapi-schema/union-empty.out       |  7 -------
 14 files changed, 27 insertions(+), 37 deletions(-)

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 128f074..999f3b9 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -187,11 +187,11 @@ prevent incomplete include files.

 Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME }

-A struct is a dictionary containing a single 'data' key whose
-value is a dictionary.  This corresponds to a struct in C or an Object
-in JSON. Each value of the 'data' dictionary must be the name of a
-type, or a one-element array containing a type name.  An example of a
-struct is:
+A struct is a dictionary containing a single 'data' key whose value is
+a dictionary; the dictionary may be empty.  This corresponds to a
+struct in C or an Object in JSON. Each value of the 'data' dictionary
+must be the name of a type, or a one-element array containing a type
+name.  An example of a struct is:

  { 'struct': 'MyType',
    'data': { 'member1': 'str', 'member2': 'int', '*member3': 'str' } }
@@ -288,9 +288,10 @@ or:    { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME,

 Union types are used to let the user choose between several different
 variants for an object.  There are two flavors: simple (no
-discriminator or base), flat (both discriminator and base).  A union
+discriminator or base), and flat (both discriminator and base).  A union
 type is defined using a data dictionary as explained in the following
-paragraphs.
+paragraphs.  The data dictionary for either type of union must not
+be empty.

 A simple union type defines a mapping from automatic discriminator
 values to data types like in this example:
diff --git a/scripts/qapi.py b/scripts/qapi.py
index e9006e4..87a650d 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -590,7 +590,10 @@ def check_union(expr, expr_info):
                                 "Discriminator '%s' must be of enumeration "
                                 "type" % discriminator)

-    # Check every branch
+    # Check every branch; don't allow an empty union
+    if len(members) == 0:
+        raise QAPIExprError(expr_info,
+                            "Union '%s' cannot have empty 'data'" % name)
     for (key, value) in members.items():
         check_name(expr_info, "Member of union '%s'" % name, key)

@@ -613,7 +616,11 @@ def check_alternate(expr, expr_info):
     members = expr['data']
     types_seen = {}

-    # Check every branch
+    # Check every branch; require at least two branches
+    if len(members) < 2:
+        raise QAPIExprError(expr_info,
+                            "Alternate '%s' should have at least two branches "
+                            "in 'data'" % name)
     for (key, value) in members.items():
         check_name(expr_info, "Member of alternate '%s'" % name, key)

@@ -1062,6 +1069,7 @@ class QAPISchemaObjectTypeVariants(object):
         assert bool(tag_member) != bool(tag_name)
         assert (isinstance(tag_name, str) or
                 isinstance(tag_member, QAPISchemaObjectTypeMember))
+        assert len(variants) > 0
         for v in variants:
             assert isinstance(v, QAPISchemaObjectTypeVariant)
         self.tag_name = tag_name
diff --git a/tests/qapi-schema/alternate-empty.err b/tests/qapi-schema/alternate-empty.err
index e69de29..bb06c5b 100644
--- a/tests/qapi-schema/alternate-empty.err
+++ b/tests/qapi-schema/alternate-empty.err
@@ -0,0 +1 @@
+tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data'
diff --git a/tests/qapi-schema/alternate-empty.exit b/tests/qapi-schema/alternate-empty.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/alternate-empty.exit
+++ b/tests/qapi-schema/alternate-empty.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/alternate-empty.json b/tests/qapi-schema/alternate-empty.json
index db3820f..fff15ba 100644
--- a/tests/qapi-schema/alternate-empty.json
+++ b/tests/qapi-schema/alternate-empty.json
@@ -1,2 +1,2 @@
-# FIXME - alternates should list at least two types to be useful
+# alternates must list at least two types to be useful
 { 'alternate': 'Alt', 'data': { 'i': 'int' } }
diff --git a/tests/qapi-schema/alternate-empty.out b/tests/qapi-schema/alternate-empty.out
index f78f174..e69de29 100644
--- a/tests/qapi-schema/alternate-empty.out
+++ b/tests/qapi-schema/alternate-empty.out
@@ -1,5 +0,0 @@
-object :empty
-alternate Alt
-    case i: int
-enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
-    prefix QTYPE
diff --git a/tests/qapi-schema/flat-union-empty.err b/tests/qapi-schema/flat-union-empty.err
index e69de29..15754f5 100644
--- a/tests/qapi-schema/flat-union-empty.err
+++ b/tests/qapi-schema/flat-union-empty.err
@@ -0,0 +1 @@
+tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data'
diff --git a/tests/qapi-schema/flat-union-empty.exit b/tests/qapi-schema/flat-union-empty.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/flat-union-empty.exit
+++ b/tests/qapi-schema/flat-union-empty.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/flat-union-empty.json b/tests/qapi-schema/flat-union-empty.json
index 67dd297..77f1d9a 100644
--- a/tests/qapi-schema/flat-union-empty.json
+++ b/tests/qapi-schema/flat-union-empty.json
@@ -1,4 +1,4 @@
-# FIXME - flat unions should not be empty
+# flat unions cannot be empty
 { 'enum': 'Empty', 'data': [ ] }
 { 'struct': 'Base', 'data': { 'type': 'Empty' } }
 { 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } }
diff --git a/tests/qapi-schema/flat-union-empty.out b/tests/qapi-schema/flat-union-empty.out
index 1a58e07..e69de29 100644
--- a/tests/qapi-schema/flat-union-empty.out
+++ b/tests/qapi-schema/flat-union-empty.out
@@ -1,10 +0,0 @@
-object :empty
-object Base
-    base :empty
-    member type: Empty optional=False
-enum Empty []
-enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
-    prefix QTYPE
-object Union
-    base Base
-    tag type
diff --git a/tests/qapi-schema/union-empty.err b/tests/qapi-schema/union-empty.err
index e69de29..12c2022 100644
--- a/tests/qapi-schema/union-empty.err
+++ b/tests/qapi-schema/union-empty.err
@@ -0,0 +1 @@
+tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data'
diff --git a/tests/qapi-schema/union-empty.exit b/tests/qapi-schema/union-empty.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/union-empty.exit
+++ b/tests/qapi-schema/union-empty.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/union-empty.json b/tests/qapi-schema/union-empty.json
index 1785007..1f0b13c 100644
--- a/tests/qapi-schema/union-empty.json
+++ b/tests/qapi-schema/union-empty.json
@@ -1,2 +1,2 @@
-# FIXME - unions should not be empty
+# unions cannot be empty
 { 'union': 'Union', 'data': { } }
diff --git a/tests/qapi-schema/union-empty.out b/tests/qapi-schema/union-empty.out
index 57fcbd1..e69de29 100644
--- a/tests/qapi-schema/union-empty.out
+++ b/tests/qapi-schema/union-empty.out
@@ -1,7 +0,0 @@
-object :empty
-enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
-    prefix QTYPE
-object Union
-    base :empty
-    member type: UnionKind optional=False
-enum UnionKind []
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 04/16] qapi: Drop useless 'data' member of unions
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (2 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 03/16] qapi: Forbid empty unions and useless alternates Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 05/16] qapi: Hide tag_name data member of variants Eric Blake
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Now that we no longer have any clients of the 'void *data'
member injected into unions, we can drop it.  Update the
testsuite to drop the negative test union-clash-data, and
replace it with a positive test in qapi-schema-test that
proves that we no longer have a name collision.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: rebase to earlier changes
---
 scripts/qapi-types.py                   |  9 ---------
 tests/Makefile                          |  1 -
 tests/qapi-schema/qapi-schema-test.json |  2 +-
 tests/qapi-schema/qapi-schema-test.out  |  4 ++--
 tests/qapi-schema/union-clash-data.err  |  0
 tests/qapi-schema/union-clash-data.exit |  1 -
 tests/qapi-schema/union-clash-data.json |  7 -------
 tests/qapi-schema/union-clash-data.out  | 11 -----------
 8 files changed, 3 insertions(+), 32 deletions(-)
 delete mode 100644 tests/qapi-schema/union-clash-data.err
 delete mode 100644 tests/qapi-schema/union-clash-data.exit
 delete mode 100644 tests/qapi-schema/union-clash-data.json
 delete mode 100644 tests/qapi-schema/union-clash-data.out

diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 47a6523..8597942 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -99,17 +99,8 @@ static inline %(base)s *qapi_%(c_name)s_base(const %(c_name)s *obj)


 def gen_variants(variants):
-    # FIXME: What purpose does data serve, besides preventing a union that
-    # has a branch named 'data'? We use it in qapi-visit.py to decide
-    # whether to bypass the switch statement if visiting the discriminator
-    # failed; but since we 0-initialize structs, and cannot tell what
-    # branch of the union is in use if the discriminator is invalid, there
-    # should not be any data leaks even without a data pointer.  Or, if
-    # 'data' is merely added to guarantee we don't have an empty union,
-    # shouldn't we enforce that at .json parse time?
     ret = mcgen('''
     union { /* union tag is @%(c_name)s */
-        void *data;
 ''',
                 c_name=c_name(variants.tag_member.name))

diff --git a/tests/Makefile b/tests/Makefile
index b7352f1..84caf98 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -356,7 +356,6 @@ qapi-schema += unicode-str.json
 qapi-schema += union-base-no-discriminator.json
 qapi-schema += union-branch-case.json
 qapi-schema += union-clash-branches.json
-qapi-schema += union-clash-data.json
 qapi-schema += union-empty.json
 qapi-schema += union-invalid-base.json
 qapi-schema += union-optional-branch.json
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index a0fdb88..44c1965 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -112,7 +112,7 @@
             'number': ['number'],
             'boolean': ['bool'],
             'string': ['str'],
-            'sizes': ['size'],
+            'data': ['size'],
             'any': ['any'] } }

 # testing commands
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index a2a3c8b..e6088a5 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -171,9 +171,9 @@ object UserDefNativeListUnion
     case number: :obj-numberList-wrapper
     case boolean: :obj-boolList-wrapper
     case string: :obj-strList-wrapper
-    case sizes: :obj-sizeList-wrapper
+    case data: :obj-sizeList-wrapper
     case any: :obj-anyList-wrapper
-enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes', 'any']
+enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'data', 'any']
 object UserDefOne
     base UserDefZero
     member string: str optional=False
diff --git a/tests/qapi-schema/union-clash-data.err b/tests/qapi-schema/union-clash-data.err
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/qapi-schema/union-clash-data.exit b/tests/qapi-schema/union-clash-data.exit
deleted file mode 100644
index 573541a..0000000
--- a/tests/qapi-schema/union-clash-data.exit
+++ /dev/null
@@ -1 +0,0 @@
-0
diff --git a/tests/qapi-schema/union-clash-data.json b/tests/qapi-schema/union-clash-data.json
deleted file mode 100644
index 7308e69..0000000
--- a/tests/qapi-schema/union-clash-data.json
+++ /dev/null
@@ -1,7 +0,0 @@
-# Union branch 'data'
-# FIXME: this parses, but then fails to compile due to a duplicate 'data'
-# (one from the branch name, another as a filler to avoid an empty union).
-# we should either detect the collision at parse time, or change the
-# generated struct to allow this to compile.
-{ 'union': 'TestUnion',
-  'data': { 'data': 'int' } }
diff --git a/tests/qapi-schema/union-clash-data.out b/tests/qapi-schema/union-clash-data.out
deleted file mode 100644
index 19031a2..0000000
--- a/tests/qapi-schema/union-clash-data.out
+++ /dev/null
@@ -1,11 +0,0 @@
-object :empty
-object :obj-int-wrapper
-    base :empty
-    member data: int optional=False
-enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
-    prefix QTYPE
-object TestUnion
-    base :empty
-    member type: TestUnionKind optional=False
-    case data: :obj-int-wrapper
-enum TestUnionKind ['data']
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 05/16] qapi: Hide tag_name data member of variants
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (3 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 04/16] qapi: Drop useless 'data' member of unions Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 06/16] qapi: Plumb in 'box' to qapi generator lower levels Eric Blake
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Clean up the only remaining external use of the tag_name field of
QAPISchemaObjectTypeVariants, by explicitly listing the generated
'type' tag for all variants in the testsuite.  Then we can mark the
tag_name field as private by adding a leading underscore to prevent
any further use.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: rebase to earlier changes; but may be worth dropping this patch
---
 scripts/qapi.py                        |  8 ++++----
 tests/qapi-schema/qapi-schema-test.out | 10 ++++++++++
 tests/qapi-schema/test-qapi.py         |  3 +--
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 87a650d..311bed9 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1072,7 +1072,7 @@ class QAPISchemaObjectTypeVariants(object):
         assert len(variants) > 0
         for v in variants:
             assert isinstance(v, QAPISchemaObjectTypeVariant)
-        self.tag_name = tag_name
+        self._tag_name = tag_name
         self.tag_member = tag_member
         self.variants = variants

@@ -1082,8 +1082,8 @@ class QAPISchemaObjectTypeVariants(object):

     def check(self, schema, seen):
         if not self.tag_member:    # flat union
-            self.tag_member = seen[c_name(self.tag_name)]
-            assert self.tag_name == self.tag_member.name
+            self.tag_member = seen[c_name(self._tag_name)]
+            assert self._tag_name == self.tag_member.name
         assert isinstance(self.tag_member.type, QAPISchemaEnumType)
         for v in self.variants:
             v.check(schema)
@@ -1123,7 +1123,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
     def __init__(self, name, info, variants):
         QAPISchemaType.__init__(self, name, info)
         assert isinstance(variants, QAPISchemaObjectTypeVariants)
-        assert not variants.tag_name
+        assert variants.tag_member
         variants.set_owner(name)
         variants.tag_member.set_owner(self.name)
         self.variants = variants
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index e6088a5..755393a 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -76,21 +76,27 @@ object :obj-user_def_cmd2-arg
     member ud1a: UserDefOne optional=False
     member ud1b: UserDefOne optional=True
 alternate AltIntNum
+    tag type
     case i: int
     case n: number
 alternate AltNumInt
+    tag type
     case n: number
     case i: int
 alternate AltNumStr
+    tag type
     case n: number
     case s: str
 alternate AltStrBool
+    tag type
     case s: str
     case b: bool
 alternate AltStrInt
+    tag type
     case s: str
     case i: int
 alternate AltStrNum
+    tag type
     case s: str
     case n: number
 event EVENT_A :empty
@@ -133,6 +139,7 @@ object UserDefA
     member boolean: bool optional=False
     member a_b: int optional=True
 alternate UserDefAlternate
+    tag type
     case uda: UserDefA
     case s: str
     case i: int
@@ -159,6 +166,7 @@ object UserDefFlatUnion2
 object UserDefNativeListUnion
     base :empty
     member type: UserDefNativeListUnionKind optional=False
+    tag type
     case integer: :obj-intList-wrapper
     case s8: :obj-int8List-wrapper
     case s16: :obj-int16List-wrapper
@@ -207,6 +215,7 @@ object UserDefZero
     member integer: int optional=False
 event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
 alternate __org.qemu_x-Alt
+    tag type
     case __org.qemu_x-branch: str
     case b: __org.qemu_x-Base
 object __org.qemu_x-Base
@@ -223,6 +232,7 @@ object __org.qemu_x-Struct2
 object __org.qemu_x-Union1
     base :empty
     member type: __org.qemu_x-Union1Kind optional=False
+    tag type
     case __org.qemu_x-branch: :obj-str-wrapper
 enum __org.qemu_x-Union1Kind ['__org.qemu_x-branch']
 object __org.qemu_x-Union2
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index 649677e..bedd145 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -47,8 +47,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
     @staticmethod
     def _print_variants(variants):
         if variants:
-            if variants.tag_name:
-                print '    tag %s' % variants.tag_name
+            print '    tag %s' % variants.tag_member.name
             for v in variants.variants:
                 print '    case %s: %s' % (v.name, v.type.name)

-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 06/16] qapi: Plumb in 'box' to qapi generator lower levels
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (4 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 05/16] qapi: Hide tag_name data member of variants Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 07/16] qapi: Implement boxed types for commands/events Eric Blake
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

A future patch will add support for passing a qapi union
type as the 'data' of a command.  But to do that, the user
function for implementing the command, as called by the
generated marshal command, must take the corresponding C
struct as a single boxed pointer, rather than a breakdown
into one parameter per member.  This patch adds the
internal plubming of a 'box' flag associated with each
command and event.  For this patch, no behavior changes,
other than the testsuite outputting the value of the new
flag (always False for now).

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: rebase to earlier changes
---
 scripts/qapi-commands.py                | 61 +++++++++++++++++++--------------
 scripts/qapi-event.py                   | 34 ++++++++++--------
 scripts/qapi-introspect.py              |  4 +--
 scripts/qapi.py                         | 46 +++++++++++++++----------
 tests/qapi-schema/event-case.out        |  1 +
 tests/qapi-schema/ident-with-escape.out |  2 +-
 tests/qapi-schema/indented-expr.out     |  4 +--
 tests/qapi-schema/qapi-schema-test.out  | 19 ++++++----
 tests/qapi-schema/test-qapi.py          |  8 +++--
 9 files changed, 106 insertions(+), 73 deletions(-)

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 9d455c3..efdeb70 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -16,24 +16,27 @@ from qapi import *
 import re


-def gen_command_decl(name, arg_type, ret_type):
+def gen_command_decl(name, arg_type, box, ret_type):
     return mcgen('''
 %(c_type)s qmp_%(c_name)s(%(params)s);
 ''',
                  c_type=(ret_type and ret_type.c_type()) or 'void',
                  c_name=c_name(name),
-                 params=gen_params(arg_type, 'Error **errp'))
+                 params=gen_params(arg_type, box, 'Error **errp'))


-def gen_call(name, arg_type, ret_type):
+def gen_call(name, arg_type, box, ret_type):
     ret = ''

     argstr = ''
     assert arg_type
-    for memb in arg_type.members:
-        if memb.optional:
-            argstr += 'has_%s, ' % c_name(memb.name)
-        argstr += '%s, ' % c_name(memb.name)
+    if box and not arg_type.is_empty():
+        assert False    # not implemented
+    else:
+        for memb in arg_type.members:
+            if memb.optional:
+                argstr += 'has_%s, ' % c_name(memb.name)
+            argstr += '%s, ' % c_name(memb.name)

     lhs = ''
     if ret_type:
@@ -54,7 +57,7 @@ def gen_call(name, arg_type, ret_type):
     return ret


-def gen_marshal_vars(arg_type, ret_type):
+def gen_marshal_vars(arg_type, box, ret_type):
     ret = mcgen('''
     Error *err = NULL;
 ''')
@@ -73,18 +76,21 @@ def gen_marshal_vars(arg_type, ret_type):
     Visitor *v;
 ''')

-        for memb in arg_type.members:
-            if memb.optional:
-                ret += mcgen('''
+        if box:
+            assert False    # not implemented
+        else:
+            for memb in arg_type.members:
+                if memb.optional:
+                    ret += mcgen('''
     bool has_%(c_name)s = false;
 ''',
-                             c_name=c_name(memb.name))
-            ret += mcgen('''
+                                 c_name=c_name(memb.name))
+                ret += mcgen('''
     %(c_type)s %(c_name)s = %(c_null)s;
 ''',
-                         c_name=c_name(memb.name),
-                         c_type=memb.type.c_type(),
-                         c_null=memb.type.c_null())
+                             c_name=c_name(memb.name),
+                             c_type=memb.type.c_type(),
+                             c_null=memb.type.c_null())
         ret += '\n'
     else:
         ret += mcgen('''
@@ -95,7 +101,7 @@ def gen_marshal_vars(arg_type, ret_type):
     return ret


-def gen_marshal_input_visit(arg_type, dealloc=False):
+def gen_marshal_input_visit(arg_type, box, dealloc=False):
     ret = ''

     if arg_type.is_empty():
@@ -112,7 +118,10 @@ def gen_marshal_input_visit(arg_type, dealloc=False):
     v = qmp_input_get_visitor(qiv);
 ''')

-    ret += gen_visit_fields(arg_type.members, skiperr=dealloc)
+    if box:
+        assert False    # not implemented
+    else:
+        ret += gen_visit_fields(arg_type.members, skiperr=dealloc)

     if dealloc:
         ret += mcgen('''
@@ -164,7 +173,7 @@ def gen_marshal_decl(name):
                  proto=gen_marshal_proto(name))


-def gen_marshal(name, arg_type, ret_type):
+def gen_marshal(name, arg_type, box, ret_type):
     ret = mcgen('''

 %(proto)s
@@ -172,9 +181,9 @@ def gen_marshal(name, arg_type, ret_type):
 ''',
                 proto=gen_marshal_proto(name))

-    ret += gen_marshal_vars(arg_type, ret_type)
-    ret += gen_marshal_input_visit(arg_type)
-    ret += gen_call(name, arg_type, ret_type)
+    ret += gen_marshal_vars(arg_type, box, ret_type)
+    ret += gen_marshal_input_visit(arg_type, box)
+    ret += gen_call(name, arg_type, box, ret_type)

     # 'goto out' produced by gen_marshal_input_visit->gen_visit_fields()
     # for each arg_type member, and by gen_call() for ret_type
@@ -186,7 +195,7 @@ out:
     ret += mcgen('''
     error_propagate(errp, err);
 ''')
-    ret += gen_marshal_input_visit(arg_type, dealloc=True)
+    ret += gen_marshal_input_visit(arg_type, box, dealloc=True)
     ret += mcgen('''
 }
 ''')
@@ -241,16 +250,16 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
         self._visited_ret_types = None

     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, box):
         if not gen:
             return
-        self.decl += gen_command_decl(name, arg_type, ret_type)
+        self.decl += gen_command_decl(name, arg_type, box, ret_type)
         if ret_type and ret_type not in self._visited_ret_types:
             self._visited_ret_types.add(ret_type)
             self.defn += gen_marshal_output(ret_type)
         if middle_mode:
             self.decl += gen_marshal_decl(name)
-        self.defn += gen_marshal(name, arg_type, ret_type)
+        self.defn += gen_marshal(name, arg_type, box, ret_type)
         if not middle_mode:
             self._regy += gen_register_command(name, success_response)

diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index e694b1b..451d077 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -14,21 +14,21 @@
 from qapi import *


-def gen_event_send_proto(name, arg_type):
+def gen_event_send_proto(name, arg_type, box):
     return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
         'c_name': c_name(name.lower()),
-        'param': gen_params(arg_type, 'Error **errp')}
+        'param': gen_params(arg_type, box, 'Error **errp')}


-def gen_event_send_decl(name, arg_type):
+def gen_event_send_decl(name, arg_type, box):
     return mcgen('''

 %(proto)s;
 ''',
-                 proto=gen_event_send_proto(name, arg_type))
+                 proto=gen_event_send_proto(name, arg_type, box))


-def gen_event_send(name, arg_type):
+def gen_event_send(name, arg_type, box):
     ret = mcgen('''

 %(proto)s
@@ -37,7 +37,7 @@ def gen_event_send(name, arg_type):
     Error *err = NULL;
     QMPEventFuncEmit emit;
 ''',
-                proto=gen_event_send_proto(name, arg_type))
+                proto=gen_event_send_proto(name, arg_type, box))

     assert arg_type
     if not arg_type.is_empty():
@@ -64,13 +64,19 @@ def gen_event_send(name, arg_type):
     qov = qmp_output_visitor_new();
     v = qmp_output_get_visitor(qov);

+''')
+
+        if box:
+            assert False     # not implemented
+        else:
+            ret += mcgen('''
     visit_start_struct(v, "%(name)s", NULL, 0, &err);
 ''',
-                     name=name)
-        ret += gen_err_check()
-        ret += gen_visit_fields(arg_type.members, need_cast=True,
-                                label='out_obj')
-        ret += mcgen('''
+                         name=name)
+            ret += gen_err_check()
+            ret += gen_visit_fields(arg_type.members, need_cast=True,
+                                    label='out_obj')
+            ret += mcgen('''
     visit_check_struct(v, &err);
 out_obj:
     visit_end_struct(v);
@@ -119,9 +125,9 @@ class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
         self.defn += gen_enum_lookup(event_enum_name, self._event_names)
         self._event_names = None

-    def visit_event(self, name, info, arg_type):
-        self.decl += gen_event_send_decl(name, arg_type)
-        self.defn += gen_event_send(name, arg_type)
+    def visit_event(self, name, info, arg_type, box):
+        self.decl += gen_event_send_decl(name, arg_type, box)
+        self.defn += gen_event_send(name, arg_type, box)
         self._event_names.append(name)


diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index 64f2cd0..293740e 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -154,14 +154,14 @@ const char %(c_name)s[] = %(c_string)s;
                                     for m in variants.variants]})

     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, box):
         arg_type = arg_type or self._schema.the_empty_object_type
         ret_type = ret_type or self._schema.the_empty_object_type
         self._gen_json(name, 'command',
                        {'arg-type': self._use_type(arg_type),
                         'ret-type': self._use_type(ret_type)})

-    def visit_event(self, name, info, arg_type):
+    def visit_event(self, name, info, arg_type, box):
         arg_type = arg_type or self._schema.the_empty_object_type
         self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 311bed9..b408a82 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -813,10 +813,10 @@ class QAPISchemaVisitor(object):
         pass

     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, box):
         pass

-    def visit_event(self, name, info, arg_type):
+    def visit_event(self, name, info, arg_type, box):
         pass


@@ -1147,7 +1147,8 @@ class QAPISchemaAlternateType(QAPISchemaType):


 class QAPISchemaCommand(QAPISchemaEntity):
-    def __init__(self, name, info, arg_type, ret_type, gen, success_response):
+    def __init__(self, name, info, arg_type, ret_type, gen, success_response,
+                 box):
         QAPISchemaEntity.__init__(self, name, info)
         assert not arg_type or isinstance(arg_type, str)
         assert not ret_type or isinstance(ret_type, str)
@@ -1157,12 +1158,14 @@ class QAPISchemaCommand(QAPISchemaEntity):
         self.ret_type = None
         self.gen = gen
         self.success_response = success_response
+        self.box = box

     def check(self, schema):
         if self._arg_type_name:
             self.arg_type = schema.lookup_type(self._arg_type_name)
             assert isinstance(self.arg_type, QAPISchemaObjectType)
-            assert not self.arg_type.variants   # not implemented
+            if not self.box:
+                assert not self.arg_type.variants
         if self._ret_type_name:
             self.ret_type = schema.lookup_type(self._ret_type_name)
             assert isinstance(self.ret_type, QAPISchemaType)
@@ -1170,24 +1173,26 @@ class QAPISchemaCommand(QAPISchemaEntity):
     def visit(self, visitor):
         visitor.visit_command(self.name, self.info,
                               self.arg_type, self.ret_type,
-                              self.gen, self.success_response)
+                              self.gen, self.success_response, self.box)


 class QAPISchemaEvent(QAPISchemaEntity):
-    def __init__(self, name, info, arg_type):
+    def __init__(self, name, info, arg_type, box):
         QAPISchemaEntity.__init__(self, name, info)
         assert not arg_type or isinstance(arg_type, str)
         self._arg_type_name = arg_type
         self.arg_type = None
+        self.box = box

     def check(self, schema):
         if self._arg_type_name:
             self.arg_type = schema.lookup_type(self._arg_type_name)
             assert isinstance(self.arg_type, QAPISchemaObjectType)
-            assert not self.arg_type.variants   # not implemented
+            if not self.box:
+                assert not self.arg_type.variants

     def visit(self, visitor):
-        visitor.visit_event(self.name, self.info, self.arg_type)
+        visitor.visit_event(self.name, self.info, self.arg_type, self.box)


 class QAPISchema(object):
@@ -1361,6 +1366,7 @@ class QAPISchema(object):
         rets = expr.get('returns')
         gen = expr.get('gen', True)
         success_response = expr.get('success-response', True)
+        box = expr.get('box', False)
         if isinstance(data, dict):
             data = self._make_implicit_object_type(
                 name, info, 'arg', self._make_members(data, info))
@@ -1368,15 +1374,16 @@ class QAPISchema(object):
             assert len(rets) == 1
             rets = self._make_array_type(rets[0], info)
         self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
-                                           success_response))
+                                           success_response, box))

     def _def_event(self, expr, info):
         name = expr['event']
         data = expr.get('data', {})
+        box = expr.get('box', False)
         if isinstance(data, dict):
             data = self._make_implicit_object_type(
                 name, info, 'arg', self._make_members(data, info))
-        self._def_entity(QAPISchemaEvent(name, info, data))
+        self._def_entity(QAPISchemaEvent(name, info, data, box))

     def _def_exprs(self):
         for expr_elem in self.exprs:
@@ -1619,17 +1626,20 @@ extern const char *const %(c_name)s_lookup[];
     return ret


-def gen_params(arg_type, extra):
+def gen_params(arg_type, box, extra):
     assert arg_type
-    assert not arg_type.variants
     ret = ''
     sep = ''
-    for memb in arg_type.members:
-        ret += sep
-        sep = ', '
-        if memb.optional:
-            ret += 'bool has_%s, ' % c_name(memb.name)
-        ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
+    if box and not arg_type.is_empty():
+        assert False     # not implemented
+    else:
+        for memb in arg_type.members:
+            ret += sep
+            sep = ', '
+            if memb.optional:
+                ret += 'bool has_%s, ' % c_name(memb.name)
+            ret += '%s %s' % (memb.type.c_type(is_param=True),
+                              c_name(memb.name))
     if extra:
         ret += sep + extra
     return ret
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index 18866d9..9fa846c 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -2,3 +2,4 @@ object :empty
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
 event oops :empty
+   box=False
diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
index 142cd19..1b415e7 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -5,4 +5,4 @@ object :obj-fooA-arg
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
 command fooA :obj-fooA-arg -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index 5c25fcd..9f5c1e9 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -2,6 +2,6 @@ object :empty
 enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
     prefix QTYPE
 command eins :empty -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command zwei :empty -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 755393a..8731caa 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -100,9 +100,13 @@ alternate AltStrNum
     case s: str
     case n: number
 event EVENT_A :empty
+   box=False
 event EVENT_B :empty
+   box=False
 event EVENT_C :obj-EVENT_C-arg
+   box=False
 event EVENT_D :obj-EVENT_D-arg
+   box=False
 object Empty1
     base :empty
 object Empty2
@@ -214,6 +218,7 @@ object UserDefZero
     base :empty
     member integer: int optional=False
 event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
+   box=False
 alternate __org.qemu_x-Alt
     tag type
     case __org.qemu_x-branch: str
@@ -240,16 +245,16 @@ object __org.qemu_x-Union2
     tag __org.qemu_x-member1
     case __org.qemu_x-value: __org.qemu_x-Struct2
 command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command guest-get-time :obj-guest-get-time-arg -> int
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command guest-sync :obj-guest-sync-arg -> any
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command user_def_cmd :empty -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command user_def_cmd0 Empty2 -> Empty2
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command user_def_cmd1 :obj-user_def_cmd1-arg -> None
-   gen=True success_response=True
+   gen=True success_response=True box=False
 command user_def_cmd2 :obj-user_def_cmd2-arg -> UserDefTwo
-   gen=True success_response=True
+   gen=True success_response=True box=False
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index bedd145..d82af59 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -36,13 +36,15 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
         self._print_variants(variants)

     def visit_command(self, name, info, arg_type, ret_type,
-                      gen, success_response):
+                      gen, success_response, box):
         print 'command %s %s -> %s' % \
             (name, arg_type and arg_type.name, ret_type and ret_type.name)
-        print '   gen=%s success_response=%s' % (gen, success_response)
+        print '   gen=%s success_response=%s box=%s' % (gen, success_response,
+                                                        box)

-    def visit_event(self, name, info, arg_type):
+    def visit_event(self, name, info, arg_type, box):
         print 'event %s %s' % (name, arg_type and arg_type.name)
+        print '   box=%s' % box

     @staticmethod
     def _print_variants(variants):
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 07/16] qapi: Implement boxed types for commands/events
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (5 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 06/16] qapi: Plumb in 'box' to qapi generator lower levels Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 08/16] qapi: support implicit structs in OptsVisitor Eric Blake
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Turn on the ability to pass command and event arguments in
a single boxed parameter.  For structs, it makes it possible
to pass a single qapi type instead of a breakout of all
struct members; for unions, it is now possible to use a
union as the data for a command or event.

Generated code is unchanged, as long as no client uses the
new feature.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: retitle, rebase, and merge v5 40/46 and 41/46 into one patch
---
 docs/qapi-code-gen.txt                  | 24 ++++++++++++++++++++++--
 scripts/qapi-commands.py                | 18 +++++++++++++++---
 scripts/qapi-event.py                   | 11 +++++++++--
 scripts/qapi.py                         | 27 ++++++++++++++++++++-------
 tests/Makefile                          |  2 ++
 tests/qapi-schema/args-bad-box.err      |  1 +
 tests/qapi-schema/args-bad-box.exit     |  1 +
 tests/qapi-schema/args-bad-box.json     |  2 ++
 tests/qapi-schema/args-bad-box.out      |  0
 tests/qapi-schema/args-box-anon.err     |  1 +
 tests/qapi-schema/args-box-anon.exit    |  1 +
 tests/qapi-schema/args-box-anon.json    |  2 ++
 tests/qapi-schema/args-box-anon.out     |  0
 tests/qapi-schema/args-union.err        |  2 +-
 tests/qapi-schema/args-union.json       |  3 +--
 tests/qapi-schema/qapi-schema-test.json |  6 +++++-
 tests/qapi-schema/qapi-schema-test.out  | 10 +++++++++-
 tests/test-qmp-commands.c               | 12 ++++++++++++
 18 files changed, 104 insertions(+), 19 deletions(-)
 create mode 100644 tests/qapi-schema/args-bad-box.err
 create mode 100644 tests/qapi-schema/args-bad-box.exit
 create mode 100644 tests/qapi-schema/args-bad-box.json
 create mode 100644 tests/qapi-schema/args-bad-box.out
 create mode 100644 tests/qapi-schema/args-box-anon.err
 create mode 100644 tests/qapi-schema/args-box-anon.exit
 create mode 100644 tests/qapi-schema/args-box-anon.json
 create mode 100644 tests/qapi-schema/args-box-anon.out

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 999f3b9..bd437c8 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -409,7 +409,7 @@ following example objects:
 === Commands ===

 Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
-         '*returns': TYPE-NAME,
+         '*returns': TYPE-NAME, '*box': true,
          '*gen': false, '*success-response': false }

 Commands are defined by using a dictionary containing several members,
@@ -460,6 +460,17 @@ which would validate this Client JSON Protocol transaction:
  => { "execute": "my-second-command" }
  <= { "return": [ { "value": "one" }, { } ] }

+By default, the generator creates a marshalling function that converts
+an input QDict into a function call implemented by the user, and
+declares a prototype for the user's function which has a parameter for
+each member of the argument struct, including boolean arguments that
+describe whether optional arguments were provided.  But if the QAPI
+description includes the key 'box' with the boolean value true, the
+user call prototype will have only a single parameter for the overall
+generated C structure.  The 'box' key is required in order to use a
+union as an input argument, since it is not possible to list all
+members of the union as separate parameters.
+
 In rare cases, QAPI cannot express a type-safe representation of a
 corresponding Client JSON Protocol command.  You then have to suppress
 generation of a marshalling function by including a key 'gen' with
@@ -483,7 +494,8 @@ use of this field.

 === Events ===

-Usage: { 'event': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT }
+Usage: { 'event': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
+         '*box': true }

 Events are defined with the keyword 'event'.  It is not allowed to
 name an event 'MAX', since the generator also produces a C enumeration
@@ -504,6 +516,14 @@ Resulting in this JSON object:
   "data": { "b": "test string" },
   "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }

+By default, the generator creates a C function that takes as
+parameters each member of the argument struct and turns it into the
+appropriate JSON Client event.  But if the QAPI description includes
+the key 'box' with the boolean value true, the event function will
+have only a single parameter for the overall generated C structure.
+The 'box' key is required in order to use a union as the data key,
+since it is not possible to list all members of the union as separate
+parameters.

 == Client JSON Protocol introspection ==

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index efdeb70..d47ee10 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -31,7 +31,7 @@ def gen_call(name, arg_type, box, ret_type):
     argstr = ''
     assert arg_type
     if box and not arg_type.is_empty():
-        assert False    # not implemented
+        argstr = 'arg, '
     else:
         for memb in arg_type.members:
             if memb.optional:
@@ -77,7 +77,10 @@ def gen_marshal_vars(arg_type, box, ret_type):
 ''')

         if box:
-            assert False    # not implemented
+            ret += mcgen('''
+    %(c_type)s arg = %(c_null)s;
+''',
+                         c_type=arg_type.c_type(), c_null=arg_type.c_null())
         else:
             for memb in arg_type.members:
                 if memb.optional:
@@ -119,7 +122,16 @@ def gen_marshal_input_visit(arg_type, box, dealloc=False):
 ''')

     if box:
-        assert False    # not implemented
+        if dealloc:
+            errp = 'NULL'
+        else:
+            errp = '&err'
+        ret += mcgen('''
+    visit_type_%(c_name)s(v, NULL, &arg, %(errp)s);
+
+''',
+                     c_name=arg_type.c_name(), errp=errp)
+        ret += gen_err_check(skiperr=dealloc)
     else:
         ret += gen_visit_fields(arg_type.members, skiperr=dealloc)

diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 451d077..bae200d 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -41,8 +41,11 @@ def gen_event_send(name, arg_type, box):

     assert arg_type
     if not arg_type.is_empty():
-        ret += mcgen('''
+        if not box:
+            ret += mcgen('''
     QObject *obj;
+''')
+        ret += mcgen('''
     QmpOutputVisitor *qov;
     Visitor *v;

@@ -67,7 +70,11 @@ def gen_event_send(name, arg_type, box):
 ''')

         if box:
-            assert False     # not implemented
+            ret += mcgen('''
+    visit_type_%(c_name)s(v, NULL, &arg, &err);
+''',
+                         c_name=arg_type.c_name(), name=arg_type.name)
+            ret += gen_err_check()
         else:
             ret += mcgen('''
     visit_start_struct(v, "%(name)s", NULL, 0, &err);
diff --git a/scripts/qapi.py b/scripts/qapi.py
index b408a82..84c0bd0 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -521,10 +521,14 @@ def check_type(expr_info, source, value, allow_array=False,

 def check_command(expr, expr_info):
     name = expr['command']
+    box = expr.get('box', False)

+    args_meta = ['struct']
+    if box:
+        args_meta += ['union']
     check_type(expr_info, "'data' for command '%s'" % name,
-               expr.get('data'), allow_dict=True, allow_optional=True,
-               allow_metas=['struct'])
+               expr.get('data'), allow_dict=not box, allow_optional=True,
+               allow_metas=args_meta)
     returns_meta = ['union', 'struct']
     if name in returns_whitelist:
         returns_meta += ['built-in', 'alternate', 'enum']
@@ -536,11 +540,15 @@ def check_command(expr, expr_info):
 def check_event(expr, expr_info):
     global events
     name = expr['event']
+    box = expr.get('box', False)
+    meta = ['struct']

+    if box:
+        meta += ['union']
     events.append(name)
     check_type(expr_info, "'data' for event '%s'" % name,
-               expr.get('data'), allow_dict=True, allow_optional=True,
-               allow_metas=['struct'])
+               expr.get('data'), allow_dict=not box, allow_optional=True,
+               allow_metas=meta)


 def check_union(expr, expr_info):
@@ -681,6 +689,10 @@ def check_keys(expr_elem, meta, required, optional=[]):
             raise QAPIExprError(info,
                                 "'%s' of %s '%s' should only use false value"
                                 % (key, meta, name))
+        if key == 'box' and value is not True:
+            raise QAPIExprError(info,
+                                "'%s' of %s '%s' should only use true value"
+                                % (key, meta, name))
     for key in required:
         if key not in expr:
             raise QAPIExprError(info,
@@ -712,10 +724,10 @@ def check_exprs(exprs):
             add_struct(expr, info)
         elif 'command' in expr:
             check_keys(expr_elem, 'command', [],
-                       ['data', 'returns', 'gen', 'success-response'])
+                       ['data', 'returns', 'gen', 'success-response', 'box'])
             add_name(expr['command'], info, 'command')
         elif 'event' in expr:
-            check_keys(expr_elem, 'event', [], ['data'])
+            check_keys(expr_elem, 'event', [], ['data', 'box'])
             add_name(expr['event'], info, 'event')
         else:
             raise QAPIExprError(expr_elem['info'],
@@ -1631,7 +1643,8 @@ def gen_params(arg_type, box, extra):
     ret = ''
     sep = ''
     if box and not arg_type.is_empty():
-        assert False     # not implemented
+        ret += '%s arg' % arg_type.c_type(is_param=True)
+        sep = ', '
     else:
         for memb in arg_type.members:
             ret += sep
diff --git a/tests/Makefile b/tests/Makefile
index 84caf98..3e5d17d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -253,6 +253,8 @@ qapi-schema += args-alternate.json
 qapi-schema += args-any.json
 qapi-schema += args-array-empty.json
 qapi-schema += args-array-unknown.json
+qapi-schema += args-bad-box.json
+qapi-schema += args-box-anon.json
 qapi-schema += args-int.json
 qapi-schema += args-invalid.json
 qapi-schema += args-member-array-bad.json
diff --git a/tests/qapi-schema/args-bad-box.err b/tests/qapi-schema/args-bad-box.err
new file mode 100644
index 0000000..16afe3c
--- /dev/null
+++ b/tests/qapi-schema/args-bad-box.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-bad-box.json:2: 'box' of command 'foo' should only use true value
diff --git a/tests/qapi-schema/args-bad-box.exit b/tests/qapi-schema/args-bad-box.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/args-bad-box.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/args-bad-box.json b/tests/qapi-schema/args-bad-box.json
new file mode 100644
index 0000000..8d5737a
--- /dev/null
+++ b/tests/qapi-schema/args-bad-box.json
@@ -0,0 +1,2 @@
+# 'box' should only appear with value true
+{ 'command': 'foo', 'box': false }
diff --git a/tests/qapi-schema/args-bad-box.out b/tests/qapi-schema/args-bad-box.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/args-box-anon.err b/tests/qapi-schema/args-box-anon.err
new file mode 100644
index 0000000..11eaefc
--- /dev/null
+++ b/tests/qapi-schema/args-box-anon.err
@@ -0,0 +1 @@
+tests/qapi-schema/args-box-anon.json:2: 'data' for command 'foo' should be a type name
diff --git a/tests/qapi-schema/args-box-anon.exit b/tests/qapi-schema/args-box-anon.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/args-box-anon.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/args-box-anon.json b/tests/qapi-schema/args-box-anon.json
new file mode 100644
index 0000000..947e3c6
--- /dev/null
+++ b/tests/qapi-schema/args-box-anon.json
@@ -0,0 +1,2 @@
+# 'box' can only be used with named types
+{ 'command': 'foo', 'box': true, 'data': { 'string': 'str' } }
diff --git a/tests/qapi-schema/args-box-anon.out b/tests/qapi-schema/args-box-anon.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/args-union.err b/tests/qapi-schema/args-union.err
index 1d693d7..f8ad223 100644
--- a/tests/qapi-schema/args-union.err
+++ b/tests/qapi-schema/args-union.err
@@ -1 +1 @@
-tests/qapi-schema/args-union.json:4: 'data' for command 'oops' cannot use union type 'Uni'
+tests/qapi-schema/args-union.json:3: 'data' for command 'oops' cannot use union type 'Uni'
diff --git a/tests/qapi-schema/args-union.json b/tests/qapi-schema/args-union.json
index 7bdcbb7..c0ce091 100644
--- a/tests/qapi-schema/args-union.json
+++ b/tests/qapi-schema/args-union.json
@@ -1,4 +1,3 @@
-# we do not allow union arguments
-# TODO should we support this?
+# use of union arguments requires 'box':true
 { 'union': 'Uni', 'data': { 'case1': 'int', 'case2': 'str' } }
 { 'command': 'oops', 'data': 'Uni' }
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 44c1965..d0bc3d2 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -126,6 +126,9 @@
 { 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' },
   'returns': 'int' }
 { 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' }
+{ 'command': 'boxed-empty', 'box': true }
+{ 'command': 'boxed-struct', 'box': true, 'data': 'UserDefZero' }
+{ 'command': 'boxed-union', 'data': 'UserDefNativeListUnion', 'box': true }

 # For testing integer range flattening in opts-visitor. The following schema
 # corresponds to the option format:
@@ -146,13 +149,14 @@
 { 'struct': 'EventStructOne',
   'data': { 'struct1': 'UserDefOne', 'string': 'str', '*enum2': 'EnumOne' } }

-{ 'event': 'EVENT_A' }
+{ 'event': 'EVENT_A', 'box': true }
 { 'event': 'EVENT_B',
   'data': { } }
 { 'event': 'EVENT_C',
   'data': { '*a': 'int', '*b': 'UserDefOne', 'c': 'str' } }
 { 'event': 'EVENT_D',
   'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } }
+{ 'event': 'EVENT_E', 'box': true, 'data': 'UserDefZero' }

 # test that we correctly compile downstream extensions, as well as munge
 # ticklish names
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 8731caa..3dc133e 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -100,13 +100,15 @@ alternate AltStrNum
     case s: str
     case n: number
 event EVENT_A :empty
-   box=False
+   box=True
 event EVENT_B :empty
    box=False
 event EVENT_C :obj-EVENT_C-arg
    box=False
 event EVENT_D :obj-EVENT_D-arg
    box=False
+event EVENT_E UserDefZero
+   box=True
 object Empty1
     base :empty
 object Empty2
@@ -246,6 +248,12 @@ object __org.qemu_x-Union2
     case __org.qemu_x-value: __org.qemu_x-Struct2
 command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1
    gen=True success_response=True box=False
+command boxed-empty :empty -> None
+   gen=True success_response=True box=True
+command boxed-struct UserDefZero -> None
+   gen=True success_response=True box=True
+command boxed-union UserDefNativeListUnion -> None
+   gen=True success_response=True box=True
 command guest-get-time :obj-guest-get-time-arg -> int
    gen=True success_response=True box=False
 command guest-sync :obj-guest-sync-arg -> any
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index d3466a4..a58a425 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -59,6 +59,18 @@ QObject *qmp_guest_sync(QObject *arg, Error **errp)
     return arg;
 }

+void qmp_boxed_empty(Error **errp)
+{
+}
+
+void qmp_boxed_struct(UserDefZero *arg, Error **errp)
+{
+}
+
+void qmp_boxed_union(UserDefNativeListUnion *arg, Error **errp)
+{
+}
+
 __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
                                               __org_qemu_x_StructList *b,
                                               __org_qemu_x_Union2 *c,
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 08/16] qapi: support implicit structs in OptsVisitor
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (6 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 07/16] qapi: Implement boxed types for commands/events Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 09/16] qapi: Change Netdev into a flat union Eric Blake
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Michael Roth, armbru, Kővágó, Zoltán

From: Kővágó, Zoltán <dirty.ice.hu@gmail.com>

They are required for flat unions (you still have to allocate the
structs).

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Message-Id: <88451f26df139c09b56b1525f3c5afeea43dd3db.1441627175.git.DirtY.iCE.hu@gmail.com>
[rebase to latest tree]
Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: rebase from original posting and add to series
---
 qapi/opts-visitor.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c
index 28f9a8a..286d655 100644
--- a/qapi/opts-visitor.c
+++ b/qapi/opts-visitor.c
@@ -157,6 +157,12 @@ opts_start_struct(Visitor *v, const char *name, void **obj,
     return result;
 }

+static bool
+opts_start_implicit_struct(Visitor *v, void **obj, size_t size, Error **errp)
+{
+    return opts_start_struct(v, NULL, obj, size, errp);
+}
+

 static void
 opts_check_struct(Visitor *v, Error **errp)
@@ -199,6 +205,12 @@ opts_end_struct(Visitor *v)
     ov->fake_id_opt = NULL;
 }

+static void
+opts_end_implicit_struct(Visitor *v)
+{
+    opts_end_struct(v);
+}
+

 static GQueue *
 lookup_distinct(const OptsVisitor *ov, const char *name, Error **errp)
@@ -521,6 +533,9 @@ opts_visitor_new(const QemuOpts *opts)
     ov->visitor.check_struct = &opts_check_struct;
     ov->visitor.end_struct   = &opts_end_struct;

+    ov->visitor.start_implicit_struct = &opts_start_implicit_struct;
+    ov->visitor.end_implicit_struct = &opts_end_implicit_struct;
+
     ov->visitor.start_list = &opts_start_list;
     ov->visitor.next_list  = &opts_next_list;
     ov->visitor.end_list   = &opts_end_list;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 09/16] qapi: Change Netdev into a flat union
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (7 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 08/16] qapi: support implicit structs in OptsVisitor Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 10/16] net: Use correct type for bool flag Eric Blake
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Maydell, Michael S. Tsirkin, Jason Wang, Vincenzo Maffione,
	Alexander Graf, Max Filippov, Gerd Hoffmann, Dmitry Fleytman,
	Edgar E. Iglesias, Rob Herring, open list:X86, armbru,
	Scott Feldman, Kővágó, Zoltán, Jiri Pirko,
	Stefano Stabellini, Alistair Francis, Beniamino Galvani,
	open list:Musicpal, Jan Kiszka, Scott Wood, Giuseppe Lettieri,
	Luiz Capitulino, Luigi Rizzo, David Gibson, Peter Crosthwaite,
	Michael Walle, open list:ppce500, Peter Chubb

From: Kővágó, Zoltán <dirty.ice.hu@gmail.com>

Except qapi-schema.json, this patch was generated by:

find . -name .git -prune -o -type f \! -name '*~' -print0 | \
  xargs -0 sed -i \
    -e 's/NetClientOptionsKind/NetClientDriver/g' \
    -e 's/NET_CLIENT_OPTIONS_KIND_/NET_CLIENT_DRIVER_/g' \
    -e 's/netdev->opts/netdev/g'

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Message-Id: <01a527fbf1a5de880091f98cf011616a78adeeee.1441627176.git.DirtY.iCE.hu@gmail.com>

Additional changes:
Rebase the patch on top of an earlier change from netdev->kind to
netdev->type, so that tweak is no longer needed here.  Rebase to
latest master which enhanced multiqueue.

Rework so that NetdevLegacy doesn't pollute QMP command but is instead
copied piecewise into the new Netdev, which means that NetClientOptions
must still remain in qapi. Since legacy previously always rejected
'hubport', we can now make that explicit by having the two unions be
slightly different; but that means we must manually map between the
two structures.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: rebase to latest master
---
 hw/arm/musicpal.c                |   2 +-
 hw/core/qdev-properties-system.c |   2 +-
 hw/net/allwinner_emac.c          |   2 +-
 hw/net/cadence_gem.c             |   2 +-
 hw/net/dp8393x.c                 |   2 +-
 hw/net/e1000.c                   |   2 +-
 hw/net/eepro100.c                |   2 +-
 hw/net/etraxfs_eth.c             |   2 +-
 hw/net/fsl_etsec/etsec.c         |   2 +-
 hw/net/imx_fec.c                 |   2 +-
 hw/net/lan9118.c                 |   2 +-
 hw/net/lance.c                   |   2 +-
 hw/net/mcf_fec.c                 |   2 +-
 hw/net/milkymist-minimac2.c      |   2 +-
 hw/net/mipsnet.c                 |   2 +-
 hw/net/ne2000-isa.c              |   2 +-
 hw/net/ne2000.c                  |   2 +-
 hw/net/opencores_eth.c           |   2 +-
 hw/net/pcnet-pci.c               |   2 +-
 hw/net/rocker/rocker_fp.c        |   2 +-
 hw/net/rtl8139.c                 |   2 +-
 hw/net/smc91c111.c               |   2 +-
 hw/net/spapr_llan.c              |   2 +-
 hw/net/stellaris_enet.c          |   2 +-
 hw/net/vhost_net.c               |  16 ++---
 hw/net/virtio-net.c              |  10 +--
 hw/net/vmxnet3.c                 |   2 +-
 hw/net/xen_nic.c                 |   2 +-
 hw/net/xgmac.c                   |   2 +-
 hw/net/xilinx_axienet.c          |   2 +-
 hw/net/xilinx_ethlite.c          |   2 +-
 hw/usb/dev-network.c             |   2 +-
 include/net/net.h                |   4 +-
 monitor.c                        |  14 ++---
 net/dump.c                       |   6 +-
 net/hub.c                        |  22 +++----
 net/l2tpv3.c                     |   6 +-
 net/net.c                        | 133 +++++++++++++++++++++++++--------------
 net/netmap.c                     |   4 +-
 net/slirp.c                      |   6 +-
 net/socket.c                     |   8 +--
 net/tap-win32.c                  |   6 +-
 net/tap.c                        |  24 +++----
 net/vde.c                        |   6 +-
 net/vhost-user.c                 |  18 +++---
 qapi-schema.json                 |  57 +++++++++++++----
 46 files changed, 234 insertions(+), 166 deletions(-)

diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index b534bb9..527b703 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -374,7 +374,7 @@ static void eth_cleanup(NetClientState *nc)
 }

 static NetClientInfo net_mv88w8618_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = eth_receive,
     .cleanup = eth_cleanup,
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index ad3c428ff..959fdea 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -229,7 +229,7 @@ static void set_netdev(Object *obj, Visitor *v, const char *name,
     }

     queues = qemu_find_net_clients_except(str, peers,
-                                          NET_CLIENT_OPTIONS_KIND_NIC,
+                                          NET_CLIENT_DRIVER_NIC,
                                           MAX_QUEUE_NUM);
     if (queues == 0) {
         err = -ENOENT;
diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c
index 0407dee..4fdf824 100644
--- a/hw/net/allwinner_emac.c
+++ b/hw/net/allwinner_emac.c
@@ -422,7 +422,7 @@ static const MemoryRegionOps aw_emac_mem_ops = {
 };

 static NetClientInfo net_aw_emac_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = aw_emac_can_receive,
     .receive = aw_emac_receive,
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 3639fc1..9fe7d19 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -1181,7 +1181,7 @@ static void gem_set_link(NetClientState *nc)
 }

 static NetClientInfo net_gem_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = gem_can_receive,
     .receive = gem_receive,
diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
index ab607e4..fb57900 100644
--- a/hw/net/dp8393x.c
+++ b/hw/net/dp8393x.c
@@ -810,7 +810,7 @@ static void dp8393x_reset(DeviceState *dev)
 }

 static NetClientInfo net_dp83932_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = dp8393x_can_receive,
     .receive = dp8393x_receive,
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index bec06e9..2dd1722 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -1779,7 +1779,7 @@ pci_e1000_uninit(PCIDevice *dev)
 }

 static NetClientInfo net_e1000_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = e1000_can_receive,
     .receive = e1000_receive,
diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c
index 685a478..8ba02f4 100644
--- a/hw/net/eepro100.c
+++ b/hw/net/eepro100.c
@@ -1848,7 +1848,7 @@ static void pci_nic_uninit(PCIDevice *pci_dev)
 }

 static NetClientInfo net_eepro100_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = nic_receive,
 };
diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c
index d600275..f43a170 100644
--- a/hw/net/etraxfs_eth.c
+++ b/hw/net/etraxfs_eth.c
@@ -577,7 +577,7 @@ static const MemoryRegionOps eth_ops = {
 };

 static NetClientInfo net_etraxfs_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = eth_receive,
     .link_status_changed = eth_set_link,
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index 04bb41d..48ee27b 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -369,7 +369,7 @@ static void etsec_set_link_status(NetClientState *nc)
 }

 static NetClientInfo net_etsec_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = etsec_receive,
     .link_status_changed = etsec_set_link_status,
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index c50bf7f..092d77a 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -651,7 +651,7 @@ static void imx_fec_cleanup(NetClientState *nc)
 }

 static NetClientInfo net_imx_fec_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = imx_fec_can_receive,
     .receive = imx_fec_receive,
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
index 1734b52..e18b021 100644
--- a/hw/net/lan9118.c
+++ b/hw/net/lan9118.c
@@ -1311,7 +1311,7 @@ static const MemoryRegionOps lan9118_16bit_mem_ops = {
 };

 static NetClientInfo net_lan9118_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = lan9118_receive,
     .link_status_changed = lan9118_set_link,
diff --git a/hw/net/lance.c b/hw/net/lance.c
index 780b39d..7940c05 100644
--- a/hw/net/lance.c
+++ b/hw/net/lance.c
@@ -92,7 +92,7 @@ static const MemoryRegionOps lance_mem_ops = {
 };

 static NetClientInfo net_lance_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = pcnet_receive,
     .link_status_changed = pcnet_set_link_status,
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
index 21928f9..5386597 100644
--- a/hw/net/mcf_fec.c
+++ b/hw/net/mcf_fec.c
@@ -506,7 +506,7 @@ static const MemoryRegionOps mcf_fec_ops = {
 };

 static NetClientInfo net_mcf_fec_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = mcf_fec_receive,
 };
diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c
index 6302b8b..b05c801 100644
--- a/hw/net/milkymist-minimac2.c
+++ b/hw/net/milkymist-minimac2.c
@@ -443,7 +443,7 @@ static void milkymist_minimac2_reset(DeviceState *d)
 }

 static NetClientInfo net_milkymist_minimac2_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = minimac2_rx,
 };
diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c
index f261011..b9bf03f 100644
--- a/hw/net/mipsnet.c
+++ b/hw/net/mipsnet.c
@@ -218,7 +218,7 @@ static const VMStateDescription vmstate_mipsnet = {
 };

 static NetClientInfo net_mipsnet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = mipsnet_receive,
 };
diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c
index 630cab3..615b401 100644
--- a/hw/net/ne2000-isa.c
+++ b/hw/net/ne2000-isa.c
@@ -42,7 +42,7 @@ typedef struct ISANE2000State {
 } ISANE2000State;

 static NetClientInfo net_ne2000_isa_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = ne2000_receive,
 };
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
index 010f9ef..457f8ae 100644
--- a/hw/net/ne2000.c
+++ b/hw/net/ne2000.c
@@ -705,7 +705,7 @@ void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size)
 }

 static NetClientInfo net_ne2000_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = ne2000_receive,
 };
diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c
index 3642046..4b6407b 100644
--- a/hw/net/opencores_eth.c
+++ b/hw/net/opencores_eth.c
@@ -473,7 +473,7 @@ static ssize_t open_eth_receive(NetClientState *nc,
 }

 static NetClientInfo net_open_eth_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = open_eth_can_receive,
     .receive = open_eth_receive,
diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c
index b4d60b8..c04c3a2 100644
--- a/hw/net/pcnet-pci.c
+++ b/hw/net/pcnet-pci.c
@@ -271,7 +271,7 @@ static void pci_pcnet_uninit(PCIDevice *dev)
 }

 static NetClientInfo net_pci_pcnet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = pcnet_receive,
     .link_status_changed = pcnet_set_link_status,
diff --git a/hw/net/rocker/rocker_fp.c b/hw/net/rocker/rocker_fp.c
index 5906396..a5a173f 100644
--- a/hw/net/rocker/rocker_fp.c
+++ b/hw/net/rocker/rocker_fp.c
@@ -166,7 +166,7 @@ static void fp_port_set_link_status(NetClientState *nc)
 }

 static NetClientInfo fp_port_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = fp_port_receive,
     .receive_iov = fp_port_receive_iov,
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
index 68e43f3..05cb8ee 100644
--- a/hw/net/rtl8139.c
+++ b/hw/net/rtl8139.c
@@ -3411,7 +3411,7 @@ static void rtl8139_set_link_status(NetClientState *nc)
 }

 static NetClientInfo net_rtl8139_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = rtl8139_can_receive,
     .receive = rtl8139_receive,
diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c
index c19cdd1..47db078 100644
--- a/hw/net/smc91c111.c
+++ b/hw/net/smc91c111.c
@@ -754,7 +754,7 @@ static const MemoryRegionOps smc91c111_mem_ops = {
 };

 static NetClientInfo net_smc91c111_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = smc91c111_can_receive_nc,
     .receive = smc91c111_receive,
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index 1ca5e9c..4ee4b92 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -188,7 +188,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
 }

 static NetClientInfo net_spapr_vlan_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = spapr_vlan_can_receive,
     .receive = spapr_vlan_receive,
diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c
index 21a4773..10290fe 100644
--- a/hw/net/stellaris_enet.c
+++ b/hw/net/stellaris_enet.c
@@ -449,7 +449,7 @@ static void stellaris_enet_reset(stellaris_enet_state *s)
 }

 static NetClientInfo net_stellaris_enet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = stellaris_enet_receive,
 };
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 318c3e6..e540694 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -91,10 +91,10 @@ static const int *vhost_net_get_feature_bits(struct vhost_net *net)
     const int *feature_bits = 0;

     switch (net->nc->info->type) {
-    case NET_CLIENT_OPTIONS_KIND_TAP:
+    case NET_CLIENT_DRIVER_TAP:
         feature_bits = kernel_feature_bits;
         break;
-    case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
+    case NET_CLIENT_DRIVER_VHOST_USER:
         feature_bits = user_feature_bits;
         break;
     default:
@@ -126,7 +126,7 @@ uint64_t vhost_net_get_max_queues(VHostNetState *net)
 static int vhost_net_get_fd(NetClientState *backend)
 {
     switch (backend->info->type) {
-    case NET_CLIENT_OPTIONS_KIND_TAP:
+    case NET_CLIENT_DRIVER_TAP:
         return tap_get_fd(backend);
     default:
         fprintf(stderr, "vhost-net requires tap backend\n");
@@ -243,7 +243,7 @@ static int vhost_net_start_one(struct vhost_net *net,
         net->nc->info->poll(net->nc, false);
     }

-    if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
         qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
         file.fd = net->backend;
         for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
@@ -258,7 +258,7 @@ static int vhost_net_start_one(struct vhost_net *net,
     return 0;
 fail:
     file.fd = -1;
-    if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
         while (file.index-- > 0) {
             const VhostOps *vhost_ops = net->dev.vhost_ops;
             int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
@@ -280,7 +280,7 @@ static void vhost_net_stop_one(struct vhost_net *net,
 {
     struct vhost_vring_file file = { .fd = -1 };

-    if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
+    if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
         for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
             const VhostOps *vhost_ops = net->dev.vhost_ops;
             int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
@@ -408,10 +408,10 @@ VHostNetState *get_vhost_net(NetClientState *nc)
     }

     switch (nc->info->type) {
-    case NET_CLIENT_OPTIONS_KIND_TAP:
+    case NET_CLIENT_DRIVER_TAP:
         vhost_net = tap_get_vhost_net(nc);
         break;
-    case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
+    case NET_CLIENT_DRIVER_VHOST_USER:
         vhost_net = vhost_user_get_vhost_net(nc);
         break;
     default:
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index a877614..6628b76 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -406,11 +406,11 @@ static int peer_attach(VirtIONet *n, int index)
         return 0;
     }

-    if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
+    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
         vhost_set_vring_enable(nc->peer, 1);
     }

-    if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
+    if (nc->peer->info->type != NET_CLIENT_DRIVER_TAP) {
         return 0;
     }

@@ -425,11 +425,11 @@ static int peer_detach(VirtIONet *n, int index)
         return 0;
     }

-    if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
+    if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
         vhost_set_vring_enable(nc->peer, 0);
     }

-    if (nc->peer->info->type !=  NET_CLIENT_OPTIONS_KIND_TAP) {
+    if (nc->peer->info->type !=  NET_CLIENT_DRIVER_TAP) {
         return 0;
     }

@@ -1604,7 +1604,7 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
 }

 static NetClientInfo net_virtio_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = virtio_net_can_receive,
     .receive = virtio_net_receive,
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index 37373e5..4159e89 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -2001,7 +2001,7 @@ static void vmxnet3_set_link_status(NetClientState *nc)
 }

 static NetClientInfo net_vmxnet3_info = {
-        .type = NET_CLIENT_OPTIONS_KIND_NIC,
+        .type = NET_CLIENT_DRIVER_NIC,
         .size = sizeof(NICState),
         .receive = vmxnet3_receive,
         .link_status_changed = vmxnet3_set_link_status,
diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c
index 0da16b4..bf90a25 100644
--- a/hw/net/xen_nic.c
+++ b/hw/net/xen_nic.c
@@ -279,7 +279,7 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
 /* ------------------------------------------------------------- */

 static NetClientInfo net_xen_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = net_rx_packet,
 };
diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c
index 15fb681..ccf8a77 100644
--- a/hw/net/xgmac.c
+++ b/hw/net/xgmac.c
@@ -370,7 +370,7 @@ out:
 }

 static NetClientInfo net_xgmac_enet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = eth_rx,
 };
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
index d63c423..cc464c9 100644
--- a/hw/net/xilinx_axienet.c
+++ b/hw/net/xilinx_axienet.c
@@ -933,7 +933,7 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size)
 }

 static NetClientInfo net_xilinx_enet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = eth_rx,
 };
diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c
index ad6b553..ab555f6 100644
--- a/hw/net/xilinx_ethlite.c
+++ b/hw/net/xilinx_ethlite.c
@@ -214,7 +214,7 @@ static void xilinx_ethlite_reset(DeviceState *dev)
 }

 static NetClientInfo net_xilinx_ethlite_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .can_receive = eth_can_rx,
     .receive = eth_rx,
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index 7800cee..97b2c2a 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -1330,7 +1330,7 @@ static void usb_net_handle_destroy(USBDevice *dev)
 }

 static NetClientInfo net_usbnet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .type = NET_CLIENT_DRIVER_NIC,
     .size = sizeof(NICState),
     .receive = usbnet_receive,
     .cleanup = usbnet_cleanup,
diff --git a/include/net/net.h b/include/net/net.h
index 7af3e15..a5ca4ee 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -59,7 +59,7 @@ typedef int (SetVnetLE)(NetClientState *, bool);
 typedef int (SetVnetBE)(NetClientState *, bool);

 typedef struct NetClientInfo {
-    NetClientOptionsKind type;
+    NetClientDriver type;
     size_t size;
     NetReceive *receive;
     NetReceive *receive_raw;
@@ -105,7 +105,7 @@ typedef struct NICState {
 char *qemu_mac_strdup_printf(const uint8_t *macaddr);
 NetClientState *qemu_find_netdev(const char *id);
 int qemu_find_net_clients_except(const char *id, NetClientState **ncs,
-                                 NetClientOptionsKind type, int max);
+                                 NetClientDriver type, int max);
 NetClientState *qemu_new_net_client(NetClientInfo *info,
                                     NetClientState *peer,
                                     const char *model,
diff --git a/monitor.c b/monitor.c
index e7e7ae2..fc3db89 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3033,8 +3033,8 @@ void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str)
     }
     len = strlen(str);
     readline_set_completion_index(rs, len);
-    for (i = 0; NetClientOptionsKind_lookup[i]; i++) {
-        add_completion_option(rs, str, NetClientOptionsKind_lookup[i]);
+    for (i = 0; NetClientDriver_lookup[i]; i++) {
+        add_completion_option(rs, str, NetClientDriver_lookup[i]);
     }
 }

@@ -3234,7 +3234,7 @@ void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
         NetClientState *ncs[MAX_QUEUE_NUM];
         int count, i;
         count = qemu_find_net_clients_except(NULL, ncs,
-                                             NET_CLIENT_OPTIONS_KIND_NONE,
+                                             NET_CLIENT_DRIVER_NONE,
                                              MAX_QUEUE_NUM);
         for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
             const char *name = ncs[i]->name;
@@ -3259,7 +3259,7 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)

     len = strlen(str);
     readline_set_completion_index(rs, len);
-    count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_OPTIONS_KIND_NIC,
+    count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_DRIVER_NIC,
                                          MAX_QUEUE_NUM);
     for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
         QemuOpts *opts;
@@ -3371,7 +3371,7 @@ void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str)
     readline_set_completion_index(rs, len);
     if (nb_args == 2) {
         count = qemu_find_net_clients_except(NULL, ncs,
-                                             NET_CLIENT_OPTIONS_KIND_NONE,
+                                             NET_CLIENT_DRIVER_NONE,
                                              MAX_QUEUE_NUM);
         for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
             int id;
@@ -3388,13 +3388,13 @@ void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str)
         return;
     } else if (nb_args == 3) {
         count = qemu_find_net_clients_except(NULL, ncs,
-                                             NET_CLIENT_OPTIONS_KIND_NIC,
+                                             NET_CLIENT_DRIVER_NIC,
                                              MAX_QUEUE_NUM);
         for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
             int id;
             const char *name;

-            if (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT ||
+            if (ncs[i]->info->type == NET_CLIENT_DRIVER_HUBPORT ||
                 net_hub_id_for_client(ncs[i], &id)) {
                 continue;
             }
diff --git a/net/dump.c b/net/dump.c
index b75b49a..f3bb80f 100644
--- a/net/dump.c
+++ b/net/dump.c
@@ -170,7 +170,7 @@ static void dumpclient_cleanup(NetClientState *nc)
 }

 static NetClientInfo net_dump_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_DUMP,
+    .type = NET_CLIENT_DRIVER_DUMP,
     .size = sizeof(DumpNetClient),
     .receive = dumpclient_receive,
     .receive_iov = dumpclient_receive_iov,
@@ -187,8 +187,8 @@ int net_init_dump(const Netdev *netdev, const char *name,
     NetClientState *nc;
     DumpNetClient *dnc;

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_DUMP);
-    dump = netdev->opts->u.dump;
+    assert(netdev->type == NET_CLIENT_DRIVER_DUMP);
+    dump = netdev->u.dump;

     assert(peer);

diff --git a/net/hub.c b/net/hub.c
index 9a57905..42f1b5c 100644
--- a/net/hub.c
+++ b/net/hub.c
@@ -130,7 +130,7 @@ static void net_hub_port_cleanup(NetClientState *nc)
 }

 static NetClientInfo net_hub_port_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_HUBPORT,
+    .type = NET_CLIENT_DRIVER_HUBPORT,
     .size = sizeof(NetHubPort),
     .can_receive = net_hub_port_can_receive,
     .receive = net_hub_port_receive,
@@ -265,10 +265,10 @@ int net_hub_id_for_client(NetClientState *nc, int *id)
 {
     NetHubPort *port;

-    if (nc->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
+    if (nc->info->type == NET_CLIENT_DRIVER_HUBPORT) {
         port = DO_UPCAST(NetHubPort, nc, nc);
     } else if (nc->peer != NULL && nc->peer->info->type ==
-            NET_CLIENT_OPTIONS_KIND_HUBPORT) {
+            NET_CLIENT_DRIVER_HUBPORT) {
         port = DO_UPCAST(NetHubPort, nc, nc->peer);
     } else {
         return -ENOENT;
@@ -285,9 +285,9 @@ int net_init_hubport(const Netdev *netdev, const char *name,
 {
     const NetdevHubPortOptions *hubport;

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT);
+    assert(netdev->type == NET_CLIENT_DRIVER_HUBPORT);
     assert(!peer);
-    hubport = netdev->opts->u.hubport;
+    hubport = netdev->u.hubport;

     net_hub_add_port(hubport->hubid, name);
     return 0;
@@ -314,14 +314,14 @@ void net_hub_check_clients(void)
             }

             switch (peer->info->type) {
-            case NET_CLIENT_OPTIONS_KIND_NIC:
+            case NET_CLIENT_DRIVER_NIC:
                 has_nic = 1;
                 break;
-            case NET_CLIENT_OPTIONS_KIND_USER:
-            case NET_CLIENT_OPTIONS_KIND_TAP:
-            case NET_CLIENT_OPTIONS_KIND_SOCKET:
-            case NET_CLIENT_OPTIONS_KIND_VDE:
-            case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
+            case NET_CLIENT_DRIVER_USER:
+            case NET_CLIENT_DRIVER_TAP:
+            case NET_CLIENT_DRIVER_SOCKET:
+            case NET_CLIENT_DRIVER_VDE:
+            case NET_CLIENT_DRIVER_VHOST_USER:
                 has_host_dev = 1;
                 break;
             default:
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
index c3511d7..423e9ef 100644
--- a/net/l2tpv3.c
+++ b/net/l2tpv3.c
@@ -516,7 +516,7 @@ static void net_l2tpv3_cleanup(NetClientState *nc)
 }

 static NetClientInfo net_l2tpv3_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_L2TPV3,
+    .type = NET_CLIENT_DRIVER_L2TPV3,
     .size = sizeof(NetL2TPV3State),
     .receive = net_l2tpv3_receive_dgram,
     .receive_iov = net_l2tpv3_receive_dgram_iov,
@@ -545,8 +545,8 @@ int net_init_l2tpv3(const Netdev *netdev,
     s->queue_tail = 0;
     s->header_mismatch = false;

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_L2TPV3);
-    l2tpv3 = netdev->opts->u.l2tpv3;
+    assert(netdev->type == NET_CLIENT_DRIVER_L2TPV3);
+    l2tpv3 = netdev->u.l2tpv3;

     if (l2tpv3->has_ipv6 && l2tpv3->ipv6) {
         s->ipv6 = l2tpv3->ipv6;
diff --git a/net/net.c b/net/net.c
index 0902ed2..a6f9be9 100644
--- a/net/net.c
+++ b/net/net.c
@@ -317,7 +317,7 @@ NICState *qemu_new_nic(NetClientInfo *info,
     NICState *nic;
     int i, queues = MAX(1, conf->peers.queues);

-    assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC);
+    assert(info->type == NET_CLIENT_DRIVER_NIC);
     assert(info->size >= sizeof(NICState));

     nic = g_malloc0(info->size + sizeof(NetClientState) * queues);
@@ -388,13 +388,13 @@ void qemu_del_net_client(NetClientState *nc)
     int queues, i;
     NetFilterState *nf, *next;

-    assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC);
+    assert(nc->info->type != NET_CLIENT_DRIVER_NIC);

     /* If the NetClientState belongs to a multiqueue backend, we will change all
      * other NetClientStates also.
      */
     queues = qemu_find_net_clients_except(nc->name, ncs,
-                                          NET_CLIENT_OPTIONS_KIND_NIC,
+                                          NET_CLIENT_DRIVER_NIC,
                                           MAX_QUEUE_NUM);
     assert(queues != 0);

@@ -403,7 +403,7 @@ void qemu_del_net_client(NetClientState *nc)
     }

     /* If there is a peer NIC, delete and cleanup client, but do not free. */
-    if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
+    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
         NICState *nic = qemu_get_nic(nc->peer);
         if (nic->peer_deleted) {
             return;
@@ -459,7 +459,7 @@ void qemu_foreach_nic(qemu_nic_foreach func, void *opaque)
     NetClientState *nc;

     QTAILQ_FOREACH(nc, &net_clients, next) {
-        if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
+        if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
             if (nc->queue_index == 0) {
                 func(qemu_get_nic(nc), opaque);
             }
@@ -621,7 +621,7 @@ void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge)
 {
     nc->receive_disabled = 0;

-    if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
+    if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_HUBPORT) {
         if (net_hub_flush(nc->peer)) {
             qemu_notify_event();
         }
@@ -790,7 +790,7 @@ NetClientState *qemu_find_netdev(const char *id)
     NetClientState *nc;

     QTAILQ_FOREACH(nc, &net_clients, next) {
-        if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC)
+        if (nc->info->type == NET_CLIENT_DRIVER_NIC)
             continue;
         if (!strcmp(nc->name, id)) {
             return nc;
@@ -801,7 +801,7 @@ NetClientState *qemu_find_netdev(const char *id)
 }

 int qemu_find_net_clients_except(const char *id, NetClientState **ncs,
-                                 NetClientOptionsKind type, int max)
+                                 NetClientDriver type, int max)
 {
     NetClientState *nc;
     int ret = 0;
@@ -882,8 +882,8 @@ static int net_init_nic(const Netdev *netdev, const char *name,
     NICInfo *nd;
     const NetLegacyNicOptions *nic;

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_NIC);
-    nic = netdev->opts->u.nic;
+    assert(netdev->type == NET_CLIENT_DRIVER_NIC);
+    nic = netdev->u.nic;

     idx = nic_get_free_idx();
     if (idx == -1 || nb_nics >= MAX_NICS) {
@@ -943,39 +943,38 @@ static int net_init_nic(const Netdev *netdev, const char *name,
 }


-static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND__MAX])(
+static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
     const Netdev *netdev,
     const char *name,
     NetClientState *peer, Error **errp) = {
-        [NET_CLIENT_OPTIONS_KIND_NIC]       = net_init_nic,
+        [NET_CLIENT_DRIVER_NIC]       = net_init_nic,
 #ifdef CONFIG_SLIRP
-        [NET_CLIENT_OPTIONS_KIND_USER]      = net_init_slirp,
+        [NET_CLIENT_DRIVER_USER]      = net_init_slirp,
 #endif
-        [NET_CLIENT_OPTIONS_KIND_TAP]       = net_init_tap,
-        [NET_CLIENT_OPTIONS_KIND_SOCKET]    = net_init_socket,
+        [NET_CLIENT_DRIVER_TAP]       = net_init_tap,
+        [NET_CLIENT_DRIVER_SOCKET]    = net_init_socket,
 #ifdef CONFIG_VDE
-        [NET_CLIENT_OPTIONS_KIND_VDE]       = net_init_vde,
+        [NET_CLIENT_DRIVER_VDE]       = net_init_vde,
 #endif
 #ifdef CONFIG_NETMAP
-        [NET_CLIENT_OPTIONS_KIND_NETMAP]    = net_init_netmap,
+        [NET_CLIENT_DRIVER_NETMAP]    = net_init_netmap,
 #endif
-        [NET_CLIENT_OPTIONS_KIND_DUMP]      = net_init_dump,
+        [NET_CLIENT_DRIVER_DUMP]      = net_init_dump,
 #ifdef CONFIG_NET_BRIDGE
-        [NET_CLIENT_OPTIONS_KIND_BRIDGE]    = net_init_bridge,
+        [NET_CLIENT_DRIVER_BRIDGE]    = net_init_bridge,
 #endif
-        [NET_CLIENT_OPTIONS_KIND_HUBPORT]   = net_init_hubport,
+        [NET_CLIENT_DRIVER_HUBPORT]   = net_init_hubport,
 #ifdef CONFIG_VHOST_NET_USED
-        [NET_CLIENT_OPTIONS_KIND_VHOST_USER] = net_init_vhost_user,
+        [NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user,
 #endif
 #ifdef CONFIG_L2TPV3
-        [NET_CLIENT_OPTIONS_KIND_L2TPV3]    = net_init_l2tpv3,
+        [NET_CLIENT_DRIVER_L2TPV3]    = net_init_l2tpv3,
 #endif
 };


 static int net_client_init1(const void *object, int is_netdev, Error **errp)
 {
-    const NetClientOptions *opts;
     Netdev legacy = {0};
     const Netdev *netdev;
     const char *name;
@@ -983,34 +982,72 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)

     if (is_netdev) {
         netdev = object;
-        opts = netdev->opts;
         name = netdev->id;

-        if (opts->type == NET_CLIENT_OPTIONS_KIND_DUMP ||
-            opts->type == NET_CLIENT_OPTIONS_KIND_NIC ||
-            !net_client_init_fun[opts->type]) {
+        if (netdev->type == NET_CLIENT_DRIVER_DUMP ||
+            netdev->type == NET_CLIENT_DRIVER_NIC ||
+            !net_client_init_fun[netdev->type]) {
             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
                        "a netdev backend type");
             return -1;
         }
     } else {
         const NetLegacy *net = object;
+        const NetClientOptions *opts = net->opts;
         legacy.id = net->id;
-        opts = legacy.opts = net->opts;
         netdev = &legacy;
         /* missing optional values have been initialized to "all bits zero" */
         name = net->has_id ? net->id : net->name;

-        if (opts->type == NET_CLIENT_OPTIONS_KIND_NONE) {
+        /* Map the old options to the new flat type */
+        switch (opts->type) {
+        case NET_CLIENT_OPTIONS_KIND_NONE:
             return 0; /* nothing to do */
-        }
-        if (opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) {
-            error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
-                       "a net type");
-            return -1;
+        case NET_CLIENT_OPTIONS_KIND_NIC:
+            legacy.type = NET_CLIENT_DRIVER_NIC;
+            legacy.u.nic = opts->u.nic;
+            break;
+        case NET_CLIENT_OPTIONS_KIND_USER:
+            legacy.type = NET_CLIENT_DRIVER_USER;
+            legacy.u.user = opts->u.user;
+            break;
+        case NET_CLIENT_OPTIONS_KIND_TAP:
+            legacy.type = NET_CLIENT_DRIVER_TAP;
+            legacy.u.tap = opts->u.tap;
+            break;
+        case NET_CLIENT_OPTIONS_KIND_L2TPV3:
+            legacy.type = NET_CLIENT_DRIVER_L2TPV3;
+            legacy.u.l2tpv3 = opts->u.l2tpv3;
+            break;
+        case NET_CLIENT_OPTIONS_KIND_SOCKET:
+            legacy.type = NET_CLIENT_DRIVER_SOCKET;
+            legacy.u.socket = opts->u.socket;
+            break;
+        case NET_CLIENT_OPTIONS_KIND_VDE:
+            legacy.type = NET_CLIENT_DRIVER_VDE;
+            legacy.u.vde = opts->u.vde;
+            break;
+        case NET_CLIENT_OPTIONS_KIND_DUMP:
+            legacy.type = NET_CLIENT_DRIVER_DUMP;
+            legacy.u.dump = opts->u.dump;
+            break;
+        case NET_CLIENT_OPTIONS_KIND_BRIDGE:
+            legacy.type = NET_CLIENT_DRIVER_BRIDGE;
+            legacy.u.bridge = opts->u.bridge;
+            break;
+        case NET_CLIENT_OPTIONS_KIND_NETMAP:
+            legacy.type = NET_CLIENT_DRIVER_NETMAP;
+            legacy.u.netmap = opts->u.netmap;
+            break;
+        case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
+            legacy.type = NET_CLIENT_DRIVER_VHOST_USER;
+            legacy.u.vhost_user = opts->u.vhost_user;
+            break;
+        default:
+            abort();
         }

-        if (!net_client_init_fun[opts->type]) {
+        if (!net_client_init_fun[netdev->type]) {
             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
                        "a net backend type (maybe it is not compiled "
                        "into this binary)");
@@ -1018,17 +1055,17 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
         }

         /* Do not add to a vlan if it's a nic with a netdev= parameter. */
-        if (opts->type != NET_CLIENT_OPTIONS_KIND_NIC ||
+        if (netdev->type != NET_CLIENT_DRIVER_NIC ||
             !opts->u.nic->has_netdev) {
             peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL);
         }
     }

-    if (net_client_init_fun[opts->type](netdev, name, peer, errp) < 0) {
+    if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) {
         /* FIXME drop when all init functions store an Error */
         if (errp && !*errp) {
             error_setg(errp, QERR_DEVICE_INIT_FAILED,
-                       NetClientOptionsKind_lookup[opts->type]);
+                       NetClientDriver_lookup[netdev->type]);
         }
         return -1;
     }
@@ -1127,7 +1164,7 @@ void hmp_host_net_remove(Monitor *mon, const QDict *qdict)
                      device, vlan_id);
         return;
     }
-    if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
+    if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
         error_report("invalid host network device '%s'", device);
         return;
     }
@@ -1195,7 +1232,7 @@ void print_net_client(Monitor *mon, NetClientState *nc)

     monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name,
                    nc->queue_index,
-                   NetClientOptionsKind_lookup[nc->info->type],
+                   NetClientDriver_lookup[nc->info->type],
                    nc->info_str);
     if (!QTAILQ_EMPTY(&nc->filters)) {
         monitor_printf(mon, "filters:\n");
@@ -1224,7 +1261,7 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name,
         }

         /* only query rx-filter information of NIC */
-        if (nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC) {
+        if (nc->info->type != NET_CLIENT_DRIVER_NIC) {
             if (has_name) {
                 error_setg(errp, "net client(%s) isn't a NIC", name);
                 return NULL;
@@ -1270,7 +1307,7 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name,
 void hmp_info_network(Monitor *mon, const QDict *qdict)
 {
     NetClientState *nc, *peer;
-    NetClientOptionsKind type;
+    NetClientDriver type;

     net_hub_info(mon);

@@ -1283,10 +1320,10 @@ void hmp_info_network(Monitor *mon, const QDict *qdict)
             continue;
         }

-        if (!peer || type == NET_CLIENT_OPTIONS_KIND_NIC) {
+        if (!peer || type == NET_CLIENT_DRIVER_NIC) {
             print_net_client(mon, nc);
         } /* else it's a netdev connected to a NIC, printed with the NIC */
-        if (peer && type == NET_CLIENT_OPTIONS_KIND_NIC) {
+        if (peer && type == NET_CLIENT_DRIVER_NIC) {
             monitor_printf(mon, " \\ ");
             print_net_client(mon, peer);
         }
@@ -1300,7 +1337,7 @@ void qmp_set_link(const char *name, bool up, Error **errp)
     int queues, i;

     queues = qemu_find_net_clients_except(name, ncs,
-                                          NET_CLIENT_OPTIONS_KIND__MAX,
+                                          NET_CLIENT_DRIVER__MAX,
                                           MAX_QUEUE_NUM);

     if (queues == 0) {
@@ -1327,7 +1364,7 @@ void qmp_set_link(const char *name, bool up, Error **errp)
          * multiple clients that can still communicate with each other in
          * disconnected mode. For now maintain this compatibility.
          */
-        if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
+        if (nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
             for (i = 0; i < queues; i++) {
                 ncs[i]->peer->link_down = !up;
             }
@@ -1368,7 +1405,7 @@ void net_cleanup(void)
      */
     while (!QTAILQ_EMPTY(&net_clients)) {
         nc = QTAILQ_FIRST(&net_clients);
-        if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
+        if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
             qemu_del_nic(qemu_get_nic(nc));
         } else {
             qemu_del_net_client(nc);
@@ -1400,7 +1437,7 @@ void net_check_clients(void)
     QTAILQ_FOREACH(nc, &net_clients, next) {
         if (!nc->peer) {
             fprintf(stderr, "Warning: %s %s has no peer\n",
-                    nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC ?
+                    nc->info->type == NET_CLIENT_DRIVER_NIC ?
                     "nic" : "netdev", nc->name);
         }
     }
diff --git a/net/netmap.c b/net/netmap.c
index 89419c1..068748b 100644
--- a/net/netmap.c
+++ b/net/netmap.c
@@ -415,7 +415,7 @@ static void netmap_set_offload(NetClientState *nc, int csum, int tso4, int tso6,

 /* NetClientInfo methods */
 static NetClientInfo net_netmap_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NETMAP,
+    .type = NET_CLIENT_DRIVER_NETMAP,
     .size = sizeof(NetmapState),
     .receive = netmap_receive,
     .receive_iov = netmap_receive_iov,
@@ -436,7 +436,7 @@ static NetClientInfo net_netmap_info = {
 int net_init_netmap(const Netdev *netdev,
                     const char *name, NetClientState *peer, Error **errp)
 {
-    const NetdevNetmapOptions *netmap_opts = netdev->opts->u.netmap;
+    const NetdevNetmapOptions *netmap_opts = netdev->u.netmap;
     NetClientState *nc;
     Error *err = NULL;
     NetmapPriv me;
diff --git a/net/slirp.c b/net/slirp.c
index a3c40d9..f10c1b8 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -126,7 +126,7 @@ static void net_slirp_cleanup(NetClientState *nc)
 }

 static NetClientInfo net_slirp_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_USER,
+    .type = NET_CLIENT_DRIVER_USER,
     .size = sizeof(SlirpState),
     .receive = net_slirp_receive,
     .cleanup = net_slirp_cleanup,
@@ -746,8 +746,8 @@ int net_init_slirp(const Netdev *netdev, const char *name,
     const NetdevUserOptions *user;
     const char **dnssearch;

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_USER);
-    user = netdev->opts->u.user;
+    assert(netdev->type == NET_CLIENT_DRIVER_USER);
+    user = netdev->u.user;

     vnet = user->has_net ? g_strdup(user->net) :
            user->has_ip  ? g_strdup_printf("%s/24", user->ip) :
diff --git a/net/socket.c b/net/socket.c
index 0098896..6251579 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -346,7 +346,7 @@ static void net_socket_cleanup(NetClientState *nc)
 }

 static NetClientInfo net_dgram_socket_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_SOCKET,
+    .type = NET_CLIENT_DRIVER_SOCKET,
     .size = sizeof(NetSocketState),
     .receive = net_socket_receive_dgram,
     .cleanup = net_socket_cleanup,
@@ -429,7 +429,7 @@ static void net_socket_connect(void *opaque)
 }

 static NetClientInfo net_socket_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_SOCKET,
+    .type = NET_CLIENT_DRIVER_SOCKET,
     .size = sizeof(NetSocketState),
     .receive = net_socket_receive,
     .cleanup = net_socket_cleanup,
@@ -706,8 +706,8 @@ int net_init_socket(const Netdev *netdev, const char *name,
     Error *err = NULL;
     const NetdevSocketOptions *sock;

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET);
-    sock = netdev->opts->u.socket;
+    assert(netdev->type == NET_CLIENT_DRIVER_SOCKET);
+    sock = netdev->u.socket;

     if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast +
         sock->has_udp != 1) {
diff --git a/net/tap-win32.c b/net/tap-win32.c
index e442727..fdf27ce 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -750,7 +750,7 @@ static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
 }

 static NetClientInfo net_tap_win32_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_TAP,
+    .type = NET_CLIENT_DRIVER_TAP,
     .size = sizeof(TAPState),
     .receive = tap_receive,
     .cleanup = tap_cleanup,
@@ -794,8 +794,8 @@ int net_init_tap(const Netdev *netdev, const char *name,
     /* FIXME error_setg(errp, ...) on failure */
     const NetdevTapOptions *tap;

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
-    tap = netdev->opts->u.tap;
+    assert(netdev->type == NET_CLIENT_DRIVER_TAP);
+    tap = netdev->u.tap;

     if (!tap->has_ifname) {
         error_report("tap: no interface name");
diff --git a/net/tap.c b/net/tap.c
index b218913..0dabfeb 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -221,7 +221,7 @@ static bool tap_has_ufo(NetClientState *nc)
 {
     TAPState *s = DO_UPCAST(TAPState, nc, nc);

-    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    assert(nc->info->type == NET_CLIENT_DRIVER_TAP);

     return s->has_ufo;
 }
@@ -230,7 +230,7 @@ static bool tap_has_vnet_hdr(NetClientState *nc)
 {
     TAPState *s = DO_UPCAST(TAPState, nc, nc);

-    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    assert(nc->info->type == NET_CLIENT_DRIVER_TAP);

     return !!s->host_vnet_hdr_len;
 }
@@ -239,7 +239,7 @@ static bool tap_has_vnet_hdr_len(NetClientState *nc, int len)
 {
     TAPState *s = DO_UPCAST(TAPState, nc, nc);

-    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    assert(nc->info->type == NET_CLIENT_DRIVER_TAP);

     return !!tap_probe_vnet_hdr_len(s->fd, len);
 }
@@ -248,7 +248,7 @@ static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
 {
     TAPState *s = DO_UPCAST(TAPState, nc, nc);

-    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
     assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) ||
            len == sizeof(struct virtio_net_hdr));

@@ -260,7 +260,7 @@ static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr)
 {
     TAPState *s = DO_UPCAST(TAPState, nc, nc);

-    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
     assert(!!s->host_vnet_hdr_len == using_vnet_hdr);

     s->using_vnet_hdr = using_vnet_hdr;
@@ -326,14 +326,14 @@ static void tap_poll(NetClientState *nc, bool enable)
 int tap_get_fd(NetClientState *nc)
 {
     TAPState *s = DO_UPCAST(TAPState, nc, nc);
-    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
     return s->fd;
 }

 /* fd support */

 static NetClientInfo net_tap_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_TAP,
+    .type = NET_CLIENT_DRIVER_TAP,
     .size = sizeof(TAPState),
     .receive = tap_receive,
     .receive_raw = tap_receive_raw,
@@ -565,8 +565,8 @@ int net_init_bridge(const Netdev *netdev, const char *name,
     TAPState *s;
     int fd, vnet_hdr;

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_BRIDGE);
-    bridge = netdev->opts->u.bridge;
+    assert(netdev->type == NET_CLIENT_DRIVER_BRIDGE);
+    bridge = netdev->u.bridge;

     helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER;
     br     = bridge->has_br     ? bridge->br     : DEFAULT_BRIDGE_INTERFACE;
@@ -728,8 +728,8 @@ int net_init_tap(const Netdev *netdev, const char *name,
     const char *vhostfdname;
     char ifname[128];

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
-    tap = netdev->opts->u.tap;
+    assert(netdev->type == NET_CLIENT_DRIVER_TAP);
+    tap = netdev->u.tap;
     queues = tap->has_queues ? tap->queues : 1;
     vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL;

@@ -890,7 +890,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
 VHostNetState *tap_get_vhost_net(NetClientState *nc)
 {
     TAPState *s = DO_UPCAST(TAPState, nc, nc);
-    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP);
+    assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
     return s->vhost_net;
 }

diff --git a/net/vde.c b/net/vde.c
index 23834d7..c590335 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -68,7 +68,7 @@ static void vde_cleanup(NetClientState *nc)
 }

 static NetClientInfo net_vde_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_VDE,
+    .type = NET_CLIENT_DRIVER_VDE,
     .size = sizeof(VDEState),
     .receive = vde_receive,
     .cleanup = vde_cleanup,
@@ -115,8 +115,8 @@ int net_init_vde(const Netdev *netdev, const char *name,
     /* FIXME error_setg(errp, ...) on failure */
     const NetdevVdeOptions *vde;

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_VDE);
-    vde = netdev->opts->u.vde;
+    assert(netdev->type == NET_CLIENT_DRIVER_VDE);
+    vde = netdev->u.vde;

     /* missing optional values have been initialized to "all bits zero" */
     if (net_vde_init(peer, "vde", name, vde->sock, vde->port, vde->group,
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 506398e..1f138f6 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -32,7 +32,7 @@ typedef struct VhostUserChardevProps {
 VHostNetState *vhost_user_get_vhost_net(NetClientState *nc)
 {
     VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc);
-    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
+    assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);
     return s->vhost_net;
 }

@@ -47,7 +47,7 @@ static void vhost_user_stop(int queues, NetClientState *ncs[])
     int i;

     for (i = 0; i < queues; i++) {
-        assert (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
+        assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);

         s = DO_UPCAST(VhostUserState, nc, ncs[i]);
         if (!vhost_user_running(s)) {
@@ -71,7 +71,7 @@ static int vhost_user_start(int queues, NetClientState *ncs[])
     options.backend_type = VHOST_BACKEND_TYPE_USER;

     for (i = 0; i < queues; i++) {
-        assert (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
+        assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);

         s = DO_UPCAST(VhostUserState, nc, ncs[i]);
         if (vhost_user_running(s)) {
@@ -146,20 +146,20 @@ static void vhost_user_cleanup(NetClientState *nc)

 static bool vhost_user_has_vnet_hdr(NetClientState *nc)
 {
-    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
+    assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);

     return true;
 }

 static bool vhost_user_has_ufo(NetClientState *nc)
 {
-    assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
+    assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_USER);

     return true;
 }

 static NetClientInfo net_vhost_user_info = {
-        .type = NET_CLIENT_OPTIONS_KIND_VHOST_USER,
+        .type = NET_CLIENT_DRIVER_VHOST_USER,
         .size = sizeof(VhostUserState),
         .receive = vhost_user_receive,
         .cleanup = vhost_user_cleanup,
@@ -176,7 +176,7 @@ static void net_vhost_user_event(void *opaque, int event)
     int queues;

     queues = qemu_find_net_clients_except(name, ncs,
-                                          NET_CLIENT_OPTIONS_KIND_NIC,
+                                          NET_CLIENT_DRIVER_NIC,
                                           MAX_QUEUE_NUM);
     s = DO_UPCAST(VhostUserState, nc, ncs[0]);
     trace_vhost_user_event(s->chr->label, event);
@@ -301,8 +301,8 @@ int net_init_vhost_user(const Netdev *netdev, const char *name,
     const NetdevVhostUserOptions *vhost_user_opts;
     CharDriverState *chr;

-    assert(netdev->opts->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
-    vhost_user_opts = netdev->opts->u.vhost_user;
+    assert(netdev->type == NET_CLIENT_DRIVER_VHOST_USER);
+    vhost_user_opts = netdev->u.vhost_user;

     chr = net_vhost_parse_chardev(vhost_user_opts, errp);
     if (!chr) {
diff --git a/qapi-schema.json b/qapi-schema.json
index 2e31733..73de7b0 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2673,16 +2673,42 @@
     '*queues':        'int' } }

 ##
-# @NetClientOptions
+# @NetClientDriver
 #
-# A discriminated record of network device traits.
+# Available netdev drivers.
+#
+# Since 2.5
+##
+{ 'enum': 'NetClientDriver',
+  'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde', 'dump',
+            'bridge', 'hubport', 'netmap', 'vhost-user' ] }
+
+##
+# @NetdevBase
+#
+# Captures the common configuration of a network device.
+#
+# @id: identifier for monitor commands.
+#
+# @type: Specify the driver used for interpreting remaining arguments.
+#
+# Since 1.2
+##
+{ 'struct': 'NetdevBase',
+  'data': { 'id': 'str', 'type': 'NetClientDriver' } }
+
+##
+# @Netdev
+#
+# Captures the configuration of a network device.
 #
 # Since 1.2
 #
 # 'l2tpv3' - since 2.1
-#
 ##
-{ 'union': 'NetClientOptions',
+{ 'union': 'Netdev',
+  'base': 'NetdevBase',
+  'discriminator': 'type',
   'data': {
     'none':     'NetdevNoneOptions',
     'nic':      'NetLegacyNicOptions',
@@ -2720,20 +2746,25 @@
     'opts':  'NetClientOptions' } }

 ##
-# @Netdev
+# @NetClientOptions
 #
-# Captures the configuration of a network device.
-#
-# @id: identifier for monitor commands.
-#
-# @opts: device type specific properties
+# Like Netdev, but for use only by the legacy command line options
 #
 # Since 1.2
 ##
-{ 'struct': 'Netdev',
+{ 'union': 'NetClientOptions',
   'data': {
-    'id':   'str',
-    'opts': 'NetClientOptions' } }
+    'none':     'NetdevNoneOptions',
+    'nic':      'NetLegacyNicOptions',
+    'user':     'NetdevUserOptions',
+    'tap':      'NetdevTapOptions',
+    'l2tpv3':   'NetdevL2TPv3Options',
+    'socket':   'NetdevSocketOptions',
+    'vde':      'NetdevVdeOptions',
+    'dump':     'NetdevDumpOptions',
+    'bridge':   'NetdevBridgeOptions',
+    'netmap':   'NetdevNetmapOptions',
+    'vhost-user': 'NetdevVhostUserOptions' } }

 ##
 # @NetFilterDirection
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 10/16] net: Use correct type for bool flag
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (8 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 09/16] qapi: Change Netdev into a flat union Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 11/16] net: Complete qapi-fication of netdev_add Eric Blake
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jason Wang, armbru, Gerd Hoffmann

is_netdev is only used as a bool, so make it one.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: rebase to latest context
---
 hw/usb/dev-network.c |  2 +-
 include/net/net.h    |  2 +-
 net/net.c            | 12 ++++++------
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index 97b2c2a..174bad4 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -1392,7 +1392,7 @@ static USBDevice *usb_net_init(USBBus *bus, const char *cmdline)
     qemu_opt_set(opts, "type", "nic", &error_abort);
     qemu_opt_set(opts, "model", "usb", &error_abort);

-    idx = net_client_init(opts, 0, &local_err);
+    idx = net_client_init(opts, false, &local_err);
     if (local_err) {
         error_report_err(local_err);
         return NULL;
diff --git a/include/net/net.h b/include/net/net.h
index a5ca4ee..401b91d 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -185,7 +185,7 @@ extern const char *host_net_devices[];
 extern const char *legacy_tftp_prefix;
 extern const char *legacy_bootp_filename;

-int net_client_init(QemuOpts *opts, int is_netdev, Error **errp);
+int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp);
 int net_client_parse(QemuOptsList *opts_list, const char *str);
 int net_init_clients(void);
 void net_check_clients(void);
diff --git a/net/net.c b/net/net.c
index a6f9be9..14c6021 100644
--- a/net/net.c
+++ b/net/net.c
@@ -973,7 +973,7 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
 };


-static int net_client_init1(const void *object, int is_netdev, Error **errp)
+static int net_client_init1(const void *object, bool is_netdev, Error **errp)
 {
     Netdev legacy = {0};
     const Netdev *netdev;
@@ -1083,7 +1083,7 @@ static void net_visit(Visitor *v, int is_netdev, void **object, Error **errp)
 }


-int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
+int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
 {
     void *object = NULL;
     Error *err = NULL;
@@ -1145,7 +1145,7 @@ void hmp_host_net_add(Monitor *mon, const QDict *qdict)

     qemu_opt_set(opts, "type", device, &error_abort);

-    net_client_init(opts, 0, &local_err);
+    net_client_init(opts, false, &local_err);
     if (local_err) {
         error_report_err(local_err);
         monitor_printf(mon, "adding host network device %s failed\n", device);
@@ -1175,7 +1175,7 @@ void hmp_host_net_remove(Monitor *mon, const QDict *qdict)

 void netdev_add(QemuOpts *opts, Error **errp)
 {
-    net_client_init(opts, 1, errp);
+    net_client_init(opts, true, errp);
 }

 void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp)
@@ -1461,7 +1461,7 @@ static int net_init_client(void *dummy, QemuOpts *opts, Error **errp)
 {
     Error *local_err = NULL;

-    net_client_init(opts, 0, &local_err);
+    net_client_init(opts, false, &local_err);
     if (local_err) {
         error_report_err(local_err);
         return -1;
@@ -1475,7 +1475,7 @@ static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp)
     Error *local_err = NULL;
     int ret;

-    ret = net_client_init(opts, 1, &local_err);
+    ret = net_client_init(opts, true, &local_err);
     if (local_err) {
         error_report_err(local_err);
         return -1;
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 11/16] net: Complete qapi-fication of netdev_add
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (9 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 10/16] net: Use correct type for bool flag Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 12/16] qapi: Allow anonymous base for flat union Eric Blake
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: Jason Wang, armbru

We finally have all the required pieces for doing a type-safe
representation of netdev_add as a flat union, where the
discriminator 'type' now selects which additional members may
appear in the "arguments" JSON object sent over QMP, while
making no changes to the set of previously-valid QMP commands
that would work, and without breaking command line parsing.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: don't lose qemu_opts handling
---
 include/net/net.h |  1 -
 net/net.c         |  6 +++---
 qapi-schema.json  | 15 +++------------
 qmp-commands.hx   |  2 +-
 4 files changed, 7 insertions(+), 17 deletions(-)

diff --git a/include/net/net.h b/include/net/net.h
index 401b91d..b962b95 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -193,7 +193,6 @@ void net_cleanup(void);
 void hmp_host_net_add(Monitor *mon, const QDict *qdict);
 void hmp_host_net_remove(Monitor *mon, const QDict *qdict);
 void netdev_add(QemuOpts *opts, Error **errp);
-void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp);

 int net_hub_id_for_client(NetClientState *nc, int *id);
 NetClientState *net_hub_port_find(int hub_id);
diff --git a/net/net.c b/net/net.c
index 14c6021..dfb5794 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1178,7 +1178,7 @@ void netdev_add(QemuOpts *opts, Error **errp)
     net_client_init(opts, true, errp);
 }

-void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp)
+void qmp_netdev_add(Netdev *netdev, Error **errp)
 {
     Error *local_err = NULL;
     QemuOptsList *opts_list;
@@ -1189,12 +1189,12 @@ void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp)
         goto out;
     }

-    opts = qemu_opts_from_qdict(opts_list, qdict, &local_err);
+    opts = qemu_opts_create(opts_list, netdev->id, 1, &local_err);
     if (local_err) {
         goto out;
     }

-    netdev_add(opts, &local_err);
+    net_client_init1(netdev, true, &local_err);
     if (local_err) {
         qemu_opts_del(opts);
         goto out;
diff --git a/qapi-schema.json b/qapi-schema.json
index 73de7b0..a400fa3 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2257,26 +2257,17 @@
 #
 # Add a network backend.
 #
-# @type: the type of network backend.  Current valid values are 'user', 'tap',
-#        'vde', 'socket', 'dump' and 'bridge'
+# @type: the type of network backend; determines which additional arguments
+#        are valid. See Netdev documentation for more details.
 #
 # @id: the name of the new network backend
 #
-# Additional arguments depend on the type.
-#
-# TODO This command effectively bypasses QAPI completely due to its
-# "additional arguments" business.  It shouldn't have been added to
-# the schema in this form.  It should be qapified properly, or
-# replaced by a properly qapified command.
-#
 # Since: 0.14.0
 #
 # Returns: Nothing on success
 #          If @type is not a valid network backend, DeviceNotFound
 ##
-{ 'command': 'netdev_add',
-  'data': {'type': 'str', 'id': 'str'},
-  'gen': false }                # so we can get the additional arguments
+{ 'command': 'netdev_add', 'data': 'Netdev', 'box': true }

 ##
 # @netdev_del:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7b235ee..2a2f53c 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -922,7 +922,7 @@ EQMP
     {
         .name       = "netdev_add",
         .args_type  = "netdev:O",
-        .mhandler.cmd_new = qmp_netdev_add,
+        .mhandler.cmd_new = qmp_marshal_netdev_add,
     },

 SQMP
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 12/16] qapi: Allow anonymous base for flat union
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (10 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 11/16] net: Complete qapi-fication of netdev_add Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 13/16] qapi: Use anonymous base in SchemaInfo Eric Blake
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Rather than requiring all flat unions to explicitly create
a separate base struct, we want to allow the qapi schema
to specify the common fields via an inline dictionary. This
is similar to how commands can specify inline types for the
arguments.

Now that the feature is legal, we can drop the former
flat-union-bad-base negative test, and instead change the
positive tests in qapi-schema-test to use it.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: avoid redundant error check in gen_visit_union(), rebase to
earlier gen_err_check() improvements
---
 docs/qapi-code-gen.txt                     | 28 ++++++++++++++--------------
 scripts/qapi-types.py                      |  8 +++++---
 scripts/qapi-visit.py                      | 10 +++++++---
 scripts/qapi.py                            | 11 +++++++++--
 tests/Makefile                             |  1 -
 tests/qapi-schema/flat-union-bad-base.err  |  1 -
 tests/qapi-schema/flat-union-bad-base.exit |  1 -
 tests/qapi-schema/flat-union-bad-base.json | 13 -------------
 tests/qapi-schema/flat-union-bad-base.out  |  0
 tests/qapi-schema/qapi-schema-test.json    |  2 +-
 tests/qapi-schema/qapi-schema-test.out     |  6 +++++-
 11 files changed, 41 insertions(+), 40 deletions(-)
 delete mode 100644 tests/qapi-schema/flat-union-bad-base.err
 delete mode 100644 tests/qapi-schema/flat-union-bad-base.exit
 delete mode 100644 tests/qapi-schema/flat-union-bad-base.json
 delete mode 100644 tests/qapi-schema/flat-union-bad-base.out

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index bd437c8..f5e0033 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -283,7 +283,7 @@ better than open-coding the field to be type 'str'.
 === Union types ===

 Usage: { 'union': STRING, 'data': DICT }
-or:    { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME,
+or:    { 'union': STRING, 'data': DICT, 'base': STRUCT-NAME-OR-DICT,
          'discriminator': ENUM-MEMBER-OF-BASE }

 Union types are used to let the user choose between several different
@@ -319,13 +319,16 @@ an implicit C enum 'NameKind' is created, corresponding to the union
 the union can be named 'max', as this would collide with the implicit
 enum.  The value for each branch can be of any type.

-A flat union definition specifies a struct as its base, and
-avoids nesting on the wire.  All branches of the union must be
-complex types, and the top-level fields of the union dictionary on
-the wire will be combination of fields from both the base type and the
-appropriate branch type (when merging two dictionaries, there must be
-no keys in common).  The 'discriminator' field must be the name of an
-enum-typed member of the base struct.
+A flat union definition avoids nesting on the wire, and specifies a
+set of common fields that occur in all variants of the union.  The
+'base' key must specifiy either a type name (the type must be a
+struct, not a union), or a dictionary representing an anonymous type.
+All branches of the union must be complex types, and the top-level
+fields of the union dictionary on the wire will be combination of
+fields from both the base type and the appropriate branch type (when
+merging two dictionaries, there must be no keys in common).  The
+'discriminator' field must be the name of an enum-typed member of the
+base struct.

 The following example enhances the above simple union example by
 adding a common field 'readonly', renaming the discriminator to
@@ -333,10 +336,8 @@ something more applicable, and reducing the number of {} required on
 the wire:

  { 'enum': 'BlockdevDriver', 'data': [ 'file', 'qcow2' ] }
- { 'struct': 'BlockdevCommonOptions',
-   'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } }
  { 'union': 'BlockdevOptions',
-   'base': 'BlockdevCommonOptions',
+   'base': { 'driver': 'BlockdevDriver', 'readonly': 'bool' },
    'discriminator': 'driver',
    'data': { 'file': 'FileOptions',
              'qcow2': 'Qcow2Options' } }
@@ -354,7 +355,7 @@ code generator can ensure that branches exist for all values of the
 enum (although the order of the keys need not match the declaration of
 the enum).  In the resulting generated C data types, a flat union is
 represented as a struct with the base member fields included directly,
-and then a union of structures for each branch of the struct.
+and then a union of pointers to structures for each branch of the struct.

 A simple union can always be re-written as a flat union where the base
 class has a single member named 'type', and where each branch of the
@@ -365,10 +366,9 @@ union has a struct with a single member named 'data'.  That is,
 is identical on the wire to:

  { 'enum': 'Enum', 'data': ['one', 'two'] }
- { 'struct': 'Base', 'data': { 'type': 'Enum' } }
  { 'struct': 'Branch1', 'data': { 'data': 'str' } }
  { 'struct': 'Branch2', 'data': { 'data': 'int' } }
- { 'union': 'Flat', 'base': 'Base', 'discriminator': 'type',
+ { 'union': 'Flat': 'base': { 'type': 'Enum' }, 'discriminator': 'type',
    'data': { 'one': 'Branch1', 'two': 'Branch2' } }


diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 8597942..1a68a05 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -56,12 +56,14 @@ struct %(c_name)s {
                 c_name=c_name(name))

     if base and not base.is_empty():
-        ret += mcgen('''
+        if not base.is_implicit():
+            ret += mcgen('''
     /* Members inherited from %(c_name)s: */
 ''',
-                     c_name=base.c_name())
+                         c_name=base.c_name())
         ret += gen_struct_fields(base.members)
-        ret += mcgen('''
+        if not base.is_implicit():
+            ret += mcgen('''
     /* Own members: */
 ''')
     ret += gen_struct_fields(members)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 193a1b6..6264aa3 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -90,7 +90,7 @@ def gen_visit_struct_fields(name, base, members):
     if base.is_empty() and not members:
         return ret

-    if not base.is_empty():
+    if not base.is_empty() and not base.is_implicit():
         ret += gen_visit_fields_decl(base)

     struct_fields_seen.add(name)
@@ -103,7 +103,7 @@ static void visit_type_%(c_name)s_fields(Visitor *v, %(c_name)s **obj, Error **e
 ''',
                  c_name=c_name(name))

-    if not base.is_empty():
+    if not base.is_empty() and not base.is_implicit():
         ret += mcgen('''
     visit_type_%(c_type)s_fields(v, (%(c_type)s **)obj, &err);
 ''',
@@ -231,7 +231,11 @@ def gen_visit_object(name, base, members, variants):

     assert base
     if not base.is_empty():
-        ret += gen_visit_fields_decl(base)
+        if base.is_implicit():
+            assert not members
+            members = base.members
+        else:
+            ret += gen_visit_fields_decl(base)
     if members:
         ret += gen_visit_struct_fields(name, base, members)
     if variants:
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 84c0bd0..11d9e56 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -329,6 +329,8 @@ class QAPISchemaParser(object):


 def find_base_fields(base):
+    if isinstance(base, dict):
+        return base
     base_struct_define = find_struct(base)
     if not base_struct_define:
         return None
@@ -570,9 +572,9 @@ def check_union(expr, expr_info):

     # Else, it's a flat union.
     else:
-        # The object must have a string member 'base'.
+        # The object must have a string or dictionary 'base'.
         check_type(expr_info, "'base' for union '%s'" % name,
-                   base, allow_metas=['struct'])
+                   base, allow_dict=True, allow_metas=['struct'])
         if not base:
             raise QAPIExprError(expr_info,
                                 "Flat union '%s' must have a base"
@@ -1044,6 +1046,8 @@ class QAPISchemaMember(object):
             owner = owner[5:]
             if owner.endswith('-arg'):
                 return '(parameter of %s)' % owner[:-4]
+            elif owner.endswith('-base'):
+                return '(base of %s)' % owner[:-5]
             else:
                 assert owner.endswith('-wrapper')
                 # Unreachable and not implemented
@@ -1343,6 +1347,9 @@ class QAPISchema(object):
         base = expr.get('base', ':empty')
         tag_name = expr.get('discriminator')
         tag_member = None
+        if isinstance(base, dict):
+            base = (self._make_implicit_object_type(
+                    name, info, 'base', self._make_members(base, info)))
         if tag_name:
             variants = [self._make_variant(key, value)
                         for (key, value) in data.iteritems()]
diff --git a/tests/Makefile b/tests/Makefile
index 3e5d17d..f6cf6f2 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -291,7 +291,6 @@ qapi-schema += escape-too-short.json
 qapi-schema += event-case.json
 qapi-schema += event-nest-struct.json
 qapi-schema += flat-union-array-branch.json
-qapi-schema += flat-union-bad-base.json
 qapi-schema += flat-union-bad-discriminator.json
 qapi-schema += flat-union-base-any.json
 qapi-schema += flat-union-base-union.json
diff --git a/tests/qapi-schema/flat-union-bad-base.err b/tests/qapi-schema/flat-union-bad-base.err
deleted file mode 100644
index 79b8a71..0000000
--- a/tests/qapi-schema/flat-union-bad-base.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/flat-union-bad-base.json:9: 'base' for union 'TestUnion' should be a type name
diff --git a/tests/qapi-schema/flat-union-bad-base.exit b/tests/qapi-schema/flat-union-bad-base.exit
deleted file mode 100644
index d00491f..0000000
--- a/tests/qapi-schema/flat-union-bad-base.exit
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/flat-union-bad-base.json b/tests/qapi-schema/flat-union-bad-base.json
deleted file mode 100644
index e2e622b..0000000
--- a/tests/qapi-schema/flat-union-bad-base.json
+++ /dev/null
@@ -1,13 +0,0 @@
-# we require the base to be an existing struct
-# TODO: should we allow an anonymous inline base type?
-{ 'enum': 'TestEnum',
-  'data': [ 'value1', 'value2' ] }
-{ 'struct': 'TestTypeA',
-  'data': { 'string': 'str' } }
-{ 'struct': 'TestTypeB',
-  'data': { 'integer': 'int' } }
-{ 'union': 'TestUnion',
-  'base': { 'enum1': 'TestEnum', 'kind': 'str' },
-  'discriminator': 'enum1',
-  'data': { 'value1': 'TestTypeA',
-            'value2': 'TestTypeB' } }
diff --git a/tests/qapi-schema/flat-union-bad-base.out b/tests/qapi-schema/flat-union-bad-base.out
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index d0bc3d2..d7d0de8 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -78,7 +78,7 @@
 # this variant of UserDefFlatUnion defaults to a union that uses fields with
 # allocated types to test corner cases in the cleanup/dealloc visitor
 { 'union': 'UserDefFlatUnion2',
-  'base': 'UserDefUnionBase',
+  'base': { 'string': 'str', 'enum1': 'EnumOne' },
   'discriminator': 'enum1',
   'data': { 'value1' : 'UserDefC', # intentional forward reference
             'value2' : 'UserDefB',
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 3dc133e..5b5b37c 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -10,6 +10,10 @@ object :obj-EVENT_D-arg
     member b: str optional=False
     member c: str optional=True
     member enum3: EnumOne optional=True
+object :obj-UserDefFlatUnion2-base
+    base :empty
+    member string: str optional=False
+    member enum1: EnumOne optional=False
 object :obj-__org.qemu_x-command-arg
     base :empty
     member a: __org.qemu_x-EnumList optional=False
@@ -164,7 +168,7 @@ object UserDefFlatUnion
     case value2: UserDefB
     case value3: UserDefB
 object UserDefFlatUnion2
-    base UserDefUnionBase
+    base :obj-UserDefFlatUnion2-base
     tag enum1
     case value1: UserDefC
     case value2: UserDefB
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 13/16] qapi: Use anonymous base in SchemaInfo
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (11 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 12/16] qapi: Allow anonymous base for flat union Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 14/16] qapi: Use anonymous base in Netdev Eric Blake
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru

Now that the generator supports it, we might as well use an
anonymous base rather than breaking out a single-use
SchemaInfoBase structure.

Oddly enough, this change does not affect the resulting
introspection output (because we already inline the members of
a base type into an object, and had no independent use of the
base type reachable from a command).

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: new patch
---
 qapi/introspect.json | 12 +-----------
 1 file changed, 1 insertion(+), 11 deletions(-)

diff --git a/qapi/introspect.json b/qapi/introspect.json
index 9e9369e..3fd81fb 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -75,16 +75,6 @@
             'command', 'event' ] }

 ##
-# @SchemaInfoBase
-#
-# Members common to any @SchemaInfo.
-#
-# Since: 2.5
-##
-{ 'struct': 'SchemaInfoBase',
-  'data': { 'name': 'str', 'meta-type': 'SchemaMetaType' } }
-
-##
 # @SchemaInfo
 #
 # @name: the entity's name, inherited from @base.
@@ -103,7 +93,7 @@
 # Since: 2.5
 ##
 { 'union': 'SchemaInfo',
-  'base': 'SchemaInfoBase',
+  'base': { 'name': 'str', 'meta-type': 'SchemaMetaType' },
   'discriminator': 'meta-type',
   'data': {
       'builtin': 'SchemaInfoBuiltin',
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 14/16] qapi: Use anonymous base in Netdev
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (12 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 13/16] qapi: Use anonymous base in SchemaInfo Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 15/16] qapi: Use anonymous base in CpuInfo Eric Blake
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru

Now that the generator supports it, we might as well use an
anonymous base rather than breaking out a single-use NetdevBase
structure.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: new patch
---
 qapi-schema.json | 20 +++++---------------
 1 file changed, 5 insertions(+), 15 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index a400fa3..ad3030f 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2675,30 +2675,20 @@
             'bridge', 'hubport', 'netmap', 'vhost-user' ] }

 ##
-# @NetdevBase
-#
-# Captures the common configuration of a network device.
-#
-# @id: identifier for monitor commands.
-#
-# @type: Specify the driver used for interpreting remaining arguments.
-#
-# Since 1.2
-##
-{ 'struct': 'NetdevBase',
-  'data': { 'id': 'str', 'type': 'NetClientDriver' } }
-
-##
 # @Netdev
 #
 # Captures the configuration of a network device.
 #
+# @id: identifier for monitor commands.
+#
+# @type: Specify the driver used for interpreting remaining arguments.
+#
 # Since 1.2
 #
 # 'l2tpv3' - since 2.1
 ##
 { 'union': 'Netdev',
-  'base': 'NetdevBase',
+  'base': { 'id': 'str', 'type': 'NetClientDriver' },
   'discriminator': 'type',
   'data': {
     'none':     'NetdevNoneOptions',
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 15/16] qapi: Use anonymous base in CpuInfo
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (13 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 14/16] qapi: Use anonymous base in Netdev Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 16/16] qapi: Populate info['name'] for each entity Eric Blake
  2015-12-23 20:58 ` [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Now that the generator supports it, we might as well use an
anonymous base rather than breaking out a single-use CpuInfoBase
structure.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6: new patch
---
 qapi-schema.json | 20 ++++++--------------
 scripts/qapi.py  |  2 +-
 2 files changed, 7 insertions(+), 15 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index ad3030f..4daf54a 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -753,9 +753,9 @@
   'data': ['x86', 'sparc', 'ppc', 'mips', 'tricore', 'other' ] }

 ##
-# @CpuInfoBase:
+# @CpuInfo:
 #
-# Common information about a virtual CPU
+# Information about a virtual CPU
 #
 # @CPU: the index of the virtual CPU
 #
@@ -776,18 +776,10 @@
 # Notes: @halted is a transient state that changes frequently.  By the time the
 #        data is sent to the client, the guest may no longer be halted.
 ##
-{ 'struct': 'CpuInfoBase',
-  'data': {'CPU': 'int', 'current': 'bool', 'halted': 'bool',
-           'qom_path': 'str', 'thread_id': 'int', 'arch': 'CpuInfoArch' } }
-
-##
-# @CpuInfo:
-#
-# Information about a virtual CPU
-#
-# Since: 0.14.0
-##
-{ 'union': 'CpuInfo', 'base': 'CpuInfoBase', 'discriminator': 'arch',
+{ 'union': 'CpuInfo',
+  'base': {'CPU': 'int', 'current': 'bool', 'halted': 'bool',
+           'qom_path': 'str', 'thread_id': 'int', 'arch': 'CpuInfoArch' },
+  'discriminator': 'arch',
   'data': { 'x86': 'CpuInfoX86',
             'sparc': 'CpuInfoSPARC',
             'ppc': 'CpuInfoPPC',
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 11d9e56..d534d41 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -62,8 +62,8 @@ returns_whitelist = [
 # Whitelist of entities allowed to violate case conventions
 case_whitelist = [
     # From QMP:
+    ':obj-CpuInfo-base',    # CPU, visible through query-cpu
     'ACPISlotType',         # DIMM, visible through query-acpi-ospm-status
-    'CpuInfoBase',          # CPU, visible through query-cpu
     'CpuInfoMIPS',          # PC, visible through query-cpu
     'CpuInfoTricore',       # PC, visible through query-cpu
     'InputAxis',            # TODO: drop when x-input-send-event is fixed
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [Qemu-devel] [PATCH v6 16/16] qapi: Populate info['name'] for each entity
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (14 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 15/16] qapi: Use anonymous base in CpuInfo Eric Blake
@ 2015-12-23 20:55 ` Eric Blake
  2015-12-23 20:58 ` [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru, Michael Roth

Every non-implicit entity is associated with an 'info'
dictionary, but it is not easy to reverse-engineer the name of
the top-most entity associated with that 'info'.  Our use of
'case_whitelist' (added in commit 893e1f2) is thus currently
tied to the owner of a member instead; but now that anonymous
types are starting to be used in more places such as CpuInfo,
this requires whitelist exceptions to know how an implicit name
will be generated.

While we have a ._pretty_owner() that maps from implicit names
back to a human readable phrase, that is more than just a plain
top-level entity name.  What's more, the .check_clash() method
may be called for the same member object more than once, with
different caller 'info' objects (such as a base and derived
object); if a clash is only introduced in the derived class,
reporting the error on behalf of the base class named in
member.owner seems wrong.

Add a new info['name'] field to track the information we need,
allowing us to change 'case_whitelist' to use only names present
in the qapi files.

Unfortunately, there is no one good place to add the mapping:
at the point 'info' is created in QAPISchemaParser.__init__(),
we don't know the name.  Info is then stored into
QAPISchemaParser.exprs, which then then gets fed to
QAPISchema.__init__() via the global check_exprs(), but we want
check_exprs() to go away.  And QAPISchema._def_exprs() sees
every entity, except that the various _def_FOO() helpers don't
return anything.  So we have to modify all of the _def_FOO()
methods.

Signed-off-by: Eric Blake <eblake@redhat.com>

---
v6 (subset E): sink later in series, and rework commit message
v14 (subset D): rearrange assignment, improve commit message
v13 (subset D): new patch
---
 scripts/qapi.py | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index d534d41..b8980e1 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -62,8 +62,8 @@ returns_whitelist = [
 # Whitelist of entities allowed to violate case conventions
 case_whitelist = [
     # From QMP:
-    ':obj-CpuInfo-base',    # CPU, visible through query-cpu
     'ACPISlotType',         # DIMM, visible through query-acpi-ospm-status
+    'CpuInfo',              # CPU and PC, visible through query-cpu
     'CpuInfoMIPS',          # PC, visible through query-cpu
     'CpuInfoTricore',       # PC, visible through query-cpu
     'InputAxis',            # TODO: drop when x-input-send-event is fixed
@@ -1029,7 +1029,7 @@ class QAPISchemaMember(object):

     def check_clash(self, info, seen):
         cname = c_name(self.name)
-        if cname.lower() != cname and self.owner not in case_whitelist:
+        if cname.lower() != cname and info['name'] not in case_whitelist:
             raise QAPIExprError(info,
                                 "%s should not use uppercase" % self.describe())
         if cname in seen:
@@ -1302,7 +1302,7 @@ class QAPISchema(object):
         return name

     def _def_enum_type(self, expr, info):
-        name = expr['enum']
+        name = info['name'] = expr['enum']
         data = expr['data']
         prefix = expr.get('prefix')
         self._def_entity(QAPISchemaEnumType(
@@ -1323,7 +1323,7 @@ class QAPISchema(object):
                 for (key, value) in data.iteritems()]

     def _def_struct_type(self, expr, info):
-        name = expr['struct']
+        name = info['name'] = expr['struct']
         base = expr.get('base', ':empty')
         data = expr['data']
         self._def_entity(QAPISchemaObjectType(name, info, base,
@@ -1342,7 +1342,7 @@ class QAPISchema(object):
         return QAPISchemaObjectTypeVariant(case, typ)

     def _def_union_type(self, expr, info):
-        name = expr['union']
+        name = info['name'] = expr['union']
         data = expr['data']
         base = expr.get('base', ':empty')
         tag_name = expr.get('discriminator')
@@ -1368,7 +1368,7 @@ class QAPISchema(object):
                                                               variants)))

     def _def_alternate_type(self, expr, info):
-        name = expr['alternate']
+        name = info['name'] = expr['alternate']
         data = expr['data']
         variants = [self._make_variant(key, value)
                     for (key, value) in data.iteritems()]
@@ -1380,7 +1380,7 @@ class QAPISchema(object):
                                                                  variants)))

     def _def_command(self, expr, info):
-        name = expr['command']
+        name = info['name'] = expr['command']
         data = expr.get('data', {})
         rets = expr.get('returns')
         gen = expr.get('gen', True)
@@ -1396,7 +1396,7 @@ class QAPISchema(object):
                                            success_response, box))

     def _def_event(self, expr, info):
-        name = expr['event']
+        name = info['name'] = expr['event']
         data = expr.get('data', {})
         box = expr.get('box', False)
         if isinstance(data, dict):
-- 
2.4.3

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F)
  2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
                   ` (15 preceding siblings ...)
  2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 16/16] qapi: Populate info['name'] for each entity Eric Blake
@ 2015-12-23 20:58 ` Eric Blake
  16 siblings, 0 replies; 18+ messages in thread
From: Eric Blake @ 2015-12-23 20:58 UTC (permalink / raw)
  To: qemu-devel; +Cc: armbru

[-- Attachment #1: Type: text/plain, Size: 495 bytes --]

On 12/23/2015 01:55 PM, Eric Blake wrote:
> Prerequisites:
> + my qapi cleanups subset E v8:
> https://lists.gnu.org/archive/html/qemu-devel/2015-12/msg03863.html

Also available as a tag at this location:
git fetch git://repo.or.cz/qemu/ericb.git qapi-cleanupv6f

and part of my branch of pending qapi changes, at:
http://repo.or.cz/qemu/ericb.git/shortlog/refs/heads/qapi

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2015-12-23 20:58 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-23 20:55 [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 01/16] net: use Netdev instead of NetClientOptions in client init Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 02/16] qapi: Avoid use of 'data' member of qapi unions Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 03/16] qapi: Forbid empty unions and useless alternates Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 04/16] qapi: Drop useless 'data' member of unions Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 05/16] qapi: Hide tag_name data member of variants Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 06/16] qapi: Plumb in 'box' to qapi generator lower levels Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 07/16] qapi: Implement boxed types for commands/events Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 08/16] qapi: support implicit structs in OptsVisitor Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 09/16] qapi: Change Netdev into a flat union Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 10/16] net: Use correct type for bool flag Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 11/16] net: Complete qapi-fication of netdev_add Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 12/16] qapi: Allow anonymous base for flat union Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 13/16] qapi: Use anonymous base in SchemaInfo Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 14/16] qapi: Use anonymous base in Netdev Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 15/16] qapi: Use anonymous base in CpuInfo Eric Blake
2015-12-23 20:55 ` [Qemu-devel] [PATCH v6 16/16] qapi: Populate info['name'] for each entity Eric Blake
2015-12-23 20:58 ` [Qemu-devel] [PATCH v6 00/16] qapi netdev_add introspection (post-introspection cleanups subset F) Eric Blake

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