From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59918) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bzBVH-0006hh-7m for qemu-devel@nongnu.org; Tue, 25 Oct 2016 19:51:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bzBVD-0004PR-9v for qemu-devel@nongnu.org; Tue, 25 Oct 2016 19:51:35 -0400 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:57578) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1bzBVD-0004PA-1D for qemu-devel@nongnu.org; Tue, 25 Oct 2016 19:51:31 -0400 Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.17/8.16.0.17) with SMTP id u9PNnX5d002219 for ; Tue, 25 Oct 2016 19:51:29 -0400 Received: from e17.ny.us.ibm.com (e17.ny.us.ibm.com [129.33.205.207]) by mx0a-001b2d01.pphosted.com with ESMTP id 26ad0fnu1p-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Tue, 25 Oct 2016 19:51:29 -0400 Received: from localhost by e17.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Oct 2016 19:51:28 -0400 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Michael Roth In-Reply-To: <1476435656-3100-4-git-send-email-stefanha@redhat.com> References: <1476435656-3100-1-git-send-email-stefanha@redhat.com> <1476435656-3100-4-git-send-email-stefanha@redhat.com> Date: Tue, 25 Oct 2016 18:51:19 -0500 Message-Id: <20161025235119.17113.17155@loki> Subject: Re: [Qemu-devel] [PATCH v2 3/4] sockets: add AF_VSOCK support List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Stefan Hajnoczi , qemu-devel@nongnu.org Quoting Stefan Hajnoczi (2016-10-14 04:00:55) > Add the AF_VSOCK address family so that qemu-ga will be able to use > virtio-vsock. > = > The AF_VSOCK address family uses address tuples. The cid is > the unique identifier comparable to an IP address. AF_VSOCK does not > use name resolution so it's easy to convert between struct sockaddr_vm > and strings. > = > This patch defines a VsockSocketAddress instead of trying to piggy-back > on InetSocketAddress. This is cleaner in the long run since it avoids > lots of IPv4 vs IPv6 vs vsock special casing. > = > Signed-off-by: Stefan Hajnoczi > --- > v2: > * s/seasy/easy/ typo fix in commit description [Eric] > * Use %n to check for trailing characters in addresses [Eric] > --- > qapi-schema.json | 23 +++++- > util/qemu-sockets.c | 227 ++++++++++++++++++++++++++++++++++++++++++++++= ++++++ > 2 files changed, 249 insertions(+), 1 deletion(-) > = > diff --git a/qapi-schema.json b/qapi-schema.json > index 9e47b47..12aea99 100644 > --- a/qapi-schema.json > +++ b/qapi-schema.json > @@ -988,12 +988,14 @@ > # > # @unix: unix socket > # > +# @vsock: vsock family (since 2.8) > +# > # @unknown: otherwise > # > # Since: 2.1 > ## > { 'enum': 'NetworkAddressFamily', > - 'data': [ 'ipv4', 'ipv6', 'unix', 'unknown' ] } > + 'data': [ 'ipv4', 'ipv6', 'unix', 'vsock', 'unknown' ] } > = > ## > # @VncBasicInfo > @@ -3018,6 +3020,24 @@ > 'path': 'str' } } > = > ## > +# @VsockSocketAddress > +# > +# Captures a socket address in the vsock namespace. > +# > +# @cid: unique host identifier > +# @port: port > +# > +# Note that string types are used to allow for possible future hostname = or > +# service resolution support. > +# > +# Since 2.8 > +## > +{ 'struct': 'VsockSocketAddress', > + 'data': { > + 'cid': 'str', > + 'port': 'str' } } > + > +## > # @SocketAddress > # > # Captures the address of a socket, which could also be a named file des= criptor > @@ -3028,6 +3048,7 @@ > 'data': { > 'inet': 'InetSocketAddress', > 'unix': 'UnixSocketAddress', > + 'vsock': 'VsockSocketAddress', > 'fd': 'String' } } > = > ## > diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c > index 6db48b3..6ef3cc5 100644 > --- a/util/qemu-sockets.c > +++ b/util/qemu-sockets.c > @@ -17,6 +17,10 @@ > */ > #include "qemu/osdep.h" > = > +#ifdef AF_VSOCK > +#include > +#endif /* AF_VSOCK */ I have this series applied locally but I hit some build issues on Ubuntu 14.04 due to linux/vm_sockets.h not being provided by Ubuntu 14.04's linux-libc-dev package. It is however included with linux-libc-dev in 16.04. linux-headers package includes it in both cases, but installs to /usr/src/linux-headers*, which are not part of the default include path. Do you think we need a configure check and CONFIG_AF_VSOCK flag instead? > + > #include "monitor/monitor.h" > #include "qapi/error.h" > #include "qemu/sockets.h" > @@ -75,6 +79,9 @@ NetworkAddressFamily inet_netfamily(int family) > case PF_INET6: return NETWORK_ADDRESS_FAMILY_IPV6; > case PF_INET: return NETWORK_ADDRESS_FAMILY_IPV4; > case PF_UNIX: return NETWORK_ADDRESS_FAMILY_UNIX; > +#ifdef AF_VSOCK > + case PF_VSOCK: return NETWORK_ADDRESS_FAMILY_VSOCK; > +#endif /* AF_VSOCK */ > } > return NETWORK_ADDRESS_FAMILY_UNKNOWN; > } > @@ -650,6 +657,181 @@ int inet_connect(const char *str, Error **errp) > return sock; > } > = > +#ifdef AF_VSOCK > +static bool vsock_parse_vaddr_to_sockaddr(const VsockSocketAddress *vadd= r, > + struct sockaddr_vm *svm, > + Error **errp) > +{ > + unsigned long long val; > + > + memset(svm, 0, sizeof(*svm)); > + svm->svm_family =3D AF_VSOCK; > + > + if (parse_uint_full(vaddr->cid, &val, 10) < 0 || > + val > UINT32_MAX) { > + error_setg(errp, "Failed to parse cid '%s'", vaddr->cid); > + return false; > + } > + svm->svm_cid =3D val; > + > + if (parse_uint_full(vaddr->port, &val, 10) < 0 || > + val > UINT32_MAX) { > + error_setg(errp, "Failed to parse port '%s'", vaddr->port); > + return false; > + } > + svm->svm_port =3D val; > + > + return true; > +} > + > +static int vsock_connect_addr(const struct sockaddr_vm *svm, bool *in_pr= ogress, > + ConnectState *connect_state, Error **errp) > +{ > + int sock, rc; > + > + *in_progress =3D false; > + > + sock =3D qemu_socket(AF_VSOCK, SOCK_STREAM, 0); > + if (sock < 0) { > + error_setg_errno(errp, errno, "Failed to create socket"); > + return -1; > + } > + if (connect_state !=3D NULL) { > + qemu_set_nonblock(sock); > + } > + /* connect to peer */ > + do { > + rc =3D 0; > + if (connect(sock, (const struct sockaddr *)svm, sizeof(*svm)) < = 0) { > + rc =3D -errno; > + } > + } while (rc =3D=3D -EINTR); > + > + if (connect_state !=3D NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { > + connect_state->fd =3D sock; > + qemu_set_fd_handler(sock, NULL, wait_for_connect, connect_state); > + *in_progress =3D true; > + } else if (rc < 0) { > + error_setg_errno(errp, errno, "Failed to connect socket"); > + closesocket(sock); > + return -1; > + } > + return sock; > +} > + > +static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp, > + NonBlockingConnectHandler *callback, > + void *opaque) > +{ > + struct sockaddr_vm svm; > + int sock =3D -1; > + bool in_progress; > + ConnectState *connect_state =3D NULL; > + > + if (!vsock_parse_vaddr_to_sockaddr(vaddr, &svm, errp)) { > + return -1; > + } > + > + if (callback !=3D NULL) { > + connect_state =3D g_malloc0(sizeof(*connect_state)); > + connect_state->callback =3D callback; > + connect_state->opaque =3D opaque; > + } > + > + sock =3D vsock_connect_addr(&svm, &in_progress, connect_state, errp); > + if (sock < 0) { > + /* do nothing */ > + } else if (in_progress) { > + /* wait_for_connect() will do the rest */ > + return sock; > + } else { > + if (callback) { > + callback(sock, NULL, opaque); > + } > + } > + g_free(connect_state); > + return sock; > +} > + > +static int vsock_listen_saddr(VsockSocketAddress *vaddr, > + Error **errp) > +{ > + struct sockaddr_vm svm; > + int slisten; > + > + if (!vsock_parse_vaddr_to_sockaddr(vaddr, &svm, errp)) { > + return -1; > + } > + > + slisten =3D qemu_socket(AF_VSOCK, SOCK_STREAM, 0); > + if (slisten < 0) { > + error_setg_errno(errp, errno, "Failed to create socket"); > + return -1; > + } > + > + if (bind(slisten, (const struct sockaddr *)&svm, sizeof(svm)) !=3D 0= ) { > + error_setg_errno(errp, errno, "Failed to bind socket"); > + closesocket(slisten); > + return -1; > + } > + > + if (listen(slisten, 1) !=3D 0) { > + error_setg_errno(errp, errno, "Failed to listen on socket"); > + closesocket(slisten); > + return -1; > + } > + return slisten; > +} > + > +static VsockSocketAddress *vsock_parse(const char *str, Error **errp) > +{ > + VsockSocketAddress *addr =3D NULL; > + char cid[33]; > + char port[33]; > + int n; > + > + if (sscanf(str, "%32[^:]:%32[^,]%n", cid, port, &n) !=3D 2) { > + error_setg(errp, "error parsing address '%s'", str); > + return NULL; > + } > + if (str[n] !=3D '\0') { > + error_setg(errp, "trailing characters in address '%s'", str); > + return NULL; > + } > + > + addr =3D g_new0(VsockSocketAddress, 1); > + addr->cid =3D g_strdup(cid); > + addr->port =3D g_strdup(port); > + return addr; > +} > +#else > +static void vsock_unsupported(Error **errp) > +{ > + error_setg(errp, "socket family AF_VSOCK unsupported"); > +} > + > +static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp, > + NonBlockingConnectHandler *callback, > + void *opaque) > +{ > + vsock_unsupported(errp); > + return -1; > +} > + > +static int vsock_listen_saddr(VsockSocketAddress *vaddr, > + Error **errp) > +{ > + vsock_unsupported(errp); > + return -1; > +} > + > +static VsockSocketAddress *vsock_parse(const char *str, Error **errp) > +{ > + vsock_unsupported(errp); > + return NULL; > +} > +#endif /* AF_VSOCK */ > + > #ifndef _WIN32 > = > static int unix_listen_saddr(UnixSocketAddress *saddr, > @@ -864,6 +1046,12 @@ SocketAddress *socket_parse(const char *str, Error = **errp) > addr->u.fd.data =3D g_new(String, 1); > addr->u.fd.data->str =3D g_strdup(str + 3); > } > + } else if (strstart(str, "vsock:", NULL)) { > + addr->type =3D SOCKET_ADDRESS_KIND_VSOCK; > + addr->u.vsock.data =3D vsock_parse(str + strlen("vsock:"), errp); > + if (addr->u.vsock.data =3D=3D NULL) { > + goto fail; > + } > } else { > addr->type =3D SOCKET_ADDRESS_KIND_INET; > addr->u.inet.data =3D inet_parse(str, errp); > @@ -900,6 +1088,10 @@ int socket_connect(SocketAddress *addr, Error **err= p, > } > break; > = > + case SOCKET_ADDRESS_KIND_VSOCK: > + fd =3D vsock_connect_saddr(addr->u.vsock.data, errp, callback, o= paque); > + break; > + > default: > abort(); > } > @@ -923,6 +1115,10 @@ int socket_listen(SocketAddress *addr, Error **errp) > fd =3D monitor_get_fd(cur_mon, addr->u.fd.data->str, errp); > break; > = > + case SOCKET_ADDRESS_KIND_VSOCK: > + fd =3D vsock_listen_saddr(addr->u.vsock.data, errp); > + break; > + > default: > abort(); > } > @@ -1022,6 +1218,26 @@ socket_sockaddr_to_address_unix(struct sockaddr_st= orage *sa, > } > #endif /* WIN32 */ > = > +#ifdef AF_VSOCK > +static SocketAddress * > +socket_sockaddr_to_address_vsock(struct sockaddr_storage *sa, > + socklen_t salen, > + Error **errp) > +{ > + SocketAddress *addr; > + VsockSocketAddress *vaddr; > + struct sockaddr_vm *svm =3D (struct sockaddr_vm *)sa; > + > + addr =3D g_new0(SocketAddress, 1); > + addr->type =3D SOCKET_ADDRESS_KIND_VSOCK; > + addr->u.vsock.data =3D vaddr =3D g_new0(VsockSocketAddress, 1); > + vaddr->cid =3D g_strdup_printf("%u", svm->svm_cid); > + vaddr->port =3D g_strdup_printf("%u", svm->svm_port); > + > + return addr; > +} > +#endif /* AF_VSOCK */ > + > SocketAddress * > socket_sockaddr_to_address(struct sockaddr_storage *sa, > socklen_t salen, > @@ -1037,6 +1253,11 @@ socket_sockaddr_to_address(struct sockaddr_storage= *sa, > return socket_sockaddr_to_address_unix(sa, salen, errp); > #endif /* WIN32 */ > = > +#ifdef AF_VSOCK > + case AF_VSOCK: > + return socket_sockaddr_to_address_vsock(sa, salen, errp); > +#endif > + > default: > error_setg(errp, "socket family %d unsupported", > sa->ss_family); > @@ -1103,6 +1324,12 @@ char *socket_address_to_string(struct SocketAddres= s *addr, Error **errp) > buf =3D g_strdup(addr->u.fd.data->str); > break; > = > + case SOCKET_ADDRESS_KIND_VSOCK: > + buf =3D g_strdup_printf("%s:%s", > + addr->u.vsock.data->cid, > + addr->u.vsock.data->port); > + break; > + > default: > error_setg(errp, "socket family %d unsupported", > addr->type); > -- = > 2.7.4 >=20