[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2 3/4] sockets: add AF_VSOCK support
From: |
Michael Roth |
Subject: |
Re: [Qemu-devel] [PATCH v2 3/4] sockets: add AF_VSOCK support |
Date: |
Tue, 25 Oct 2016 18:51:19 -0500 |
User-agent: |
alot/0.3.6 |
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 <address@hidden>
> ---
> 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?
> +
> #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
>
[Qemu-devel] [PATCH v2 2/4] qga: drop unnecessary GA_CHANNEL_UNIX_LISTEN checks, Stefan Hajnoczi, 2016/10/14
[Qemu-devel] [PATCH v2 4/4] qga: add vsock-listen method, Stefan Hajnoczi, 2016/10/14