From 15ef4c05396195e9ee63c7afb49106eb5933fc83 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 20 Dec 2016 14:24:27 +0000 Subject: [PATCH] socket-util: add AF_VSOCK address family The AF_VSOCK address family facilitates guest<->host communication on VMware and KVM (virtio-vsock). Adding support to elogind allows guest agents to be launched through .socket unit files. Today guest agents are stand-alone daemons running inside guests that do not take advantage of elogind socket activation. --- src/basic/socket-util.c | 76 ++++++++++++++++++++++++++++++++++++++--- src/basic/socket-util.h | 1 + 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 151586479..6a8ca1d7e 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -112,6 +112,30 @@ int socket_address_parse(SocketAddress *a, const char *s) { memcpy(a->sockaddr.un.sun_path+1, s+1, l); a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l; + } else if (startswith(s, "vsock:")) { + /* AF_VSOCK socket in vsock:cid:port notation */ + const char *cid_start = s + strlen("vsock:"); + + e = strchr(cid_start, ':'); + if (!e) + return -EINVAL; + + r = safe_atou(e+1, &u); + if (r < 0) + return r; + + n = strndupa(cid_start, e - cid_start); + if (!isempty(n)) { + r = safe_atou(n, &a->sockaddr.vm.svm_cid); + if (r < 0) + return r; + } else + a->sockaddr.vm.svm_cid = VMADDR_CID_ANY; + + a->sockaddr.vm.svm_family = AF_VSOCK; + a->sockaddr.vm.svm_port = u; + a->size = sizeof(struct sockaddr_vm); + } else { e = strchr(s, ':'); if (e) { @@ -288,6 +312,15 @@ int socket_address_verify(const SocketAddress *a) { return 0; + case AF_VSOCK: + if (a->size != sizeof(struct sockaddr_vm)) + return -EINVAL; + + if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM) + return -EINVAL; + + return 0; + default: return -EAFNOSUPPORT; } @@ -393,6 +426,15 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { break; + case AF_VSOCK: + if (a->sockaddr.vm.svm_cid != b->sockaddr.vm.svm_cid) + return false; + + if (a->sockaddr.vm.svm_port != b->sockaddr.vm.svm_port) + return false; + + break; + default: /* Cannot compare, so we assume the addresses are different */ return false; @@ -486,11 +528,22 @@ int sockaddr_port(const struct sockaddr *_sa, unsigned *port) { assert(sa); - if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6)) - return -EAFNOSUPPORT; + switch (sa->sa.sa_family) { + case AF_INET: + *port = be16toh(sa->in.sin_port); + return 0; - *port = be16toh(sa->sa.sa_family == AF_INET6 ? sa->in6.sin6_port : sa->in.sin_port); - return 0; + case AF_INET6: + *port = be16toh(sa->in6.sin6_port); + return 0; + + case AF_VSOCK: + *port = sa->vm.svm_port; + return 0; + + default: + return -EAFNOSUPPORT; + } } int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) { @@ -593,6 +646,18 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ break; + case AF_VSOCK: + if (include_port) + r = asprintf(&p, + "vsock:%u:%u", + sa->vm.svm_cid, + sa->vm.svm_port); + else + r = asprintf(&p, "vsock:%u", sa->vm.svm_cid); + if (r < 0) + return -ENOMEM; + break; + default: return -EOPNOTSUPP; } @@ -750,6 +815,9 @@ bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b if (a->sa.sa_family == AF_INET6) return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr)) == 0; + if (a->sa.sa_family == AF_VSOCK) + return a->vm.svm_cid == b->vm.svm_cid; + return false; } #endif // 0 diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index b17c14189..ce55baa9b 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -40,6 +40,7 @@ union sockaddr_union { struct sockaddr_nl nl; struct sockaddr_storage storage; struct sockaddr_ll ll; + struct sockaddr_vm vm; }; #if 0 /// UNNEEDED by elogind -- 2.30.2