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.
This commit is contained in:
Stefan Hajnoczi 2016-12-21 17:02:08 +00:00
parent 0fc0f14bfd
commit 359a5bcf78
3 changed files with 28 additions and 3 deletions

View file

@ -216,6 +216,14 @@
<varname>BindIPv6Only=</varname> setting (see below). <varname>BindIPv6Only=</varname> setting (see below).
</para> </para>
<para>If the address string is a string in the format
<literal>vsock:x:y</literal>, it is read as CID <literal>x</literal> on
a port <literal>y</literal> address in the
<constant>AF_VSOCK</constant> family. The CID is a unique 32-bit
integer identifier in <constant>AF_VSOCK</constant> analogous to an IP
address. Specifying the CID is optional, and may be set to the empty
string.</para>
<para>Note that <constant>SOCK_SEQPACKET</constant> (i.e. <para>Note that <constant>SOCK_SEQPACKET</constant> (i.e.
<varname>ListenSequentialPacket=</varname>) is only available <varname>ListenSequentialPacket=</varname>) is only available
for <constant>AF_UNIX</constant> sockets. for <constant>AF_UNIX</constant> sockets.

View file

@ -1292,7 +1292,7 @@ static int service_spawn(
return r; 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; _cleanup_free_ char *addr = NULL;
char *t; char *t;
unsigned port; unsigned port;

View file

@ -485,12 +485,13 @@ static void peer_address_hash_func(const void *p, struct siphash *state) {
const SocketPeer *s = p; const SocketPeer *s = p;
assert(s); assert(s);
assert(IN_SET(s->peer.sa.sa_family, AF_INET, AF_INET6));
if (s->peer.sa.sa_family == AF_INET) if (s->peer.sa.sa_family == AF_INET)
siphash24_compress(&s->peer.in.sin_addr, sizeof(s->peer.in.sin_addr), state); siphash24_compress(&s->peer.in.sin_addr, sizeof(s->peer.in.sin_addr), state);
else if (s->peer.sa.sa_family == AF_INET6) else if (s->peer.sa.sa_family == AF_INET6)
siphash24_compress(&s->peer.in6.sin6_addr, sizeof(s->peer.in6.sin6_addr), state); 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 else
assert_not_reached("Unknown address family."); 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)); return memcmp(&x->peer.in.sin_addr, &y->peer.in.sin_addr, sizeof(x->peer.in.sin_addr));
case AF_INET6: case AF_INET6:
return memcmp(&x->peer.in6.sin6_addr, &y->peer.in6.sin6_addr, sizeof(x->peer.in6.sin6_addr)); 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!"); 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) if (r < 0)
return log_error_errno(errno, "getpeername failed: %m"); 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; *p = NULL;
return 0; return 0;
} }
@ -941,6 +948,16 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) {
break; 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: default:
assert_not_reached("Unhandled socket type."); assert_not_reached("Unhandled socket type.");
} }