]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-netlink: make rtnl_set_link_name() optionally append alternative names
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 16 May 2023 04:29:37 +0000 (13:29 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 16 May 2023 07:37:31 +0000 (16:37 +0900)
src/libsystemd/sd-netlink/netlink-util.c
src/libsystemd/sd-netlink/netlink-util.h
src/libsystemd/sd-netlink/test-netlink.c
src/udev/udev-event.c

index 6cd916a2097b484f3d6a116d34cf6ca34d1523d2..6ded66b935cb592f2b921934c892713409f66602 100644 (file)
 #include "process-util.h"
 #include "strv.h"
 
-int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
+static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
-        _cleanup_strv_free_ char **alternative_names = NULL;
-        bool altname_deleted = false;
         int r;
 
         assert(rtnl);
         assert(ifindex > 0);
         assert(name);
 
-        if (!ifname_valid(name))
+        /* Assign the requested name. */
+        r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
+        if (r < 0)
+                return r;
+
+        return sd_netlink_call(*rtnl, message, 0, NULL);
+}
+
+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;
+        int r;
+
+        assert(rtnl);
+        assert(ifindex > 0);
+
+        if (isempty(name) && strv_isempty(alternative_names))
+                return 0;
+
+        if (name && !ifname_valid(name))
                 return -EINVAL;
 
-        r = rtnl_get_link_alternative_names(rtnl, ifindex, &alternative_names);
+        /* If the requested name is already assigned as an alternative name, then first drop it. */
+        r = rtnl_get_link_alternative_names(rtnl, ifindex, &original_altnames);
         if (r < 0)
                 log_debug_errno(r, "Failed to get alternative names on network interface %i, ignoring: %m",
                                 ifindex);
 
-        if (strv_contains(alternative_names, name)) {
-                r = rtnl_delete_link_alternative_names(rtnl, ifindex, STRV_MAKE(name));
-                if (r < 0)
-                        return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
-                                               name, ifindex);
+        if (name) {
+                if (strv_contains(original_altnames, name)) {
+                        r = rtnl_delete_link_alternative_names(rtnl, ifindex, STRV_MAKE(name));
+                        if (r < 0)
+                                return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
+                                                       name, ifindex);
+
+                        altname_deleted = true;
+                }
 
-                altname_deleted = true;
+                r = set_link_name(rtnl, ifindex, name);
+                if (r < 0)
+                        goto fail;
         }
 
-        r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
-        if (r < 0)
-                goto fail;
+        /* Filter out already assigned names from requested alternative names. Also, dedup the request. */
+        STRV_FOREACH(a, alternative_names) {
+                if (streq_ptr(name, *a))
+                        continue;
 
-        r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
-        if (r < 0)
-                goto fail;
+                if (strv_contains(original_altnames, *a))
+                        continue;
 
-        r = sd_netlink_call(*rtnl, message, 0, NULL);
-        if (r < 0)
-                goto fail;
+                if (strv_contains(new_altnames, *a))
+                        continue;
+
+                if (!ifname_valid_full(*a, IFNAME_VALID_ALTERNATIVE))
+                        continue;
+
+                r = strv_extend(&new_altnames, *a);
+                if (r < 0)
+                        return r;
+        }
+
+        strv_sort(new_altnames);
+
+        /* Finally, assign alternative names. */
+        r = rtnl_set_link_alternative_names(rtnl, ifindex, new_altnames);
+        if (r == -EEXIST) /* Already assigned to another interface? */
+                STRV_FOREACH(a, new_altnames) {
+                        r = rtnl_set_link_alternative_names(rtnl, ifindex, STRV_MAKE(*a));
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to assign '%s' as an alternative name on network interface %i, ignoring: %m",
+                                                *a, ifindex);
+                }
+        else if (r < 0)
+                log_debug_errno(r, "Failed to assign alternative names on network interface %i, ignoring: %m", ifindex);
 
         return 0;
 
index 72d16fa9a914c844590fc85595aac15b6349350b..2f9f7e96766f5f8b839dedf6002bf12e032eb8c7 100644 (file)
@@ -28,7 +28,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free);
 
 int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret);
 
-int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *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);
+}
 int rtnl_set_link_properties(
                 sd_netlink **rtnl,
                 int ifindex,
index 9ad8ecf32053a127e52540280032d66b13e00dfd..43124b99ae87482cdf2d170a7ff68fde2d25e445 100644 (file)
@@ -662,12 +662,13 @@ TEST(rtnl_set_link_name) {
         assert_se(strv_contains(alternative_names, "testlongalternativename"));
         assert_se(strv_contains(alternative_names, "test-shortname"));
 
-        assert_se(rtnl_set_link_name(&rtnl, ifindex, "testlongalternativename") == -EINVAL);
-        assert_se(rtnl_set_link_name(&rtnl, ifindex, "test-shortname") >= 0);
+        assert_se(rtnl_set_link_name(&rtnl, ifindex, "testlongalternativename", NULL) == -EINVAL);
+        assert_se(rtnl_set_link_name(&rtnl, ifindex, "test-shortname", STRV_MAKE("testlongalternativename", "test-shortname", "test-additional-name")) >= 0);
 
         alternative_names = strv_free(alternative_names);
         assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
         assert_se(strv_contains(alternative_names, "testlongalternativename"));
+        assert_se(strv_contains(alternative_names, "test-additional-name"));
         assert_se(!strv_contains(alternative_names, "test-shortname"));
 
         assert_se(rtnl_delete_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename")) >= 0);
@@ -675,6 +676,7 @@ TEST(rtnl_set_link_name) {
         alternative_names = strv_free(alternative_names);
         assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
         assert_se(!strv_contains(alternative_names, "testlongalternativename"));
+        assert_se(strv_contains(alternative_names, "test-additional-name"));
         assert_se(!strv_contains(alternative_names, "test-shortname"));
 }
 
index 88b01f4e1b61dfc7324a9091ae7dc24ec742a11f..7f6d8e4a752aa9619885d0c1e5a70eb8ac36c07d 100644 (file)
@@ -976,7 +976,7 @@ static int rename_netif(UdevEvent *event) {
                 goto revert;
         }
 
-        r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
+        r = rtnl_set_link_name(&event->rtnl, ifindex, event->name, NULL);
         if (r < 0) {
                 if (r == -EBUSY) {
                         log_device_info(dev, "Network interface '%s' is already up, cannot rename to '%s'.",