|
@@ -37,6 +37,9 @@
|
|
|
#include "qmp-commands.h"
|
|
|
#include "hw/qdev.h"
|
|
|
#include "iov.h"
|
|
|
+#include "qapi-visit.h"
|
|
|
+#include "qapi/opts-visitor.h"
|
|
|
+#include "qapi/qapi-dealloc-visitor.h"
|
|
|
|
|
|
/* Net bridge is currently not supported for W32. */
|
|
|
#if !defined(_WIN32)
|
|
@@ -239,7 +242,7 @@ NICState *qemu_new_nic(NetClientInfo *info,
|
|
|
VLANClientState *nc;
|
|
|
NICState *nic;
|
|
|
|
|
|
- assert(info->type == NET_CLIENT_TYPE_NIC);
|
|
|
+ assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC);
|
|
|
assert(info->size >= sizeof(NICState));
|
|
|
|
|
|
nc = qemu_new_net_client(info, conf->vlan, conf->peer, model, name);
|
|
@@ -282,7 +285,7 @@ static void qemu_free_vlan_client(VLANClientState *vc)
|
|
|
void qemu_del_vlan_client(VLANClientState *vc)
|
|
|
{
|
|
|
/* If there is a peer NIC, delete and cleanup client, but do not free. */
|
|
|
- if (!vc->vlan && vc->peer && vc->peer->info->type == NET_CLIENT_TYPE_NIC) {
|
|
|
+ if (!vc->vlan && vc->peer && vc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
|
|
|
NICState *nic = DO_UPCAST(NICState, nc, vc->peer);
|
|
|
if (nic->peer_deleted) {
|
|
|
return;
|
|
@@ -298,7 +301,7 @@ void qemu_del_vlan_client(VLANClientState *vc)
|
|
|
}
|
|
|
|
|
|
/* If this is a peer NIC and peer has already been deleted, free it now. */
|
|
|
- if (!vc->vlan && vc->peer && vc->info->type == NET_CLIENT_TYPE_NIC) {
|
|
|
+ if (!vc->vlan && vc->peer && vc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
|
|
|
NICState *nic = DO_UPCAST(NICState, nc, vc);
|
|
|
if (nic->peer_deleted) {
|
|
|
qemu_free_vlan_client(vc->peer);
|
|
@@ -341,14 +344,14 @@ void qemu_foreach_nic(qemu_nic_foreach func, void *opaque)
|
|
|
VLANState *vlan;
|
|
|
|
|
|
QTAILQ_FOREACH(nc, &non_vlan_clients, next) {
|
|
|
- if (nc->info->type == NET_CLIENT_TYPE_NIC) {
|
|
|
+ if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
|
|
|
func(DO_UPCAST(NICState, nc, nc), opaque);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QTAILQ_FOREACH(vlan, &vlans, next) {
|
|
|
QTAILQ_FOREACH(nc, &vlan->clients, next) {
|
|
|
- if (nc->info->type == NET_CLIENT_TYPE_NIC) {
|
|
|
+ if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) {
|
|
|
func(DO_UPCAST(NICState, nc, nc), opaque);
|
|
|
}
|
|
|
}
|
|
@@ -664,7 +667,7 @@ VLANClientState *qemu_find_netdev(const char *id)
|
|
|
VLANClientState *vc;
|
|
|
|
|
|
QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
|
|
|
- if (vc->info->type == NET_CLIENT_TYPE_NIC)
|
|
|
+ if (vc->info->type == NET_CLIENT_OPTIONS_KIND_NIC)
|
|
|
continue;
|
|
|
if (!strcmp(vc->name, id)) {
|
|
|
return vc;
|
|
@@ -745,11 +748,15 @@ int net_handle_fd_param(Monitor *mon, const char *param)
|
|
|
return fd;
|
|
|
}
|
|
|
|
|
|
-static int net_init_nic(QemuOpts *opts, const char *name, VLANState *vlan)
|
|
|
+static int net_init_nic(const NetClientOptions *opts, const char *name,
|
|
|
+ VLANState *vlan)
|
|
|
{
|
|
|
int idx;
|
|
|
NICInfo *nd;
|
|
|
- const char *netdev;
|
|
|
+ const NetLegacyNicOptions *nic;
|
|
|
+
|
|
|
+ assert(opts->kind == NET_CLIENT_OPTIONS_KIND_NIC);
|
|
|
+ nic = opts->nic;
|
|
|
|
|
|
idx = nic_get_free_idx();
|
|
|
if (idx == -1 || nb_nics >= MAX_NICS) {
|
|
@@ -761,10 +768,10 @@ static int net_init_nic(QemuOpts *opts, const char *name, VLANState *vlan)
|
|
|
|
|
|
memset(nd, 0, sizeof(*nd));
|
|
|
|
|
|
- if ((netdev = qemu_opt_get(opts, "netdev"))) {
|
|
|
- nd->netdev = qemu_find_netdev(netdev);
|
|
|
+ if (nic->has_netdev) {
|
|
|
+ nd->netdev = qemu_find_netdev(nic->netdev);
|
|
|
if (!nd->netdev) {
|
|
|
- error_report("netdev '%s' not found", netdev);
|
|
|
+ error_report("netdev '%s' not found", nic->netdev);
|
|
|
return -1;
|
|
|
}
|
|
|
} else {
|
|
@@ -774,26 +781,28 @@ static int net_init_nic(QemuOpts *opts, const char *name, VLANState *vlan)
|
|
|
if (name) {
|
|
|
nd->name = g_strdup(name);
|
|
|
}
|
|
|
- if (qemu_opt_get(opts, "model")) {
|
|
|
- nd->model = g_strdup(qemu_opt_get(opts, "model"));
|
|
|
+ if (nic->has_model) {
|
|
|
+ nd->model = g_strdup(nic->model);
|
|
|
}
|
|
|
- if (qemu_opt_get(opts, "addr")) {
|
|
|
- nd->devaddr = g_strdup(qemu_opt_get(opts, "addr"));
|
|
|
+ if (nic->has_addr) {
|
|
|
+ nd->devaddr = g_strdup(nic->addr);
|
|
|
}
|
|
|
|
|
|
- if (qemu_opt_get(opts, "macaddr") &&
|
|
|
- net_parse_macaddr(nd->macaddr.a, qemu_opt_get(opts, "macaddr")) < 0) {
|
|
|
+ if (nic->has_macaddr &&
|
|
|
+ net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) {
|
|
|
error_report("invalid syntax for ethernet address");
|
|
|
return -1;
|
|
|
}
|
|
|
qemu_macaddr_default_if_unset(&nd->macaddr);
|
|
|
|
|
|
- nd->nvectors = qemu_opt_get_number(opts, "vectors",
|
|
|
- DEV_NVECTORS_UNSPECIFIED);
|
|
|
- if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
|
|
|
- (nd->nvectors < 0 || nd->nvectors > 0x7ffffff)) {
|
|
|
- error_report("invalid # of vectors: %d", nd->nvectors);
|
|
|
- return -1;
|
|
|
+ if (nic->has_vectors) {
|
|
|
+ if (nic->vectors > 0x7ffffff) {
|
|
|
+ error_report("invalid # of vectors: %"PRIu32, nic->vectors);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ nd->nvectors = nic->vectors;
|
|
|
+ } else {
|
|
|
+ nd->nvectors = DEV_NVECTORS_UNSPECIFIED;
|
|
|
}
|
|
|
|
|
|
nd->used = 1;
|
|
@@ -802,371 +811,128 @@ static int net_init_nic(QemuOpts *opts, const char *name, VLANState *vlan)
|
|
|
return idx;
|
|
|
}
|
|
|
|
|
|
-#define NET_COMMON_PARAMS_DESC \
|
|
|
- { \
|
|
|
- .name = "type", \
|
|
|
- .type = QEMU_OPT_STRING, \
|
|
|
- .help = "net client type (nic, tap etc.)", \
|
|
|
- }, { \
|
|
|
- .name = "vlan", \
|
|
|
- .type = QEMU_OPT_NUMBER, \
|
|
|
- .help = "vlan number", \
|
|
|
- }, { \
|
|
|
- .name = "name", \
|
|
|
- .type = QEMU_OPT_STRING, \
|
|
|
- .help = "identifier for monitor commands", \
|
|
|
- }
|
|
|
-
|
|
|
-typedef int (*net_client_init_func)(QemuOpts *opts,
|
|
|
- const char *name,
|
|
|
- VLANState *vlan);
|
|
|
-
|
|
|
-/* magic number, but compiler will warn if too small */
|
|
|
-#define NET_MAX_DESC 20
|
|
|
-
|
|
|
-static const struct {
|
|
|
- const char *type;
|
|
|
- net_client_init_func init;
|
|
|
- QemuOptDesc desc[NET_MAX_DESC];
|
|
|
-} net_client_types[NET_CLIENT_TYPE_MAX] = {
|
|
|
- [NET_CLIENT_TYPE_NONE] = {
|
|
|
- .type = "none",
|
|
|
- .desc = {
|
|
|
- NET_COMMON_PARAMS_DESC,
|
|
|
- { /* end of list */ }
|
|
|
- },
|
|
|
- },
|
|
|
- [NET_CLIENT_TYPE_NIC] = {
|
|
|
- .type = "nic",
|
|
|
- .init = net_init_nic,
|
|
|
- .desc = {
|
|
|
- NET_COMMON_PARAMS_DESC,
|
|
|
- {
|
|
|
- .name = "netdev",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "id of -netdev to connect to",
|
|
|
- },
|
|
|
- {
|
|
|
- .name = "macaddr",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "MAC address",
|
|
|
- }, {
|
|
|
- .name = "model",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "device model (e1000, rtl8139, virtio etc.)",
|
|
|
- }, {
|
|
|
- .name = "addr",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "PCI device address",
|
|
|
- }, {
|
|
|
- .name = "vectors",
|
|
|
- .type = QEMU_OPT_NUMBER,
|
|
|
- .help = "number of MSI-x vectors, 0 to disable MSI-X",
|
|
|
- },
|
|
|
- { /* end of list */ }
|
|
|
- },
|
|
|
- },
|
|
|
+
|
|
|
+static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])(
|
|
|
+ const NetClientOptions *opts,
|
|
|
+ const char *name,
|
|
|
+ VLANState *vlan) = {
|
|
|
+ [NET_CLIENT_OPTIONS_KIND_NIC] = net_init_nic,
|
|
|
#ifdef CONFIG_SLIRP
|
|
|
- [NET_CLIENT_TYPE_USER] = {
|
|
|
- .type = "user",
|
|
|
- .init = net_init_slirp,
|
|
|
- .desc = {
|
|
|
- NET_COMMON_PARAMS_DESC,
|
|
|
- {
|
|
|
- .name = "hostname",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "client hostname reported by the builtin DHCP server",
|
|
|
- }, {
|
|
|
- .name = "restrict",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "isolate the guest from the host (y|yes|n|no)",
|
|
|
- }, {
|
|
|
- .name = "ip",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "legacy parameter, use net= instead",
|
|
|
- }, {
|
|
|
- .name = "net",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "IP address and optional netmask",
|
|
|
- }, {
|
|
|
- .name = "host",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "guest-visible address of the host",
|
|
|
- }, {
|
|
|
- .name = "tftp",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "root directory of the built-in TFTP server",
|
|
|
- }, {
|
|
|
- .name = "bootfile",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "BOOTP filename, for use with tftp=",
|
|
|
- }, {
|
|
|
- .name = "dhcpstart",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "the first of the 16 IPs the built-in DHCP server can assign",
|
|
|
- }, {
|
|
|
- .name = "dns",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "guest-visible address of the virtual nameserver",
|
|
|
- }, {
|
|
|
- .name = "smb",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "root directory of the built-in SMB server",
|
|
|
- }, {
|
|
|
- .name = "smbserver",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "IP address of the built-in SMB server",
|
|
|
- }, {
|
|
|
- .name = "hostfwd",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "guest port number to forward incoming TCP or UDP connections",
|
|
|
- }, {
|
|
|
- .name = "guestfwd",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "IP address and port to forward guest TCP connections",
|
|
|
- },
|
|
|
- { /* end of list */ }
|
|
|
- },
|
|
|
- },
|
|
|
+ [NET_CLIENT_OPTIONS_KIND_USER] = net_init_slirp,
|
|
|
#endif
|
|
|
- [NET_CLIENT_TYPE_TAP] = {
|
|
|
- .type = "tap",
|
|
|
- .init = net_init_tap,
|
|
|
- .desc = {
|
|
|
- NET_COMMON_PARAMS_DESC,
|
|
|
- {
|
|
|
- .name = "ifname",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "interface name",
|
|
|
- },
|
|
|
-#ifndef _WIN32
|
|
|
- {
|
|
|
- .name = "fd",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "file descriptor of an already opened tap",
|
|
|
- }, {
|
|
|
- .name = "script",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "script to initialize the interface",
|
|
|
- }, {
|
|
|
- .name = "downscript",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "script to shut down the interface",
|
|
|
- }, {
|
|
|
-#ifdef CONFIG_NET_BRIDGE
|
|
|
- .name = "helper",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "command to execute to configure bridge",
|
|
|
- }, {
|
|
|
-#endif
|
|
|
- .name = "sndbuf",
|
|
|
- .type = QEMU_OPT_SIZE,
|
|
|
- .help = "send buffer limit"
|
|
|
- }, {
|
|
|
- .name = "vnet_hdr",
|
|
|
- .type = QEMU_OPT_BOOL,
|
|
|
- .help = "enable the IFF_VNET_HDR flag on the tap interface"
|
|
|
- }, {
|
|
|
- .name = "vhost",
|
|
|
- .type = QEMU_OPT_BOOL,
|
|
|
- .help = "enable vhost-net network accelerator",
|
|
|
- }, {
|
|
|
- .name = "vhostfd",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "file descriptor of an already opened vhost net device",
|
|
|
- }, {
|
|
|
- .name = "vhostforce",
|
|
|
- .type = QEMU_OPT_BOOL,
|
|
|
- .help = "force vhost on for non-MSIX virtio guests",
|
|
|
- },
|
|
|
-#endif /* _WIN32 */
|
|
|
- { /* end of list */ }
|
|
|
- },
|
|
|
- },
|
|
|
- [NET_CLIENT_TYPE_SOCKET] = {
|
|
|
- .type = "socket",
|
|
|
- .init = net_init_socket,
|
|
|
- .desc = {
|
|
|
- NET_COMMON_PARAMS_DESC,
|
|
|
- {
|
|
|
- .name = "fd",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "file descriptor of an already opened socket",
|
|
|
- }, {
|
|
|
- .name = "listen",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "port number, and optional hostname, to listen on",
|
|
|
- }, {
|
|
|
- .name = "connect",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "port number, and optional hostname, to connect to",
|
|
|
- }, {
|
|
|
- .name = "mcast",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "UDP multicast address and port number",
|
|
|
- }, {
|
|
|
- .name = "localaddr",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "source address and port for multicast and udp packets",
|
|
|
- }, {
|
|
|
- .name = "udp",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "UDP unicast address and port number",
|
|
|
- },
|
|
|
- { /* end of list */ }
|
|
|
- },
|
|
|
- },
|
|
|
+ [NET_CLIENT_OPTIONS_KIND_TAP] = net_init_tap,
|
|
|
+ [NET_CLIENT_OPTIONS_KIND_SOCKET] = net_init_socket,
|
|
|
#ifdef CONFIG_VDE
|
|
|
- [NET_CLIENT_TYPE_VDE] = {
|
|
|
- .type = "vde",
|
|
|
- .init = net_init_vde,
|
|
|
- .desc = {
|
|
|
- NET_COMMON_PARAMS_DESC,
|
|
|
- {
|
|
|
- .name = "sock",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "socket path",
|
|
|
- }, {
|
|
|
- .name = "port",
|
|
|
- .type = QEMU_OPT_NUMBER,
|
|
|
- .help = "port number",
|
|
|
- }, {
|
|
|
- .name = "group",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "group owner of socket",
|
|
|
- }, {
|
|
|
- .name = "mode",
|
|
|
- .type = QEMU_OPT_NUMBER,
|
|
|
- .help = "permissions for socket",
|
|
|
- },
|
|
|
- { /* end of list */ }
|
|
|
- },
|
|
|
- },
|
|
|
+ [NET_CLIENT_OPTIONS_KIND_VDE] = net_init_vde,
|
|
|
#endif
|
|
|
- [NET_CLIENT_TYPE_DUMP] = {
|
|
|
- .type = "dump",
|
|
|
- .init = net_init_dump,
|
|
|
- .desc = {
|
|
|
- NET_COMMON_PARAMS_DESC,
|
|
|
- {
|
|
|
- .name = "len",
|
|
|
- .type = QEMU_OPT_SIZE,
|
|
|
- .help = "per-packet size limit (64k default)",
|
|
|
- }, {
|
|
|
- .name = "file",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "dump file path (default is qemu-vlan0.pcap)",
|
|
|
- },
|
|
|
- { /* end of list */ }
|
|
|
- },
|
|
|
- },
|
|
|
+ [NET_CLIENT_OPTIONS_KIND_DUMP] = net_init_dump,
|
|
|
#ifdef CONFIG_NET_BRIDGE
|
|
|
- [NET_CLIENT_TYPE_BRIDGE] = {
|
|
|
- .type = "bridge",
|
|
|
- .init = net_init_bridge,
|
|
|
- .desc = {
|
|
|
- NET_COMMON_PARAMS_DESC,
|
|
|
- {
|
|
|
- .name = "br",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "bridge name",
|
|
|
- }, {
|
|
|
- .name = "helper",
|
|
|
- .type = QEMU_OPT_STRING,
|
|
|
- .help = "command to execute to configure bridge",
|
|
|
- },
|
|
|
- { /* end of list */ }
|
|
|
- },
|
|
|
- },
|
|
|
-#endif /* CONFIG_NET_BRIDGE */
|
|
|
+ [NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge,
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
-int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
|
|
|
+
|
|
|
+static int net_client_init1(const void *object, int is_netdev, Error **errp)
|
|
|
{
|
|
|
+ union {
|
|
|
+ const Netdev *netdev;
|
|
|
+ const NetLegacy *net;
|
|
|
+ } u;
|
|
|
+ const NetClientOptions *opts;
|
|
|
const char *name;
|
|
|
- const char *type;
|
|
|
- int i;
|
|
|
-
|
|
|
- type = qemu_opt_get(opts, "type");
|
|
|
- if (!type) {
|
|
|
- error_set(errp, QERR_MISSING_PARAMETER, "type");
|
|
|
- return -1;
|
|
|
- }
|
|
|
|
|
|
if (is_netdev) {
|
|
|
- if (strcmp(type, "tap") != 0 &&
|
|
|
-#ifdef CONFIG_NET_BRIDGE
|
|
|
- strcmp(type, "bridge") != 0 &&
|
|
|
-#endif
|
|
|
+ u.netdev = object;
|
|
|
+ opts = u.netdev->opts;
|
|
|
+ name = u.netdev->id;
|
|
|
+
|
|
|
+ switch (opts->kind) {
|
|
|
#ifdef CONFIG_SLIRP
|
|
|
- strcmp(type, "user") != 0 &&
|
|
|
+ case NET_CLIENT_OPTIONS_KIND_USER:
|
|
|
#endif
|
|
|
+ case NET_CLIENT_OPTIONS_KIND_TAP:
|
|
|
+ case NET_CLIENT_OPTIONS_KIND_SOCKET:
|
|
|
#ifdef CONFIG_VDE
|
|
|
- strcmp(type, "vde") != 0 &&
|
|
|
+ case NET_CLIENT_OPTIONS_KIND_VDE:
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_NET_BRIDGE
|
|
|
+ case NET_CLIENT_OPTIONS_KIND_BRIDGE:
|
|
|
#endif
|
|
|
- strcmp(type, "socket") != 0) {
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "type",
|
|
|
"a netdev backend type");
|
|
|
return -1;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ u.net = object;
|
|
|
+ opts = u.net->opts;
|
|
|
+ /* missing optional values have been initialized to "all bits zero" */
|
|
|
+ name = u.net->has_id ? u.net->id : u.net->name;
|
|
|
+ }
|
|
|
|
|
|
- if (qemu_opt_get(opts, "vlan")) {
|
|
|
- error_set(errp, QERR_INVALID_PARAMETER, "vlan");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- if (qemu_opt_get(opts, "name")) {
|
|
|
- error_set(errp, QERR_INVALID_PARAMETER, "name");
|
|
|
- return -1;
|
|
|
+ if (net_client_init_fun[opts->kind]) {
|
|
|
+ VLANState *vlan = NULL;
|
|
|
+
|
|
|
+ /* Do not add to a vlan if it's a -netdev or a nic with a netdev=
|
|
|
+ * parameter. */
|
|
|
+ if (!is_netdev &&
|
|
|
+ (opts->kind != NET_CLIENT_OPTIONS_KIND_NIC ||
|
|
|
+ !opts->nic->has_netdev)) {
|
|
|
+ vlan = qemu_find_vlan(u.net->has_vlan ? u.net->vlan : 0, true);
|
|
|
}
|
|
|
- if (!qemu_opts_id(opts)) {
|
|
|
- error_set(errp, QERR_MISSING_PARAMETER, "id");
|
|
|
+
|
|
|
+ if (net_client_init_fun[opts->kind](opts, name, vlan) < 0) {
|
|
|
+ /* TODO push error reporting into init() methods */
|
|
|
+ error_set(errp, QERR_DEVICE_INIT_FAILED,
|
|
|
+ NetClientOptionsKind_lookup[opts->kind]);
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
- name = qemu_opts_id(opts);
|
|
|
- if (!name) {
|
|
|
- name = qemu_opt_get(opts, "name");
|
|
|
+static void net_visit(Visitor *v, int is_netdev, void **object, Error **errp)
|
|
|
+{
|
|
|
+ if (is_netdev) {
|
|
|
+ visit_type_Netdev(v, (Netdev **)object, NULL, errp);
|
|
|
+ } else {
|
|
|
+ visit_type_NetLegacy(v, (NetLegacy **)object, NULL, errp);
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- for (i = 0; i < NET_CLIENT_TYPE_MAX; i++) {
|
|
|
- if (net_client_types[i].type != NULL &&
|
|
|
- !strcmp(net_client_types[i].type, type)) {
|
|
|
- Error *local_err = NULL;
|
|
|
- VLANState *vlan = NULL;
|
|
|
- int ret;
|
|
|
|
|
|
- qemu_opts_validate(opts, &net_client_types[i].desc[0], &local_err);
|
|
|
- if (error_is_set(&local_err)) {
|
|
|
- error_propagate(errp, local_err);
|
|
|
- return -1;
|
|
|
- }
|
|
|
+int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
|
|
|
+{
|
|
|
+ void *object = NULL;
|
|
|
+ Error *err = NULL;
|
|
|
+ int ret = -1;
|
|
|
|
|
|
- /* Do not add to a vlan if it's a -netdev or a nic with a
|
|
|
- * netdev= parameter. */
|
|
|
- if (!(is_netdev ||
|
|
|
- (strcmp(type, "nic") == 0 && qemu_opt_get(opts, "netdev")))) {
|
|
|
- vlan = qemu_find_vlan(qemu_opt_get_number(opts, "vlan", 0), 1);
|
|
|
- }
|
|
|
+ {
|
|
|
+ OptsVisitor *ov = opts_visitor_new(opts);
|
|
|
|
|
|
- ret = 0;
|
|
|
- if (net_client_types[i].init) {
|
|
|
- ret = net_client_types[i].init(opts, name, vlan);
|
|
|
- if (ret < 0) {
|
|
|
- /* TODO push error reporting into init() methods */
|
|
|
- error_set(errp, QERR_DEVICE_INIT_FAILED, type);
|
|
|
- return -1;
|
|
|
- }
|
|
|
- }
|
|
|
- return ret;
|
|
|
- }
|
|
|
+ net_visit(opts_get_visitor(ov), is_netdev, &object, &err);
|
|
|
+ opts_visitor_cleanup(ov);
|
|
|
}
|
|
|
|
|
|
- error_set(errp, QERR_INVALID_PARAMETER_VALUE, "type",
|
|
|
- "a network client type");
|
|
|
- return -1;
|
|
|
+ if (!err) {
|
|
|
+ ret = net_client_init1(object, is_netdev, &err);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (object) {
|
|
|
+ QapiDeallocVisitor *dv = qapi_dealloc_visitor_new();
|
|
|
+
|
|
|
+ net_visit(qapi_dealloc_get_visitor(dv), is_netdev, &object, NULL);
|
|
|
+ qapi_dealloc_visitor_cleanup(dv);
|
|
|
+ }
|
|
|
+
|
|
|
+ error_propagate(errp, err);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
static int net_host_check_device(const char *device)
|
|
|
{
|
|
|
int i;
|
|
@@ -1286,14 +1052,14 @@ void qmp_netdev_del(const char *id, Error **errp)
|
|
|
static void print_net_client(Monitor *mon, VLANClientState *vc)
|
|
|
{
|
|
|
monitor_printf(mon, "%s: type=%s,%s\n", vc->name,
|
|
|
- net_client_types[vc->info->type].type, vc->info_str);
|
|
|
+ NetClientOptionsKind_lookup[vc->info->type], vc->info_str);
|
|
|
}
|
|
|
|
|
|
void do_info_network(Monitor *mon)
|
|
|
{
|
|
|
VLANState *vlan;
|
|
|
VLANClientState *vc, *peer;
|
|
|
- net_client_type type;
|
|
|
+ NetClientOptionsKind type;
|
|
|
|
|
|
QTAILQ_FOREACH(vlan, &vlans, next) {
|
|
|
monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
|
|
@@ -1307,11 +1073,11 @@ void do_info_network(Monitor *mon)
|
|
|
QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
|
|
|
peer = vc->peer;
|
|
|
type = vc->info->type;
|
|
|
- if (!peer || type == NET_CLIENT_TYPE_NIC) {
|
|
|
+ if (!peer || type == NET_CLIENT_OPTIONS_KIND_NIC) {
|
|
|
monitor_printf(mon, " ");
|
|
|
print_net_client(mon, vc);
|
|
|
} /* else it's a netdev connected to a NIC, printed with the NIC */
|
|
|
- if (peer && type == NET_CLIENT_TYPE_NIC) {
|
|
|
+ if (peer && type == NET_CLIENT_OPTIONS_KIND_NIC) {
|
|
|
monitor_printf(mon, " \\ ");
|
|
|
print_net_client(mon, peer);
|
|
|
}
|
|
@@ -1399,13 +1165,13 @@ void net_check_clients(void)
|
|
|
|
|
|
QTAILQ_FOREACH(vc, &vlan->clients, next) {
|
|
|
switch (vc->info->type) {
|
|
|
- case NET_CLIENT_TYPE_NIC:
|
|
|
+ case NET_CLIENT_OPTIONS_KIND_NIC:
|
|
|
has_nic = 1;
|
|
|
break;
|
|
|
- case NET_CLIENT_TYPE_USER:
|
|
|
- case NET_CLIENT_TYPE_TAP:
|
|
|
- case NET_CLIENT_TYPE_SOCKET:
|
|
|
- case NET_CLIENT_TYPE_VDE:
|
|
|
+ case NET_CLIENT_OPTIONS_KIND_USER:
|
|
|
+ case NET_CLIENT_OPTIONS_KIND_TAP:
|
|
|
+ case NET_CLIENT_OPTIONS_KIND_SOCKET:
|
|
|
+ case NET_CLIENT_OPTIONS_KIND_VDE:
|
|
|
has_host_dev = 1;
|
|
|
break;
|
|
|
default: ;
|
|
@@ -1421,7 +1187,7 @@ void net_check_clients(void)
|
|
|
QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
|
|
|
if (!vc->peer) {
|
|
|
fprintf(stderr, "Warning: %s %s has no peer\n",
|
|
|
- vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev",
|
|
|
+ vc->info->type == NET_CLIENT_OPTIONS_KIND_NIC ? "nic" : "netdev",
|
|
|
vc->name);
|
|
|
}
|
|
|
}
|