From 882ac6e769c5c8d1742e49028043ba2ce691b045 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 20 Dec 2016 14:10:54 +0000 Subject: socket-util: introduce port argument in sockaddr_port() sockaddr_port() either returns a >= 0 port number or a negative errno. This works for AF_INET and AF_INET6 because port ranges are only 16-bit. In AF_VSOCK ports are 32-bit so an int cannot represent all port number and negative errnos. Separate the port and the return code. --- src/core/service.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/service.c') diff --git a/src/core/service.c b/src/core/service.c index 73a8104d17..dc7b685cd3 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1295,7 +1295,7 @@ static int service_spawn( if (r == 0 && IN_SET(sa.sa.sa_family, AF_INET, AF_INET6)) { _cleanup_free_ char *addr = NULL; char *t; - int port; + unsigned port; r = sockaddr_pretty(&sa.sa, salen, true, false, &addr); if (r < 0) @@ -1306,9 +1306,9 @@ static int service_spawn( return -ENOMEM; our_env[n_env++] = t; - port = sockaddr_port(&sa.sa); - if (port < 0) - return port; + r = sockaddr_port(&sa.sa, &port); + if (r < 0) + return r; if (asprintf(&t, "REMOTE_PORT=%u", port) < 0) return -ENOMEM; -- cgit v1.2.3-54-g00ecf From 359a5bcf78a89626ca9119668c0362f3b7bfe9c3 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Dec 2016 17:02:08 +0000 Subject: core: add AF_VSOCK support to socket units Accept AF_VSOCK listen addresses in socket unit files. Both guest and host can now take advantage of socket activation. The QEMU guest agent has recently been modified to support socket activation and can run over AF_VSOCK with this patch. --- man/systemd.socket.xml | 8 ++++++++ src/core/service.c | 2 +- src/core/socket.c | 21 +++++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) (limited to 'src/core/service.c') diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 0ce1203cfb..1d20a8f7f7 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -216,6 +216,14 @@ BindIPv6Only= setting (see below). + If the address string is a string in the format + vsock:x:y, it is read as CID x on + a port y address in the + AF_VSOCK family. The CID is a unique 32-bit + integer identifier in AF_VSOCK analogous to an IP + address. Specifying the CID is optional, and may be set to the empty + string. + Note that SOCK_SEQPACKET (i.e. ListenSequentialPacket=) is only available for AF_UNIX sockets. diff --git a/src/core/service.c b/src/core/service.c index dc7b685cd3..54074ff7bc 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1292,7 +1292,7 @@ static int service_spawn( return r; } - if (r == 0 && IN_SET(sa.sa.sa_family, AF_INET, AF_INET6)) { + if (r == 0 && IN_SET(sa.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK)) { _cleanup_free_ char *addr = NULL; char *t; unsigned port; diff --git a/src/core/socket.c b/src/core/socket.c index 521688bed5..c4ce88c5f4 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -485,12 +485,13 @@ static void peer_address_hash_func(const void *p, struct siphash *state) { const SocketPeer *s = p; assert(s); - assert(IN_SET(s->peer.sa.sa_family, AF_INET, AF_INET6)); if (s->peer.sa.sa_family == AF_INET) siphash24_compress(&s->peer.in.sin_addr, sizeof(s->peer.in.sin_addr), state); else if (s->peer.sa.sa_family == AF_INET6) siphash24_compress(&s->peer.in6.sin6_addr, sizeof(s->peer.in6.sin6_addr), state); + else if (s->peer.sa.sa_family == AF_VSOCK) + siphash24_compress(&s->peer.vm.svm_cid, sizeof(s->peer.vm.svm_cid), state); else assert_not_reached("Unknown address family."); } @@ -508,6 +509,12 @@ static int peer_address_compare_func(const void *a, const void *b) { return memcmp(&x->peer.in.sin_addr, &y->peer.in.sin_addr, sizeof(x->peer.in.sin_addr)); case AF_INET6: return memcmp(&x->peer.in6.sin6_addr, &y->peer.in6.sin6_addr, sizeof(x->peer.in6.sin6_addr)); + case AF_VSOCK: + if (x->peer.vm.svm_cid < y->peer.vm.svm_cid) + return -1; + if (x->peer.vm.svm_cid > y->peer.vm.svm_cid) + return 1; + return 0; } assert_not_reached("Black sheep in the family!"); } @@ -594,7 +601,7 @@ int socket_acquire_peer(Socket *s, int fd, SocketPeer **p) { if (r < 0) return log_error_errno(errno, "getpeername failed: %m"); - if (!IN_SET(sa.peer.sa.sa_family, AF_INET, AF_INET6)) { + if (!IN_SET(sa.peer.sa.sa_family, AF_INET, AF_INET6, AF_VSOCK)) { *p = NULL; return 0; } @@ -941,6 +948,16 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) { break; } + case AF_VSOCK: + if (asprintf(&r, + "%u-%u:%u-%u:%u", + nr, + local.vm.svm_cid, local.vm.svm_port, + remote.vm.svm_cid, remote.vm.svm_port) < 0) + return -ENOMEM; + + break; + default: assert_not_reached("Unhandled socket type."); } -- cgit v1.2.3-54-g00ecf