@@ -214,6 +214,8 @@ extern NICInfo nd_table[MAX_NICS];
extern const char *host_net_devices[];
/* from net.c */
+bool netdev_is_modern(const char *optarg);
+void netdev_parse_modern(const char *optarg);
void net_client_parse(QemuOptsList *opts_list, const char *str);
void show_netdevs(void);
void net_init_clients(void);
@@ -54,6 +54,7 @@
#include "net/colo-compare.h"
#include "net/filter.h"
#include "qapi/string-output-visitor.h"
+#include "qapi/qobject-input-visitor.h"
/* Net bridge is currently not supported for W32. */
#if !defined(_WIN32)
@@ -63,6 +64,16 @@
static VMChangeStateEntry *net_change_state_entry;
static QTAILQ_HEAD(, NetClientState) net_clients;
+typedef struct NetdevQueueEntry {
+ Netdev *nd;
+ Location loc;
+ QSIMPLEQ_ENTRY(NetdevQueueEntry) entry;
+} NetdevQueueEntry;
+
+typedef QSIMPLEQ_HEAD(, NetdevQueueEntry) NetdevQueue;
+
+static NetdevQueue nd_queue = QSIMPLEQ_HEAD_INITIALIZER(nd_queue);
+
/***********************************************************/
/* network device redirectors */
@@ -1562,6 +1573,20 @@ out:
return ret;
}
+static void netdev_init_modern(void)
+{
+ while (!QSIMPLEQ_EMPTY(&nd_queue)) {
+ NetdevQueueEntry *nd = QSIMPLEQ_FIRST(&nd_queue);
+
+ QSIMPLEQ_REMOVE_HEAD(&nd_queue, entry);
+ loc_push_restore(&nd->loc);
+ net_client_init1(nd->nd, true, &error_fatal);
+ loc_pop(&nd->loc);
+ qapi_free_Netdev(nd->nd);
+ g_free(nd);
+ }
+}
+
void net_init_clients(void)
{
net_change_state_entry =
@@ -1569,6 +1594,8 @@ void net_init_clients(void)
QTAILQ_INIT(&net_clients);
+ netdev_init_modern();
+
qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL,
&error_fatal);
@@ -1579,6 +1606,36 @@ void net_init_clients(void)
&error_fatal);
}
+/*
+ * Does this -netdev argument use modern rather than traditional syntax?
+ * Modern syntax is to be parsed with netdev_parse_modern().
+ * Traditional syntax is to be parsed with net_client_parse().
+ */
+bool netdev_is_modern(const char *optarg)
+{
+ return false;
+}
+
+/*
+ * netdev_parse_modern() uses modern, more expressive syntax than
+ * net_client_parse(), but supports only the -netdev option.
+ * netdev_parse_modern() appends to @nd_queue, whereas net_client_parse()
+ * appends to @qemu_netdev_opts.
+ */
+void netdev_parse_modern(const char *optarg)
+{
+ Visitor *v;
+ NetdevQueueEntry *nd;
+
+ v = qobject_input_visitor_new_str(optarg, "type", &error_fatal);
+ nd = g_new(NetdevQueueEntry, 1);
+ visit_type_Netdev(v, NULL, &nd->nd, &error_fatal);
+ visit_free(v);
+ loc_save(&nd->loc);
+
+ QSIMPLEQ_INSERT_TAIL(&nd_queue, nd, entry);
+}
+
void net_client_parse(QemuOptsList *opts_list, const char *optarg)
{
if (!qemu_opts_parse_noisily(opts_list, optarg, true)) {
@@ -2793,7 +2793,11 @@ void qemu_init(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_netdev:
default_net = 0;
- net_client_parse(qemu_find_opts("netdev"), optarg);
+ if (netdev_is_modern(optarg)) {
+ netdev_parse_modern(optarg);
+ } else {
+ net_client_parse(qemu_find_opts("netdev"), optarg);
+ }
break;
case QEMU_OPTION_nic:
default_net = 0;