diff options
| -rw-r--r-- | MAINTAINERS | 8 | ||||
| -rw-r--r-- | hw/vfio/pci-quirks.c | 6 | ||||
| -rw-r--r-- | hw/vfio/pci.c | 39 | ||||
| -rw-r--r-- | hw/vfio/pci.h | 1 | ||||
| -rw-r--r-- | include/qemu/sockets.h | 10 | ||||
| -rw-r--r-- | trace-events | 2 | ||||
| -rw-r--r-- | ui/vnc.c | 18 | ||||
| -rw-r--r-- | util/qemu-sockets.c | 344 |
8 files changed, 222 insertions, 206 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 4030e2749d..7865145ea2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1260,6 +1260,14 @@ F: io/ F: include/io/ F: tests/test-io-* +Sockets +M: Daniel P. Berrange <berrange@redhat.com> +M: Gerd Hoffmann <kraxel@redhat.com> +M: Paolo Bonzini <pbonzini@redhat.com> +S: Maintained +F: include/qemu/sockets.h +F: util/qemu-sockets.c + Usermode Emulation ------------------ Overall diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index 30c68a1e2b..e117c41fbe 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -328,7 +328,7 @@ static void vfio_probe_ati_bar4_quirk(VFIOPCIDevice *vdev, int nr) window->data_offset = 4; window->nr_matches = 1; window->matches[0].match = 0x4000; - window->matches[0].mask = PCIE_CONFIG_SPACE_SIZE - 1; + window->matches[0].mask = vdev->config_size - 1; window->bar = nr; window->addr_mem = &quirk->mem[0]; window->data_mem = &quirk->mem[1]; @@ -674,7 +674,7 @@ static void vfio_probe_nvidia_bar5_quirk(VFIOPCIDevice *vdev, int nr) window->matches[0].match = 0x1800; window->matches[0].mask = PCI_CONFIG_SPACE_SIZE - 1; window->matches[1].match = 0x88000; - window->matches[1].mask = PCIE_CONFIG_SPACE_SIZE - 1; + window->matches[1].mask = vdev->config_size - 1; window->bar = nr; window->addr_mem = bar5->addr_mem = &quirk->mem[0]; window->data_mem = bar5->data_mem = &quirk->mem[1]; @@ -765,7 +765,7 @@ static void vfio_probe_nvidia_bar0_quirk(VFIOPCIDevice *vdev, int nr) memory_region_init_io(mirror->mem, OBJECT(vdev), &vfio_nvidia_mirror_quirk, mirror, "vfio-nvidia-bar0-88000-mirror-quirk", - PCIE_CONFIG_SPACE_SIZE); + vdev->config_size); memory_region_add_subregion_overlap(&vdev->bars[nr].region.mem, mirror->offset, mirror->mem, 1); diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 1fb868c244..e66c47ff6a 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -356,6 +356,13 @@ static void vfio_msi_interrupt(void *opaque) if (vdev->interrupt == VFIO_INT_MSIX) { get_msg = msix_get_message; notify = msix_notify; + + /* A masked vector firing needs to use the PBA, enable it */ + if (msix_is_masked(&vdev->pdev, nr)) { + set_bit(nr, vdev->msix->pending); + memory_region_set_enabled(&vdev->pdev.msix_pba_mmio, true); + trace_vfio_msix_pba_enable(vdev->vbasedev.name); + } } else if (vdev->interrupt == VFIO_INT_MSI) { get_msg = msi_get_message; notify = msi_notify; @@ -535,6 +542,14 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, } } + /* Disable PBA emulation when nothing more is pending. */ + clear_bit(nr, vdev->msix->pending); + if (find_first_bit(vdev->msix->pending, + vdev->nr_vectors) == vdev->nr_vectors) { + memory_region_set_enabled(&vdev->pdev.msix_pba_mmio, false); + trace_vfio_msix_pba_disable(vdev->vbasedev.name); + } + return 0; } @@ -738,6 +753,9 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) vfio_msi_disable_common(vdev); + memset(vdev->msix->pending, 0, + BITS_TO_LONGS(vdev->msix->entries) * sizeof(unsigned long)); + trace_vfio_msix_disable(vdev->vbasedev.name); } @@ -1251,6 +1269,8 @@ static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos) { int ret; + vdev->msix->pending = g_malloc0(BITS_TO_LONGS(vdev->msix->entries) * + sizeof(unsigned long)); ret = msix_init(&vdev->pdev, vdev->msix->entries, &vdev->bars[vdev->msix->table_bar].region.mem, vdev->msix->table_bar, vdev->msix->table_offset, @@ -1264,6 +1284,24 @@ static int vfio_msix_setup(VFIOPCIDevice *vdev, int pos) return ret; } + /* + * The PCI spec suggests that devices provide additional alignment for + * MSI-X structures and avoid overlapping non-MSI-X related registers. + * For an assigned device, this hopefully means that emulation of MSI-X + * structures does not affect the performance of the device. If devices + * fail to provide that alignment, a significant performance penalty may + * result, for instance Mellanox MT27500 VFs: + * http://www.spinics.net/lists/kvm/msg125881.html + * + * The PBA is simply not that important for such a serious regression and + * most drivers do not appear to look at it. The solution for this is to + * disable the PBA MemoryRegion unless it's being used. We disable it + * here and only enable it if a masked vector fires through QEMU. As the + * vector-use notifier is called, which occurs on unmask, we test whether + * PBA emulation is needed and again disable if not. + */ + memory_region_set_enabled(&vdev->pdev.msix_pba_mmio, false); + return 0; } @@ -1275,6 +1313,7 @@ static void vfio_teardown_msi(VFIOPCIDevice *vdev) msix_uninit(&vdev->pdev, &vdev->bars[vdev->msix->table_bar].region.mem, &vdev->bars[vdev->msix->pba_bar].region.mem); + g_free(vdev->msix->pending); } } diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index f004d52b69..62565878fc 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -95,6 +95,7 @@ typedef struct VFIOMSIXInfo { uint32_t pba_offset; MemoryRegion mmap_mem; void *mmap; + unsigned long *pending; } VFIOMSIXInfo; typedef struct VFIOPCIDevice { diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index c1a81fa619..cde2f5e0d6 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -26,12 +26,9 @@ int inet_aton(const char *cp, struct in_addr *ia); #endif /* !_WIN32 */ -#include "qemu/option.h" #include "qapi/error.h" #include "qapi-types.h" -extern QemuOptsList socket_optslist; - /* misc helpers */ int qemu_socket(int domain, int type, int protocol); int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); @@ -54,23 +51,16 @@ int socket_set_fast_reuse(int fd); typedef void NonBlockingConnectHandler(int fd, Error *err, void *opaque); InetSocketAddress *inet_parse(const char *str, Error **errp); -int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp); int inet_listen(const char *str, char *ostr, int olen, int socktype, int port_offset, Error **errp); -int inet_connect_opts(QemuOpts *opts, Error **errp, - NonBlockingConnectHandler *callback, void *opaque); int inet_connect(const char *str, Error **errp); int inet_nonblocking_connect(const char *str, NonBlockingConnectHandler *callback, void *opaque, Error **errp); -int inet_dgram_opts(QemuOpts *opts, Error **errp); NetworkAddressFamily inet_netfamily(int family); -int unix_listen_opts(QemuOpts *opts, Error **errp); int unix_listen(const char *path, char *ostr, int olen, Error **errp); -int unix_connect_opts(QemuOpts *opts, Error **errp, - NonBlockingConnectHandler *callback, void *opaque); int unix_connect(const char *path, Error **errp); int unix_nonblocking_connect(const char *str, NonBlockingConnectHandler *callback, diff --git a/trace-events b/trace-events index 934a7b6402..c9ac144cee 100644 --- a/trace-events +++ b/trace-events @@ -1631,6 +1631,8 @@ vfio_msi_interrupt(const char *name, int index, uint64_t addr, int data) " (%s) vfio_msix_vector_do_use(const char *name, int index) " (%s) vector %d used" vfio_msix_vector_release(const char *name, int index) " (%s) vector %d released" vfio_msix_enable(const char *name) " (%s)" +vfio_msix_pba_disable(const char *name) " (%s)" +vfio_msix_pba_enable(const char *name) " (%s)" vfio_msix_disable(const char *name) " (%s)" vfio_msi_enable(const char *name, int nr_vectors) " (%s) Enabled %d MSI vectors" vfio_msi_disable(const char *name) " (%s)" diff --git a/ui/vnc.c b/ui/vnc.c index 85e3462a27..339f8c35b2 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -3502,8 +3502,10 @@ void vnc_display_open(const char *id, Error **errp) const char *websocket = qemu_opt_get(opts, "websocket"); int to = qemu_opt_get_number(opts, "to", 0); - bool has_ipv4 = qemu_opt_get_bool(opts, "ipv4", false); - bool has_ipv6 = qemu_opt_get_bool(opts, "ipv6", false); + bool has_ipv4 = qemu_opt_get(opts, "ipv4"); + bool has_ipv6 = qemu_opt_get(opts, "ipv6"); + bool ipv4 = qemu_opt_get_bool(opts, "ipv4", false); + bool ipv6 = qemu_opt_get_bool(opts, "ipv6", false); saddr = g_new0(SocketAddress, 1); if (websocket) { @@ -3551,8 +3553,10 @@ void vnc_display_open(const char *id, Error **errp) saddr->u.inet->has_to = true; saddr->u.inet->to = to + 5900; } - saddr->u.inet->ipv4 = saddr->u.inet->has_ipv4 = has_ipv4; - saddr->u.inet->ipv6 = saddr->u.inet->has_ipv6 = has_ipv6; + saddr->u.inet->ipv4 = ipv4; + saddr->u.inet->has_ipv4 = has_ipv4; + saddr->u.inet->ipv6 = ipv6; + saddr->u.inet->has_ipv6 = has_ipv6; if (vs->ws_enabled) { wsaddr->type = SOCKET_ADDRESS_KIND_INET; @@ -3564,8 +3568,10 @@ void vnc_display_open(const char *id, Error **errp) wsaddr->u.inet->has_to = true; wsaddr->u.inet->to = to; } - wsaddr->u.inet->ipv4 = wsaddr->u.inet->has_ipv4 = has_ipv4; - wsaddr->u.inet->ipv6 = wsaddr->u.inet->has_ipv6 = has_ipv6; + wsaddr->u.inet->ipv4 = ipv4; + wsaddr->u.inet->has_ipv4 = has_ipv4; + wsaddr->u.inet->ipv6 = ipv6; + wsaddr->u.inet->has_ipv6 = has_ipv6; } } } else { diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 922efb3179..f455a1748f 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -36,39 +36,6 @@ # define AI_V4MAPPED 0 #endif -/* used temporarily until all users are converted to QemuOpts */ -QemuOptsList socket_optslist = { - .name = "socket", - .head = QTAILQ_HEAD_INITIALIZER(socket_optslist.head), - .desc = { - { - .name = "path", - .type = QEMU_OPT_STRING, - },{ - .name = "host", - .type = QEMU_OPT_STRING, - },{ - .name = "port", - .type = QEMU_OPT_STRING, - },{ - .name = "localaddr", - .type = QEMU_OPT_STRING, - },{ - .name = "localport", - .type = QEMU_OPT_STRING, - },{ - .name = "to", - .type = QEMU_OPT_NUMBER, - },{ - .name = "ipv4", - .type = QEMU_OPT_BOOL, - },{ - .name = "ipv6", - .type = QEMU_OPT_BOOL, - }, - { /* end if list */ } - }, -}; static int inet_getport(struct addrinfo *e) { @@ -114,36 +81,78 @@ NetworkAddressFamily inet_netfamily(int family) return NETWORK_ADDRESS_FAMILY_UNKNOWN; } -int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) +/* + * Matrix we're trying to apply + * + * ipv4 ipv6 family + * - - PF_UNSPEC + * - f PF_INET + * - t PF_INET6 + * f - PF_INET6 + * f f <error> + * f t PF_INET6 + * t - PF_INET + * t f PF_INET + * t t PF_INET6 + * + * NB, this matrix is only about getting the neccessary results + * from getaddrinfo(). Some of the cases require further work + * after reading results from getaddrinfo in order to fully + * apply the logic the end user wants. eg with the last case + * ipv4=t + ipv6=t + PF_INET6, getaddrinfo alone can only + * guarantee the ipv6=t part of the request - we need more + * checks to provide ipv4=t part of the guarantee. This is + * outside scope of this method and not currently handled by + * callers at all. + */ +static int inet_ai_family_from_address(InetSocketAddress *addr, + Error **errp) +{ + if (addr->has_ipv6 && addr->has_ipv4 && + !addr->ipv6 && !addr->ipv4) { + error_setg(errp, "Cannot disable IPv4 and IPv6 at same time"); + return PF_UNSPEC; + } + if ((addr->has_ipv6 && addr->ipv6) || (addr->has_ipv4 && !addr->ipv4)) { + return PF_INET6; + } + if ((addr->has_ipv4 && addr->ipv4) || (addr->has_ipv6 && !addr->ipv6)) { + return PF_INET; + } + return PF_UNSPEC; +} + +static int inet_listen_saddr(InetSocketAddress *saddr, + int port_offset, + bool update_addr, + Error **errp) { struct addrinfo ai,*res,*e; - const char *addr; char port[33]; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; - int slisten, rc, to, port_min, port_max, p; + int slisten, rc, port_min, port_max, p; + Error *err = NULL; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; - ai.ai_family = PF_UNSPEC; + ai.ai_family = inet_ai_family_from_address(saddr, &err); ai.ai_socktype = SOCK_STREAM; - if ((qemu_opt_get(opts, "host") == NULL)) { + if (err) { + error_propagate(errp, err); + return -1; + } + + if (saddr->host == NULL) { error_setg(errp, "host not specified"); return -1; } - if (qemu_opt_get(opts, "port") != NULL) { - pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port")); + if (saddr->port != NULL) { + pstrcpy(port, sizeof(port), saddr->port); } else { port[0] = '\0'; } - addr = qemu_opt_get(opts, "host"); - - to = qemu_opt_get_number(opts, "to", 0); - if (qemu_opt_get_bool(opts, "ipv4", 0)) - ai.ai_family = PF_INET; - if (qemu_opt_get_bool(opts, "ipv6", 0)) - ai.ai_family = PF_INET6; /* lookup */ if (port_offset) { @@ -163,11 +172,11 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) } snprintf(port, sizeof(port), "%d", (int)baseport + port_offset); } - rc = getaddrinfo(strlen(addr) ? addr : NULL, + rc = getaddrinfo(strlen(saddr->host) ? saddr->host : NULL, strlen(port) ? port : NULL, &ai, &res); if (rc != 0) { - error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, - gai_strerror(rc)); + error_setg(errp, "address resolution failed for %s:%s: %s", + saddr->host, port, gai_strerror(rc)); return -1; } @@ -195,7 +204,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) #endif port_min = inet_getport(e); - port_max = to ? to + port_offset : port_min; + port_max = saddr->has_to ? saddr->to + port_offset : port_min; for (p = port_min; p <= port_max; p++) { inet_setport(e, p); if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { @@ -219,13 +228,15 @@ listen: freeaddrinfo(res); return -1; } - qemu_opt_set(opts, "host", uaddr, &error_abort); - qemu_opt_set_number(opts, "port", inet_getport(e) - port_offset, - &error_abort); - qemu_opt_set_bool(opts, "ipv6", e->ai_family == PF_INET6, - &error_abort); - qemu_opt_set_bool(opts, "ipv4", e->ai_family != PF_INET6, - &error_abort); + if (update_addr) { + g_free(saddr->host); + saddr->host = g_strdup(uaddr); + g_free(saddr->port); + saddr->port = g_strdup_printf("%d", + inet_getport(e) - port_offset); + saddr->has_ipv6 = saddr->ipv6 = e->ai_family == PF_INET6; + saddr->has_ipv4 = saddr->ipv4 = e->ai_family != PF_INET6; + } freeaddrinfo(res); return slisten; } @@ -340,38 +351,34 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, return sock; } -static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) +static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr, + Error **errp) { struct addrinfo ai, *res; int rc; - const char *addr; - const char *port; + Error *err = NULL; memset(&ai, 0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG; - ai.ai_family = PF_UNSPEC; + ai.ai_family = inet_ai_family_from_address(saddr, &err); ai.ai_socktype = SOCK_STREAM; - addr = qemu_opt_get(opts, "host"); - port = qemu_opt_get(opts, "port"); - if (addr == NULL || port == NULL) { - error_setg(errp, "host and/or port not specified"); + if (err) { + error_propagate(errp, err); return NULL; } - if (qemu_opt_get_bool(opts, "ipv4", 0)) { - ai.ai_family = PF_INET; - } - if (qemu_opt_get_bool(opts, "ipv6", 0)) { - ai.ai_family = PF_INET6; + if (saddr->host == NULL || saddr->port == NULL) { + error_setg(errp, "host and/or port not specified"); + return NULL; } /* lookup */ - rc = getaddrinfo(addr, port, &ai, &res); + rc = getaddrinfo(saddr->host, saddr->port, &ai, &res); if (rc != 0) { - error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, - gai_strerror(rc)); + error_setg(errp, "address resolution failed for %s:%s: %s", + saddr->host, saddr->port, gai_strerror(rc)); return NULL; } return res; @@ -380,8 +387,7 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) /** * Create a socket and connect it to an address. * - * @opts: QEMU options, recognized parameters strings "host" and "port", - * bools "ipv4" and "ipv6". + * @saddr: Inet socket address specification * @errp: set on error * @callback: callback function for non-blocking connect * @opaque: opaque for callback function @@ -392,8 +398,8 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) * function succeeds, callback will be called when the connection * completes, with the file descriptor on success, or -1 on error. */ -int inet_connect_opts(QemuOpts *opts, Error **errp, - NonBlockingConnectHandler *callback, void *opaque) +static int inet_connect_saddr(InetSocketAddress *saddr, Error **errp, + NonBlockingConnectHandler *callback, void *opaque) { Error *local_err = NULL; struct addrinfo *res, *e; @@ -401,7 +407,7 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, bool in_progress; ConnectState *connect_state = NULL; - res = inet_parse_connect_opts(opts, errp); + res = inet_parse_connect_saddr(saddr, errp); if (!res) { return -1; } @@ -440,21 +446,29 @@ int inet_connect_opts(QemuOpts *opts, Error **errp, return sock; } -int inet_dgram_opts(QemuOpts *opts, Error **errp) +static int inet_dgram_saddr(InetSocketAddress *sraddr, + InetSocketAddress *sladdr, + Error **errp) { struct addrinfo ai, *peer = NULL, *local = NULL; const char *addr; const char *port; int sock = -1, rc; + Error *err = NULL; /* lookup peer addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG; - ai.ai_family = PF_UNSPEC; + ai.ai_family = inet_ai_family_from_address(sraddr, &err); ai.ai_socktype = SOCK_DGRAM; - addr = qemu_opt_get(opts, "host"); - port = qemu_opt_get(opts, "port"); + if (err) { + error_propagate(errp, err); + return -1; + } + + addr = sraddr->host; + port = sraddr->port; if (addr == NULL || strlen(addr) == 0) { addr = "localhost"; } @@ -463,11 +477,6 @@ int inet_dgram_opts(QemuOpts *opts, Error **errp) return -1; } - if (qemu_opt_get_bool(opts, "ipv4", 0)) - ai.ai_family = PF_INET; - if (qemu_opt_get_bool(opts, "ipv6", 0)) - ai.ai_family = PF_INET6; - if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); @@ -480,13 +489,19 @@ int inet_dgram_opts(QemuOpts *opts, Error **errp) ai.ai_family = peer->ai_family; ai.ai_socktype = SOCK_DGRAM; - addr = qemu_opt_get(opts, "localaddr"); - port = qemu_opt_get(opts, "localport"); - if (addr == NULL || strlen(addr) == 0) { + if (sladdr) { + addr = sladdr->host; + port = sladdr->port; + if (addr == NULL || strlen(addr) == 0) { + addr = NULL; + } + if (!port || strlen(port) == 0) { + port = "0"; + } + } else { addr = NULL; - } - if (!port || strlen(port) == 0) port = "0"; + } if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, @@ -595,54 +610,31 @@ fail: return NULL; } -static void inet_addr_to_opts(QemuOpts *opts, const InetSocketAddress *addr) -{ - bool ipv4 = addr->has_ipv4 && addr->ipv4; - bool ipv6 = addr->has_ipv6 && addr->ipv6; - - if (ipv4 || ipv6) { - qemu_opt_set_bool(opts, "ipv4", ipv4, &error_abort); - qemu_opt_set_bool(opts, "ipv6", ipv6, &error_abort); - } else if (addr->has_ipv4 || addr->has_ipv6) { - qemu_opt_set_bool(opts, "ipv4", !addr->has_ipv4, &error_abort); - qemu_opt_set_bool(opts, "ipv6", !addr->has_ipv6, &error_abort); - } - if (addr->has_to) { - qemu_opt_set_number(opts, "to", addr->to, &error_abort); - } - qemu_opt_set(opts, "host", addr->host, &error_abort); - qemu_opt_set(opts, "port", addr->port, &error_abort); -} - int inet_listen(const char *str, char *ostr, int olen, int socktype, int port_offset, Error **errp) { - QemuOpts *opts; char *optstr; int sock = -1; InetSocketAddress *addr; addr = inet_parse(str, errp); if (addr != NULL) { - opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - inet_addr_to_opts(opts, addr); - qapi_free_InetSocketAddress(addr); - sock = inet_listen_opts(opts, port_offset, errp); + sock = inet_listen_saddr(addr, port_offset, true, errp); if (sock != -1 && ostr) { optstr = strchr(str, ','); - if (qemu_opt_get_bool(opts, "ipv6", 0)) { + if (addr->ipv6) { snprintf(ostr, olen, "[%s]:%s%s", - qemu_opt_get(opts, "host"), - qemu_opt_get(opts, "port"), + addr->host, + addr->port, optstr ? optstr : ""); } else { snprintf(ostr, olen, "%s:%s%s", - qemu_opt_get(opts, "host"), - qemu_opt_get(opts, "port"), + addr->host, + addr->port, optstr ? optstr : ""); } } - qemu_opts_del(opts); + qapi_free_InetSocketAddress(addr); } return sock; } @@ -657,17 +649,13 @@ int inet_listen(const char *str, char *ostr, int olen, **/ int inet_connect(const char *str, Error **errp) { - QemuOpts *opts; int sock = -1; InetSocketAddress *addr; addr = inet_parse(str, errp); if (addr != NULL) { - opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - inet_addr_to_opts(opts, addr); + sock = inet_connect_saddr(addr, errp, NULL, NULL); qapi_free_InetSocketAddress(addr); - sock = inet_connect_opts(opts, errp, NULL, NULL); - qemu_opts_del(opts); } return sock; } @@ -689,7 +677,6 @@ int inet_nonblocking_connect(const char *str, NonBlockingConnectHandler *callback, void *opaque, Error **errp) { - QemuOpts *opts; int sock = -1; InetSocketAddress *addr; @@ -697,21 +684,19 @@ int inet_nonblocking_connect(const char *str, addr = inet_parse(str, errp); if (addr != NULL) { - opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - inet_addr_to_opts(opts, addr); + sock = inet_connect_saddr(addr, errp, callback, opaque); qapi_free_InetSocketAddress(addr); - sock = inet_connect_opts(opts, errp, callback, opaque); - qemu_opts_del(opts); } return sock; } #ifndef _WIN32 -int unix_listen_opts(QemuOpts *opts, Error **errp) +static int unix_listen_saddr(UnixSocketAddress *saddr, + bool update_addr, + Error **errp) { struct sockaddr_un un; - const char *path = qemu_opt_get(opts, "path"); int sock, fd; sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); @@ -722,8 +707,8 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; - if (path && strlen(path)) { - snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + if (saddr->path && strlen(saddr->path)) { + snprintf(un.sun_path, sizeof(un.sun_path), "%s", saddr->path); } else { const char *tmpdir = getenv("TMPDIR"); tmpdir = tmpdir ? tmpdir : "/tmp"; @@ -748,7 +733,10 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) goto err; } close(fd); - qemu_opt_set(opts, "path", un.sun_path, &error_abort); + if (update_addr) { + g_free(saddr->path); + saddr->path = g_strdup(un.sun_path); + } } if (unlink(un.sun_path) < 0 && errno != ENOENT) { @@ -772,15 +760,14 @@ err: return -1; } -int unix_connect_opts(QemuOpts *opts, Error **errp, - NonBlockingConnectHandler *callback, void *opaque) +static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp, + NonBlockingConnectHandler *callback, void *opaque) { struct sockaddr_un un; - const char *path = qemu_opt_get(opts, "path"); ConnectState *connect_state = NULL; int sock, rc; - if (path == NULL) { + if (saddr->path == NULL) { error_setg(errp, "unix connect: no path specified"); return -1; } @@ -799,7 +786,7 @@ int unix_connect_opts(QemuOpts *opts, Error **errp, memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; - snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); + snprintf(un.sun_path, sizeof(un.sun_path), "%s", saddr->path); /* connect to peer */ do { @@ -832,15 +819,17 @@ int unix_connect_opts(QemuOpts *opts, Error **errp, #else -int unix_listen_opts(QemuOpts *opts, Error **errp) +static int unix_listen_saddr(UnixSocketAddress *saddr, + bool update_addr, + Error **errp) { error_setg(errp, "unix sockets are not available on windows"); errno = ENOTSUP; return -1; } -int unix_connect_opts(QemuOpts *opts, Error **errp, - NonBlockingConnectHandler *callback, void *opaque) +static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp, + NonBlockingConnectHandler *callback, void *opaque) { error_setg(errp, "unix sockets are not available on windows"); errno = ENOTSUP; @@ -851,11 +840,11 @@ int unix_connect_opts(QemuOpts *opts, Error **errp, /* compatibility wrapper */ int unix_listen(const char *str, char *ostr, int olen, Error **errp) { - QemuOpts *opts; char *path, *optstr; int sock, len; + UnixSocketAddress *saddr; - opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); + saddr = g_new0(UnixSocketAddress, 1); optstr = strchr(str, ','); if (optstr) { @@ -863,30 +852,29 @@ int unix_listen(const char *str, char *ostr, int olen, Error **errp) if (len) { path = g_malloc(len+1); snprintf(path, len+1, "%.*s", len, str); - qemu_opt_set(opts, "path", path, &error_abort); - g_free(path); + saddr->path = path; } } else { - qemu_opt_set(opts, "path", str, &error_abort); + saddr->path = g_strdup(str); } - sock = unix_listen_opts(opts, errp); + sock = unix_listen_saddr(saddr, true, errp); if (sock != -1 && ostr) - snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : ""); - qemu_opts_del(opts); + snprintf(ostr, olen, "%s%s", saddr->path, optstr ? optstr : ""); + qapi_free_UnixSocketAddress(saddr); return sock; } int unix_connect(const char *path, Error **errp) { - QemuOpts *opts; + UnixSocketAddress *saddr; int sock; - opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - qemu_opt_set(opts, "path", path, &error_abort); - sock = unix_connect_opts(opts, errp, NULL, NULL); - qemu_opts_del(opts); + saddr = g_new0(UnixSocketAddress, 1); + saddr->path = g_strdup(path); + sock = unix_connect_saddr(saddr, errp, NULL, NULL); + qapi_free_UnixSocketAddress(saddr); return sock; } @@ -895,15 +883,15 @@ int unix_nonblocking_connect(const char *path, NonBlockingConnectHandler *callback, void *opaque, Error **errp) { - QemuOpts *opts; + UnixSocketAddress *saddr; int sock = -1; g_assert(callback != NULL); - opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); - qemu_opt_set(opts, "path", path, &error_abort); - sock = unix_connect_opts(opts, errp, callback, opaque); - qemu_opts_del(opts); + saddr = g_new0(UnixSocketAddress, 1); + saddr->path = g_strdup(path); + sock = unix_connect_saddr(saddr, errp, callback, opaque); + qapi_free_UnixSocketAddress(saddr); return sock; } @@ -947,19 +935,15 @@ fail: int socket_connect(SocketAddress *addr, Error **errp, NonBlockingConnectHandler *callback, void *opaque) { - QemuOpts *opts; int fd; - opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); switch (addr->type) { case SOCKET_ADDRESS_KIND_INET: - inet_addr_to_opts(opts, addr->u.inet); - fd = inet_connect_opts(opts, errp, callback, opaque); + fd = inet_connect_saddr(addr->u.inet, errp, callback, opaque); break; case SOCKET_ADDRESS_KIND_UNIX: - qemu_opt_set(opts, "path", addr->u.q_unix->path, &error_abort); - fd = unix_connect_opts(opts, errp, callback, opaque); + fd = unix_connect_saddr(addr->u.q_unix, errp, callback, opaque); break; case SOCKET_ADDRESS_KIND_FD: @@ -973,25 +957,20 @@ int socket_connect(SocketAddress *addr, Error **errp, default: abort(); } - qemu_opts_del(opts); return fd; } int socket_listen(SocketAddress *addr, Error **errp) { - QemuOpts *opts; int fd; - opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); switch (addr->type) { case SOCKET_ADDRESS_KIND_INET: - inet_addr_to_opts(opts, addr->u.inet); - fd = inet_listen_opts(opts, 0, errp); + fd = inet_listen_saddr(addr->u.inet, 0, false, errp); break; case SOCKET_ADDRESS_KIND_UNIX: - qemu_opt_set(opts, "path", addr->u.q_unix->path, &error_abort); - fd = unix_listen_opts(opts, errp); + fd = unix_listen_saddr(addr->u.q_unix, false, errp); break; case SOCKET_ADDRESS_KIND_FD: @@ -1001,31 +980,22 @@ int socket_listen(SocketAddress *addr, Error **errp) default: abort(); } - qemu_opts_del(opts); return fd; } int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp) { - QemuOpts *opts; int fd; - opts = qemu_opts_create(&socket_optslist, NULL, 0, &error_abort); switch (remote->type) { case SOCKET_ADDRESS_KIND_INET: - inet_addr_to_opts(opts, remote->u.inet); - if (local) { - qemu_opt_set(opts, "localaddr", local->u.inet->host, &error_abort); - qemu_opt_set(opts, "localport", local->u.inet->port, &error_abort); - } - fd = inet_dgram_opts(opts, errp); + fd = inet_dgram_saddr(remote->u.inet, local ? local->u.inet : NULL, errp); break; default: error_setg(errp, "socket type unsupported for datagram"); fd = -1; } - qemu_opts_del(opts); return fd; } |