From 716bf93c4bde07c1870b9b0837f2ec33f36686f1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Mar 2025 11:36:05 +0100 Subject: [PATCH] nsresource: add client-side wrapper for creating tap links --- src/nspawn/nspawn.c | 2 +- src/shared/nsresource.c | 73 +++++++++++++++++++++++++++++++++++++++-- src/shared/nsresource.h | 3 +- 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index e3c5d6b7327..87cae525ca8 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -5459,7 +5459,7 @@ static int run_container( } else { _cleanup_free_ char *host_ifname = NULL; - r = nsresource_add_netif(userns_fd, child_netns_fd, /* namespace_ifname= */ NULL, &host_ifname, /* ret_namespace_ifname= */ NULL); + r = nsresource_add_netif_veth(userns_fd, child_netns_fd, /* namespace_ifname= */ NULL, &host_ifname, /* ret_namespace_ifname= */ NULL); if (r < 0) return log_error_errno(r, "Failed to add network interface to container: %m"); diff --git a/src/shared/nsresource.c b/src/shared/nsresource.c index 5c6792507e9..2652d2a6245 100644 --- a/src/shared/nsresource.c +++ b/src/shared/nsresource.c @@ -257,6 +257,7 @@ int nsresource_add_cgroup(int userns_fd, int cgroup_fd) { typedef struct InterfaceParams { char *host_interface_name; char *namespace_interface_name; + unsigned interface_fd_index; } InterfaceParams; static void interface_params_done(InterfaceParams *p) { @@ -266,7 +267,7 @@ static void interface_params_done(InterfaceParams *p) { free(p->namespace_interface_name); } -int nsresource_add_netif( +int nsresource_add_netif_veth( int userns_fd, int netns_fd, const char *namespace_ifname, @@ -330,8 +331,8 @@ int nsresource_add_netif( return log_debug_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to add network to user namespace: %s", error_id); static const sd_json_dispatch_field dispatch_table[] = { - { "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, host_interface_name), 0 }, - { "namespaceInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, namespace_interface_name), 0 }, + { "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, host_interface_name), SD_JSON_MANDATORY }, + { "namespaceInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, namespace_interface_name), SD_JSON_MANDATORY }, }; _cleanup_(interface_params_done) InterfaceParams p = {}; @@ -346,3 +347,69 @@ int nsresource_add_netif( return 1; } + +int nsresource_add_netif_tap( + int userns_fd, + char **ret_host_ifname) { + + _cleanup_close_ int _userns_fd = -EBADF; + _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL; + int r, userns_fd_idx; + const char *error_id; + + if (userns_fd < 0) { + _userns_fd = namespace_open_by_type(NAMESPACE_USER); + if (_userns_fd < 0) + return _userns_fd; + + userns_fd = _userns_fd; + } + + r = sd_varlink_connect_address(&vl, "/run/systemd/io.systemd.NamespaceResource"); + if (r < 0) + return log_debug_errno(r, "Failed to connect to namespace resource manager: %m"); + + r = sd_varlink_set_allow_fd_passing_output(vl, true); + if (r < 0) + return log_debug_errno(r, "Failed to enable varlink fd passing for write: %m"); + + r = sd_varlink_set_allow_fd_passing_input(vl, true); + if (r < 0) + return log_debug_errno(r, "Failed to enable varlink fd passing for read: %m"); + + userns_fd_idx = sd_varlink_push_dup_fd(vl, userns_fd); + if (userns_fd_idx < 0) + return log_debug_errno(userns_fd_idx, "Failed to push userns fd into varlink connection: %m"); + + sd_json_variant *reply = NULL; + r = sd_varlink_callbo( + vl, + "io.systemd.NamespaceResource.AddNetworkToUserNamespace", + &reply, + &error_id, + SD_JSON_BUILD_PAIR("userNamespaceFileDescriptor", SD_JSON_BUILD_UNSIGNED(userns_fd_idx)), + SD_JSON_BUILD_PAIR("mode", JSON_BUILD_CONST_STRING("tap"))); + if (r < 0) + return log_debug_errno(r, "Failed to call AddNetworkToUserNamespace() varlink call: %m"); + if (error_id) + return log_debug_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to add network to user namespace: %s", error_id); + + static const sd_json_dispatch_field dispatch_table[] = { + { "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, host_interface_name), SD_JSON_MANDATORY }, + { "interfaceFileDescriptor", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, offsetof(InterfaceParams, namespace_interface_name), SD_JSON_MANDATORY }, + }; + + _cleanup_(interface_params_done) InterfaceParams p = {}; + r = sd_json_dispatch(reply, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p); + if (r < 0) + return r; + + _cleanup_close_ int tap_fd = sd_varlink_take_fd(vl, p.interface_fd_index); + if (tap_fd < 0) + return tap_fd; + + if (ret_host_ifname) + *ret_host_ifname = TAKE_PTR(p.host_interface_name); + + return TAKE_FD(tap_fd); +} diff --git a/src/shared/nsresource.h b/src/shared/nsresource.h index 6b807b327bf..48274fd1a53 100644 --- a/src/shared/nsresource.h +++ b/src/shared/nsresource.h @@ -7,4 +7,5 @@ int nsresource_allocate_userns(const char *name, uint64_t size); int nsresource_register_userns(const char *name, int userns_fd); int nsresource_add_mount(int userns_fd, int mount_fd); int nsresource_add_cgroup(int userns_fd, int cgroup_fd); -int nsresource_add_netif(int userns_fd, int netns_fd, const char *namespace_ifname, char **ret_host_ifname, char **ret_namespace_ifname); +int nsresource_add_netif_veth(int userns_fd, int netns_fd, const char *namespace_ifname, char **ret_host_ifname, char **ret_namespace_ifname); +int nsresource_add_netif_tap(int userns_fd, char **ret_host_ifname); -- 2.47.3