diff options
Diffstat (limited to 'src/udev/udev-event.c')
-rw-r--r-- | src/udev/udev-event.c | 135 |
1 files changed, 124 insertions, 11 deletions
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index ed6f203ce7..897f98b321 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -771,17 +771,17 @@ out: return err; } -static int rename_netif(struct udev_event *event) { - struct udev_device *dev = event->dev; - char name[IFNAMSIZ]; - const char *oldname; +#ifdef ENABLE_RULE_GENERATOR +/* function to return the count of rules that assign NAME= to a value matching arg#2 , defined in udev-rules.c */ +int udev_rules_assigning_name_to(struct udev_rules *rules,const char *match_name); +#endif + +static int rename_netif_dev_fromname_toname(struct udev_device *dev,const char *oldname,const char *name) { int r; int sk; struct ifreq ifr; - oldname = udev_device_get_sysname(dev); - - strscpy(name, IFNAMSIZ, event->name); + log_debug("changing net interface name from '%s' to '%s'\n",oldname,name); sk = socket(PF_INET, SOCK_DGRAM, 0); if (sk < 0) @@ -791,13 +791,52 @@ static int rename_netif(struct udev_event *event) { strscpy(ifr.ifr_name, IFNAMSIZ, oldname); strscpy(ifr.ifr_newname, IFNAMSIZ, name); r = ioctl(sk, SIOCSIFNAME, &ifr); - if (r < 0) - return log_error_errno(-errno, "Error changing net interface name '%s' to '%s': %m", oldname, name); - log_debug("renamed network interface '%s' to '%s'", oldname, name); +#ifdef ENABLE_RULE_GENERATOR + int loop; + + if (r == 0) { + log_info("renamed network interface %s to %s\n", ifr.ifr_name, ifr.ifr_newname); + goto out; + } + /* keep trying if the destination interface name already exists */ + log_debug("collision on rename of network interface %s to %s , retrying until timeout\n", + ifr.ifr_name, ifr.ifr_newname); + + r = -errno; + if (r != -EEXIST) + goto out; + + /* wait a maximum of 90 seconds for our target to become available */ + loop = 90 * 20; + while (loop--) { + const struct timespec duration = { 0, 1000 * 1000 * 1000 / 20 }; + + nanosleep(&duration, NULL); + + r = ioctl(sk, SIOCSIFNAME, &ifr); + if (r == 0) { + log_info("renamed network interface %s to %s\n", ifr.ifr_name, ifr.ifr_newname); + break; + } + r = -errno; + if (r != -EEXIST) + break; + } + +out: +#endif + if (r < 0) + log_error_errno(-errno, "Error changing net interface name %s to %s: %m\n", ifr.ifr_name, ifr.ifr_newname); + else + log_debug("renamed network interface '%s' to '%s'", oldname, name); close(sk); - return 0; + return r; +} + +static int rename_netif(struct udev_event *event) { + return rename_netif_dev_fromname_toname(event->dev,udev_device_get_sysname(event->dev),event->name); } void udev_event_execute_rules(struct udev_event *event, @@ -843,6 +882,79 @@ void udev_event_execute_rules(struct udev_event *event, sigmask); /* rename a new network interface, if needed */ + + /* ENABLE_RULE_GENERATOR conditional: + * if this is a net iface, and it is an add event, + * and as long as all of the following are FALSE: + * - no NAME target and the current name is not being used + * - there is a NAME target and it is the same as the current name + * - the rules can successfully be searched for the current name (not really part of the conditional) + * the run the rename. + * + * note - udev_rules_assigning_name_to is run when event->name is NULL to ensure renames happen, + * but also on its own to check if a temp-rename is necessary when event->name exists. + * + * A temp-rename is necessary when: + * - there is no rule renaming the current iface but the current name IS used in some other rule + * - there is a rule renaming the current iface, + * the current name IS used AND the target name != the current name + */ + +#ifdef ENABLE_RULE_GENERATOR + int r; + if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") && + (event->name == NULL && (r=udev_rules_assigning_name_to(rules,udev_device_get_sysname(dev))) > 0 || + event->name != NULL && !streq(event->name, udev_device_get_sysname(dev)))) { + char syspath[UTIL_PATH_SIZE]; + char *pos; + char *finalifname = event->name; + char newifname[IFNAMSIZ]; + + /* r is the number of rules that assign a device with NAME= this sysname */ + if (r > 0 || (r=udev_rules_assigning_name_to(rules,udev_device_get_sysname(dev))) > 0) { + /* have a conflict, rename to a temp name */ + char *newpos; + int ifidnum; + + /* build the temporary iface name */ + strscpy(newifname, IFNAMSIZ, udev_device_get_sysname(dev)); + newpos=pos=&newifname[strcspn(newifname,"0123456789")]; + ifidnum=(int)strtol(pos,&newpos,10); + *pos='\0'; + if (newpos > pos && *newpos == '\0') /* append new iface num to name */ + /* use udev_device_get_ifindex(dev) as it is unique to every iface */ + snprintf(pos,IFNAMSIZ+(newifname-pos), "%d", 128 - udev_device_get_ifindex(dev)); + + /* note, r > 0, which will skip the post-rename stuff if no rename occurs */ + + /* if sysname isn't already the tmpname (ie there is no numeric component), do the rename */ + if (!streq(newifname,udev_device_get_sysname(dev))) { + r = rename_netif_dev_fromname_toname(dev,udev_device_get_sysname(dev),newifname); + if (r == 0) { + finalifname = newifname; + log_debug("renamed netif to '%s' for collision avoidance\n", newifname); + } else { + log_error("could not rename netif to '%s' for collision avoidance\n",newifname); + } + } + /* rename it now to its final target if its not already there */ + if (event->name != NULL && !streq(event->name, newifname)) { + r = rename_netif_dev_fromname_toname(dev,newifname,event->name); + if (r == 0) + finalifname = event->name; + } + + } else { /* no need to rename to a tempname first, do a regular direct rename to event->name */ + + r = 1; /* skip the post-rename stuff if no rename occurs */ + if (!streq(event->name, udev_device_get_sysname(dev))) + r = rename_netif(event); + } + + if (r == 0) { + log_debug("renamed netif to '%s'\n", finalifname); + r = udev_device_rename(dev, finalifname); +#else if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") && event->name != NULL && !streq(event->name, udev_device_get_sysname(dev))) { int r; @@ -853,6 +965,7 @@ void udev_event_execute_rules(struct udev_event *event, udev_device_get_sysname(dev), event->name); else { r = udev_device_rename(dev, event->name); +#endif if (r < 0) log_warning_errno(r, "renamed interface '%d' from '%s' to '%s', but could not update udev_device: %m", udev_device_get_ifindex(dev), udev_device_get_sysname(dev), event->name); |