diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 04bf64cce5..0c1ff34e5d 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -12,6 +12,7 @@ #include "siphash24.h" #include "sparse-endian.h" #include "stdio-util.h" +#include "udev-util.h" #include "virt.h" #define SYSTEMD_PEN 43793 @@ -182,6 +183,13 @@ int dhcp_identifier_set_iaid( /* not yet ready */ return -EBUSY; + r = device_is_renaming(device); + if (r < 0) + return r; + if (r > 0) + /* device is under renaming */ + return -EBUSY; + name = net_get_name(device); } } diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c index 3928dfbabf..628ce507a0 100644 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ b/src/libsystemd/sd-netlink/netlink-util.c @@ -13,6 +13,9 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) { assert(ifindex > 0); assert(name); + if (!ifname_valid(name)) + return -EINVAL; + if (!*rtnl) { r = sd_netlink_open(rtnl); if (r < 0) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 1738a0d944..9e3cd71a09 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -31,6 +31,7 @@ #include "strv.h" #include "sysctl-util.h" #include "tmpfile-util.h" +#include "udev-util.h" #include "util.h" #include "virt.h" @@ -3624,6 +3625,16 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) { return 0; } + r = device_is_renaming(device); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to determine the device is renamed or not: %m"); + goto failed; + } + if (r > 0) { + log_link_debug(link, "Interface is under renaming, pending initialization."); + return 0; + } + r = link_initialized(link, device); if (r < 0) goto failed; @@ -3767,20 +3778,14 @@ int link_update(Link *link, sd_netlink_message *m) { r = sd_netlink_message_read_string(m, IFLA_IFNAME, &ifname); if (r >= 0 && !streq(ifname, link->ifname)) { + Manager *manager = link->manager; + log_link_info(link, "Interface name change detected, %s has been renamed to %s.", link->ifname, ifname); - if (link->state == LINK_STATE_PENDING) { - r = free_and_strdup(&link->ifname, ifname); - if (r < 0) - return r; - } else { - Manager *manager = link->manager; - - link_drop(link); - r = link_add(manager, m, &link); - if (r < 0) - return r; - } + link_drop(link); + r = link_add(manager, m, &link); + if (r < 0) + return r; } r = sd_netlink_message_read_u32(m, IFLA_MTU, &mtu); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 079cd3e1d1..c87f907957 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -26,6 +26,7 @@ #include "strv.h" #include "sysctl-util.h" #include "tmpfile-util.h" +#include "udev-util.h" #include "virt.h" /* use 8 MB for receive socket kernel queue. */ @@ -194,7 +195,7 @@ static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *devi return 0; } - if (!STR_IN_SET(action, "add", "change")) { + if (!STR_IN_SET(action, "add", "change", "move")) { log_device_debug(device, "Ignoring udev %s event for device.", action); return 0; } @@ -205,6 +206,16 @@ static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *devi return 0; } + r = device_is_renaming(device); + if (r < 0) { + log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m", action); + return 0; + } + if (r > 0) { + log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed: %m"); + return 0; + } + r = link_get(m, ifindex, &link); if (r < 0) { if (r != -ENODEV) diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c index 4200032b3b..6847d715f6 100644 --- a/src/shared/udev-util.c +++ b/src/shared/udev-util.c @@ -169,3 +169,15 @@ int device_wait_for_initialization(sd_device *device, const char *subsystem, sd_ *ret = TAKE_PTR(data.device); return 0; } + +int device_is_renaming(sd_device *dev) { + int r; + + assert(dev); + + r = sd_device_get_property_value(dev, "ID_RENAMING", NULL); + if (r < 0 && r != -ENOENT) + return r; + + return r >= 0; +} diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h index 932c4a9cd5..c45d6a11fd 100644 --- a/src/shared/udev-util.h +++ b/src/shared/udev-util.h @@ -27,3 +27,4 @@ static inline int udev_parse_config(void) { } int device_wait_for_initialization(sd_device *device, const char *subsystem, sd_device **ret); +int device_is_renaming(sd_device *dev); diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 9ede330c27..cefc2f4445 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -696,7 +696,6 @@ int udev_event_spawn(UdevEvent *event, static int rename_netif(UdevEvent *event) { sd_device *dev = event->dev; const char *action, *oldname; - char name[IFNAMSIZ]; int ifindex, r; if (!event->name) @@ -722,16 +721,21 @@ static int rename_netif(UdevEvent *event) { if (r < 0) return log_device_error_errno(dev, r, "Failed to get ifindex: %m"); - strscpy(name, IFNAMSIZ, event->name); - r = rtnl_set_link_name(&event->rtnl, ifindex, name); + r = rtnl_set_link_name(&event->rtnl, ifindex, event->name); if (r < 0) - return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m", ifindex, oldname, name); + return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m", + ifindex, oldname, event->name); + + /* Set ID_RENAMING boolean property here, and drop it in the corresponding move uevent later. */ + r = device_add_property(dev, "ID_RENAMING", "1"); + if (r < 0) + log_device_warning_errno(dev, r, "Failed to add 'ID_RENAMING' property: %m"); r = device_rename(dev, event->name); if (r < 0) - return log_warning_errno(r, "Network interface %i is renamed from '%s' to '%s', but could not update sd_device object: %m", ifindex, oldname, name); + log_device_warning_errno(dev, r, "Failed to update properties with new name '%s': %m", event->name); - log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, name); + log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, event->name); return 1; } @@ -816,17 +820,38 @@ static void event_execute_rules_on_remove( (void) udev_node_remove(dev); } +static int udev_event_on_move(UdevEvent *event) { + sd_device *dev = event->dev; + int r; + + if (event->dev_db_clone && + sd_device_get_devnum(dev, NULL) < 0) { + r = device_copy_properties(dev, event->dev_db_clone); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to copy properties from cloned sd_device object, ignoring: %m"); + } + + /* Drop previously added property */ + r = device_add_property(dev, "ID_RENAMING", NULL); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to remove 'ID_RENAMING' property, ignoring: %m"); + + return 0; +} + int udev_event_execute_rules(UdevEvent *event, usec_t timeout_usec, Hashmap *properties_list, UdevRules *rules) { - sd_device *dev = event->dev; const char *subsystem, *action; + sd_device *dev; int r; assert(event); assert(rules); + dev = event->dev; + r = sd_device_get_subsystem(dev, &subsystem); if (r < 0) return log_device_error_errno(dev, r, "Failed to get subsystem: %m"); @@ -844,21 +869,12 @@ int udev_event_execute_rules(UdevEvent *event, if (r < 0) log_device_debug_errno(dev, r, "Failed to clone sd_device object, ignoring: %m"); - if (event->dev_db_clone) { - r = sd_device_get_devnum(dev, NULL); - if (r < 0) { - if (r != -ENOENT) - log_device_debug_errno(dev, r, "Failed to get devnum, ignoring: %m"); + if (event->dev_db_clone && sd_device_get_devnum(dev, NULL) >= 0) + /* Disable watch during event processing. */ + (void) udev_watch_end(event->dev_db_clone); - if (streq(action, "move")) { - r = device_copy_properties(dev, event->dev_db_clone); - if (r < 0) - log_device_debug_errno(dev, r, "Failed to copy properties from cloned device, ignoring: %m"); - } - } else - /* Disable watch during event processing. */ - (void) udev_watch_end(event->dev_db_clone); - } + if (streq(action, "move")) + (void) udev_event_on_move(event); (void) udev_rules_apply_to_event(rules, event, timeout_usec, properties_list);