diff options
Diffstat (limited to 'src/libsystemd/sd-netlink/netlink-util.c')
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-util.c | 89 |
1 files changed, 69 insertions, 20 deletions
diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c index 6cd916a209..6ded66b935 100644 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ b/src/libsystemd/sd-netlink/netlink-util.c @@ -11,44 +11,93 @@ #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; |