]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #31022 from aafeijoo-suse/bash-completion-cryptenroll-2
authorLuca Boccassi <bluca@debian.org>
Fri, 19 Jan 2024 18:00:10 +0000 (18:00 +0000)
committerGitHub <noreply@github.com>
Fri, 19 Jan 2024 18:00:10 +0000 (18:00 +0000)
fix typo and add some missing options to bash-completion

42 files changed:
catalog/systemd.catalog.in
man/org.freedesktop.portable1.xml
src/basic/namespace-util.c
src/basic/namespace-util.h
src/basic/process-util.c
src/basic/process-util.h
src/basic/terminal-util.c
src/boot/efi/devicetree.c
src/journal/journalctl.c
src/libsystemd/sd-bus/bus-container.c
src/libsystemd/sd-device/device-private.h
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-netlink/netlink-types-genl.c
src/libsystemd/sd-netlink/netlink-util.c
src/libsystemd/sd-netlink/netlink-util.h
src/libsystemd/sd-netlink/test-netlink.c
src/login/logind-dbus.c
src/login/logind-user.c
src/login/pam_systemd.c
src/machine/machine-dbus.c
src/network/networkd-dhcp-prefix-delegation.c
src/network/networkd-dhcp4.c
src/network/networkd-ndisc.c
src/network/networkd-queue.c
src/network/networkd-route-nexthop.c
src/network/networkd-route-nexthop.h
src/network/networkd-route.c
src/network/networkd-route.h
src/nspawn/nspawn-mount.c
src/nspawn/nspawn-network.c
src/nspawn/nspawn-network.h
src/nspawn/nspawn.c
src/portable/portable.c
src/shared/logs-show.c
src/shared/machine-id-setup.c
src/shared/mount-util.c
src/shared/socket-netlink.c
src/shared/udev-util.c
src/shared/udev-util.h
src/systemd/sd-messages.h
test/TEST-13-NSPAWN/test.sh
test/units/testsuite-13.nspawn.sh

index 8591a654aa5b6ebac7aa1181437355cff3a2dde3..04e90e0b75fdbddd26b78f069dd4efb7f9024d80 100644 (file)
@@ -748,3 +748,23 @@ Compatibility support for System V services in systemd is deprecated. Please
 make sure to update the package in question to provide proper, native systemd
 unit files. Contact vendor if necessary. Compatibility support for System V
 services is deprecated and will be removed soon.
