diff options
author | Laszlo Ersek <lersek@redhat.com> | 2012-07-17 16:17:13 +0200 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> | 2012-07-23 11:55:18 +0100 |
commit | 6687b79d636cd60ed9adb1177d0d946b58fa7717 (patch) | |
tree | 26380fc6c6a92c1774bbc6b2d3620a6a97c39dbe /net.c | |
parent | 2be64a68ed05c65fc510dc450a1eb1823edf9330 (diff) | |
download | hqemu-6687b79d636cd60ed9adb1177d0d946b58fa7717.zip hqemu-6687b79d636cd60ed9adb1177d0d946b58fa7717.tar.gz |
convert net_client_init() to OptsVisitor
The net_client_init() prototype is kept intact.
Based on "is_netdev", the QemuOpts-rooted QemuOpt-list is parsed as a
Netdev or a NetLegacy. The original meat of net_client_init() is moved to
and simplified in net_client_init1():
Fields not common between -net and -netdev are clearly separated. Getting
the name for the init functions is cleaner: Netdev::id is mandatory, and
all init functions handle a NULL NetLegacy::name. NetLegacy::vlan
explicitly depends on -net (see below).
Verifying the "type=" option for -netdev can be turned into a switch.
Format validation with qemu_opts_validate() can be removed because the
visitor covers it. Relatedly, the "net_client_types" array is reduced to
an array of init functions that can be directly indexed by opts->kind.
(Help text is available in the schema JSON.)
The outermost negation in the condition around qemu_find_vlan() was
flattened, because it expresses the dependent code's requirements more
clearly.
VLAN lookup is avoided if there's no init function to pass the VLAN to.
Whenever the value of type=... is needed, we substitute
NetClientOptionsKind_lookup[kind].
The individual init functions are not converted yet, thus the original
QemuOpts instance is passed transparently.
v1->v2:
- NetLegacy::name is optional. Tracked it through all init functions: they
all handle a NULL name. Updated commit message accordingly.
v2->v3:
- NetLegacy::id is allowed and takes precedence over NetLegacy::name.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Diffstat (limited to 'net.c')
-rw-r--r-- | net.c | 429 |
1 files changed, 96 insertions, 333 deletions
@@ -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) @@ -745,7 +748,8 @@ 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(QemuOpts *opts, const NetClientOptions *new_opts, + const char *name, VLANState *vlan) { int idx; NICInfo *nd; @@ -802,371 +806,130 @@ 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_OPTIONS_KIND_MAX] = { - [NET_CLIENT_OPTIONS_KIND_NONE] = { - .type = "none", - .desc = { - NET_COMMON_PARAMS_DESC, - { /* end of list */ } - }, - }, - [NET_CLIENT_OPTIONS_KIND_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])( + QemuOpts *old_opts, + const NetClientOptions *new_opts, + const char *name, + VLANState *vlan) = { + [NET_CLIENT_OPTIONS_KIND_NIC] = net_init_nic, #ifdef CONFIG_SLIRP - [NET_CLIENT_OPTIONS_KIND_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 */ } - }, - }, -#endif - [NET_CLIENT_OPTIONS_KIND_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", - }, { + [NET_CLIENT_OPTIONS_KIND_USER] = net_init_slirp, #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_OPTIONS_KIND_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_OPTIONS_KIND_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_OPTIONS_KIND_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_OPTIONS_KIND_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, + QemuOpts *old_opts, 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](old_opts, 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_OPTIONS_KIND_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, opts, &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,7 +1049,7 @@ 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) |