diff mbox

[v2,3/4] sockets: add AF_VSOCK support

Message ID 20161101005814.24053.89188@loki
State New
Headers show

Commit Message

Michael Roth Nov. 1, 2016, 12:58 a.m. UTC
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 <stefanha@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:


> 
> > +
> >  #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
> > 
> 
>
diff mbox

Patch

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