+
+-- 187c62eb1e7f463bb530394f52cb090f
+Subject: A Portable Service has been attached
+Defined-By: systemd
+Support: %SUPPORT_URL%
+Documentation: https://systemd.io/PORTABLE_SERVICES/
+
+A new Portable Service @PORTABLE_ROOT@ (with extensions: @PORTABLE_EXTENSION@) has
+been attached to the system and is now available for use. The list of attached
+Portable Services can be queried with 'portablectl list'.
+
+-- 76c5c754d628490d8ecba4c9d042112b
+Subject: A Portable Service has been detached
+Defined-By: systemd
+Support: %SUPPORT_URL%
+Documentation: https://systemd.io/PORTABLE_SERVICES/
+
+A Portable Service @PORTABLE_ROOT@ (with extensions: @PORTABLE_EXTENSION@) has been
+detached from the system and is no longer available for use. The list of attached
+Portable Services can be queried with 'portablectl list'.
index e0070d33b6e4faf09e0e7326ee89d2f8fd6be669..a41da4f5c3cd20a7da3f5c6da1b0e0776f2b11de 100644 (file)
@@ -310,11 +310,11 @@ node /org/freedesktop/portable1 {
       <para>The <function>AttachImageWithExtensions()</function>,
       <function>DetachImageWithExtensions()</function> and
       <function>ReattachImageWithExtensions()</function> methods take in options as flags instead of
-      booleans to allow for extendability. <varname>SD_SYSTEMD_PORTABLE_FORCE_ATTACH</varname> will cause
-      safety checks that ensure the units are not running while the new image is attached or detached
-      to be skipped. <varname>SD_SYSTEMD_PORTABLE_FORCE_EXTENSION</varname> will cause the check that the
+      booleans to allow for extendability. <varname>SD_SYSTEMD_PORTABLE_FORCE_ATTACH</varname> will bypass
+      the safety checks that ensure the units are not running while the image is attached or detached.
+      <varname>SD_SYSTEMD_PORTABLE_FORCE_EXTENSION</varname> will bypass the check that ensures the
       <filename>extension-release.<replaceable>NAME</replaceable></filename> file in the extension image
-      matches the image name to be skipped. They are defined as follows:</para>
+      matches the image name. They are defined as follows:</para>
 
       <programlisting>
 #define SD_SYSTEMD_PORTABLE_RUNTIME            (UINT64_C(1) &lt;&lt; 0)
index 2101f617ad2026c273cb816ea4f19bebf7749632..d517263b36b147bdc245ef707967bb513b2ca851 100644 (file)
@@ -33,71 +33,78 @@ const struct namespace_info namespace_info[] = {
 
 #define pid_namespace_path(pid, type) procfs_file_alloca(pid, namespace_info[type].proc_path)
 
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
-        _cleanup_close_ int pidnsfd = -EBADF, mntnsfd = -EBADF, netnsfd = -EBADF, usernsfd = -EBADF;
-        int rfd = -EBADF;
+int namespace_open(
+                pid_t pid,
+                int *ret_pidns_fd,
+                int *ret_mntns_fd,
+                int *ret_netns_fd,
+                int *ret_userns_fd,
+                int *ret_root_fd) {
+
+        _cleanup_close_ int pidns_fd = -EBADF, mntns_fd = -EBADF, netns_fd = -EBADF,
+                userns_fd = -EBADF, root_fd = -EBADF;
 
         assert(pid >= 0);
 
-        if (mntns_fd) {
-                const char *mntns;
+        if (ret_pidns_fd) {
+                const char *pidns;
 
-                mntns = pid_namespace_path(pid, NAMESPACE_MOUNT);
-                mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (mntnsfd < 0)
+                pidns = pid_namespace_path(pid, NAMESPACE_PID);
+                pidns_fd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (pidns_fd < 0)
                         return -errno;
         }
 
-        if (pidns_fd) {
-                const char *pidns;
+        if (ret_mntns_fd) {
+                const char *mntns;
 
-                pidns = pid_namespace_path(pid, NAMESPACE_PID);
-                pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (pidnsfd < 0)
+                mntns = pid_namespace_path(pid, NAMESPACE_MOUNT);
+                mntns_fd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (mntns_fd < 0)
                         return -errno;
         }
 
-        if (netns_fd) {
+        if (ret_netns_fd) {
                 const char *netns;
 
                 netns = pid_namespace_path(pid, NAMESPACE_NET);
-                netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (netnsfd < 0)
+                netns_fd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (netns_fd < 0)
                         return -errno;
         }
 
-        if (userns_fd) {
+        if (ret_userns_fd) {
                 const char *userns;
 
                 userns = pid_namespace_path(pid, NAMESPACE_USER);
-                usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (usernsfd < 0 && errno != ENOENT)
+                userns_fd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (userns_fd < 0 && errno != ENOENT)
                         return -errno;
         }
 
-        if (root_fd) {
+        if (ret_root_fd) {
                 const char *root;
 
                 root = procfs_file_alloca(pid, "root");
-                rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
-                if (rfd < 0)
+                root_fd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+                if (root_fd < 0)
                         return -errno;
         }
 
-        if (pidns_fd)
-                *pidns_fd = TAKE_FD(pidnsfd);
+        if (ret_pidns_fd)
+                *ret_pidns_fd = TAKE_FD(pidns_fd);
 
-        if (mntns_fd)
-                *mntns_fd = TAKE_FD(mntnsfd);
+        if (ret_mntns_fd)
+                *ret_mntns_fd = TAKE_FD(mntns_fd);
 
-        if (netns_fd)
-                *netns_fd = TAKE_FD(netnsfd);
+        if (ret_netns_fd)
+                *ret_netns_fd = TAKE_FD(netns_fd);
 
-        if (userns_fd)
-                *userns_fd = TAKE_FD(usernsfd);
+        if (ret_userns_fd)
+                *ret_userns_fd = TAKE_FD(userns_fd);
 
-        if (root_fd)
-                *root_fd = TAKE_FD(rfd);
+        if (ret_root_fd)
+                *ret_root_fd = TAKE_FD(root_fd);
 
         return 0;
 }
@@ -221,7 +228,7 @@ int userns_acquire(const char *uid_map, const char *gid_map) {
 
         r = safe_fork("(sd-mkuserns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL|FORK_NEW_USERNS, &pid);
         if (r < 0)
-                return r;
+                return log_debug_errno(r, "Failed to fork process (sd-mkuserns): %m");
         if (r == 0)
                 /* Child. We do nothing here, just freeze until somebody kills us. */
                 freeze();
@@ -229,19 +236,50 @@ int userns_acquire(const char *uid_map, const char *gid_map) {
         xsprintf(path, "/proc/" PID_FMT "/uid_map", pid);
         r = write_string_file(path, uid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
-                return log_error_errno(r, "Failed to write UID map: %m");
+                return log_debug_errno(r, "Failed to write UID map: %m");
 
         xsprintf(path, "/proc/" PID_FMT "/gid_map", pid);
         r = write_string_file(path, gid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
-                return log_error_errno(r, "Failed to write GID map: %m");
-
-        r = namespace_open(pid, NULL, NULL, NULL, &userns_fd, NULL);
+                return log_debug_errno(r, "Failed to write GID map: %m");
+
+        r = namespace_open(pid,
+                           /* ret_pidns_fd = */ NULL,
+                           /* ret_mntns_fd = */ NULL,
+                           /* ret_netns_fd = */ NULL,
+                           &userns_fd,
+                           /* ret_root_fd = */ NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to open userns fd: %m");
+                return log_debug_errno(r, "Failed to open userns fd: %m");
 
         return TAKE_FD(userns_fd);
+}
+
+int netns_acquire(void) {
+        _cleanup_(sigkill_waitp) pid_t pid = 0;
+        _cleanup_close_ int netns_fd = -EBADF;
+        int r;
+
+        /* Forks off a process in a new network namespace, acquires a network namespace fd, and then kills
+         * the process again. This way we have a netns fd that is not bound to any process. */
+
+        r = safe_fork("(sd-mknetns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGKILL|FORK_NEW_NETNS, &pid);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to fork process (sd-mknetns): %m");
+        if (r == 0)
+                /* Child. We do nothing here, just freeze until somebody kills us. */
+                freeze();
+
+        r = namespace_open(pid,
+                           /* ret_pidns_fd = */ NULL,
+                           /* ret_mntns_fd = */ NULL,
+                           &netns_fd,
+                           /* ret_userns_fd = */ NULL,
+                           /* ret_root_fd = */ NULL);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to open netns fd: %m");
 
+        return TAKE_FD(netns_fd);
 }
 
 int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type) {
index be5b2281d3c4c1bc556ffd1898c2b7b857ddbf1c..d1d015612fd2d2fd4880022b03e5e81e2ca16b45 100644 (file)
@@ -22,7 +22,13 @@ extern const struct namespace_info {
         unsigned int clone_flag;
 } namespace_info[_NAMESPACE_TYPE_MAX + 1];
 
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
+int namespace_open(
+                pid_t pid,
+                int *ret_pidns_fd,
+                int *ret_mntns_fd,
+                int *ret_netns_fd,
+                int *ret_userns_fd,
+                int *ret_root_fd);
 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
 
 int fd_is_ns(int fd, unsigned long nsflag);
@@ -45,4 +51,5 @@ static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
 }
 
 int userns_acquire(const char *uid_map, const char *gid_map);
+int netns_acquire(void);
 int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type);
index d75d25af9975416896c0048dd0c1b7df14b5f8f0..697c8d9c6baf91bd23d54a22131f618ca8737e4c 100644 (file)
@@ -1541,10 +1541,11 @@ int safe_fork_full(
                 }
         }
 
-        if ((flags & (FORK_NEW_MOUNTNS|FORK_NEW_USERNS)) != 0)
+        if ((flags & (FORK_NEW_MOUNTNS|FORK_NEW_USERNS|FORK_NEW_NETNS)) != 0)
                 pid = raw_clone(SIGCHLD|
                                 (FLAGS_SET(flags, FORK_NEW_MOUNTNS) ? CLONE_NEWNS : 0) |
-                                (FLAGS_SET(flags, FORK_NEW_USERNS) ? CLONE_NEWUSER : 0));
+                                (FLAGS_SET(flags, FORK_NEW_USERNS) ? CLONE_NEWUSER : 0) |
+                                (FLAGS_SET(flags, FORK_NEW_NETNS) ? CLONE_NEWNET : 0));
         else
                 pid = fork();
         if (pid < 0)
index de6a2bd2038cfff6897375c48dfbbb64a1c9aa2f..b270fc82ea1641f53c230a2a62b11d0b24276238 100644 (file)
@@ -154,11 +154,11 @@ int must_be_root(void);
 
 pid_t clone_with_nested_stack(int (*fn)(void *), int flags, void *userdata);
 
-/* ðŸ’£ Note that FORK_NEW_USERNS + FORK_NEW_MOUNTNS should not be called in threaded programs, because they
- * cause us to use raw_clone() which does not synchronize the glibc malloc() locks, and thus will cause
- * deadlocks if the parent uses threads and the child does memory allocations. Hence: if the parent is
- * threaded these flags may not be used. These flags cannot be used if the parent uses threads or the child
- * uses malloc(). ðŸ’£ */
+/* ðŸ’£ Note that FORK_NEW_USERNS, FORK_NEW_MOUNTNS, or FORK_NEW_NETNS should not be called in threaded
+ * programs, because they cause us to use raw_clone() which does not synchronize the glibc malloc() locks,
+ * and thus will cause deadlocks if the parent uses threads and the child does memory allocations. Hence: if
+ * the parent is threaded these flags may not be used. These flags cannot be used if the parent uses threads
+ * or the child uses malloc(). ðŸ’£ */
 typedef enum ForkFlags {
         FORK_RESET_SIGNALS      = 1 <<  0, /* Reset all signal handlers and signal mask */
         FORK_CLOSE_ALL_FDS      = 1 <<  1, /* Close all open file descriptors in the child, except for 0,1,2 */
@@ -179,6 +179,7 @@ typedef enum ForkFlags {
         FORK_CLOEXEC_OFF        = 1 << 16, /* In the child: turn off O_CLOEXEC on all fds in except_fds[] */
         FORK_KEEP_NOTIFY_SOCKET = 1 << 17, /* Unless this specified, $NOTIFY_SOCKET will be unset. */
         FORK_DETACH             = 1 << 18, /* Double fork if needed to ensure PID1/subreaper is parent */
+        FORK_NEW_NETNS          = 1 << 19, /* Run child in its own network namespace                             ðŸ’£ DO NOT USE IN THREADED PROGRAMS! ðŸ’£ */
 } ForkFlags;
 
 int safe_fork_full(
index 488541ed23be3bd20866cf012d5fce26f1e416ff..4c1824bc83f52a9fa0393587fde06c55ef2b17e1 100644 (file)
@@ -1211,7 +1211,7 @@ int openpt_allocate_in_namespace(pid_t pid, int flags, char **ret_slave) {
 
         assert(pid > 0);
 
-        r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+        r = namespace_open(pid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, &usernsfd, &rootfd);
         if (r < 0)
                 return r;
 
@@ -1262,7 +1262,7 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
         pid_t child;
         int r;
 
-        r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+        r = namespace_open(pid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, &usernsfd, &rootfd);
         if (r < 0)
                 return r;
 
index b13978051035aa4a25db98d071fbd5ec0c92bdc0..61a43cd77d20efed8dbc32dc4f60185d2e82270a 100644 (file)
@@ -33,8 +33,9 @@ static EFI_STATUS devicetree_fixup(struct devicetree_state *state, size_t len) {
         assert(state);
 
         err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_DT_FIXUP_PROTOCOL), NULL, (void **) &fixup);
+        /* Skip fixup if we cannot locate device tree fixup protocol */
         if (err != EFI_SUCCESS)
-                return log_error_status(EFI_SUCCESS, "Could not locate device tree fixup protocol, skipping.");
+                return EFI_SUCCESS;
 
         size = devicetree_allocated(state);
         err = fixup->Fixup(fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &size,
index 58c7993d0b6f978c6c99ea15dc6cf0797d4b8074..d3ec22e224ef369c1295fbe605fc2550807f7ee5 100644 (file)
@@ -1915,47 +1915,93 @@ static int verify(sd_journal *j, bool verbose) {
         return r;
 }
 
-static int simple_varlink_call(const char *option, const char *method) {
-        _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL;
-        const char *fn;
+static int varlink_connect_journal(Varlink **ret_link) {
+        const char *address;
         int r;
 
-        if (arg_machine)
-                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "%s is not supported in conjunction with --machine=.", option);
-
-        fn = arg_namespace ?
-                strjoina("/run/systemd/journal.", arg_namespace, "/io.systemd.journal") :
-                "/run/systemd/journal/io.systemd.journal";
+        address = arg_namespace ?
+                  strjoina("/run/systemd/journal.", arg_namespace, "/io.systemd.journal") :
+                  "/run/systemd/journal/io.systemd.journal";
 
-        r = varlink_connect_address(&link, fn);
+        r = varlink_connect_address(ret_link, address);
         if (r < 0)
-                return log_error_errno(r, "Failed to connect to %s: %m", fn);
+                return r;
 
-        (void) varlink_set_description(link, "journal");
-        (void) varlink_set_relative_timeout(link, USEC_INFINITY);
+        (void) varlink_set_description(*ret_link, "journal");
+        (void) varlink_set_relative_timeout(*ret_link, USEC_INFINITY);
 
-        return varlink_call_and_log(link, method, /* parameters= */ NULL, /* ret_parameters= */ NULL);
+        return 0;
 }
 
 static int flush_to_var(void) {
+        _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL;
+        int r;
+
+        if (arg_machine || arg_namespace)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "--flush is not supported in conjunction with %s.",
+                                       arg_machine ? "--machine=" : "--namespace=");
+
         if (access("/run/systemd/journal/flushed", F_OK) >= 0)
                 return 0; /* Already flushed, no need to contact journald */
         if (errno != ENOENT)
                 return log_error_errno(errno, "Unable to check for existence of /run/systemd/journal/flushed: %m");
 
-        return simple_varlink_call("--flush", "io.systemd.Journal.FlushToVar");
+        r = varlink_connect_journal(&link);
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to Varlink socket: %m");
+
+        return varlink_call_and_log(link, "io.systemd.Journal.FlushToVar", /* parameters= */ NULL, /* ret_parameters= */ NULL);
 }
 
 static int relinquish_var(void) {
-        return simple_varlink_call("--relinquish-var/--smart-relinquish-var", "io.systemd.Journal.RelinquishVar");
+        _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL;
+        int r;
+
+        if (arg_machine || arg_namespace)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "--(smart-)relinquish-var is not supported in conjunction with %s.",
+                                       arg_machine ? "--machine=" : "--namespace=");
+
+        r = varlink_connect_journal(&link);
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to Varlink socket: %m");
+
+        return varlink_call_and_log(link, "io.systemd.Journal.RelinquishVar", /* parameters= */ NULL, /* ret_parameters= */ NULL);
 }
 
 static int rotate(void) {
-        return simple_varlink_call("--rotate", "io.systemd.Journal.Rotate");
+        _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL;
+        int r;
+
+        if (arg_machine)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "--rotate is not supported in conjunction with --machine=.");
+
+        r = varlink_connect_journal(&link);
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to Varlink socket: %m");
+
+        return varlink_call_and_log(link, "io.systemd.Journal.Rotate", /* parameters= */ NULL, /* ret_parameters= */ NULL);
 }
 
 static int sync_journal(void) {
-        return simple_varlink_call("--sync", "io.systemd.Journal.Synchronize");
+        _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL;
+        int r;
+
+        if (arg_machine)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "--sync is not supported in conjunction with --machine=.");
+
+        r = varlink_connect_journal(&link);
+        if (ERRNO_IS_NEG_DISCONNECT(r) && arg_namespace)
+                /* If the namespaced sd-journald instance was shut down due to inactivity, it should already
+                 * be synchronized */
+                return 0;
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to Varlink socket: %m");
+
+        return varlink_call_and_log(link, "io.systemd.Journal.Synchronize", /* parameters= */ NULL, /* ret_parameters= */ NULL);
 }
 
 static int action_list_fields(sd_journal *j) {
index 4146a6efd322c31455d43faac6a89db338e79518..2eca82b0338c4b845c18b87998a4776977eb54ac 100644 (file)
@@ -34,7 +34,7 @@ int bus_container_connect_socket(sd_bus *b) {
                 log_debug("sd-bus: connecting bus%s%s to namespace of PID "PID_FMT"...",
                           b->description ? " " : "", strempty(b->description), b->nspid);
 
-        r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+        r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, &usernsfd, &rootfd);
         if (r < 0)
                 return log_debug_errno(r, "Failed to open namespace of PID "PID_FMT": %m", b->nspid);
 
index 79a0013dc71d1085aaf6e63dcda484503730bd97..e1f3b6e80cf72380c30d00f2562deb9c9ca64e4e 100644 (file)
@@ -21,6 +21,7 @@ int device_get_property_bool(sd_device *device, const char *key);
 int device_get_property_int(sd_device *device, const char *key, int *ret);
 int device_get_sysattr_int(sd_device *device, const char *sysattr, int *ret_value);
 int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned *ret_value);
+int device_get_sysattr_u32(sd_device *device, const char *sysattr, uint32_t *ret_value);
 int device_get_sysattr_bool(sd_device *device, const char *sysattr);
 int device_get_device_id(sd_device *device, const char **ret);
 int device_get_devlink_priority(sd_device *device, int *ret);
index f18c8e69220bcb9502a835a61192e101db181e55..22b6437823839c4e53f1d55ac4620af499aecbee 100644 (file)
@@ -2423,6 +2423,25 @@ int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned
         return v > 0;
 }
 
+int device_get_sysattr_u32(sd_device *device, const char *sysattr, uint32_t *ret_value) {
+        const char *value;
+        int r;
+
+        r = sd_device_get_sysattr_value(device, sysattr, &value);
+        if (r < 0)
+                return r;
+
+        uint32_t v;
+        r = safe_atou32(value, &v);
+        if (r < 0)
+                return log_device_debug_errno(device, r, "Failed to parse '%s' attribute: %m", sysattr);
+
+        if (ret_value)
+                *ret_value = v;
+        /* We return "true" if the value is positive. */
+        return v > 0;
+}
+
 int device_get_sysattr_bool(sd_device *device, const char *sysattr) {
         const char *value;
         int r;
index 6fe9adcdbd437a456168de52629cb985ed275c45..226ac865c9372b79d51192f17ea4d3aa95d46b98 100644 (file)
@@ -199,6 +199,7 @@ static const NLAPolicy genl_nl80211_policies[] = {
         [NL80211_ATTR_SSID]        = BUILD_POLICY_WITH_SIZE(BINARY, IEEE80211_MAX_SSID_LEN),
         [NL80211_ATTR_STATUS_CODE] = BUILD_POLICY(U16),
         [NL80211_ATTR_4ADDR]       = BUILD_POLICY(U8),
+        [NL80211_ATTR_NETNS_FD]    = BUILD_POLICY(U32),
 };
 
 /***************** genl wireguard type systems *****************/
index 832159a649822d2f1cc4fd4b19d396b0ce717085..a591c7d6d6077635c5c4e0de99de8d685ea914b5 100644 (file)
@@ -20,6 +20,13 @@ static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
         assert(name);
 
         /* Assign the requested name. */
+
+        if (!*rtnl) {
+                r = sd_netlink_open(rtnl);
+                if (r < 0)
+                        return r;
+        }
+
         r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
         if (r < 0)
                 return r;
@@ -31,6 +38,37 @@ static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
         return sd_netlink_call(*rtnl, message, 0, NULL);
 }
 
+int rtnl_rename_link(sd_netlink **rtnl, const char *orig_name, const char *new_name) {
+        _cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
+        int r, ifindex;
+
+        assert(orig_name);
+        assert(new_name);
+
+        /* This does not check alternative names. Callers must check the requested name is not used as an
+         * alternative name. */
+
+        if (streq(orig_name, new_name))
+                return 0;
+
+        if (!ifname_valid(new_name))
+                return -EINVAL;
+
+        if (!rtnl)
+                rtnl = &our_rtnl;
+        if (!*rtnl) {
+                r = sd_netlink_open(rtnl);
+                if (r < 0)
+                        return r;
+        }
+
+        ifindex = rtnl_resolve_ifname(rtnl, orig_name);
+        if (ifindex < 0)
+                return ifindex;
+
+        return set_link_name(rtnl, ifindex, new_name);
+}
+
 int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const *alternative_names) {
         _cleanup_strv_free_ char **original_altnames = NULL, **new_altnames = NULL;
         bool altname_deleted = false;
index 56bbfd30d11d39c6e60aa83e8f7405a2cef85fc9..b895ac41d19b307021be83a5ce5d863f059f78a9 100644 (file)
@@ -31,6 +31,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free);
 
 int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret);
 
+int rtnl_rename_link(sd_netlink **rtnl, const char *orig_name, const char *new_name);
 int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const* alternative_names);
 static inline int rtnl_append_link_alternative_names(sd_netlink **rtnl, int ifindex, char* const *alternative_names) {
         return rtnl_set_link_name(rtnl, ifindex, NULL, alternative_names);
index 13aedc4dbec8dcf9c97fde96bdfe5d2a567820ec..fb3150f1310ef4c22100e29e896e735248681db8 100644 (file)
@@ -681,6 +681,19 @@ TEST(rtnl_set_link_name) {
         _cleanup_free_ char *resolved = NULL;
         assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-additional-name", &resolved) == ifindex);
         assert_se(streq_ptr(resolved, "test-shortname"));
+        resolved = mfree(resolved);
+
+        assert_se(rtnl_rename_link(&rtnl, "test-shortname", "test-shortname") >= 0);
+        assert_se(rtnl_rename_link(&rtnl, "test-shortname", "test-shortname2") >= 0);
+        assert_se(rtnl_rename_link(NULL, "test-shortname2", "test-shortname3") >= 0);
+
+        assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-additional-name", &resolved) == ifindex);
+        assert_se(streq_ptr(resolved, "test-shortname3"));
+        resolved = mfree(resolved);
+
+        assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-shortname3", &resolved) == ifindex);
+        assert_se(streq_ptr(resolved, "test-shortname3"));
+        resolved = mfree(resolved);
 }
 
 DEFINE_TEST_MAIN(LOG_DEBUG);
index 2f722d2491063cb2a01c2e1c43cc1c38c53614ad..8f70253ef6342c1aee0326c7257a1d5dde12d242 100644 (file)
@@ -141,9 +141,9 @@ int manager_get_session_from_creds(
         assert(m);
         assert(ret);
 
-        if (SEAT_IS_SELF(name)) /* the caller's own session */
+        if (SESSION_IS_SELF(name)) /* the caller's own session */
                 return get_sender_session(m, message, false, error, ret);
-        if (SEAT_IS_AUTO(name)) /* The caller's own session if they have one, otherwise their user's display session */
+        if (SESSION_IS_AUTO(name)) /* The caller's own session if they have one, otherwise their user's display session */
                 return get_sender_session(m, message, true, error, ret);
 
         session = hashmap_get(m->sessions, name);
index e6e57ad79ee41ac5c529706b1c5e04c176ad0061..01709a2747ef13d0416aa3cef39273a1a7abeea1 100644 (file)
@@ -532,13 +532,8 @@ int user_stop(User *u, bool force) {
                 return 0;
         }
 
-        LIST_FOREACH(sessions_by_user, s, u->sessions) {
-                int k;
-
-                k = session_stop(s, force);
-                if (k < 0)
-                        r = k;
-        }
+        LIST_FOREACH(sessions_by_user, s, u->sessions)
+                RET_GATHER(r, session_stop(s, force));
 
         user_stop_service(u, force);
 
@@ -550,7 +545,7 @@ int user_stop(User *u, bool force) {
 }
 
 int user_finalize(User *u) {
-        int r = 0, k;
+        int r = 0;
 
         assert(u);
 
@@ -560,11 +555,8 @@ int user_finalize(User *u) {
         if (u->started)
                 log_debug("User %s logged out.", u->user_record->user_name);
 
-        LIST_FOREACH(sessions_by_user, s, u->sessions) {
-                k = session_finalize(s);
-                if (k < 0)
-                        r = k;
-        }
+        LIST_FOREACH(sessions_by_user, s, u->sessions)
+                RET_GATHER(r, session_finalize(s));
 
         /* Clean SysV + POSIX IPC objects, but only if this is not a system user. Background: in many setups cronjobs
          * are run in full PAM and thus logind sessions, even if the code run doesn't belong to actual users but to
@@ -572,11 +564,8 @@ int user_finalize(User *u) {
          * cases, as we shouldn't accidentally remove a system service's IPC objects while it is running, just because
          * a cronjob running as the same user just finished. Hence: exclude system users generally from IPC clean-up,
          * and do it only for normal users. */
-        if (u->manager->remove_ipc && !uid_is_system(u->user_record->uid)) {
-                k = clean_ipc_by_uid(u->user_record->uid);
-                if (k < 0)
-                        r = k;
-        }
+        if (u->manager->remove_ipc && !uid_is_system(u->user_record->uid))
+                RET_GATHER(r, clean_ipc_by_uid(u->user_record->uid));
 
         (void) unlink(u->state_file);
         user_add_to_gc_queue(u);
index d7814a7275dfb4f4ee96325036eb30ce04dc440b..db623a3eaa1a1029d251acb6e035e52611e67fd2 100644 (file)
@@ -802,13 +802,21 @@ typedef struct SessionContext {
         const char *runtime_max_sec;
 } SessionContext;
 
-static int create_session_message(sd_bus *bus, pam_handle_t *handle, const SessionContext *context, bool avoid_pidfd, sd_bus_message **ret) {
+static int create_session_message(
+                sd_bus *bus,
+                pam_handle_t *handle,
+                const SessionContext *context,
+                bool avoid_pidfd,
+                sd_bus_message **ret) {
+
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        int r, pidfd = -EBADFD;
+        _cleanup_close_ int pidfd = -EBADF;
+        int r;
 
         assert(bus);
         assert(handle);
         assert(context);
+        assert(ret);
 
         if (!avoid_pidfd) {
                 pidfd = pidfd_open(getpid_cached(), 0);
@@ -1066,39 +1074,39 @@ _public_ PAM_EXTERN int pam_sm_open_session(
         r = create_session_message(bus,
                                    handle,
                                    &context,
-                                   false /* avoid_pidfd = */,
+                                   /* avoid_pidfd = */ false,
                                    &m);
         if (r < 0)
                 return pam_bus_log_create_error(handle, r);
 
         r = sd_bus_call(bus, m, LOGIN_SLOW_BUS_CALL_TIMEOUT_USEC, &error, &reply);
+        if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+                sd_bus_error_free(&error);
+                pam_debug_syslog(handle, debug,
+                                 "CreateSessionWithPIDFD() API is not available, retrying with CreateSession().");
+
+                m = sd_bus_message_unref(m);
+                r = create_session_message(bus,
+                                           handle,
+                                           &context,
+                                           /* avoid_pidfd = */ true,
+                                           &m);
+                if (r < 0)
+                        return pam_bus_log_create_error(handle, r);
+
+                r = sd_bus_call(bus, m, LOGIN_SLOW_BUS_CALL_TIMEOUT_USEC, &error, &reply);
+        }
         if (r < 0) {
                 if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) {
+                        /* We are already in a session, don't do anything */
                         pam_debug_syslog(handle, debug,
                                          "Not creating session: %s", bus_error_message(&error, r));
-                        /* We are already in a session, don't do anything */
                         goto success;
-                } else if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
-                        pam_debug_syslog(handle, debug,
-                                         "CreateSessionWithPIDFD() API is not available, retrying with CreateSession().");
-
-                        m = sd_bus_message_unref(m);
-                        r = create_session_message(bus,
-                                                   handle,
-                                                   &context,
-                                                   true /* avoid_pidfd = */,
-                                                   &m);
-                        if (r < 0)
-                                return pam_bus_log_create_error(handle, r);
-
-                        sd_bus_error_free(&error);
-                        r = sd_bus_call(bus, m, LOGIN_SLOW_BUS_CALL_TIMEOUT_USEC, &error, &reply);
-                }
-                if (r < 0) {
-                        pam_syslog(handle, LOG_ERR,
-                                   "Failed to create session: %s", bus_error_message(&error, r));
-                        return PAM_SESSION_ERR;
                 }
+
+                pam_syslog(handle, LOG_ERR,
+                           "Failed to create session: %s", bus_error_message(&error, r));
+                return PAM_SESSION_ERR;
         }
 
         r = sd_bus_message_read(reply,
index 6c2c2232fe3a6b46a908f52439409323f5a552ff..a7a53eacaf8861f49c585b3c1fdcf62169a77103 100644 (file)
@@ -232,7 +232,12 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
                 if (streq(us, them))
                         return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
 
-                r = namespace_open(m->leader.pid, NULL, NULL, &netns_fd, NULL, NULL);
+                r = namespace_open(m->leader.pid,
+                                   /* ret_pidns_fd = */ NULL,
+                                   /* ret_mntns_fd = */ NULL,
+                                   &netns_fd,
+                                   /* ret_userns_fd = */ NULL,
+                                   /* ret_root_fd = */ NULL);
                 if (r < 0)
                         return r;
 
@@ -366,7 +371,12 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
                 _cleanup_fclose_ FILE *f = NULL;
                 pid_t child;
 
-                r = namespace_open(m->leader.pid, &pidns_fd, &mntns_fd, NULL, NULL, &root_fd);
+                r = namespace_open(m->leader.pid,
+                                   &pidns_fd,
+                                   &mntns_fd,
+                                   /* ret_netns_fd = */ NULL,
+                                   /* ret_userns_fd = */ NULL,
+                                   &root_fd);
                 if (r < 0)
                         return r;
 
@@ -1069,7 +1079,12 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda
                 _cleanup_close_pair_ int pair[2] = EBADF_PAIR;
                 pid_t child;
 
-                r = namespace_open(m->leader.pid, NULL, &mntns_fd, NULL, NULL, &root_fd);
+                r = namespace_open(m->leader.pid,
+                                   /* ret_pidns_fd = */ NULL,
+                                   &mntns_fd,
+                                   /* ret_netns_fd = */ NULL,
+                                   /* ret_userns_fd = */ NULL,
+                                   &root_fd);
                 if (r < 0)
                         return r;
 
index aecdaa5b257f227efa4a31b449a766b5b93c18d0..b0e4afdc45fb950b22714fa9b7ed3dc1a7c87924 100644 (file)
@@ -309,8 +309,7 @@ static int dhcp_pd_request_route(Link *link, const struct in6_addr *prefix, usec
         else
                 route_unmark(existing);
 
-        r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp_pd_messages,
-                               dhcp_pd_route_handler, NULL);
+        r = link_request_route(link, route, &link->dhcp_pd_messages, dhcp_pd_route_handler);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to request DHCP-PD prefix route: %m");
 
@@ -708,7 +707,7 @@ static int dhcp_request_unreachable_route(
         else
                 route_unmark(existing);
 
-        r = link_request_route(link, TAKE_PTR(route), true, counter, callback, NULL);
+        r = link_request_route(link, route, counter, callback);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to request unreachable route for DHCP delegated prefix %s: %m",
                                             IN6_ADDR_PREFIX_TO_STRING(addr, prefixlen));
@@ -806,8 +805,7 @@ static int dhcp4_pd_request_default_gateway_on_6rd_tunnel(Link *link, const stru
         else
                 route_unmark(existing);
 
-        r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp_pd_messages,
-                               dhcp_pd_route_handler, NULL);
+        r = link_request_route(link, route, &link->dhcp_pd_messages, dhcp_pd_route_handler);
         if (r < 0)
                 return log_link_debug_errno(link, r, "Failed to request default gateway for DHCP delegated prefix: %m");
 
index 2afda41ab5e758edba8df12c35143ba8e27b8529..28702ff4469073d7c5b6f45e05a4a42e2670f8f5 100644 (file)
@@ -353,8 +353,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request
         return 1;
 }
 
-static int dhcp4_request_route(Route *in, Link *link) {
-        _cleanup_(route_freep) Route *route = in;
+static int dhcp4_request_route(Route *route, Link *link) {
         struct in_addr server;
         Route *existing;
         int r;
@@ -399,8 +398,7 @@ static int dhcp4_request_route(Route *in, Link *link) {
         else
                 route_unmark(existing);
 
-        return link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
-                                  dhcp4_route_handler, NULL);
+        return link_request_route(link, route, &link->dhcp4_messages, dhcp4_route_handler);
 }
 
 static bool link_prefixroute(Link *link) {
@@ -433,7 +431,7 @@ static int dhcp4_request_prefix_route(Link *link) {
         if (r < 0)
                 return r;
 
-        return dhcp4_request_route(TAKE_PTR(route), link);
+        return dhcp4_request_route(route, link);
 }
 
 static int dhcp4_request_route_to_gateway(Link *link, const struct in_addr *gw) {
@@ -458,15 +456,14 @@ static int dhcp4_request_route_to_gateway(Link *link, const struct in_addr *gw)
         route->prefsrc.in = address;
         route->scope = RT_SCOPE_LINK;
 
-        return dhcp4_request_route(TAKE_PTR(route), link);
+        return dhcp4_request_route(route, link);
 }
 
 static int dhcp4_request_route_auto(
-                Route *in,
+                Route *route,
                 Link *link,
                 const struct in_addr *gw) {
 
-        _cleanup_(route_freep) Route *route = in;
         struct in_addr address;
         int r;
 
@@ -535,7 +532,7 @@ static int dhcp4_request_route_auto(
                 route->prefsrc.in = address;
         }
 
-        return dhcp4_request_route(TAKE_PTR(route), link);
+        return dhcp4_request_route(route, link);
 }
 
 static int dhcp4_request_classless_static_or_static_routes(Link *link) {
@@ -575,7 +572,7 @@ static int dhcp4_request_classless_static_or_static_routes(Link *link) {
                 if (r < 0)
                         return r;
 
-                r = dhcp4_request_route_auto(TAKE_PTR(route), link, &gw);
+                r = dhcp4_request_route_auto(route, link, &gw);
                 if (r < 0)
                         return r;
         }
@@ -627,7 +624,7 @@ static int dhcp4_request_default_gateway(Link *link) {
         route->nexthop.gw.in = router;
         route->prefsrc.in = address;
 
-        return dhcp4_request_route(TAKE_PTR(route), link);
+        return dhcp4_request_route(route, link);
 }
 
 static int dhcp4_request_semi_static_routes(Link *link) {
@@ -669,7 +666,7 @@ static int dhcp4_request_semi_static_routes(Link *link) {
 
                 route->nexthop.gw.in = gw;
 
-                r = dhcp4_request_route(TAKE_PTR(route), link);
+                r = dhcp4_request_route(route, link);
                 if (r < 0)
                         return r;
         }
@@ -712,7 +709,7 @@ static int dhcp4_request_routes_to_servers(
                 route->dst.in = *dst;
                 route->dst_prefixlen = 32;
 
-                r = dhcp4_request_route_auto(TAKE_PTR(route), link, &gw);
+                r = dhcp4_request_route_auto(route, link, &gw);
                 if (r < 0)
                         return r;
         }
index 74bb549dac8fd2167096a01f457893ebb3e33996..9f56fd23d4484bd64b6c2bd03154afc3fde0f856 100644 (file)
@@ -172,8 +172,7 @@ static void ndisc_set_route_priority(Link *link, Route *route) {
         }
 }
 
-static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
-        _cleanup_(route_freep) Route *route = in;
+static int ndisc_request_route(Route *route, Link *link, sd_ndisc_router *rt) {
         struct in6_addr router;
         uint8_t hop_limit = 0;
         uint32_t mtu = 0;
@@ -224,8 +223,7 @@ static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
 
         is_new = route_get(NULL, link, route, NULL) < 0;
 
-        r = link_request_route(link, TAKE_PTR(route), true, &link->ndisc_messages,
-                               ndisc_route_handler, NULL);
+        r = link_request_route(link, route, &link->ndisc_messages, ndisc_route_handler);
         if (r < 0)
                 return r;
         if (r > 0 && is_new)
@@ -329,7 +327,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
                 route->nexthop.gw.in6 = gateway;
                 route->lifetime_usec = lifetime_usec;
 
-                r = ndisc_request_route(TAKE_PTR(route), link, rt);
+                r = ndisc_request_route(route, link, rt);
                 if (r < 0)
                         return log_link_warning_errno(link, r, "Could not request default route: %m");
         }
@@ -353,7 +351,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
                         route->pref = preference;
                 route->lifetime_usec = lifetime_usec;
 
-                r = ndisc_request_route(TAKE_PTR(route), link, rt);
+                r = ndisc_request_route(route, link, rt);
                 if (r < 0)
                         return log_link_warning_errno(link, r, "Could not request gateway: %m");
         }
@@ -503,7 +501,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
         route->pref = preference;
         route->lifetime_usec = lifetime_usec;
 
-        r = ndisc_request_route(TAKE_PTR(route), link, rt);
+        r = ndisc_request_route(route, link, rt);
         if (r < 0)
                 return log_link_warning_errno(link, r, "Could not request prefix route: %m");
 
@@ -636,7 +634,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
         route->dst_prefixlen = prefixlen;
         route->lifetime_usec = lifetime_usec;
 
-        r = ndisc_request_route(TAKE_PTR(route), link, rt);
+        r = ndisc_request_route(route, link, rt);
         if (r < 0)
                 return log_link_warning_errno(link, r, "Could not request additional route: %m");
 
index 383f259fa7992971b86f8e67dc05966cccb459f2..f1dd6b44d251cdc71897ab014900e04593b28138 100644 (file)
@@ -58,7 +58,7 @@ static void request_hash_func(const Request *req, struct siphash *state) {
 
         siphash24_compress_typesafe(req->type, state);
 
-        if (req->type != REQUEST_TYPE_NEXTHOP) {
+        if (!IN_SET(req->type, REQUEST_TYPE_NEXTHOP, REQUEST_TYPE_ROUTE)) {
                 siphash24_compress_boolean(req->link, state);
                 if (req->link)
                         siphash24_compress_typesafe(req->link->ifindex, state);
@@ -81,7 +81,7 @@ static int request_compare_func(const struct Request *a, const struct Request *b
         if (r != 0)
                 return r;
 
-        if (a->type != REQUEST_TYPE_NEXTHOP) {
+        if (!IN_SET(a->type, REQUEST_TYPE_NEXTHOP, REQUEST_TYPE_ROUTE)) {
                 r = CMP(!!a->link, !!b->link);
                 if (r != 0)
                         return r;
index 9e14c695be12bed795be1a0b519ec71d034fa44c..5f1da286046456c1215c70a5af671a897c6fed13 100644 (file)
@@ -35,7 +35,7 @@ void route_nexthops_done(Route *route) {
         ordered_set_free(route->nexthops);
 }
 
-static void route_nexthop_hash_func_full(const RouteNextHop *nh, struct siphash *state, bool hash_all_parameters) {
+static void route_nexthop_hash_func_full(const RouteNextHop *nh, struct siphash *state, bool with_weight) {
         assert(nh);
         assert(state);
 
@@ -46,15 +46,14 @@ static void route_nexthop_hash_func_full(const RouteNextHop *nh, struct siphash
                 return;
 
         in_addr_hash_func(&nh->gw, nh->family, state);
-        if (!hash_all_parameters)
-                return;
-        siphash24_compress_typesafe(nh->weight, state);
+        if (with_weight)
+                siphash24_compress_typesafe(nh->weight, state);
         siphash24_compress_typesafe(nh->ifindex, state);
         if (nh->ifindex == 0)
                 siphash24_compress_string(nh->ifname, state); /* For Network or Request object. */
 }
 
-static int route_nexthop_compare_func_full(const RouteNextHop *a, const RouteNextHop *b, bool hash_all_parameters) {
+static int route_nexthop_compare_func_full(const RouteNextHop *a, const RouteNextHop *b, bool with_weight) {
         int r;
 
         assert(a);
@@ -71,12 +70,11 @@ static int route_nexthop_compare_func_full(const RouteNextHop *a, const RouteNex
         if (r != 0)
                 return r;
 
-        if (!hash_all_parameters)
-                return 0;
-
-        r = CMP(a->weight, b->weight);
-        if (r != 0)
-                return r;
+        if (with_weight) {
+                r = CMP(a->weight, b->weight);
+                if (r != 0)
+                        return r;
+        }
 
         r = CMP(a->ifindex, b->ifindex);
         if (r != 0)
@@ -92,11 +90,11 @@ static int route_nexthop_compare_func_full(const RouteNextHop *a, const RouteNex
 }
 
 static void route_nexthop_hash_func(const RouteNextHop *nh, struct siphash *state) {
-        route_nexthop_hash_func_full(nh, state, /* hash_all_parameters = */ true);
+        route_nexthop_hash_func_full(nh, state, /* with_weight = */ true);
 }
 
 static int route_nexthop_compare_func(const RouteNextHop *a, const RouteNextHop *b) {
-        return route_nexthop_compare_func_full(a, b, /* hash_all_parameters = */ true);
+        return route_nexthop_compare_func_full(a, b, /* with_weight = */ true);
 }
 
 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
@@ -107,8 +105,6 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
         route_nexthop_free);
 
 static size_t route_n_nexthops(const Route *route) {
-        assert(route);
-
         if (route->nexthop_id != 0 || route_type_is_reject(route))
                 return 0;
 
@@ -130,7 +126,7 @@ void route_nexthops_hash_func(const Route *route, struct siphash *state) {
                 return;
 
         case 1:
-                route_nexthop_hash_func_full(&route->nexthop, state, /* hash_all_parameters = */ false);
+                route_nexthop_hash_func_full(&route->nexthop, state, /* with_weight = */ false);
                 return;
 
         default: {
@@ -157,7 +153,7 @@ int route_nexthops_compare_func(const Route *a, const Route *b) {
                 return CMP(a->nexthop_id, b->nexthop_id);
 
         case 1:
-                return route_nexthop_compare_func_full(&a->nexthop, &b->nexthop, /* hash_all_parameters = */ false);
+                return route_nexthop_compare_func_full(&a->nexthop, &b->nexthop, /* with_weight = */ false);
 
         default: {
                 RouteNextHop *nh;
@@ -179,10 +175,31 @@ static int route_nexthop_copy(const RouteNextHop *src, RouteNextHop *dest) {
         /* unset pointer copied in the above. */
         dest->ifname = NULL;
 
-        return strdup_or_null(src->ifindex == 0 ? NULL : src->ifname, &dest->ifname);
+        return strdup_or_null(src->ifindex > 0 ? NULL : src->ifname, &dest->ifname);
+}
+
+static int route_nexthop_dup(const RouteNextHop *src, RouteNextHop **ret) {
+        _cleanup_(route_nexthop_freep) RouteNextHop *dest = NULL;
+        int r;
+
+        assert(src);
+        assert(ret);
+
+        dest = new(RouteNextHop, 1);
+        if (!dest)
+                return -ENOMEM;
+
+        r = route_nexthop_copy(src, dest);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(dest);
+        return 0;
 }
 
 int route_nexthops_copy(const Route *src, const RouteNextHop *nh, Route *dest) {
+        int r;
+
         assert(src);
         assert(dest);
 
@@ -195,7 +212,20 @@ int route_nexthops_copy(const Route *src, const RouteNextHop *nh, Route *dest) {
         if (ordered_set_isempty(src->nexthops))
                 return route_nexthop_copy(&src->nexthop, &dest->nexthop);
 
-        /* Currently, this does not copy multipath routes. */
+        ORDERED_SET_FOREACH(nh, src->nexthops) {
+                _cleanup_(route_nexthop_freep) RouteNextHop *nh_dup = NULL;
+
+                r = route_nexthop_dup(nh, &nh_dup);
+                if (r < 0)
+                        return r;
+
+                r = ordered_set_ensure_put(&dest->nexthops, &route_nexthop_hash_ops, nh_dup);
+                if (r < 0)
+                        return r;
+                assert(r > 0);
+
+                TAKE_PTR(nh_dup);
+        }
 
         return 0;
 }
@@ -311,7 +341,7 @@ int route_adjust_nexthops(Route *route, Link *link) {
         return true; /* updated */
 }
 
-int route_nexthop_get_link(Manager *manager, Link *link, const RouteNextHop *nh, Link **ret) {
+int route_nexthop_get_link(Manager *manager, const RouteNextHop *nh, Link **ret) {
         assert(manager);
         assert(nh);
 
@@ -320,20 +350,16 @@ int route_nexthop_get_link(Manager *manager, Link *link, const RouteNextHop *nh,
         if (nh->ifname)
                 return link_get_by_name(manager, nh->ifname, ret);
 
-        if (link) {
-                if (ret)
-                        *ret = link;
-                return 0;
-        }
-
         return -ENOENT;
 }
 
-static bool route_nexthop_is_ready_to_configure(const RouteNextHop *nh, Link *link, bool onlink) {
+static bool route_nexthop_is_ready_to_configure(const RouteNextHop *nh, Manager *manager, bool onlink) {
+        Link *link;
+
         assert(nh);
-        assert(link);
+        assert(manager);
 
-        if (route_nexthop_get_link(link->manager, link, nh, &link))
+        if (route_nexthop_get_link(manager, nh, &link) < 0)
                 return false;
 
         if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ true))
@@ -347,13 +373,11 @@ static bool route_nexthop_is_ready_to_configure(const RouteNextHop *nh, Link *li
         return gateway_is_ready(link, onlink, nh->family, &nh->gw);
 }
 
-int route_nexthops_is_ready_to_configure(const Route *route, Link *link) {
+int route_nexthops_is_ready_to_configure(const Route *route, Manager *manager) {
         int r;
 
         assert(route);
-        assert(link);
-
-        Manager *manager = ASSERT_PTR(link->manager);
+        assert(manager);
 
         if (route->nexthop_id != 0) {
                 struct nexthop_grp *nhg;
@@ -376,11 +400,11 @@ int route_nexthops_is_ready_to_configure(const Route *route, Link *link) {
                 return true;
 
         if (ordered_set_isempty(route->nexthops))
-                return route_nexthop_is_ready_to_configure(&route->nexthop, link, FLAGS_SET(route->flags, RTNH_F_ONLINK));
+                return route_nexthop_is_ready_to_configure(&route->nexthop, manager, FLAGS_SET(route->flags, RTNH_F_ONLINK));
 
         RouteNextHop *nh;
         ORDERED_SET_FOREACH(nh, route->nexthops)
-                if (!route_nexthop_is_ready_to_configure(nh, link, FLAGS_SET(route->flags, RTNH_F_ONLINK)))
+                if (!route_nexthop_is_ready_to_configure(nh, manager, FLAGS_SET(route->flags, RTNH_F_ONLINK)))
                         return false;
 
         return true;
@@ -451,7 +475,7 @@ int route_nexthops_to_string(const Route *route, char **ret) {
         return 0;
 }
 
-static int append_nexthop_one(Link *link, const Route *route, const RouteNextHop *nh, struct rtattr **rta, size_t offset) {
+static int append_nexthop_one(const Route *route, const RouteNextHop *nh, struct rtattr **rta, size_t offset) {
         struct rtnexthop *rtnh;
         struct rtattr *new_rta;
         int r;
@@ -462,15 +486,6 @@ static int append_nexthop_one(Link *link, const Route *route, const RouteNextHop
         assert(rta);
         assert(*rta);
 
-        if (nh->ifindex <= 0) {
-                assert(link);
-                assert(link->manager);
-
-                r = route_nexthop_get_link(link->manager, link, nh, &link);
-                if (r < 0)
-                        return r;
-        }
-
         new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
         if (!new_rta)
                 return -ENOMEM;
@@ -479,7 +494,7 @@ static int append_nexthop_one(Link *link, const Route *route, const RouteNextHop
         rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
         *rtnh = (struct rtnexthop) {
                 .rtnh_len = sizeof(*rtnh),
-                .rtnh_ifindex = nh->ifindex > 0 ? nh->ifindex : link->ifindex,
+                .rtnh_ifindex = nh->ifindex,
                 .rtnh_hops = nh->weight,
         };
 
@@ -517,7 +532,7 @@ clear:
         return r;
 }
 
-static int netlink_message_append_multipath_route(Link *link, const Route *route, sd_netlink_message *message) {
+static int netlink_message_append_multipath_route(const Route *route, sd_netlink_message *message) {
         _cleanup_free_ struct rtattr *rta = NULL;
         size_t offset;
         int r;
@@ -536,7 +551,7 @@ static int netlink_message_append_multipath_route(Link *link, const Route *route
         offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
 
         if (ordered_set_isempty(route->nexthops)) {
-                r = append_nexthop_one(link, route, &route->nexthop, &rta, offset);
+                r = append_nexthop_one(route, &route->nexthop, &rta, offset);
                 if (r < 0)
                         return r;
 
@@ -545,7 +560,7 @@ static int netlink_message_append_multipath_route(Link *link, const Route *route
                 ORDERED_SET_FOREACH(nh, route->nexthops) {
                         struct rtnexthop *rtnh;
 
-                        r = append_nexthop_one(link, route, nh, &rta, offset);
+                        r = append_nexthop_one(route, nh, &rta, offset);
                         if (r < 0)
                                 return r;
 
@@ -557,7 +572,7 @@ static int netlink_message_append_multipath_route(Link *link, const Route *route
         return sd_netlink_message_append_data(message, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
 }
 
-int route_nexthops_set_netlink_message(Link *link, const Route *route, sd_netlink_message *message) {
+int route_nexthops_set_netlink_message(const Route *route, sd_netlink_message *message) {
         int r;
 
         assert(route);
@@ -570,7 +585,7 @@ int route_nexthops_set_netlink_message(Link *link, const Route *route, sd_netlin
         if (route_type_is_reject(route))
                 return 0;
 
-        /* We request IPv6 multipath routes separatedly. Even though, if weight is non-zero, we need to use
+        /* We request IPv6 multipath routes separately. Even though, if weight is non-zero, we need to use
          * RTA_MULTIPATH, as we have no way to specify the weight of the nexthop. */
         if (ordered_set_isempty(route->nexthops) && route->nexthop.weight == 0) {
 
@@ -589,10 +604,11 @@ int route_nexthops_set_netlink_message(Link *link, const Route *route, sd_netlin
                                 return r;
                 }
 
-                return sd_netlink_message_append_u32(message, RTA_OIF, route->nexthop.ifindex > 0 ? route->nexthop.ifindex : ASSERT_PTR(link)->ifindex);
+                assert(route->nexthop.ifindex > 0);
+                return sd_netlink_message_append_u32(message, RTA_OIF, route->nexthop.ifindex);
         }
 
-        return netlink_message_append_multipath_route(link, route, message);
+        return netlink_message_append_multipath_route(route, message);
 }
 
 static int route_parse_nexthops(Route *route, const struct rtnexthop *rtnh, size_t size) {
@@ -857,6 +873,16 @@ int route_section_verify_nexthops(Route *route) {
                                          "Ignoring [Route] section from line %u.",
                                          route->section->filename, route->section->line);
 
+        if (ordered_set_size(route->nexthops) == 1) {
+                _cleanup_(route_nexthop_freep) RouteNextHop *nh = ordered_set_steal_first(route->nexthops);
+
+                route_nexthop_done(&route->nexthop);
+                route->nexthop = TAKE_STRUCT(*nh);
+
+                assert(ordered_set_isempty(route->nexthops));
+                route->nexthops = ordered_set_free(route->nexthops);
+        }
+
         return 0;
 }
 
index a63409c9e288e98e065b79d0c178e9753eafc629..5e4602d3cd369d3808b68f2cb6a524192a651b61 100644 (file)
@@ -38,12 +38,12 @@ int route_nexthops_copy(const Route *src, const RouteNextHop *nh, Route *dest);
 bool route_nexthops_needs_adjust(const Route *route);
 int route_adjust_nexthops(Route *route, Link *link);
 
-int route_nexthop_get_link(Manager *manager, Link *link, const RouteNextHop *nh, Link **ret);
-int route_nexthops_is_ready_to_configure(const Route *route, Link *link);
+int route_nexthop_get_link(Manager *manager, const RouteNextHop *nh, Link **ret);
+int route_nexthops_is_ready_to_configure(const Route *route, Manager *manager);
 
 int route_nexthops_to_string(const Route *route, char **ret);
 
-int route_nexthops_set_netlink_message(Link *link, const Route *route, sd_netlink_message *message);
+int route_nexthops_set_netlink_message(const Route *route, sd_netlink_message *message);
 int route_nexthops_read_netlink_message(Route *route, sd_netlink_message *message);
 
 int route_section_verify_nexthops(Route *route);
index f877702efc7b5f0cb3af07812da262ae723aaa8e..a142719fb7405ef0671bc1ff45502b491e7d9ddd 100644 (file)
@@ -262,24 +262,16 @@ int route_new_static(Network *network, const char *filename, unsigned section_li
         return 0;
 }
 
-static int route_add(Manager *manager, Link *link, Route *route) {
+static int route_add(Manager *manager, Route *route) {
         int r;
 
+        assert(manager);
         assert(route);
+        assert(!route->network);
+        assert(!route->wireguard);
 
-        if (route_type_is_reject(route)) {
-                assert(manager);
-
-                r = set_ensure_put(&manager->routes, &route_hash_ops, route);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return -EEXIST;
-
-                route->manager = manager;
-        } else {
-                assert(link);
-
+        Link *link;
+        if (route_nexthop_get_link(manager, &route->nexthop, &link) >= 0) {
                 r = set_ensure_put(&link->routes, &route_hash_ops, route);
                 if (r < 0)
                         return r;
@@ -287,32 +279,35 @@ static int route_add(Manager *manager, Link *link, Route *route) {
                         return -EEXIST;
 
                 route->link = link;
+                return 0;
         }
 
+        r = set_ensure_put(&manager->routes, &route_hash_ops, route);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EEXIST;
+
+        route->manager = manager;
         return 0;
 }
 
-int route_get(Manager *manager, Link *link, const Route *in, Route **ret) {
-        Route *route;
-
-        assert(in);
+int route_get(Manager *manager, Link *link, const Route *route, Route **ret) {
+        Route *existing;
 
-        if (route_type_is_reject(in)) {
-                if (!manager)
-                        return -ENOENT;
-
-                route = set_get(manager->routes, in);
-        } else {
-                if (!link)
-                        return -ENOENT;
+        if (!manager)
+                manager = ASSERT_PTR(ASSERT_PTR(link)->manager);
+        assert(route);
 
-                route = set_get(link->routes, in);
-        }
-        if (!route)
+        if (route_nexthop_get_link(manager, &route->nexthop, &link) >= 0)
+                existing = set_get(link->routes, route);
+        else
+                existing = set_get(manager->routes, route);
+        if (!existing)
                 return -ENOENT;
 
         if (ret)
-                *ret = route;
+                *ret = existing;
 
         return 0;
 }
@@ -333,19 +328,17 @@ static int route_get_link(Manager *manager, const Route *route, Link **ret) {
                 return link_get_by_index(manager, nh->ifindex, ret);
         }
 
-        return route_nexthop_get_link(manager, NULL, &route->nexthop, ret);
+        return route_nexthop_get_link(manager, &route->nexthop, ret);
 }
 
-static int route_get_request(Link *link, const Route *route, Request **ret) {
+static int route_get_request(Manager *manager, const Route *route, Request **ret) {
         Request *req;
 
-        assert(link);
-        assert(link->manager);
+        assert(manager);
         assert(route);
 
-        req = ordered_set_get(link->manager->request_queue,
+        req = ordered_set_get(manager->request_queue,
                               &(const Request) {
-                                      .link = link,
                                       .type = REQUEST_TYPE_ROUTE,
                                       .userdata = (void*) route,
                                       .hash_func = (hash_func_t) route_hash_func,
@@ -393,179 +386,6 @@ int route_dup(const Route *src, const RouteNextHop *nh, Route **ret) {
         return 0;
 }
 
-static void route_apply_nexthop(Route *route, const NextHop *nh, uint8_t nh_weight) {
-        assert(route);
-        assert(nh);
-        assert(hashmap_isempty(nh->group));
-
-        route->nexthop.family = nh->family;
-        route->nexthop.gw = nh->gw;
-
-        if (nh_weight != UINT8_MAX)
-                route->nexthop.weight = nh_weight;
-
-        if (nh->blackhole)
-                route->type = RTN_BLACKHOLE;
-}
-
-static void route_apply_route_nexthop(Route *route, const RouteNextHop *nh) {
-        assert(route);
-        assert(nh);
-
-        route->nexthop.family = nh->family;
-        route->nexthop.gw = nh->gw;
-        route->nexthop.weight = nh->weight;
-}
-
-typedef struct ConvertedRoutes {
-        size_t n;
-        Route **routes;
-        Link **links;
-} ConvertedRoutes;
-
-static ConvertedRoutes *converted_routes_free(ConvertedRoutes *c) {
-        if (!c)
-                return NULL;
-
-        for (size_t i = 0; i < c->n; i++)
-                route_free(c->routes[i]);
-
-        free(c->routes);
-        free(c->links);
-
-        return mfree(c);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(ConvertedRoutes*, converted_routes_free);
-
-static int converted_routes_new(size_t n, ConvertedRoutes **ret) {
-        _cleanup_(converted_routes_freep) ConvertedRoutes *c = NULL;
-        _cleanup_free_ Route **routes = NULL;
-        _cleanup_free_ Link **links = NULL;
-
-        assert(n > 0);
-        assert(ret);
-
-        routes = new0(Route*, n);
-        if (!routes)
-                return -ENOMEM;
-
-        links = new0(Link*, n);
-        if (!links)
-                return -ENOMEM;
-
-        c = new(ConvertedRoutes, 1);
-        if (!c)
-                return -ENOMEM;
-
-        *c = (ConvertedRoutes) {
-                .n = n,
-                .routes = TAKE_PTR(routes),
-                .links = TAKE_PTR(links),
-        };
-
-        *ret = TAKE_PTR(c);
-        return 0;
-}
-
-static bool route_needs_convert(const Route *route) {
-        assert(route);
-
-        return route->nexthop_id > 0 || !ordered_set_isempty(route->nexthops);
-}
-
-static int route_convert(Manager *manager, Link *link, const Route *route, ConvertedRoutes **ret) {
-        _cleanup_(converted_routes_freep) ConvertedRoutes *c = NULL;
-        int r;
-
-        assert(manager);
-        assert(route);
-        assert(ret);
-
-        /* link may be NULL */
-
-        if (!route_needs_convert(route)) {
-                *ret = NULL;
-                return 0;
-        }
-
-        if (route->nexthop_id > 0) {
-                struct nexthop_grp *nhg;
-                NextHop *nh;
-
-                r = nexthop_get_by_id(manager, route->nexthop_id, &nh);
-                if (r < 0)
-                        return r;
-
-                if (hashmap_isempty(nh->group)) {
-                        r = converted_routes_new(1, &c);
-                        if (r < 0)
-                                return r;
-
-                        r = route_dup(route, NULL, &c->routes[0]);
-                        if (r < 0)
-                                return r;
-
-                        route_apply_nexthop(c->routes[0], nh, UINT8_MAX);
-                        (void) link_get_by_index(manager, nh->ifindex, c->links);
-
-                        *ret = TAKE_PTR(c);
-                        return 1;
-                }
-
-                r = converted_routes_new(hashmap_size(nh->group), &c);
-                if (r < 0)
-                        return r;
-
-                size_t i = 0;
-                HASHMAP_FOREACH(nhg, nh->group) {
-                        NextHop *h;
-
-                        r = nexthop_get_by_id(manager, nhg->id, &h);
-                        if (r < 0)
-                                return r;
-
-                        r = route_dup(route, NULL, &c->routes[i]);
-                        if (r < 0)
-                                return r;
-
-                        route_apply_nexthop(c->routes[i], h, nhg->weight);
-                        (void) link_get_by_index(manager, h->ifindex, c->links + i);
-
-                        i++;
-                }
-
-                *ret = TAKE_PTR(c);
-                return 1;
-
-        }
-
-        assert(!ordered_set_isempty(route->nexthops));
-
-        r = converted_routes_new(ordered_set_size(route->nexthops), &c);
-        if (r < 0)
-                return r;
-
-        size_t i = 0;
-        RouteNextHop *nh;
-        ORDERED_SET_FOREACH(nh, route->nexthops) {
-                r = route_dup(route, NULL, &c->routes[i]);
-                if (r < 0)
-                        return r;
-
-                route_apply_route_nexthop(c->routes[i], nh);
-
-                r = route_nexthop_get_link(manager, link, nh, &c->links[i]);
-                if (r < 0)
-                        return r;
-
-                i++;
-        }
-
-        *ret = TAKE_PTR(c);
-        return 1;
-}
-
 void link_mark_routes(Link *link, NetworkConfigSource source) {
         Route *route;
 
@@ -620,14 +440,12 @@ static void log_route_debug(const Route *route, const char *str, Manager *manage
                        strna(proto), strna(scope), strna(route_type_to_string(route->type)), strna(flags));
 }
 
-static int route_set_netlink_message(const Route *route, sd_netlink_message *m, Link *link) {
+static int route_set_netlink_message(const Route *route, sd_netlink_message *m) {
         int r;
 
         assert(route);
         assert(m);
 
-        /* link may be NULL */
-
         /* rtmsg header (and relevant attributes) */
         if (route->dst_prefixlen > 0) {
                 r = netlink_message_append_in_addr_union(m, RTA_DST, route->family, &route->dst);
@@ -696,7 +514,7 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *m,
                 return r;
 
         /* nexthops */
-        r = route_nexthops_set_netlink_message(link, route, m);
+        r = route_nexthops_set_netlink_message(route, m);
         if (r < 0)
                 return r;
 
@@ -727,14 +545,12 @@ static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *l
 
 int route_remove(Route *route) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
-        unsigned char type;
         Manager *manager;
         Link *link;
         int r;
 
         assert(route);
         assert(route->manager || (route->link && route->link->manager));
-        assert(IN_SET(route->family, AF_INET, AF_INET6));
 
         link = route->link;
         manager = route->manager ?: link->manager;
@@ -745,25 +561,10 @@ int route_remove(Route *route) {
         if (r < 0)
                 return log_link_warning_errno(link, r, "Could not create netlink message: %m");
 
-        r = route_set_netlink_message(route, m, link);
+        r = route_set_netlink_message(route, m);
         if (r < 0)
                 return log_link_warning_errno(link, r, "Could not fill netlink message: %m");
 
-        if (route->family == AF_INET && route->nexthop_id > 0 && route->type == RTN_BLACKHOLE)
-                /* When IPv4 route has nexthop id and the nexthop type is blackhole, even though kernel
-                 * sends RTM_NEWROUTE netlink message with blackhole type, kernel's internal route type
-                 * fib_rt_info::type may not be blackhole. Thus, we cannot know the internal value.
-                 * Moreover, on route removal, the matching is done with the hidden value if we set
-                 * non-zero type in RTM_DELROUTE message. Note, sd_rtnl_message_new_route() sets
-                 * RTN_UNICAST by default. So, we need to clear the type here. */
-                type = RTN_UNSPEC;
-        else
-                type = route->type;
-
-        r = sd_rtnl_message_route_set_type(m, type);
-        if (r < 0)
-                return log_link_error_errno(link, r, "Could not set route type: %m");
-
         r = netlink_call_async(manager->rtnl, NULL, m, route_remove_handler,
                                link ? link_netlink_destroy_callback : NULL, link);
         if (r < 0)
@@ -790,10 +591,32 @@ int route_remove_and_drop(Route *route) {
         return 0;
 }
 
+static int link_unmark_route(Link *link, const Route *route, const RouteNextHop *nh) {
+        _cleanup_(route_freep) Route *tmp = NULL;
+        Route *existing;
+        int r;
+
+        assert(link);
+        assert(route);
+
+        r = route_dup(route, nh, &tmp);
+        if (r < 0)
+                return r;
+
+        r = route_adjust_nexthops(tmp, link);
+        if (r < 0)
+                return r;
+
+        if (route_get(link->manager, link, tmp, &existing) < 0)
+                return 0;
+
+        route_unmark(existing);
+        return 1;
+}
+
 static void manager_mark_routes(Manager *manager, bool foreign, const Link *except) {
         Route *route;
         Link *link;
-        int r;
 
         assert(manager);
 
@@ -830,21 +653,14 @@ static void manager_mark_routes(Manager *manager, bool foreign, const Link *exce
                         continue;
 
                 HASHMAP_FOREACH(route, link->network->routes_by_section) {
-                        _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
-                        Route *existing;
-
-                        r = route_convert(manager, link, route, &converted);
-                        if (r < 0)
-                                continue;
-                        if (r == 0) {
-                                if (route_get(manager, NULL, route, &existing) >= 0)
-                                        route_unmark(existing);
-                                continue;
-                        }
+                        if (route->family == AF_INET || ordered_set_isempty(route->nexthops))
+                                (void) link_unmark_route(link, route, NULL);
 
-                        for (size_t i = 0; i < converted->n; i++)
-                                if (route_get(manager, NULL, converted->routes[i], &existing) >= 0)
-                                        route_unmark(existing);
+                        else {
+                                RouteNextHop *nh;
+                                ORDERED_SET_FOREACH(nh, route->nexthops)
+                                        (void) link_unmark_route(link, route, nh);
+                        }
                 }
         }
 }
@@ -888,12 +704,11 @@ static void link_unmark_wireguard_routes(Link *link) {
         if (!link->netdev || link->netdev->kind != NETDEV_KIND_WIREGUARD)
                 return;
 
-        Route *route, *existing;
+        Route *route;
         Wireguard *w = WIREGUARD(link->netdev);
 
         SET_FOREACH(route, w->routes)
-                if (route_get(NULL, link, route, &existing) >= 0)
-                        route_unmark(existing);
+                (void) link_unmark_route(link, route, NULL);
 }
 
 int link_drop_foreign_routes(Link *link) {
@@ -929,21 +744,14 @@ int link_drop_foreign_routes(Link *link) {
         }
 
         HASHMAP_FOREACH(route, link->network->routes_by_section) {
-                _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
-                Route *existing;
+                if (route->family == AF_INET || ordered_set_isempty(route->nexthops))
+                        (void) link_unmark_route(link, route, NULL);
 
-                r = route_convert(link->manager, link, route, &converted);
-                if (r < 0)
-                        continue;
-                if (r == 0) {
-                        if (route_get(NULL, link, route, &existing) >= 0)
-                                route_unmark(existing);
-                        continue;
+                else {
+                        RouteNextHop *nh;
+                        ORDERED_SET_FOREACH(nh, route->nexthops)
+                                (void) link_unmark_route(link, route, nh);
                 }
-
-                for (size_t i = 0; i < converted->n; i++)
-                        if (route_get(NULL, link, converted->routes[i], &existing) >= 0)
-                                route_unmark(existing);
         }
 
         link_unmark_wireguard_routes(link);
@@ -1092,7 +900,7 @@ static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link
         if (r < 0)
                 return r;
 
-        r = route_set_netlink_message(route, m, link);
+        r = route_set_netlink_message(route, m);
         if (r < 0)
                 return r;
 
@@ -1105,6 +913,64 @@ static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link
         return request_call_netlink_async(link->manager->rtnl, m, req);
 }
 
+static int route_requeue_request(Request *req, Link *link, const Route *route) {
+        _unused_ _cleanup_(request_unrefp) Request *req_unref = NULL;
+        _cleanup_(route_freep) Route *tmp = NULL;
+        int r;
+
+        assert(req);
+        assert(link);
+        assert(link->manager);
+        assert(route);
+
+        /* It is not possible to adjust the Route object owned by Request, as it is used as a key to manage
+         * Request objects in the queue. Hence, we need to re-request with the updated Route object. */
+
+        if (!route_nexthops_needs_adjust(route))
+                return 0; /* The Route object does not need the adjustment. Continue with it. */
+
+        r = route_dup(route, NULL, &tmp);
+        if (r < 0)
+                return r;
+
+        r = route_adjust_nexthops(tmp, link);
+        if (r <= 0)
+                return r;
+
+        if (route_compare_func(route, tmp) == 0 && route->type == tmp->type)
+                return 0; /* No effective change?? That's OK. */
+
+        /* Avoid the request to be freed by request_detach(). */
+        req_unref = request_ref(req);
+
+        /* Detach the request from the queue, to make not the new request is deduped.
+         * Why this is necessary? IPv6 routes with different type may be handled as the same,
+         * As commented in route_adjust_nexthops(), we need to configure the adjusted type,
+         * otherwise we cannot remove the route on reconfigure or so. If we request the new Route object
+         * without detaching the current request, the new request is deduped, and the route is configured
+         * with unmodified type. */
+        request_detach(req);
+
+        /* Request the route with the adjusted Route object combined with the same other parameters. */
+        r = link_queue_request_full(link,
+                                    req->type,
+                                    tmp,
+                                    req->free_func,
+                                    req->hash_func,
+                                    req->compare_func,
+                                    req->process,
+                                    req->counter,
+                                    req->netlink_handler,
+                                    NULL);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Already queued?? That's OK. Maybe, [Route] section is effectively duplicated. */
+
+        TAKE_PTR(tmp);
+        return 1; /* New request is queued. Finish to process this request. */
+}
+
 static int route_is_ready_to_configure(const Route *route, Link *link) {
         int r;
 
@@ -1123,11 +989,11 @@ static int route_is_ready_to_configure(const Route *route, Link *link) {
                         return r;
         }
 
-        return route_nexthops_is_ready_to_configure(route, link);
+        return route_nexthops_is_ready_to_configure(route, link->manager);
 }
 
 static int route_process_request(Request *req, Link *link, Route *route) {
-        _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
+        Route *existing;
         int r;
 
         assert(req);
@@ -1141,36 +1007,6 @@ static int route_process_request(Request *req, Link *link, Route *route) {
         if (r == 0)
                 return 0;
 
-        if (route_needs_convert(route)) {
-                r = route_convert(link->manager, link, route, &converted);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Failed to convert route: %m");
-
-                assert(r > 0);
-                assert(converted);
-
-                for (size_t i = 0; i < converted->n; i++) {
-                        Route *existing;
-
-                        if (route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) < 0) {
-                                _cleanup_(route_freep) Route *tmp = NULL;
-
-                                r = route_dup(converted->routes[i], NULL, &tmp);
-                                if (r < 0)
-                                        return log_oom();
-
-                                r = route_add(link->manager, converted->links[i] ?: link, tmp);
-                                if (r < 0)
-                                        return log_link_warning_errno(link, r, "Failed to add route: %m");
-
-                                TAKE_PTR(tmp);
-                        } else {
-                                existing->source = converted->routes[i]->source;
-                                existing->provider = converted->routes[i]->provider;
-                        }
-                }
-        }
-
         usec_t now_usec;
         assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
         uint32_t sec = usec_to_sec(route->lifetime_usec, now_usec);
@@ -1178,101 +1014,100 @@ static int route_process_request(Request *req, Link *link, Route *route) {
                 log_link_debug(link, "Refuse to configure %s route with zero lifetime.",
                                network_config_source_to_string(route->source));
 
-                if (converted)
-                        for (size_t i = 0; i < converted->n; i++) {
-                                Route *existing;
-
-                                assert_se(route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) >= 0);
-                                route_cancel_requesting(existing);
-                        }
-                else
-                        route_cancel_requesting(route);
-
+                route_cancel_requesting(route);
+                if (route_get(link->manager, link, route, &existing) >= 0)
+                        route_cancel_requesting(existing);
                 return 1;
         }
 
+        r = route_requeue_request(req, link, route);
+        if (r != 0)
+                return r;
+
         r = route_configure(route, sec, link, req);
         if (r < 0)
                 return log_link_warning_errno(link, r, "Failed to configure route: %m");
 
-        if (converted)
-                for (size_t i = 0; i < converted->n; i++) {
-                        Route *existing;
-
-                        assert_se(route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) >= 0);
-                        route_enter_configuring(existing);
-                }
-        else
-                route_enter_configuring(route);
-
+        route_enter_configuring(route);
+        if (route_get(link->manager, link, route, &existing) >= 0)
+                route_enter_configuring(existing);
         return 1;
 }
 
-int link_request_route(
+static int link_request_route_one(
                 Link *link,
-                Route *route,
-                bool consume_object,
+                const Route *route,
+                const RouteNextHop *nh,
                 unsigned *message_counter,
-                route_netlink_handler_t netlink_handler,
-                Request **ret) {
+                route_netlink_handler_t netlink_handler) {
 
+        _cleanup_(route_freep) Route *tmp = NULL;
         Route *existing = NULL;
         int r;
 
         assert(link);
         assert(link->manager);
         assert(route);
-        assert(route->source != NETWORK_CONFIG_SOURCE_FOREIGN);
-        assert(!route_needs_convert(route));
-
-        (void) route_get(link->manager, link, route, &existing);
-
-        if (route->lifetime_usec == 0) {
-                if (consume_object)
-                        route_free(route);
 
-                /* The requested route is outdated. Let's remove it. */
-                return route_remove_and_drop(existing);
-        }
-
-        if (!existing) {
-                _cleanup_(route_freep) Route *tmp = NULL;
-
-                if (consume_object)
-                        tmp = route;
-                else {
-                        r = route_dup(route, NULL, &tmp);
-                        if (r < 0)
-                                return r;
-                }
+        r = route_dup(route, nh, &tmp);
+        if (r < 0)
+                return r;
 
-                r = route_add(link->manager, link, tmp);
-                if (r < 0)
-                        return r;
+        r = route_adjust_nexthops(tmp, link);
+        if (r < 0)
+                return r;
 
-                existing = TAKE_PTR(tmp);
-        } else {
-                existing->source = route->source;
-                existing->provider = route->provider;
-                existing->lifetime_usec = route->lifetime_usec;
-                if (consume_object)
-                        route_free(route);
-        }
+        if (route_get(link->manager, link, tmp, &existing) >= 0)
+                /* Copy state for logging below. */
+                tmp->state = existing->state;
 
-        log_route_debug(existing, "Requesting", link->manager);
+        log_route_debug(tmp, "Requesting", link->manager);
         r = link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
-                                    existing, NULL,
+                                    tmp,
+                                    route_free,
                                     route_hash_func,
                                     route_compare_func,
                                     route_process_request,
-                                    message_counter, netlink_handler, ret);
+                                    message_counter,
+                                    netlink_handler,
+                                    NULL);
         if (r <= 0)
                 return r;
 
-        route_enter_requesting(existing);
+        route_enter_requesting(tmp);
+        if (existing)
+                route_enter_requesting(existing);
+
+        TAKE_PTR(tmp);
         return 1;
 }
 
+int link_request_route(
+                Link *link,
+                const Route *route,
+                unsigned *message_counter,
+                route_netlink_handler_t netlink_handler) {
+
+        int r;
+
+        assert(link);
+        assert(link->manager);
+        assert(route);
+        assert(route->source != NETWORK_CONFIG_SOURCE_FOREIGN);
+
+        if (route->family == AF_INET || route_type_is_reject(route) || ordered_set_isempty(route->nexthops))
+                return link_request_route_one(link, route, NULL, message_counter, netlink_handler);
+
+        RouteNextHop *nh;
+        ORDERED_SET_FOREACH(nh, route->nexthops) {
+                r = link_request_route_one(link, route, nh, message_counter, netlink_handler);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
         int r;
 
@@ -1291,22 +1126,6 @@ static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request
         return 1;
 }
 
-static int link_request_static_route(Link *link, Route *route) {
-        assert(link);
-        assert(link->manager);
-        assert(route);
-
-        if (!route_needs_convert(route))
-                return link_request_route(link, route, false, &link->static_route_messages,
-                                          static_route_handler, NULL);
-
-        log_route_debug(route, "Requesting", link->manager);
-        return link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
-                                       route, NULL, route_hash_func, route_compare_func,
-                                       route_process_request,
-                                       &link->static_route_messages, static_route_handler, NULL);
-}
-
 static int link_request_wireguard_routes(Link *link, bool only_ipv4) {
         NetDev *netdev;
         Route *route;
@@ -1326,7 +1145,7 @@ static int link_request_wireguard_routes(Link *link, bool only_ipv4) {
                 if (only_ipv4 && route->family != AF_INET)
                         continue;
 
-                r = link_request_static_route(link, route);
+                r = link_request_route(link, route, &link->static_route_messages, static_route_handler);
                 if (r < 0)
                         return r;
         }
@@ -1350,7 +1169,7 @@ int link_request_static_routes(Link *link, bool only_ipv4) {
                 if (only_ipv4 && route->family != AF_INET)
                         continue;
 
-                r = link_request_static_route(link, route);
+                r = link_request_route(link, route, &link->static_route_messages, static_route_handler);
                 if (r < 0)
                         return r;
         }
@@ -1372,14 +1191,15 @@ int link_request_static_routes(Link *link, bool only_ipv4) {
 
 void route_cancel_request(Route *route, Link *link) {
         assert(route);
-
-        link = ASSERT_PTR(route->link ?: link);
+        Manager *manager = ASSERT_PTR(route->manager ?:
+                                      route->link ? route->link->manager :
+                                      ASSERT_PTR(link)->manager);
 
         if (!route_is_requesting(route))
                 return;
 
         Request *req;
-        if (route_get_request(link, route, &req) >= 0)
+        if (route_get_request(manager, route, &req) >= 0)
                 request_detach(req);
 
         route_cancel_requesting(route);
@@ -1387,13 +1207,14 @@ void route_cancel_request(Route *route, Link *link) {
 
 static int process_route_one(
                 Manager *manager,
-                Link *link,
                 uint16_t type,
                 Route *in,
                 const struct rta_cacheinfo *cacheinfo) {
 
         _cleanup_(route_freep) Route *tmp = in;
+        Request *req = NULL;
         Route *route = NULL;
+        Link *link = NULL;
         bool is_new = false, update_dhcp4;
         int r;
 
@@ -1401,23 +1222,23 @@ static int process_route_one(
         assert(tmp);
         assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE));
 
-        /* link may be NULL. This consumes 'in'. */
+        (void) route_get(manager, NULL, tmp, &route);
+        (void) route_get_request(manager, tmp, &req);
+        (void) route_get_link(manager, tmp, &link);
 
         update_dhcp4 = link && tmp->family == AF_INET6 && tmp->dst_prefixlen == 0;
 
-        (void) route_get(manager, link, tmp, &route);
-
         switch (type) {
         case RTM_NEWROUTE:
                 if (!route) {
-                        if (!manager->manage_foreign_routes) {
+                        if (!manager->manage_foreign_routes && !(req && req->waiting_reply)) {
                                 route_enter_configured(tmp);
                                 log_route_debug(tmp, "Ignoring received", manager);
                                 return 0;
                         }
 
                         /* If we do not know the route, then save it. */
-                        r = route_add(manager, link, tmp);
+                        r = route_add(manager, tmp);
                         if (r < 0) {
                                 log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
                                 return 0;
@@ -1428,7 +1249,16 @@ static int process_route_one(
 
                 } else
                         /* Update remembered route with the received notification. */
-                        route->flags = tmp->flags;
+                        route->nexthop.weight = tmp->nexthop.weight;
+
+                /* Also update information that cannot be obtained through netlink notification. */
+                if (req && req->waiting_reply) {
+                        Route *rt = ASSERT_PTR(req->userdata);
+
+                        route->source = rt->source;
+                        route->provider = rt->provider;
+                        route->lifetime_usec = rt->lifetime_usec;
+                }
 
                 route_enter_configured(route);
                 log_route_debug(route, is_new ? "Received new" : "Received remembered", manager);
@@ -1440,16 +1270,16 @@ static int process_route_one(
         case RTM_DELROUTE:
                 if (route) {
                         route_enter_removed(route);
-                        if (route->state == 0) {
-                                log_route_debug(route, "Forgetting", manager);
-                                route_free(route);
-                        } else
-                                log_route_debug(route, "Removed", manager);
+                        log_route_debug(route, "Forgetting removed", manager);
+                        route_free(route);
                 } else
                         log_route_debug(tmp,
                                         manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring received",
                                         manager);
 
+                if (req)
+                        route_enter_removed(req->userdata);
+
                 break;
 
         default:
@@ -1610,37 +1440,21 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma
         }
         has_cacheinfo = r >= 0;
 
-        Link *link = NULL;
-        if (tmp->nexthop.ifindex > 0) {
-                r = link_get_by_index(m, tmp->nexthop.ifindex, &link);
-                if (r < 0) {
-                        /* when enumerating we might be out of sync, but we will
-                         * get the route again, so just ignore it */
-                        if (!m->enumerating)
-                                log_warning("rtnl: received route message for link (%i) we do not know about, ignoring", tmp->nexthop.ifindex);
-                        return 0;
-                }
-        }
-
-        if (!route_needs_convert(tmp))
-                return process_route_one(m, link, type, TAKE_PTR(tmp), has_cacheinfo ? &cacheinfo : NULL);
+        if (tmp->family == AF_INET || ordered_set_isempty(tmp->nexthops))
+                return process_route_one(m, type, TAKE_PTR(tmp), has_cacheinfo ? &cacheinfo : NULL);
 
-        _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
-        r = route_convert(m, link, tmp, &converted);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: failed to convert received route, ignoring: %m");
-                return 0;
-        }
+        RouteNextHop *nh;
+        ORDERED_SET_FOREACH(nh, tmp->nexthops) {
+                _cleanup_(route_freep) Route *dup = NULL;
 
-        assert(r > 0);
-        assert(converted);
+                r = route_dup(tmp, nh, &dup);
+                if (r < 0)
+                        return log_oom();
 
-        for (size_t i = 0; i < converted->n; i++)
-                (void) process_route_one(m,
-                                         converted->links[i] ?: link,
-                                         type,
-                                         TAKE_PTR(converted->routes[i]),
-                                         has_cacheinfo ? &cacheinfo : NULL);
+                r = process_route_one(m, type, TAKE_PTR(dup), has_cacheinfo ? &cacheinfo : NULL);
+                if (r < 0)
+                        return r;
+        }
 
         return 1;
 }
index 49e78e9777ebb20e786dd090c324ed0730e475ff..e86693e3152d437d8d64835fa7c3faf594b79c53 100644 (file)
@@ -101,11 +101,9 @@ void link_foreignize_routes(Link *link);
 void route_cancel_request(Route *route, Link *link);
 int link_request_route(
                 Link *link,
-                Route *route,
-                bool consume_object,
+                const Route *route,
                 unsigned *message_counter,
-                route_netlink_handler_t netlink_handler,
-                Request **ret);
+                route_netlink_handler_t netlink_handler);
 int link_request_static_routes(Link *link, bool only_ipv4);
 
 int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
index 470f477f22c1d038742ca8390bfbc8f60ed5f1b9..24771076b44108d99c2e397500b4021c4f9b9757 100644 (file)
@@ -1388,17 +1388,30 @@ int wipe_fully_visible_fs(int mntns_fd) {
         _cleanup_close_ int orig_mntns_fd = -EBADF;
         int r, rr;
 
-        r = namespace_open(0, NULL, &orig_mntns_fd, NULL, NULL, NULL);
+        r = namespace_open(0,
+                           /* ret_pidns_fd = */ NULL,
+                           &orig_mntns_fd,
+                           /* ret_netns_fd = */ NULL,
+                           /* ret_userns_fd = */ NULL,
+                           /* ret_root_fd = */ NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to pin originating mount namespace: %m");
 
-        r = namespace_enter(-EBADF, mntns_fd, -EBADF, -EBADF, -EBADF);
+        r = namespace_enter(/* pidns_fd = */ -EBADF,
+                            mntns_fd,
+                            /* netns_fd = */ -EBADF,
+                            /* userns_fd = */ -EBADF,
+                            /* root_fd = */ -EBADF);
         if (r < 0)
                 return log_error_errno(r, "Failed to enter mount namespace: %m");
 
         rr = do_wipe_fully_visible_fs();
 
-        r = namespace_enter(-EBADF, orig_mntns_fd, -EBADF, -EBADF, -EBADF);
+        r = namespace_enter(/* pidns_fd = */ -EBADF,
+                            orig_mntns_fd,
+                            /* netns_fd = */ -EBADF,
+                            /* userns_fd = */ -EBADF,
+                            /* root_fd = */ -EBADF);
         if (r < 0)
                 return log_error_errno(r, "Failed to enter original mount namespace: %m");
 
index 369d8742b60f0be1da0a9041d2ea29b4171ed0ea..151bb1d69a0e433177a21c1cd905cbaa507d7fbf 100644 (file)
@@ -2,22 +2,31 @@
 
 #include <net/if.h>
 #include <linux/if.h>
+#include <linux/nl80211.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-private.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"
 #include "nspawn-network.h"
 #include "parse-util.h"
+#include "process-util.h"
 #include "siphash24.h"
 #include "socket-netlink.h"
 #include "socket-util.h"
@@ -503,42 +512,306 @@ int test_network_interfaces_initialized(char **iface_pairs) {
         return 0;
 }
 
-int move_network_interfaces(int netns_fd, char **iface_pairs) {
-        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+static int netns_child_begin(int netns_fd, int *ret_original_netns_fd) {
+        _cleanup_close_ int original_netns_fd = -EBADF;
         int r;
 
-        if (strv_isempty(iface_pairs))
+        assert(netns_fd >= 0);
+
+        if (ret_original_netns_fd) {
+                r = namespace_open(0,
+                                   /* ret_pidns_fd = */ NULL,
+                                   /* ret_mntns_fd = */ NULL,
+                                   &original_netns_fd,
+                                   /* ret_userns_fd = */ NULL,
+                                   /* ret_root_fd = */ NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to open original network namespace: %m");
+        }
+
+        r = namespace_enter(/* pidns_fd = */ -EBADF,
+                            /* mntns_fd = */ -EBADF,
+                            netns_fd,
+                            /* userns_fd = */ -EBADF,
+                            /* root_fd = */ -EBADF);
+        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);
+
+        return 0;
+}
+
+static int netns_fork_and_wait(int netns_fd, int *ret_original_netns_fd) {
+        int r;
+
+        assert(netns_fd >= 0);
+
+        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) {
+                if (netns_child_begin(netns_fd, ret_original_netns_fd) < 0)
+                        _exit(EXIT_FAILURE);
+
                 return 0;
+        }
 
-        r = sd_netlink_open(&rtnl);
+        if (ret_original_netns_fd)
+                *ret_original_netns_fd = -EBADF;
+
+        return 1;
+}
+
+static int needs_rename(sd_netlink **rtnl, sd_device *dev, const char *name) {
+        int r;
+
+        assert(rtnl);
+        assert(dev);
+        assert(name);
+
+        const char *ifname;
+        r = sd_device_get_sysname(dev, &ifname);
         if (r < 0)
-                return log_error_errno(r, "Failed to connect to netlink: %m");
+                return r;
 
-        STRV_FOREACH_PAIR(i, b, iface_pairs) {
-                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
-                int ifi;
+        if (streq(name, ifname))
+                return false;
 
-                ifi = rtnl_resolve_interface_or_warn(&rtnl, *i);
-                if (ifi < 0)
-                        return ifi;
+        int ifindex;
+        r = sd_device_get_ifindex(dev, &ifindex);
+        if (r < 0)
+                return r;
+
+        _cleanup_strv_free_ char **altnames = NULL;
+        r = rtnl_get_link_alternative_names(rtnl, ifindex, &altnames);
+        if (r == -EOPNOTSUPP)
+                return true; /* alternative interface name is not supported, hence the name is not
+                              * assigned to the interface. */
+        if (r < 0)
+                return r;
 
-                r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, ifi);
+        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 allocate netlink message: %m");
+                        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;
 
-                r = sd_netlink_message_append_u32(m, IFLA_NET_NS_FD, netns_fd);
+        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 append namespace fd to netlink message: %m");
+                        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");
 
-                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");
+        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_netlink_call(rtnl, m, 0, NULL);
+                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;
+
+        assert(rtnl);
+        assert(netns_fd >= 0);
+        assert(dev);
+        assert(name);
+
+        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_device_error_errno(dev, r, "Failed to get ifindex: %m");
+
+        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");
+
+        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 = 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) {
+                r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
+                if (r < 0)
+                        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");
+
+        return 0;
+}
+
+int move_network_interfaces(int netns_fd, char **iface_pairs) {
+        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL, *genl = NULL;
+        _cleanup_close_ int temp_netns_fd = -EBADF;
+        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);
+
+                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;
+        }
+
+        return 0;
+}
+
+int move_back_network_interfaces(int child_netns_fd, char **interface_pairs) {
+        _cleanup_close_ int parent_netns_fd = -EBADF;
+        int r;
+
+        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) {
+                /* Reverse network interfaces pair list so that interfaces get their initial name back.
+                 * This is about ensuring interfaces get their old name back when being moved back. */
+                interface_pairs = strv_reverse(interface_pairs);
+
+                r = move_network_interfaces(parent_netns_fd, interface_pairs);
+                _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
         }
 
         return 0;
index a785f8ea42ffc9f81c9c88f626481eef4fe685bb..9729b6e37e799fd8a75954c451233ce8e60139bd 100644 (file)
@@ -19,6 +19,7 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **iface_pairs);
 int setup_ipvlan(const char *machine_name, pid_t pid, char **iface_pairs);
 
 int move_network_interfaces(int netns_fd, char **iface_pairs);
+int move_back_network_interfaces(int child_netns_fd, char **interface_pairs);
 
 int veth_extra_parse(char ***l, const char *p);
 
index 7ec9889870cefeafcd63352d1f856c005e44567d..445d85da6f071d682a0188a9c1b664ca57952438 100644 (file)
@@ -3781,7 +3781,12 @@ static int outer_child(
                 return r;
 
         if (arg_userns_mode != USER_NAMESPACE_NO) {
-                r = namespace_open(0, NULL, &mntns_fd, NULL, NULL, NULL);
+                r = namespace_open(0,
+                                   /* ret_pidns_fd = */ NULL,
+                                   &mntns_fd,
+                                   /* ret_netns_fd = */ NULL,
+                                   /* ret_userns_fd = */ NULL,
+                                   /* ret_root_fd = */ NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to pin outer mount namespace: %m");
 
@@ -4130,7 +4135,11 @@ static int outer_child(
                  * user if user namespaces are turned on. */
 
                 if (arg_network_namespace_path) {
-                        r = namespace_enter(-1, -1, netns_fd, -1, -1);
+                        r = namespace_enter(/* pidns_fd = */ -EBADF,
+                                            /* mntns_fd = */ -EBADF,
+                                            netns_fd,
+                                            /* userns_fd = */ -EBADF,
+                                            /* root_fd = */ -EBADF);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to join network namespace: %m");
                 }
@@ -5078,7 +5087,12 @@ static int run_container(
                 if (child_netns_fd < 0) {
                         /* Make sure we have an open file descriptor to the child's network
                          * namespace so it stays alive even if the child exits. */
-                        r = namespace_open(*pid, NULL, NULL, &child_netns_fd, NULL, NULL);
+                        r = namespace_open(*pid,
+                                           /* ret_pidns_fd = */ NULL,
+                                           /* ret_mntns_fd = */ NULL,
+                                           &child_netns_fd,
+                                           /* ret_userns_fd = */ NULL,
+                                           /* ret_root_fd = */ NULL);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to open child network namespace: %m");
                 }
@@ -5363,37 +5377,9 @@ static int run_container(
         fd_kmsg_fifo = safe_close(fd_kmsg_fifo);
 
         if (arg_private_network) {
-                /* Move network interfaces back to the parent network namespace. We use `safe_fork`
-                 * to avoid having to move the parent to the child network namespace. */
-                r = safe_fork(NULL, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
+                r = move_back_network_interfaces(child_netns_fd, arg_network_interfaces);
                 if (r < 0)
                         return r;
-
-                if (r == 0) {
-                        _cleanup_close_ int parent_netns_fd = -EBADF;
-
-                        r = namespace_open(getpid_cached(), NULL, NULL, &parent_netns_fd, NULL, NULL);
-                        if (r < 0) {
-                                log_error_errno(r, "Failed to open parent network namespace: %m");
-                                _exit(EXIT_FAILURE);
-                        }
-
-                        r = namespace_enter(-1, -1, child_netns_fd, -1, -1);
-                        if (r < 0) {
-                                log_error_errno(r, "Failed to enter child network namespace: %m");
-                                _exit(EXIT_FAILURE);
-                        }
-
-                        /* Reverse network interfaces pair list so that interfaces get their initial name back.
-                         * This is about ensuring interfaces get their old name back when being moved back. */
-                        arg_network_interfaces = strv_reverse(arg_network_interfaces);
-
-                        r = move_network_interfaces(parent_netns_fd, arg_network_interfaces);
-                        if (r < 0)
-                                log_error_errno(r, "Failed to move network interfaces back to parent network namespace: %m");
-
-                        _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
-                }
         }
 
         r = wait_for_container(TAKE_PID(*pid), &container_status);
index d4b448a6274ab2f892716e24da75a1f10eb435fd..6054f0f17f8de20f2e8c09795309166169e1c0a7 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <linux/loop.h>
 
+#include "sd-messages.h"
+
 #include "bus-common-errors.h"
 #include "bus-error.h"
 #include "bus-locator.h"
@@ -1430,6 +1432,78 @@ static bool prefix_matches_compatible(char **matches, char **valid_prefixes) {
         return true;
 }
 
+static void log_portable_verb(
+                const char *verb,
+                const char *message_id,
+                const char *image_path,
+                OrderedHashmap *extension_images,
+                char **extension_image_paths,
+                PortableFlags flags) {
+
+        _cleanup_free_ char *root_base_name = NULL, *extensions_joined = NULL;
+        _cleanup_strv_free_ char **extension_base_names = NULL;
+        Image *ext;
+        int r;
+
+        assert(verb);
+        assert(message_id);
+        assert(image_path);
+        assert(!extension_images || !extension_image_paths);
+
+        /* Use the same structured metadata as it is attached to units via LogExtraFields=. The main image
+         * is logged as PORTABLE_ROOT= and extensions, if any, as individual PORTABLE_EXTENSION= fields. */
+
+        r = path_extract_filename(image_path, &root_base_name);
+        if (r < 0)
+                log_debug_errno(r, "Failed to extract basename from '%s', ignoring: %m", image_path);
+
+        ORDERED_HASHMAP_FOREACH(ext, extension_images) {
+                _cleanup_free_ char *extension_base_name = NULL;
+
+                r = path_extract_filename(ext->path, &extension_base_name);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to extract basename from '%s', ignoring: %m", ext->path);
+                        continue;
+                }
+
+                r = strv_extendf(&extension_base_names, "PORTABLE_EXTENSION=%s", extension_base_name);
+                if (r < 0)
+                        log_oom_debug();
+
+                if (!strextend_with_separator(&extensions_joined, ", ", ext->path))
+                        log_oom_debug();
+        }
+
+        STRV_FOREACH(e, extension_image_paths) {
+                _cleanup_free_ char *extension_base_name = NULL;
+
+                r = path_extract_filename(*e, &extension_base_name);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to extract basename from '%s', ignoring: %m", *e);
+                        continue;
+                }
+
+                r = strv_extendf(&extension_base_names, "PORTABLE_EXTENSION=%s", extension_base_name);
+                if (r < 0)
+                        log_oom_debug();
+
+                if (!strextend_with_separator(&extensions_joined, ", ", *e))
+                        log_oom_debug();
+        }
+
+        LOG_CONTEXT_PUSH_STRV(extension_base_names);
+
+        log_struct(LOG_INFO,
+                   LOG_MESSAGE("Successfully %s%s '%s%s%s'",
+                               verb,
+                               FLAGS_SET(flags, PORTABLE_RUNTIME) ? " ephemeral" : "",
+                               image_path,
+                               isempty(extensions_joined) ? "" : "' and its extension(s) '",
+                               strempty(extensions_joined)),
+                   message_id,
+                   "PORTABLE_ROOT=%s", strna(root_base_name));
+}
+
 int portable_attach(
                 sd_bus *bus,
                 const char *name_or_path,
@@ -1538,6 +1612,14 @@ int portable_attach(
          * operation otherwise. */
         (void) install_image_and_extensions_symlinks(image, extension_images, flags, changes, n_changes);
 
+        log_portable_verb(
+                        "attached",
+                        "MESSAGE_ID=" SD_MESSAGE_PORTABLE_ATTACHED_STR,
+                        image->path,
+                        extension_images,
+                        /* extension_image_paths= */ NULL,
+                        flags);
+
         return 0;
 }
 
@@ -1861,6 +1943,14 @@ int portable_detach(
         if (rmdir(where) >= 0)
                 portable_changes_add(changes, n_changes, PORTABLE_UNLINK, where, NULL);
 
+        log_portable_verb(
+                        "detached",
+                        "MESSAGE_ID=" SD_MESSAGE_PORTABLE_DETACHED_STR,
+                        name_or_path,
+                        /* extension_images= */ NULL,
+                        extension_image_paths,
+                        flags);
+
         return ret;
 
 not_found:
index 858b707f6c8c99da83c90624fb4be0ff1179a345..1f0279cde378abdf30f062580ecdb7b0f5561543 100644 (file)
@@ -1688,7 +1688,7 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
         if (r < 0)
                 return r;
 
-        r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, NULL, &rootfd);
+        r = namespace_open(pid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, /* ret_userns_fd = */ NULL, &rootfd);
         if (r < 0)
                 return r;
 
index d6aa667adacaf4e41a5ea8f292dd081344d57ba7..833c98b88ef1b979b03eaeb22b20a620c92ea870 100644 (file)
@@ -265,7 +265,12 @@ int machine_id_commit(const char *root) {
         fd = safe_close(fd);
 
         /* Store current mount namespace */
-        r = namespace_open(0, NULL, &initial_mntns_fd, NULL, NULL, NULL);
+        r = namespace_open(0,
+                           /* ret_pidns_fd = */ NULL,
+                           &initial_mntns_fd,
+                           /* ret_netns_fd = */ NULL,
+                           /* ret_userns_fd = */ NULL,
+                           /* ret_root_fd = */ NULL);
         if (r < 0)
                 return log_error_errno(r, "Can't fetch current mount namespace: %m");
 
@@ -284,7 +289,11 @@ int machine_id_commit(const char *root) {
                 return log_error_errno(r, "Cannot write %s. This is mandatory to get a persistent machine ID: %m", etc_machine_id);
 
         /* Return to initial namespace and proceed a lazy tmpfs unmount */
-        r = namespace_enter(-1, initial_mntns_fd, -1, -1, -1);
+        r = namespace_enter(/* pidns_fd = */ -EBADF,
+                            initial_mntns_fd,
+                            /* netns_fd = */ -EBADF,
+                            /* userns_fd = */ -EBADF,
+                            /* root_fd = */ -EBADF);
         if (r < 0)
                 return log_warning_errno(r, "Failed to switch back to initial mount namespace: %m.\nWe'll keep transient %s file until next reboot.", etc_machine_id);
 
index 3305b6360e7a427c7468fbb846113172fda4741c..bf351820a74afc8b25e20de8cb2fc4791d51e9a6 100644 (file)
@@ -1100,7 +1100,7 @@ static int mount_in_namespace(
         if (!pidref_is_set(target))
                 return -ESRCH;
 
-        r = namespace_open(target->pid, &pidns_fd, &mntns_fd, NULL, NULL, &root_fd);
+        r = namespace_open(target->pid, &pidns_fd, &mntns_fd, /* ret_netns_fd = */ NULL, /* ret_userns_fd = */ NULL, &root_fd);
         if (r < 0)
                 return log_debug_errno(r, "Failed to retrieve FDs of the target process' namespace: %m");
 
index 94b699a5ee6ae251abac21dbd2ccb12cccc8ad61..6865b045b5e9172837d207bea420f8f6668f7d1f 100644 (file)
@@ -420,11 +420,11 @@ int netns_get_nsid(int netnsfd, uint32_t *ret) {
         if (netnsfd < 0) {
                 r = namespace_open(
                                 0,
-                                /* pidns_fd= */ NULL,
-                                /* mntns_fd= */ NULL,
+                                /* ret_pidns_fd = */ NULL,
+                                /* ret_mntns_fd = */ NULL,
                                 &_netns_fd,
-                                /* userns_fd= */ NULL,
-                                /* root_fd= */ NULL);
+                                /* ret_userns_fd = */ NULL,
+                                /* ret_root_fd = */ NULL);
                 if (r < 0)
                         return r;
 
index 7a86289d166df9ca0a33b2d24eb33e4d6564b42b..4f4b675a37b9fa3a41f818aa81d2256fc6f79fe2 100644 (file)
@@ -14,6 +14,7 @@
 #include "id128-util.h"
 #include "log.h"
 #include "macro.h"
+#include "missing_threads.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "signal-util.h"
@@ -363,18 +364,22 @@ int udev_queue_is_empty(void) {
                 (errno == ENOENT ? true : -errno) : false;
 }
 
-bool udev_available(void) {
-        static int cache = -1;
+static int cached_udev_availability = -1;
+
+void reset_cached_udev_availability(void) {
+        cached_udev_availability = -1;
+}
 
+bool udev_available(void) {
         /* The service systemd-udevd is started only when /sys is read write.
          * See systemd-udevd.service: ConditionPathIsReadWrite=/sys
          * Also, our container interface (http://systemd.io/CONTAINER_INTERFACE/) states that /sys must
          * be mounted in read-only mode in containers. */
 
-        if (cache >= 0)
-                return cache;
+        if (cached_udev_availability >= 0)
+                return cached_udev_availability;
 
-        return (cache = (path_is_read_only_fs("/sys/") <= 0));
+        return (cached_udev_availability = (path_is_read_only_fs("/sys/") <= 0));
 }
 
 int device_get_vendor_string(sd_device *device, const char **ret) {
index 5f49e87116179db7989374a1fec74491de4adc3f..4d27bed1d948f26ca0de104a6a2bb7546b6f027c 100644 (file)
@@ -23,6 +23,7 @@ size_t udev_replace_chars(char *str, const char *allow);
 
 int udev_queue_is_empty(void);
 
+void reset_cached_udev_availability(void);
 bool udev_available(void);
 
 int device_get_vendor_string(sd_device *device, const char **ret);
index b220fa0113d62a7944618b8b2db99b5b1219c2ab..e3f68068a8437caedd4cdee78bdffedd4ade479f 100644 (file)
@@ -267,6 +267,11 @@ _SD_BEGIN_DECLARATIONS;
 #define SD_MESSAGE_SYSV_GENERATOR_DEPRECATED          SD_ID128_MAKE(a8,fa,8d,ac,db,1d,44,3e,95,03,b8,be,36,7a,6a,db)
 #define SD_MESSAGE_SYSV_GENERATOR_DEPRECATED_STR      SD_ID128_MAKE_STR(a8,fa,8d,ac,db,1d,44,3e,95,03,b8,be,36,7a,6a,db)
 
+#define SD_MESSAGE_PORTABLE_ATTACHED                  SD_ID128_MAKE(18,7c,62,eb,1e,7f,46,3b,b5,30,39,4f,52,cb,09,0f)
+#define SD_MESSAGE_PORTABLE_ATTACHED_STR              SD_ID128_MAKE_STR(18,7c,62,eb,1e,7f,46,3b,b5,30,39,4f,52,cb,09,0f)
+#define SD_MESSAGE_PORTABLE_DETACHED                  SD_ID128_MAKE(76,c5,c7,54,d6,28,49,0d,8e,cb,a4,c9,d0,42,11,2b)
+#define SD_MESSAGE_PORTABLE_DETACHED_STR              SD_ID128_MAKE_STR(76,c5,c7,54,d6,28,49,0d,8e,cb,a4,c9,d0,42,11,2b)
+
 _SD_END_DECLARATIONS;
 
 #endif
index 2e94156432b63f3b5edb1547e2533e8bf21be547..28d845c94bd38dbdb7f1ced606d1150ba58f0060 100755 (executable)
@@ -13,6 +13,10 @@ test_append_files() {
     local workspace="${1:?}"
     local container="$workspace/testsuite-13-container-template"
 
+    # For virtual wlan interface.
+    instmods mac80211_hwsim
+    generate_module_dependencies
+
     # Create a dummy container "template" with a minimal toolset, which we can
     # then use as a base for our nspawn/machinectl tests
     initdir="$container" setup_basic_dirs
index 8a6fa84dc96ec70cb16795aa634f3cc5e23b3bb4..e984d585ca0d91399a3d5409f42862596e5b03b6 100755 (executable)
@@ -324,7 +324,7 @@ EOF
 }
 
 nspawn_settings_cleanup() {
-    for dev in sd-host-only sd-shared{1,2} sd-macvlan{1,2} sd-ipvlan{1,2}; do
+    for dev in sd-host-only sd-shared{1,2,3} sd-macvlan{1,2} sd-ipvlan{1,2}; do
         ip link del "$dev" || :
     done
 
@@ -332,7 +332,7 @@ nspawn_settings_cleanup() {
 }
 
 testcase_nspawn_settings() {
-    local root container dev private_users
+    local root container dev private_users wlan_names='' wlan_checks=''
 
     mkdir -p /run/systemd/nspawn
     root="$(mktemp -d /var/lib/machines/testsuite-13.nspawn-settings.XXX)"
@@ -341,10 +341,17 @@ testcase_nspawn_settings() {
     rm -f "/etc/systemd/nspawn/$container.nspawn"
     mkdir -p "$root/tmp" "$root"/opt/{tmp,inaccessible,also-inaccessible}
 
-    for dev in sd-host-only sd-shared{1,2} sd-macvlan{1,2} sd-macvlanloong sd-ipvlan{1,2} sd-ipvlanlooong; do
+    # add virtual wlan interfaces
+    if modprobe mac80211_hwsim radios=2; then
+        wlan_names='wlan0 wlan1:wl-renamed1'
+        wlan_checks='ip link | grep wlan0\nip link | grep wl-renamed1'
+    fi
+
+    for dev in sd-host-only sd-shared{1,2,3} sd-macvlan{1,2} sd-macvlanloong sd-ipvlan{1,2} sd-ipvlanlooong; do
         ip link add "$dev" type dummy
     done
     udevadm settle
+    ip link property add dev sd-shared3 altname sd-altname3 altname sd-altname-tooooooooooooo-long
     ip link
     trap nspawn_settings_cleanup RETURN
 
@@ -394,7 +401,7 @@ Private=yes
 VirtualEthernet=yes
 VirtualEthernetExtra=my-fancy-veth1
 VirtualEthernetExtra=fancy-veth2:my-fancy-veth2
-Interface=sd-shared1 sd-shared2:sd-shared2
+Interface=sd-shared1 sd-shared2:sd-renamed2 sd-shared3:sd-altname3 ${wlan_names}
 MACVLAN=sd-macvlan1 sd-macvlan2:my-macvlan2 sd-macvlanloong
 IPVLAN=sd-ipvlan1 sd-ipvlan2:my-ipvlan2 sd-ipvlanlooong
 Zone=sd-zone0
@@ -437,12 +444,17 @@ ip link | grep host0@
 ip link | grep my-fancy-veth1@
 ip link | grep my-fancy-veth2@
 ip link | grep sd-shared1
-ip link | grep sd-shared2
+ip link | grep sd-renamed2
+ip link | grep sd-shared3
+ip link | grep sd-altname3
+ip link | grep sd-altname-tooooooooooooo-long
 ip link | grep mv-sd-macvlan1@
 ip link | grep my-macvlan2@
 ip link | grep iv-sd-ipvlan1@
 ip link | grep my-ipvlan2@
 EOF
+    echo -e "$wlan_checks" >>"$root/entrypoint.sh"
+
     timeout 30 systemd-nspawn --directory="$root"
 
     # And now for stuff that needs to run separately