mirror of
https://github.com/systemd/systemd.git
synced 2025-01-12 13:18:14 +03:00
socket: support socket activation of containers
This commit is contained in:
parent
842f3b0fc9
commit
01e10de3c2
@ -934,14 +934,18 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
int fd;
|
||||
FILE *f;
|
||||
|
||||
if ((r = safe_atoi(optarg, &fd)) < 0 || fd < 0) {
|
||||
r = safe_atoi(optarg, &fd);
|
||||
if (r < 0 || fd < 0) {
|
||||
log_error("Failed to parse deserialize option %s.", optarg);
|
||||
return r;
|
||||
return r < 0 ? r : -EINVAL;
|
||||
}
|
||||
|
||||
if (!(f = fdopen(fd, "r"))) {
|
||||
fd_cloexec(fd, true);
|
||||
|
||||
f = fdopen(fd, "r");
|
||||
if (!f) {
|
||||
log_error("Failed to open serialization fd: %m");
|
||||
return r;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (serialization)
|
||||
@ -1474,16 +1478,15 @@ int main(int argc, char *argv[]) {
|
||||
log_close();
|
||||
|
||||
/* Remember open file descriptors for later deserialization */
|
||||
if (serialization) {
|
||||
r = fdset_new_fill(&fds);
|
||||
if (r < 0) {
|
||||
log_error("Failed to allocate fd set: %s", strerror(-r));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
assert_se(fdset_remove(fds, fileno(serialization)) >= 0);
|
||||
r = fdset_new_fill(&fds);
|
||||
if (r < 0) {
|
||||
log_error("Failed to allocate fd set: %s", strerror(-r));
|
||||
goto finish;
|
||||
} else
|
||||
close_all_fds(NULL, 0);
|
||||
fdset_cloexec(fds, true);
|
||||
|
||||
if (serialization)
|
||||
assert_se(fdset_remove(fds, fileno(serialization)) >= 0);
|
||||
|
||||
/* Set up PATH unless it is already set */
|
||||
setenv("PATH",
|
||||
@ -1518,6 +1521,12 @@ int main(int argc, char *argv[]) {
|
||||
unsetenv("USER");
|
||||
unsetenv("LOGNAME");
|
||||
|
||||
/* We suppress the socket activation env vars, as
|
||||
* we'll try to match *any* open fd to units if
|
||||
* possible. */
|
||||
unsetenv("LISTEN_FDS");
|
||||
unsetenv("LISTEN_PID");
|
||||
|
||||
/* All other variables are left as is, so that clients
|
||||
* can still read them via /proc/1/environ */
|
||||
}
|
||||
@ -1653,10 +1662,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
/* This will close all file descriptors that were opened, but
|
||||
* not claimed by any unit. */
|
||||
if (fds) {
|
||||
fdset_free(fds);
|
||||
fds = NULL;
|
||||
}
|
||||
fdset_free(fds);
|
||||
|
||||
if (serialization) {
|
||||
fclose(serialization);
|
||||
|
@ -706,6 +706,16 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
|
||||
r = q;
|
||||
}
|
||||
|
||||
/* Any fds left? Find some unit which wants them. This is
|
||||
* useful to allow container managers to pass some file
|
||||
* descriptors to us pre-initialized. This enables
|
||||
* socket-based activation of entire containers. */
|
||||
if (fdset_size(fds) > 0) {
|
||||
q = manager_distribute_fds(m, fds);
|
||||
if (q < 0)
|
||||
r = q;
|
||||
}
|
||||
|
||||
/* Third, fire things up! */
|
||||
q = manager_coldplug(m);
|
||||
if (q < 0)
|
||||
@ -1807,7 +1817,8 @@ int manager_open_serialization(Manager *m, FILE **_f) {
|
||||
log_debug("Serializing state to %s", path);
|
||||
free(path);
|
||||
|
||||
if (!(f = fdopen(fd, "w+")))
|
||||
f = fdopen(fd, "w+");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
*_f = f;
|
||||
@ -1965,7 +1976,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
||||
if ((r = manager_load_unit(m, strstrip(name), NULL, NULL, &u)) < 0)
|
||||
goto finish;
|
||||
|
||||
if ((r = unit_deserialize(u, f, fds)) < 0)
|
||||
r = unit_deserialize(u, f, fds);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
@ -1981,6 +1993,28 @@ finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
int manager_distribute_fds(Manager *m, FDSet *fds) {
|
||||
Unit *u;
|
||||
Iterator i;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
HASHMAP_FOREACH(u, m->units, i) {
|
||||
|
||||
if (fdset_size(fds) <= 0)
|
||||
break;
|
||||
|
||||
if (UNIT_VTABLE(u)->distribute_fds) {
|
||||
r = UNIT_VTABLE(u)->distribute_fds(u, fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_reload(Manager *m) {
|
||||
int r, q;
|
||||
FILE *f;
|
||||
|
@ -272,6 +272,7 @@ int manager_open_serialization(Manager *m, FILE **_f);
|
||||
|
||||
int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool serialize_jobs);
|
||||
int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
|
||||
int manager_distribute_fds(Manager *m, FDSet *fds);
|
||||
|
||||
int manager_reload(Manager *m);
|
||||
|
||||
|
@ -1876,6 +1876,34 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int socket_distribute_fds(Unit *u, FDSet *fds) {
|
||||
Socket *s = SOCKET(u);
|
||||
SocketPort *p;
|
||||
|
||||
assert(u);
|
||||
|
||||
LIST_FOREACH(port, p, s->ports) {
|
||||
Iterator i;
|
||||
int fd;
|
||||
|
||||
if (p->type != SOCKET_SOCKET)
|
||||
continue;
|
||||
|
||||
if (p->fd >= 0)
|
||||
continue;
|
||||
|
||||
FDSET_FOREACH(fd, fds, i) {
|
||||
if (socket_address_matches_fd(&p->address, fd)) {
|
||||
p->fd = fdset_remove(fds, fd);
|
||||
s->deserialized_state = SOCKET_LISTENING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UnitActiveState socket_active_state(Unit *u) {
|
||||
assert(u);
|
||||
|
||||
@ -2288,6 +2316,7 @@ const UnitVTable socket_vtable = {
|
||||
|
||||
.serialize = socket_serialize,
|
||||
.deserialize_item = socket_deserialize_item,
|
||||
.distribute_fds = socket_distribute_fds,
|
||||
|
||||
.active_state = socket_active_state,
|
||||
.sub_state_to_string = socket_sub_state_to_string,
|
||||
|
@ -310,6 +310,9 @@ struct UnitVTable {
|
||||
/* Restore one item from the serialization */
|
||||
int (*deserialize_item)(Unit *u, const char *key, const char *data, FDSet *fds);
|
||||
|
||||
/* Try to match up fds with what we need for this unit */
|
||||
int (*distribute_fds)(Unit *u, FDSet *fds);
|
||||
|
||||
/* Boils down the more complex internal state of this unit to
|
||||
* a simpler one that the engine can understand */
|
||||
UnitActiveState (*active_state)(Unit *u);
|
||||
|
@ -515,6 +515,55 @@ bool socket_ipv6_is_supported(void) {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
bool socket_address_matches_fd(const SocketAddress *a, int fd) {
|
||||
union sockaddr_union sa;
|
||||
socklen_t salen = sizeof(sa), solen;
|
||||
int protocol, type;
|
||||
|
||||
assert(a);
|
||||
assert(fd >= 0);
|
||||
|
||||
if (getsockname(fd, &sa.sa, &salen) < 0)
|
||||
return false;
|
||||
|
||||
if (sa.sa.sa_family != a->sockaddr.sa.sa_family)
|
||||
return false;
|
||||
|
||||
solen = sizeof(type);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &solen) < 0)
|
||||
return false;
|
||||
|
||||
if (type != a->type)
|
||||
return false;
|
||||
|
||||
if (a->protocol != 0) {
|
||||
solen = sizeof(protocol);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &solen) < 0)
|
||||
return false;
|
||||
|
||||
if (protocol != a->protocol)
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (sa.sa.sa_family) {
|
||||
|
||||
case AF_INET:
|
||||
return sa.in4.sin_port == a->sockaddr.in4.sin_port &&
|
||||
sa.in4.sin_addr.s_addr == a->sockaddr.in4.sin_addr.s_addr;
|
||||
|
||||
case AF_INET6:
|
||||
return sa.in6.sin6_port == a->sockaddr.in6.sin6_port &&
|
||||
memcmp(&sa.in6.sin6_addr, &a->sockaddr.in6.sin6_addr, sizeof(struct in6_addr)) == 0;
|
||||
|
||||
case AF_UNIX:
|
||||
return salen == a->size &&
|
||||
memcmp(sa.un.sun_path, a->sockaddr.un.sun_path, salen - offsetof(struct sockaddr_un, sun_path)) == 0;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* const netlink_family_table[] = {
|
||||
[NETLINK_ROUTE] = "route",
|
||||
[NETLINK_FIREWALL] = "firewall",
|
||||
|
@ -86,6 +86,8 @@ int socket_address_listen(
|
||||
bool socket_address_is(const SocketAddress *a, const char *s, int type);
|
||||
bool socket_address_is_netlink(const SocketAddress *a, const char *s);
|
||||
|
||||
bool socket_address_matches_fd(const SocketAddress *a, int fd);
|
||||
|
||||
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b);
|
||||
|
||||
bool socket_address_needs_mount(const SocketAddress *a, const char *prefix);
|
||||
|
Loading…
Reference in New Issue
Block a user