mirror of
https://github.com/systemd/systemd.git
synced 2024-11-01 09:21:26 +03:00
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 systemd 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 systemd socket activation.
This commit is contained in:
parent
882ac6e769
commit
0fc0f14bfd
@ -113,6 +113,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) {
|
||||
@ -289,6 +313,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;
|
||||
}
|
||||
@ -394,6 +427,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;
|
||||
@ -485,11 +527,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) {
|
||||
@ -592,6 +645,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;
|
||||
}
|
||||
@ -749,6 +814,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;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "missing.h"
|
||||
#include "util.h"
|
||||
|
||||
union sockaddr_union {
|
||||
@ -40,6 +41,7 @@ union sockaddr_union {
|
||||
struct sockaddr_nl nl;
|
||||
struct sockaddr_storage storage;
|
||||
struct sockaddr_ll ll;
|
||||
struct sockaddr_vm vm;
|
||||
};
|
||||
|
||||
typedef struct SocketAddress {
|
||||
|
@ -92,6 +92,14 @@ static void test_socket_address_parse(void) {
|
||||
|
||||
assert_se(socket_address_parse(&a, "@abstract") >= 0);
|
||||
assert_se(a.sockaddr.sa.sa_family == AF_UNIX);
|
||||
|
||||
assert_se(socket_address_parse(&a, "vsock::1234") >= 0);
|
||||
assert_se(a.sockaddr.sa.sa_family == AF_VSOCK);
|
||||
assert_se(socket_address_parse(&a, "vsock:2:1234") >= 0);
|
||||
assert_se(a.sockaddr.sa.sa_family == AF_VSOCK);
|
||||
assert_se(socket_address_parse(&a, "vsock:2:1234x") < 0);
|
||||
assert_se(socket_address_parse(&a, "vsock:2x:1234") < 0);
|
||||
assert_se(socket_address_parse(&a, "vsock:2") < 0);
|
||||
}
|
||||
|
||||
static void test_socket_address_parse_netlink(void) {
|
||||
@ -145,6 +153,14 @@ static void test_socket_address_equal(void) {
|
||||
assert_se(socket_address_parse_netlink(&a, "firewall") >= 0);
|
||||
assert_se(socket_address_parse_netlink(&b, "firewall") >= 0);
|
||||
assert_se(socket_address_equal(&a, &b));
|
||||
|
||||
assert_se(socket_address_parse(&a, "vsock:2:1234") >= 0);
|
||||
assert_se(socket_address_parse(&b, "vsock:2:1234") >= 0);
|
||||
assert_se(socket_address_equal(&a, &b));
|
||||
assert_se(socket_address_parse(&b, "vsock:2:1235") >= 0);
|
||||
assert_se(!socket_address_equal(&a, &b));
|
||||
assert_se(socket_address_parse(&b, "vsock:3:1234") >= 0);
|
||||
assert_se(!socket_address_equal(&a, &b));
|
||||
}
|
||||
|
||||
static void test_socket_address_get_path(void) {
|
||||
@ -161,6 +177,9 @@ static void test_socket_address_get_path(void) {
|
||||
|
||||
assert_se(socket_address_parse(&a, "/foo/bar") >= 0);
|
||||
assert_se(streq(socket_address_get_path(&a), "/foo/bar"));
|
||||
|
||||
assert_se(socket_address_parse(&a, "vsock:2:1234") >= 0);
|
||||
assert_se(!socket_address_get_path(&a));
|
||||
}
|
||||
|
||||
static void test_socket_address_is(void) {
|
||||
@ -408,11 +427,18 @@ static void test_sockaddr_equal(void) {
|
||||
.in6.sin6_port = 0,
|
||||
.in6.sin6_addr = IN6ADDR_ANY_INIT,
|
||||
};
|
||||
union sockaddr_union e = {
|
||||
.vm.svm_family = AF_VSOCK,
|
||||
.vm.svm_port = 0,
|
||||
.vm.svm_cid = VMADDR_CID_ANY,
|
||||
};
|
||||
assert_se(sockaddr_equal(&a, &a));
|
||||
assert_se(sockaddr_equal(&a, &b));
|
||||
assert_se(sockaddr_equal(&d, &d));
|
||||
assert_se(sockaddr_equal(&e, &e));
|
||||
assert_se(!sockaddr_equal(&a, &c));
|
||||
assert_se(!sockaddr_equal(&b, &c));
|
||||
assert_se(!sockaddr_equal(&a, &e));
|
||||
}
|
||||
|
||||
static void test_sockaddr_un_len(void) {
|
||||
|
Loading…
Reference in New Issue
Block a user