summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2016-12-20 14:24:27 +0000
committerSven Eden <yamakuzure@gmx.net>2017-07-17 17:58:35 +0200
commit15ef4c05396195e9ee63c7afb49106eb5933fc83 (patch)
tree7ef4d394f7c82cbfa19c35b4f97388f30ca0be09
parent9151b5886c833a533ccad0f05bfe76af33ab67a8 (diff)
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.
-rw-r--r--src/basic/socket-util.c76
-rw-r--r--src/basic/socket-util.h1
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