diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-01-17 02:36:28 +0100 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-01-19 11:06:12 +0100 |
commit | 1c3e5b42103c5edba7162a1bac9f8541d338ea4f (patch) | |
tree | 3c45e1fb2dce6d8ec7e963ae67be2bc90c3de1ba /src | |
parent | nspawn-network: also check alternative names (diff) | |
download | systemd-1c3e5b42103c5edba7162a1bac9f8541d338ea4f.tar.xz systemd-1c3e5b42103c5edba7162a1bac9f8541d338ea4f.zip |
nspawn-network: support passing wireless interface to container
Closes #7873.
Diffstat (limited to 'src')
-rw-r--r-- | src/nspawn/nspawn-network.c | 120 |
1 files changed, 118 insertions, 2 deletions
diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index a05a2bc9e0..151bb1d69a 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -2,6 +2,7 @@ #include <net/if.h> #include <linux/if.h> +#include <linux/nl80211.h> #include <linux/veth.h> #include <sys/file.h> #include <sys/mount.h> @@ -11,6 +12,7 @@ #include "sd-netlink.h" #include "alloc-util.h" +#include "device-private.h" #include "device-util.h" #include "ether-addr-util.h" #include "fd-util.h" @@ -609,6 +611,116 @@ static int needs_rename(sd_netlink **rtnl, sd_device *dev, const char *name) { return !strv_contains(altnames, name); } +static int move_wlan_interface_impl(sd_netlink **genl, int netns_fd, sd_device *dev) { + _cleanup_(sd_netlink_unrefp) sd_netlink *our_genl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + assert(netns_fd >= 0); + assert(dev); + + if (!genl) + genl = &our_genl; + if (!*genl) { + r = sd_genl_socket_open(genl); + if (r < 0) + return log_error_errno(r, "Failed to connect to generic netlink: %m"); + } + + r = sd_genl_message_new(*genl, NL80211_GENL_NAME, NL80211_CMD_SET_WIPHY_NETNS, &m); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to allocate netlink message: %m"); + + uint32_t phy_index; + r = device_get_sysattr_u32(dev, "phy80211/index", &phy_index); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to get phy index: %m"); + + r = sd_netlink_message_append_u32(m, NL80211_ATTR_WIPHY, phy_index); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to append phy index to netlink message: %m"); + + r = sd_netlink_message_append_u32(m, NL80211_ATTR_NETNS_FD, netns_fd); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to append namespace fd to netlink message: %m"); + + r = sd_netlink_call(*genl, m, 0, NULL); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to move interface to namespace: %m"); + + return 0; +} + +static int move_wlan_interface_one( + sd_netlink **rtnl, + sd_netlink **genl, + int *temp_netns_fd, + int netns_fd, + sd_device *dev, + const char *name) { + + int r; + + assert(rtnl); + assert(genl); + assert(temp_netns_fd); + assert(netns_fd >= 0); + assert(dev); + assert(name); + + r = needs_rename(rtnl, dev, name); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to determine if the interface should be renamed to '%s': %m", name); + if (r == 0) + return move_wlan_interface_impl(genl, netns_fd, dev); + + /* The command NL80211_CMD_SET_WIPHY_NETNS takes phy instead of network interface, and does not take + * an interface name in the passed network namespace. Hence, we need to move the phy and interface to + * a temporary network namespace, rename the interface in it, and move them to the requested netns. */ + + if (*temp_netns_fd < 0) { + r = netns_acquire(); + if (r < 0) + return log_error_errno(r, "Failed to acquire new network namespace: %m"); + *temp_netns_fd = r; + } + + r = move_wlan_interface_impl(genl, *temp_netns_fd, dev); + if (r < 0) + return r; + + const char *sysname; + r = sd_device_get_sysname(dev, &sysname); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to get interface name: %m"); + + r = netns_fork_and_wait(*temp_netns_fd, NULL); + if (r < 0) + return log_error_errno(r, "Failed to fork process (nspawn-rename-wlan): %m"); + if (r == 0) { + _cleanup_(sd_device_unrefp) sd_device *temp_dev = NULL; + + r = rtnl_rename_link(NULL, sysname, name); + if (r < 0) { + log_error_errno(r, "Failed to rename network interface '%s' to '%s': %m", sysname, name); + goto finalize; + } + + r = sd_device_new_from_ifname(&temp_dev, name); + if (r < 0) { + log_error_errno(r, "Failed to acquire device '%s': %m", name); + goto finalize; + } + + r = move_wlan_interface_impl(NULL, netns_fd, temp_dev); + + finalize: + _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); + } + + return 0; +} + 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; @@ -654,7 +766,8 @@ static int move_network_interface_one(sd_netlink **rtnl, int netns_fd, sd_device } int move_network_interfaces(int netns_fd, char **iface_pairs) { - _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL, *genl = NULL; + _cleanup_close_ int temp_netns_fd = -EBADF; int r; assert(netns_fd >= 0); @@ -669,7 +782,10 @@ int move_network_interfaces(int netns_fd, char **iface_pairs) { if (r < 0) return log_error_errno(r, "Unknown interface name %s: %m", *from); - r = move_network_interface_one(&rtnl, netns_fd, dev, *to); + if (device_is_devtype(dev, "wlan")) + r = move_wlan_interface_one(&rtnl, &genl, &temp_netns_fd, netns_fd, dev, *to); + else + r = move_network_interface_one(&rtnl, netns_fd, dev, *to); if (r < 0) return r; } |