]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn-network: split out move_network_interface_one()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 17 Jan 2024 00:48:12 +0000 (09:48 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 19 Jan 2024 10:05:26 +0000 (19:05 +0900)
This also changes to use sd_device to get some attributes.
So, on moving interfaces back to the parent, we need to populate sysfs
associated to the client netns.
That may look redundant and complicated, but it makes later change
easier, and hopefully faster.

src/nspawn/nspawn-network.c

index de21c68a6db7172f698a18657b121577bb3d8d7e..27ae07eba49a3dc6476265f5cf743bb8c48f7a9c 100644 (file)
@@ -4,17 +4,21 @@
 #include <linux/if.h>
 #include <linux/veth.h>
 #include <sys/file.h>
+#include <sys/mount.h>
 
 #include "sd-device.h"
 #include "sd-id128.h"
 #include "sd-netlink.h"
 
 #include "alloc-util.h"
+#include "device-util.h"
 #include "ether-addr-util.h"
 #include "fd-util.h"
 #include "hexdecoct.h"
 #include "lock-util.h"
 #include "missing_network.h"
+#include "mkdir.h"
+#include "mount-util.h"
 #include "namespace-util.h"
 #include "netif-naming-scheme.h"
 #include "netlink-util.h"
@@ -531,6 +535,22 @@ static int netns_child_begin(int netns_fd, int *ret_original_netns_fd) {
         if (r < 0)
                 return log_error_errno(r, "Failed to enter child network namespace: %m");
 
+        r = umount_recursive("/sys/", /* flags = */ 0);
+        if (r < 0)
+                log_debug_errno(r, "Failed to unmount directories below /sys/, ignoring: %m");
+
+        (void) mkdir_p("/sys/", 0755);
+
+        /* Populate new sysfs instance associated with the client netns, to make sd_device usable. */
+        r = mount_nofollow_verbose(LOG_ERR, "sysfs", "/sys/", "sysfs",
+                                   MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, /* opts = */ NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to mount sysfs on /sys/: %m");
+
+        /* udev_avaliable() might be called previously and the result may be cached.
+         * Now, we (re-)mount sysfs. Hence, we need to reset the cache. */
+        reset_cached_udev_availability();
+
         if (ret_original_netns_fd)
                 *ret_original_netns_fd = TAKE_FD(original_netns_fd);
 
@@ -542,7 +562,7 @@ static int netns_fork_and_wait(int netns_fd, int *ret_original_netns_fd) {
 
         assert(netns_fd >= 0);
 
-        r = safe_fork("(sd-netns)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
+        r = safe_fork("(sd-netns)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to fork process (sd-netns): %m");
         if (r == 0) {
@@ -558,42 +578,71 @@ static int netns_fork_and_wait(int netns_fd, int *ret_original_netns_fd) {
         return 1;
 }
 
-int move_network_interfaces(int netns_fd, char **iface_pairs) {
-        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+static int move_network_interface_one(sd_netlink **rtnl, int netns_fd, sd_device *dev, const char *name) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         int r;
 
-        if (strv_isempty(iface_pairs))
-                return 0;
+        assert(rtnl);
+        assert(netns_fd >= 0);
+        assert(dev);
+        assert(name);
 
-        r = sd_netlink_open(&rtnl);
+        if (!*rtnl) {
+                r = sd_netlink_open(rtnl);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to connect to rtnetlink: %m");
+        }
+
+        int ifindex;
+        r = sd_device_get_ifindex(dev, &ifindex);
         if (r < 0)
-                return log_error_errno(r, "Failed to connect to netlink: %m");
+                return log_device_error_errno(dev, r, "Failed to get ifindex: %m");
 
-        STRV_FOREACH_PAIR(i, b, iface_pairs) {
-                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
-                int ifi;
+        r = sd_rtnl_message_new_link(*rtnl, &m, RTM_SETLINK, ifindex);
+        if (r < 0)
+                return log_device_error_errno(dev, r, "Failed to allocate netlink message: %m");
 
-                ifi = rtnl_resolve_interface_or_warn(&rtnl, *i);
-                if (ifi < 0)
-                        return ifi;
+        r = sd_netlink_message_append_u32(m, IFLA_NET_NS_FD, netns_fd);
+        if (r < 0)
+                return log_device_error_errno(dev, r, "Failed to append namespace fd to netlink message: %m");
 
-                r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, ifi);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to allocate netlink message: %m");
+        const char *sysname;
+        r = sd_device_get_sysname(dev, &sysname);
+        if (r < 0)
+                return log_device_error_errno(dev, r, "Failed to get sysname: %m");
 
-                r = sd_netlink_message_append_u32(m, IFLA_NET_NS_FD, netns_fd);
+        if (!streq(name, sysname)) {
+                r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to append namespace fd to netlink message: %m");
+                        return log_device_error_errno(dev, r, "Failed to add netlink interface name: %m");
+        }
+
+        r = sd_netlink_call(*rtnl, m, 0, NULL);
+        if (r < 0)
+                return log_device_error_errno(dev, r, "Failed to move interface to namespace: %m");
 
-                if (!streq(*b, *i)) {
-                        r = sd_netlink_message_append_string(m, IFLA_IFNAME, *b);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to add netlink interface name: %m");
-                }
+        return 0;
+}
 
-                r = sd_netlink_call(rtnl, m, 0, NULL);
+int move_network_interfaces(int netns_fd, char **iface_pairs) {
+        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+        int r;
+
+        assert(netns_fd >= 0);
+
+        if (strv_isempty(iface_pairs))
+                return 0;
+
+        STRV_FOREACH_PAIR(from, to, iface_pairs) {
+                _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+
+                r = sd_device_new_from_ifname(&dev, *from);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i);
+                        return log_error_errno(r, "Unknown interface name %s: %m", *from);
+
+                r = move_network_interface_one(&rtnl, netns_fd, dev, *to);
+                if (r < 0)
+                        return r;
         }
 
         return 0;