mirror of
https://github.com/systemd/systemd.git
synced 2025-03-13 00:58:27 +03:00
Merge pull request #14401 from DaanDeMeyer/nspawn-move-veth-back-to-host
nspawn: move virtual interfaces added with --network-interface back to the host
This commit is contained in:
commit
12da859a3f
@ -442,40 +442,50 @@ int remove_bridge(const char *bridge_name) {
|
||||
}
|
||||
|
||||
static int parse_interface(const char *name) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
|
||||
int ifi, r;
|
||||
|
||||
r = parse_ifindex_or_ifname(name, &ifi);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to resolve interface %s: %m", name);
|
||||
|
||||
if (path_is_read_only_fs("/sys") <= 0) {
|
||||
char ifi_str[2 + DECIMAL_STR_MAX(int)];
|
||||
|
||||
/* udev should be around. */
|
||||
|
||||
sprintf(ifi_str, "n%i", ifi);
|
||||
r = sd_device_new_from_device_id(&d, ifi_str);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get device %s: %m", name);
|
||||
|
||||
r = sd_device_get_is_initialized(d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine whether interface %s is initialized: %m", name);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Network interface %s is not initialized yet.", name);
|
||||
|
||||
r = device_is_renaming(d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine the interface %s is being renamed: %m", name);
|
||||
if (r > 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Interface %s is being renamed.", name);
|
||||
}
|
||||
|
||||
return ifi;
|
||||
}
|
||||
|
||||
int move_network_interfaces(pid_t pid, char **ifaces) {
|
||||
int test_network_interface_initialized(const char *name) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
|
||||
int ifi, r;
|
||||
char ifi_str[2 + DECIMAL_STR_MAX(int)];
|
||||
|
||||
if (path_is_read_only_fs("/sys"))
|
||||
return 0;
|
||||
|
||||
/* udev should be around. */
|
||||
|
||||
ifi = parse_interface(name);
|
||||
if (ifi < 0)
|
||||
return ifi;
|
||||
|
||||
sprintf(ifi_str, "n%i", ifi);
|
||||
r = sd_device_new_from_device_id(&d, ifi_str);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get device %s: %m", name);
|
||||
|
||||
r = sd_device_get_is_initialized(d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine whether interface %s is initialized: %m", name);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Network interface %s is not initialized yet.", name);
|
||||
|
||||
r = device_is_renaming(d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine the interface %s is being renamed: %m", name);
|
||||
if (r > 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Interface %s is being renamed.", name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int move_network_interfaces(int netns_fd, char **ifaces) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
char **i;
|
||||
int r;
|
||||
@ -499,9 +509,9 @@ int move_network_interfaces(pid_t pid, char **ifaces) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate netlink message: %m");
|
||||
|
||||
r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
|
||||
r = sd_netlink_message_append_u32(m, IFLA_NET_NS_FD, netns_fd);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to append namespace PID to netlink message: %m");
|
||||
return log_error_errno(r, "Failed to append namespace fd to netlink message: %m");
|
||||
|
||||
r = sd_netlink_call(rtnl, m, 0, NULL);
|
||||
if (r < 0)
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int test_network_interface_initialized(const char *name);
|
||||
|
||||
int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge);
|
||||
int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs);
|
||||
|
||||
@ -14,7 +16,7 @@ int remove_bridge(const char *bridge_name);
|
||||
int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces);
|
||||
int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces);
|
||||
|
||||
int move_network_interfaces(pid_t pid, char **ifaces);
|
||||
int move_network_interfaces(int netns_fd, char **ifaces);
|
||||
|
||||
int veth_extra_parse(char ***l, const char *p);
|
||||
|
||||
|
@ -848,6 +848,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Network interface name not valid: %s", optarg);
|
||||
|
||||
r = test_network_interface_initialized(optarg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (strv_extend(&arg_network_interfaces, optarg) < 0)
|
||||
return log_oom();
|
||||
|
||||
@ -861,6 +865,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"MACVLAN network interface name not valid: %s", optarg);
|
||||
|
||||
r = test_network_interface_initialized(optarg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (strv_extend(&arg_network_macvlan, optarg) < 0)
|
||||
return log_oom();
|
||||
|
||||
@ -874,6 +882,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"IPVLAN network interface name not valid: %s", optarg);
|
||||
|
||||
r = test_network_interface_initialized(optarg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (strv_extend(&arg_network_ipvlan, optarg) < 0)
|
||||
return log_oom();
|
||||
|
||||
@ -4199,7 +4211,7 @@ static int run_container(
|
||||
int ifi = 0, r;
|
||||
ssize_t l;
|
||||
sigset_t mask_chld;
|
||||
_cleanup_close_ int netns_fd = -1;
|
||||
_cleanup_close_ int child_netns_fd = -1;
|
||||
|
||||
assert_se(sigemptyset(&mask_chld) == 0);
|
||||
assert_se(sigaddset(&mask_chld, SIGCHLD) == 0);
|
||||
@ -4258,11 +4270,11 @@ static int run_container(
|
||||
return log_error_errno(errno, "Failed to install SIGCHLD handler: %m");
|
||||
|
||||
if (arg_network_namespace_path) {
|
||||
netns_fd = open(arg_network_namespace_path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (netns_fd < 0)
|
||||
child_netns_fd = open(arg_network_namespace_path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (child_netns_fd < 0)
|
||||
return log_error_errno(errno, "Cannot open file %s: %m", arg_network_namespace_path);
|
||||
|
||||
r = fd_is_network_ns(netns_fd);
|
||||
r = fd_is_network_ns(child_netns_fd);
|
||||
if (r == -EUCLEAN)
|
||||
log_debug_errno(r, "Cannot determine if passed network namespace path '%s' really refers to a network namespace, assuming it does.", arg_network_namespace_path);
|
||||
else if (r < 0)
|
||||
@ -4307,7 +4319,7 @@ static int run_container(
|
||||
master_pty_socket_pair[1],
|
||||
unified_cgroup_hierarchy_socket_pair[1],
|
||||
fds,
|
||||
netns_fd);
|
||||
child_netns_fd);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
@ -4409,7 +4421,15 @@ static int run_container(
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Child died too early");
|
||||
}
|
||||
|
||||
r = move_network_interfaces(*pid, arg_network_interfaces);
|
||||
if (child_netns_fd < 0) {
|
||||
/* Make sure we have an open file descriptor to the child's network
|
||||
* namespace so it stays alive even if the child exits. */
|
||||
r = namespace_open(*pid, NULL, NULL, &child_netns_fd, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open child network namespace: %m");
|
||||
}
|
||||
|
||||
r = move_network_interfaces(child_netns_fd, arg_network_interfaces);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -4655,6 +4675,36 @@ static int run_container(
|
||||
/* Normally redundant, but better safe than sorry */
|
||||
(void) kill(*pid, SIGKILL);
|
||||
|
||||
if (arg_private_network) {
|
||||
/* Move network interfaces back to the parent network namespace. We use `safe_fork`
|
||||
* to avoid having to move the parent to the child network namespace. */
|
||||
r = safe_fork(NULL, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_WAIT|FORK_LOG, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r == 0) {
|
||||
_cleanup_close_ int parent_netns_fd = -1;
|
||||
|
||||
r = namespace_open(getpid(), NULL, NULL, &parent_netns_fd, NULL, NULL);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to open parent network namespace: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = namespace_enter(-1, -1, child_netns_fd, -1, -1);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to enter child network namespace: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = move_network_interfaces(parent_netns_fd, arg_network_interfaces);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to move network interfaces back to parent network namespace: %m");
|
||||
|
||||
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
r = wait_for_container(*pid, &container_status);
|
||||
*pid = 0;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user