I struggled for a week having udev (on CentOS 6.3) do all kinds of silly things with the interfaces names on a server with 4 onboard 1G interfaces, an 2 dual port Mellanox ConnectX-3 cards. The short story is that udev was trying to preserve the names of the interfaces to be consistently numbered starting from eth0 and ending with eth7.

The problem: the modules for the network cards do not always get probed/loaded in the same order. Udev does the module loading automatically and considering how heavily parallel it is, if the Mellanox driver gets loaded first and the onboard tg3 driver second, udev tries to swap eth eth0-eth3 interfaces with eth4-eth7. Most of the time this leaves a huge mess behind.

I followed RedHat’s advice to stop using the “eth” names but even then udev failed to rename one or two of the eth interfaces most of the time.

Here comes the solution. Modify the 70-persistent-net.rules that udev generates, and add an extra rule for each matching interface with the following action:

IMPORT{program}="/usr/bin/flock -x %r/.udev/udev-ifrename.lock /bin/sleep 0.2"

This will delay the rule that actually does the renaming slightly, and will also make sure that the kernel only renames one network interface at a time. I have not checked if the delay is really necessary, but I certainly don’t mind it. In the end the rules file would look something like this:

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="d4:ae:52:93:12:33", ATTR{type}=="1", KERNEL=="eth*", IMPORT{program}="/usr/bin/flock -x %r/.udev/udev-ifrename.lock /bin/sleep 0.2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="d4:ae:52:93:12:33", ATTR{type}=="1", KERNEL=="eth*", NAME="nic0"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="d4:ae:52:93:12:34", ATTR{type}=="1", KERNEL=="eth*", IMPORT{program}="/usr/bin/flock -x %r/.udev/udev-ifrename.lock /bin/sleep 0.2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="d4:ae:52:93:12:34", ATTR{type}=="1", KERNEL=="eth*", NAME="nic1"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="d4:ae:52:93:12:35", ATTR{type}=="1", KERNEL=="eth*", IMPORT{program}="/usr/bin/flock -x %r/.udev/udev-ifrename.lock /bin/sleep 0.2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="d4:ae:52:93:12:35", ATTR{type}=="1", KERNEL=="eth*", NAME="nic2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="d4:ae:52:93:12:36", ATTR{type}=="1", KERNEL=="eth*", IMPORT{program}="/usr/bin/flock -x %r/.udev/udev-ifrename.lock /bin/sleep 0.2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="d4:ae:52:93:12:36", ATTR{type}=="1", KERNEL=="eth*", NAME="nic3"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:02:c9:3f:69:20", ATTR{type}=="1", KERNEL=="eth*", IMPORT{program}="/usr/bin/flock -x %r/.udev/udev-ifrename.lock /bin/sleep 0.2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:02:c9:3f:69:20", ATTR{type}=="1", KERNEL=="eth*", NAME="nic4"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:02:c9:3f:69:21", ATTR{type}=="1", KERNEL=="eth*", IMPORT{program}="/usr/bin/flock -x %r/.udev/udev-ifrename.lock /bin/sleep 0.2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:02:c9:3f:69:21", ATTR{type}=="1", KERNEL=="eth*", NAME="nic5"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:02:c9:3f:6b:20", ATTR{type}=="1", KERNEL=="eth*", IMPORT{program}="/usr/bin/flock -x %r/.udev/udev-ifrename.lock /bin/sleep 0.2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:02:c9:3f:6b:20", ATTR{type}=="1", KERNEL=="eth*", NAME="nic6"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:02:c9:3f:6b:21", ATTR{type}=="1", KERNEL=="eth*", IMPORT{program}="/usr/bin/flock -x %r/.udev/udev-ifrename.lock /bin/sleep 0.2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:02:c9:3f:6b:21", ATTR{type}=="1", KERNEL=="eth*", NAME="nic7"

And I have had no more problems with interfaces not getting renamed, even when the driver loading order would have otherwise made a mess:

$ dmesg | grep renamed
[   14.587586] udev: renamed network interface eth3 to nic3
[   14.773540] udev: renamed network interface eth2 to nic2
[   19.248634] udev: renamed network interface eth2 to nic4
[   19.449075] udev: renamed network interface eth4 to nic6
[   19.649381] udev: renamed network interface eth1 to nic1
[   19.850040] udev: renamed network interface eth3 to nic5
[   20.050527] udev: renamed network interface eth5 to nic7
[   20.250786] udev: renamed network interface eth0 to nic0