]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: remove macvlan interfaces before network namespace died
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 30 Jul 2024 05:35:33 +0000 (14:35 +0900)
committerLuca Boccassi <luca.boccassi@gmail.com>
Tue, 30 Jul 2024 10:38:50 +0000 (12:38 +0200)
This is similar to what we do for veth interfaces in remove_veth_links().

When a container rebooted, macvlan interfaces created by the previous
boot may still exist in the kernel, and that causes -EADDRINUSE after
reboot.

Hopefully fixes #680.

src/nspawn/nspawn-network.c
src/nspawn/nspawn-network.h
src/nspawn/nspawn.c

index ec5d39690e484b9df0e49c999bbbe2fba0658852..f46995bb646c8f8f14cdfb7564be09d05c7726a6 100644 (file)
@@ -821,6 +821,56 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **iface_pairs) {
         return 0;
 }
 
+static int remove_macvlan_impl(char **interface_pairs) {
+        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+        int r;
+
+        assert(interface_pairs);
+
+        r = sd_netlink_open(&rtnl);
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to netlink: %m");
+
+        STRV_FOREACH_PAIR(a, b, interface_pairs) {
+                _cleanup_free_ char *n = NULL;
+
+                n = strdup(*b);
+                if (!n)
+                        return log_oom();
+
+                (void) net_shorten_ifname(n, /* check_naming_scheme= */ true);
+
+                r = remove_one_link(rtnl, n);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to remove macvlan interface %s, ignoring: %m", n);
+        }
+
+        return 0;
+}
+
+int remove_macvlan(int child_netns_fd, char **interface_pairs) {
+        _cleanup_close_ int parent_netns_fd = -EBADF;
+        int r;
+
+        /* In some cases the kernel might pin the macvlan links on the container even after the namespace
+         * died. Hence, let's better remove them explicitly too. See issue #680. */
+
+        assert(child_netns_fd >= 0);
+
+        if (strv_isempty(interface_pairs))
+                return 0;
+
+        r = netns_fork_and_wait(child_netns_fd, &parent_netns_fd);
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                r = remove_macvlan_impl(interface_pairs);
+                _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+        }
+
+        return 0;
+}
+
 int setup_ipvlan(const char *machine_name, pid_t pid, char **iface_pairs) {
         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
         int r;
index 840fe155270da9550a9a6c2a745ca50aced72471..ed08c983472f495faf94b28ae8e4b7b81f926b1d 100644 (file)
@@ -17,6 +17,7 @@ int setup_bridge(const char *veth_name, const char *bridge_name, bool create);
 int remove_bridge(const char *bridge_name);
 
 int setup_macvlan(const char *machine_name, pid_t pid, char **iface_pairs);
+int remove_macvlan(int child_netns_fd, char **interface_pairs);
 int setup_ipvlan(const char *machine_name, pid_t pid, char **iface_pairs);
 
 int move_network_interfaces(int netns_fd, char **iface_pairs);
index 5c7b1568584ef9ef662e13356f18b1ff67da08f2..843636bf4871f769d26ac186a113f37fddf4dbfc 100644 (file)
@@ -5598,6 +5598,10 @@ static int run_container(
                 r = move_back_network_interfaces(child_netns_fd, arg_network_interfaces);
                 if (r < 0)
                         return r;
+
+                r = remove_macvlan(child_netns_fd, arg_network_macvlan);
+                if (r < 0)
+                        return r;
         }
 
         r = wait_for_container(TAKE_PID(*pid), &container_status);