Skip to content

Commit 12da859

Browse files
authored
Merge pull request systemd#14401 from DaanDeMeyer/nspawn-move-veth-back-to-host
nspawn: move virtual interfaces added with --network-interface back to the host
2 parents 2ceefe4 + 5b4855a commit 12da859

File tree

3 files changed

+92
-30
lines changed

3 files changed

+92
-30
lines changed

src/nspawn/nspawn-network.c

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -442,40 +442,50 @@ int remove_bridge(const char *bridge_name) {
442442
}
443443

444444
static int parse_interface(const char *name) {
445-
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
446445
int ifi, r;
447446

448447
r = parse_ifindex_or_ifname(name, &ifi);
449448
if (r < 0)
450449
return log_error_errno(r, "Failed to resolve interface %s: %m", name);
451450

452-
if (path_is_read_only_fs("/sys") <= 0) {
453-
char ifi_str[2 + DECIMAL_STR_MAX(int)];
451+
return ifi;
452+
}
454453

455-
/* udev should be around. */
454+
int test_network_interface_initialized(const char *name) {
455+
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
456+
int ifi, r;
457+
char ifi_str[2 + DECIMAL_STR_MAX(int)];
456458

457-
sprintf(ifi_str, "n%i", ifi);
458-
r = sd_device_new_from_device_id(&d, ifi_str);
459-
if (r < 0)
460-
return log_error_errno(r, "Failed to get device %s: %m", name);
459+
if (path_is_read_only_fs("/sys"))
460+
return 0;
461461

462-
r = sd_device_get_is_initialized(d);
463-
if (r < 0)
464-
return log_error_errno(r, "Failed to determine whether interface %s is initialized: %m", name);
465-
if (r == 0)
466-
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Network interface %s is not initialized yet.", name);
462+
/* udev should be around. */
467463

468-
r = device_is_renaming(d);
469-
if (r < 0)
470-
return log_error_errno(r, "Failed to determine the interface %s is being renamed: %m", name);
471-
if (r > 0)
472-
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Interface %s is being renamed.", name);
473-
}
464+
ifi = parse_interface(name);
465+
if (ifi < 0)
466+
return ifi;
474467

475-
return ifi;
468+
sprintf(ifi_str, "n%i", ifi);
469+
r = sd_device_new_from_device_id(&d, ifi_str);
470+
if (r < 0)
471+
return log_error_errno(r, "Failed to get device %s: %m", name);
472+
473+
r = sd_device_get_is_initialized(d);
474+
if (r < 0)
475+
return log_error_errno(r, "Failed to determine whether interface %s is initialized: %m", name);
476+
if (r == 0)
477+
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Network interface %s is not initialized yet.", name);
478+
479+
r = device_is_renaming(d);
480+
if (r < 0)
481+
return log_error_errno(r, "Failed to determine the interface %s is being renamed: %m", name);
482+
if (r > 0)
483+
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Interface %s is being renamed.", name);
484+
485+
return 0;
476486
}
477487

478-
int move_network_interfaces(pid_t pid, char **ifaces) {
488+
int move_network_interfaces(int netns_fd, char **ifaces) {
479489
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
480490
char **i;
481491
int r;
@@ -499,9 +509,9 @@ int move_network_interfaces(pid_t pid, char **ifaces) {
499509
if (r < 0)
500510
return log_error_errno(r, "Failed to allocate netlink message: %m");
501511

502-
r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
512+
r = sd_netlink_message_append_u32(m, IFLA_NET_NS_FD, netns_fd);
503513
if (r < 0)
504-
return log_error_errno(r, "Failed to append namespace PID to netlink message: %m");
514+
return log_error_errno(r, "Failed to append namespace fd to netlink message: %m");
505515

506516
r = sd_netlink_call(rtnl, m, 0, NULL);
507517
if (r < 0)

src/nspawn/nspawn-network.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <stdbool.h>
66
#include <sys/types.h>
77

8+
int test_network_interface_initialized(const char *name);
9+
810
int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge);
911
int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs);
1012

@@ -14,7 +16,7 @@ int remove_bridge(const char *bridge_name);
1416
int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces);
1517
int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces);
1618

17-
int move_network_interfaces(pid_t pid, char **ifaces);
19+
int move_network_interfaces(int netns_fd, char **ifaces);
1820

1921
int veth_extra_parse(char ***l, const char *p);
2022

src/nspawn/nspawn.c

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,10 @@ static int parse_argv(int argc, char *argv[]) {
848848
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
849849
"Network interface name not valid: %s", optarg);
850850

851+
r = test_network_interface_initialized(optarg);
852+
if (r < 0)
853+
return r;
854+
851855
if (strv_extend(&arg_network_interfaces, optarg) < 0)
852856
return log_oom();
853857

