Quoting Michael Roth (2016-10-25 18:51:19) > 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 <cid, port> 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 <stefa...@redhat.com> > > --- > > 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 > > descriptor > > @@ -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 <linux/vm_sockets.h> > > +#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?
I've applied this series with the above-mentioned configure check squashed into this patch. Here's the diff: diff --git a/configure b/configure index d3dafcb..60f1060 100755 --- a/configure +++ b/configure @@ -4605,6 +4605,33 @@ if compile_prog "" "" ; then have_rtnetlink=yes fi +########################################## +# check for usable AF_VSOCK environment +have_af_vsock=no +cat > $TMPC << EOF +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#if !defined(AF_VSOCK) +# error missing AF_VSOCK flag +#endif +#include <linux/vm_sockets.h> +int main(void) { + int sock, ret; + struct sockaddr_vm svm; + socklen_t len = sizeof(svm); + sock = socket(AF_VSOCK, SOCK_STREAM, 0); + ret = getpeername(sock, (struct sockaddr *)&svm, &len); + if ((ret == -1) && (errno == ENOTCONN)) { + return 0; + } + return -1; +} +EOF +if compile_prog "" "" ; then + have_af_vsock=yes +fi + ################################################# # Sparc implicitly links with --relax, which is # incompatible with -r, so --no-relax should be @@ -5580,6 +5607,10 @@ if test "$replication" = "yes" ; then echo "CONFIG_REPLICATION=y" >> $config_host_mak fi +if test "$have_af_vsock" = "yes" ; then + echo "CONFIG_AF_VSOCK=y" >> $config_host_mak +fi + # Hold two types of flag: # CONFIG_THREAD_SETNAME_BYTHREAD - we've got a way of setting the name on # a thread we have a handle to diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 559f452..e616f48 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -17,9 +17,9 @@ */ #include "qemu/osdep.h" -#ifdef AF_VSOCK +#ifdef CONFIG_AF_VSOCK #include <linux/vm_sockets.h> -#endif /* AF_VSOCK */ +#endif /* CONFIG_AF_VSOCK */ #include "monitor/monitor.h" #include "qapi/error.h" @@ -79,9 +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 +#ifdef CONFIG_AF_VSOCK case PF_VSOCK: return NETWORK_ADDRESS_FAMILY_VSOCK; -#endif /* AF_VSOCK */ +#endif /* CONFIG_AF_VSOCK */ } return NETWORK_ADDRESS_FAMILY_UNKNOWN; } @@ -657,7 +657,7 @@ int inet_connect(const char *str, Error **errp) return sock; } -#ifdef AF_VSOCK +#ifdef CONFIG_AF_VSOCK static bool vsock_parse_vaddr_to_sockaddr(const VsockSocketAddress *vaddr, struct sockaddr_vm *svm, Error **errp) @@ -830,7 +830,7 @@ static VsockSocketAddress *vsock_parse(const char *str, Error **errp) vsock_unsupported(errp); return NULL; } -#endif /* AF_VSOCK */ +#endif /* CONFIG_AF_VSOCK */ #ifndef _WIN32 @@ -1218,7 +1218,7 @@ socket_sockaddr_to_address_unix(struct sockaddr_storage *sa, } #endif /* WIN32 */ -#ifdef AF_VSOCK +#ifdef CONFIG_AF_VSOCK static SocketAddress * socket_sockaddr_to_address_vsock(struct sockaddr_storage *sa, socklen_t salen, @@ -1236,7 +1236,7 @@ socket_sockaddr_to_address_vsock(struct sockaddr_storage *sa, return addr; } -#endif /* AF_VSOCK */ +#endif /* CONFIG_AF_VSOCK */ SocketAddress * socket_sockaddr_to_address(struct sockaddr_storage *sa, @@ -1253,7 +1253,7 @@ socket_sockaddr_to_address(struct sockaddr_storage *sa, return socket_sockaddr_to_address_unix(sa, salen, errp); #endif /* WIN32 */ -#ifdef AF_VSOCK +#ifdef CONFIG_AF_VSOCK case AF_VSOCK: return socket_sockaddr_to_address_vsock(sa, salen, errp); #endif > > > + > > #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 *vaddr, > > + struct sockaddr_vm *svm, > > + Error **errp) > > +{ > > + unsigned long long val; > > + > > + memset(svm, 0, sizeof(*svm)); > > + svm->svm_family = 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 = 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 = val; > > + > > + return true; > > +} > > + > > +static int vsock_connect_addr(const struct sockaddr_vm *svm, bool > > *in_progress, > > + ConnectState *connect_state, Error **errp) > > +{ > > + int sock, rc; > > + > > + *in_progress = false; > > + > > + sock = qemu_socket(AF_VSOCK, SOCK_STREAM, 0); > > + if (sock < 0) { > > + error_setg_errno(errp, errno, "Failed to create socket"); > > + return -1; > > + } > > + if (connect_state != NULL) { > > + qemu_set_nonblock(sock); > > + } > > + /* connect to peer */ > > + do { > > + rc = 0; > > + if (connect(sock, (const struct sockaddr *)svm, sizeof(*svm)) < 0) > > { > > + rc = -errno; > > + } > > + } while (rc == -EINTR); > > + > > + if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { > > + connect_state->fd = sock; > > + qemu_set_fd_handler(sock, NULL, wait_for_connect, connect_state); > > + *in_progress = 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 = -1; > > + bool in_progress; > > + ConnectState *connect_state = NULL; > > + > > + if (!vsock_parse_vaddr_to_sockaddr(vaddr, &svm, errp)) { > > + return -1; > > + } > > + > > + if (callback != NULL) { > > + connect_state = g_malloc0(sizeof(*connect_state)); > > + connect_state->callback = callback; > > + connect_state->opaque = opaque; > > + } > > + > > + sock = 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 = 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)) != 0) { > > + error_setg_errno(errp, errno, "Failed to bind socket"); > > + closesocket(slisten); > > + return -1; > > + } > > + > > + if (listen(slisten, 1) != 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 = NULL; > > + char cid[33]; > > + char port[33]; > > + int n; > > + > > + if (sscanf(str, "%32[^:]:%32[^,]%n", cid, port, &n) != 2) { > > + error_setg(errp, "error parsing address '%s'", str); > > + return NULL; > > + } > > + if (str[n] != '\0') { > > + error_setg(errp, "trailing characters in address '%s'", str); > > + return NULL; > > + } > > + > > + addr = g_new0(VsockSocketAddress, 1); > > + addr->cid = g_strdup(cid); > > + addr->port = 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 = g_new(String, 1); > > addr->u.fd.data->str = g_strdup(str + 3); > > } > > + } else if (strstart(str, "vsock:", NULL)) { > > + addr->type = SOCKET_ADDRESS_KIND_VSOCK; > > + addr->u.vsock.data = vsock_parse(str + strlen("vsock:"), errp); > > + if (addr->u.vsock.data == NULL) { > > + goto fail; > > + } > > } else { > > addr->type = SOCKET_ADDRESS_KIND_INET; > > addr->u.inet.data = inet_parse(str, errp); > > @@ -900,6 +1088,10 @@ int socket_connect(SocketAddress *addr, Error **errp, > > } > > break; > > > > + case SOCKET_ADDRESS_KIND_VSOCK: > > + fd = vsock_connect_saddr(addr->u.vsock.data, errp, callback, > > opaque); > > + break; > > + > > default: > > abort(); > > } > > @@ -923,6 +1115,10 @@ int socket_listen(SocketAddress *addr, Error **errp) > > fd = monitor_get_fd(cur_mon, addr->u.fd.data->str, errp); > > break; > > > > + case SOCKET_ADDRESS_KIND_VSOCK: > > + fd = vsock_listen_saddr(addr->u.vsock.data, errp); > > + break; > > + > > default: > > abort(); > > } > > @@ -1022,6 +1218,26 @@ socket_sockaddr_to_address_unix(struct > > sockaddr_storage *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 = (struct sockaddr_vm *)sa; > > + > > + addr = g_new0(SocketAddress, 1); > > + addr->type = SOCKET_ADDRESS_KIND_VSOCK; > > + addr->u.vsock.data = vaddr = g_new0(VsockSocketAddress, 1); > > + vaddr->cid = g_strdup_printf("%u", svm->svm_cid); > > + vaddr->port = 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 SocketAddress > > *addr, Error **errp) > > buf = g_strdup(addr->u.fd.data->str); > > break; > > > > + case SOCKET_ADDRESS_KIND_VSOCK: > > + buf = 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 > > > >