@@ -861,6 +865,10 @@ static int parse_argv(int argc, char *argv[]) {
861865
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
862866
"MACVLAN network interface name not valid: %s", optarg);
863867

868+
r = test_network_interface_initialized(optarg);
869+
if (r < 0)
870+
return r;
871+
864872
if (strv_extend(&arg_network_macvlan, optarg) < 0)
865873
return log_oom();
866874

@@ -874,6 +882,10 @@ static int parse_argv(int argc, char *argv[]) {
874882
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
875883
"IPVLAN network interface name not valid: %s", optarg);
876884

885+
r = test_network_interface_initialized(optarg);
886+
if (r < 0)
887+
return r;
888+
877889
if (strv_extend(&arg_network_ipvlan, optarg) < 0)
878890
return log_oom();
879891

@@ -4199,7 +4211,7 @@ static int run_container(
41994211
int ifi = 0, r;
42004212
ssize_t l;
42014213
sigset_t mask_chld;
4202-
_cleanup_close_ int netns_fd = -1;
4214+
_cleanup_close_ int child_netns_fd = -1;
42034215

42044216
assert_se(sigemptyset(&mask_chld) == 0);
42054217
assert_se(sigaddset(&mask_chld, SIGCHLD) == 0);
@@ -4258,11 +4270,11 @@ static int run_container(
42584270
return log_error_errno(errno, "Failed to install SIGCHLD handler: %m");
42594271

42604272
if (arg_network_namespace_path) {
4261-
netns_fd = open(arg_network_namespace_path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
4262-
if (netns_fd < 0)
4273+
child_netns_fd = open(arg_network_namespace_path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
4274+
if (child_netns_fd < 0)
42634275
return log_error_errno(errno, "Cannot open file %s: %m", arg_network_namespace_path);
42644276

4265-
r = fd_is_network_ns(netns_fd);
4277+
r = fd_is_network_ns(child_netns_fd);
42664278
if (r == -EUCLEAN)
42674279
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);
42684280
else if (r < 0)
@@ -4307,7 +4319,7 @@ static int run_container(
43074319
master_pty_socket_pair[1],
43084320
unified_cgroup_hierarchy_socket_pair[1],
43094321
fds,
4310-
netns_fd);
4322+
child_netns_fd);
43114323
if (r < 0)
43124324
_exit(EXIT_FAILURE);
43134325

@@ -4409,7 +4421,15 @@ static int run_container(
44094421
return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Child died too early");
44104422
}
44114423

4412-
r = move_network_interfaces(*pid, arg_network_interfaces);
4424+
if (child_netns_fd < 0) {
4425+
/* Make sure we have an open file descriptor to the child's network
4426+
* namespace so it stays alive even if the child exits. */
4427+
r = namespace_open(*pid, NULL, NULL, &child_netns_fd, NULL, NULL);
4428+
if (r < 0)
4429+
return log_error_errno(r, "Failed to open child network namespace: %m");
4430+
}
4431+
4432+
r = move_network_interfaces(child_netns_fd, arg_network_interfaces);
44134433
if (r < 0)
44144434
return r;
44154435

@@ -4655,6 +4675,36 @@ static int run_container(
46554675
/* Normally redundant, but better safe than sorry */
46564676
(void) kill(*pid, SIGKILL);
46574677

4678+
if (arg_private_network) {
4679+
/* Move network interfaces back to the parent network namespace. We use `safe_fork`
4680+
* to avoid having to move the parent to the child network namespace. */
4681+
r = safe_fork(NULL, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_WAIT|FORK_LOG, NULL);
4682+
if (r < 0)
4683+
return r;
4684+
4685+
if (r == 0) {
4686+
_cleanup_close_ int parent_netns_fd = -1;
4687+
4688+
r = namespace_open(getpid(), NULL, NULL, &parent_netns_fd, NULL, NULL);
4689+
if (r < 0) {
4690+
log_error_errno(r, "Failed to open parent network namespace: %m");
4691+
_exit(EXIT_FAILURE);
4692+
}
4693+
4694+
r = namespace_enter(-1, -1, child_netns_fd, -1, -1);
4695+
if (r < 0) {
4696+
log_error_errno(r, "Failed to enter child network namespace: %m");
4697+
_exit(EXIT_FAILURE);
4698+
}
4699+
4700+
r = move_network_interfaces(parent_netns_fd, arg_network_interfaces);
4701+
if (r < 0)
4702+
log_error_errno(r, "Failed to move network interfaces back to parent network namespace: %m");
4703+
4704+
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
4705+
}
4706+
}
4707+
46584708
r = wait_for_container(*pid, &container_status);
46594709
*pid = 0;
46604710

0 commit comments

Comments
 (0)