# Why have my eth0 and eth1 switched again?

## dswhite42

I have two NICs - a built-in motherboard NIC (identified as a "RealTek RTL8139") and a Netgear card (curiously identified as a "Lite-On 82c168 PNIC rev 32").  There also appears to be a 3rd "NIC" - my IEEE1394 port.  These cards used to be, respectively, eth0, eth1, and eth2 but about 4 weeks ago they suddenly switched places and became eth2, eth0, and eth1 respectively.

Looking around, I traced the problem to udev, and after reading http://reactivated.net/writing_udev_rules.html#example-iface, I ran these commands:

```
> udevinfo -a -p /sys/class/net/eth0/ | grep address

    SYSFS{address}=="00:a0:cc:60:c8:43"

> udevinfo -a -p /sys/class/net/eth1/ | grep address

    SYSFS{address}=="00:50:8d:00:00:f4:a8:54"

> udevinfo -a -p /sys/class/net/eth2/ | grep address

    SYSFS{address}=="00:50:8d:f5:a8:54"
```

then created the file /etc/udev/rules.d/49-nic.rules with these rules:

```
# Force DSL connection to be "eth0" (udev default assignment: eth2)

# (DSL NIC = RealTek RTL8139)

KERNEL=="eth*", SYSFS{address}=="00:50:8d:f5:a8:54", NAME="eth0"

# Force LAN connection to be "eth1" (udev default assignment: eth0)

# (LAN NIC = Lite-On 82c168 PNIC rev 32)

KERNEL=="eth*", SYSFS{address}=="00:a0:cc:60:c8:43", NAME="eth1"

# Force 1394 connection to be "eth2" (default assignment: eth1)

# (1394 connection = IEEE-1394 IPv4 over 1394 Ethernet)

KERNEL=="eth*", SYSFS{address}=="00:50:8d:00:00:f4:a8:54", NAME="eth2"
```

This worked perfectly... for about 3 weeks.  But some update that I've gotten in the last week or so (presumably to udev?) seems to be breaking things again.  Once again eth0 and eth1 have swapped positions (eth2, the IEEE1394 interface, oddly stays the same).  

I thought perhaps my /etc/udev/rules.d/49-nic.rules wasn't being read, so I deleted it and added my custom eth* rules to the top of /etc/udev/rules.d/50-udev.rules.  But that didn't seem to make any difference.

Then after discovering the udevtest script, I gave it a try.  Here's what I get:

```
> udevtest /class/net/eth0

main: looking at device '/class/net/eth0' from subsystem 'net'

wait_for_sysfs: file '/sys/class/net/eth0/address' appeared after 0 loops

udev_rules_get_name: rule applied, 'eth0' becomes 'eth1'

rename_net_if: changing net interface name from 'eth0' to 'eth1'

udev_device_event: renamed netif to 'eth1'

main: run: '/sbin/modprobe '

main: run: '/sbin/udev_run_devd net'

main: run: 'socket:/org/kernel/udev/monitor'

> udevtest /class/net/eth1

main: looking at device '/class/net/eth1' from subsystem 'net'

wait_for_sysfs: file '/sys/class/net/eth1/address' appeared after 0 loops

udev_rules_get_name: rule applied, 'eth1' becomes 'eth0'

rename_net_if: changing net interface name from 'eth1' to 'eth0'

udev_device_event: renamed netif to 'eth0'

main: run: '/sbin/modprobe '

main: run: '/sbin/udev_run_devd net'

main: run: 'socket:/org/kernel/udev/monitor'

> udevtest /class/net/eth2

main: looking at device '/class/net/eth2' from subsystem 'net'

wait_for_sysfs: file '/sys/class/net/eth2/address' appeared after 0 loops

udev_rules_get_name: rule applied, 'eth2' becomes 'eth2'

main: run: '/sbin/modprobe '

main: run: '/sbin/udev_run_devd net'

main: run: 'socket:/org/kernel/udev/monitor'

```

So if I'm reading this right, the rules ARE being processed and eth0 is supposed to be renamed to eth1 (and vice versa).  So why is it not actually happening?  Why does 00:50:8d:00:00:f4:a8:54 remain eth1, and 00:a0:cc:60:c8:43 remains eth0?

I'm running:kernel 2.6.15-gentoo-r5

baselayout 1.12.0_pre18

portage 2.1_pre9-r2

udev 090

Thanks to anyone who can help!

----------

## dswhite42

Some further notes:I noticed this text during the boot process:

```
udevd-event[2528]: rename_net_if: error changing net interface name: File exists

udevd-event[2606]: rename_net_if: error changing net interface name: File exists

udevd-event[2746]: rename_net_if: error changing net interface name: File exists
```

This made me suspect that the reason eth0 couldn't be renamed to eth1 was that an eth1 device had already been created by the time these udev rules were being run.  And since something had already determined which NICs would be eth0, eth1, and eth2, I couldn't swap any of their names with each other.

To test this, I tried these modified udev rules:

```
KERNEL=="eth*", SYSFS{address}=="00:50:8d:f5:a8:54", NAME="neweth0"

KERNEL=="eth*", SYSFS{address}=="00:a0:cc:60:c8:43", NAME="neweth1"

KERNEL=="eth*", SYSFS{address}=="00:50:8d:00:00:f4:a8:54", NAME="neweth2"
```

Sure enough, when I rebooted, ifconfig showed neweth0, neweth1, and neweth2 instead of eth0, eth1, and eth2.  So I'm guessing something in the latest udev package is triggering an event that causes eth0, eth1, and eth2 to be created, which cannot be overwritten by my custom eth0, eth1 and eth2 assignments.

I tried these various settings of RC_COLDPLUG in /etc/conf.d/rc just to see if it would help.  

```
RC_COLDPLUG="yes"

RC_COLDPLUG="!net.eth*"

RC_COLDPLUG="no"
```

None of them made any difference - the problem still remains.

----------

## dswhite42

There are so many smart people on these forums - doesn't anyone have an idea for me?   :Sad: 

I was wondering if it had to do with the hotplug/coldplug udev issues mentioned in Bug 130766, but I'm not sure how to formulate a solution based on that...

Any help would be greatly appreciated!

----------

## Corona688

Unless you've got only one network card, it's not a good idea to use the eth0/eth1/... names, because their ordering is arbitrary and meaningless;  they can change given changes to udev, changes to the kernel, changes to the order modules are loaded, changes to global weather patterns, clinical depression, and dirty looks.  udev can't rename a device to something that already exists, which makes it very hard to force a specific order if the other device got there first.  Give them unique names instead, with udev rules like

```

# Put in /etc/udev/rules.d/10-local.rules

# Note, mac address must be lower case!

KERNEL=="eth*", SYSFS{address}=="00:11:cc:22:ee:33", NAME="lan"

KERNEL=="eth*", SYSFS{address}=="34:56:78:9a:bc:de", NAME="wan"
```

----------

## dswhite42

Well... I guess I can if worse comes to worse.  It'll mean a lot of rewriting of iptables scripts and other such things that are hardcoded for eth0 and eth1.  It's just frustrating that the rules that were supposed to make it work did fix the problem... then 3 weeks later something apparently came along in udev 090 that broke it again.   :Sad: 

----------

## Corona688

 *dswhite42 wrote:*   

> Well... I guess I can if worse comes to worse.  It'll mean a lot of rewriting of iptables scripts and other such things that are hardcoded for eth0 and eth1.  It's just frustrating that the rules that were supposed to make it work did fix the problem... then 3 weeks later something apparently came along in udev 090 that broke it again.  

  I know the feeling, but this has been a perennial problem in linux since the beginning, unique names might be the first and only dependable solution I've seen for it.

----------

## Genone

 *dswhite42 wrote:*   

> It'll mean a lot of rewriting of iptables scripts and other such things that are hardcoded for eth0 and eth1.

 

sed should make that rather easy, no?

----------

## guero61

You should be able to control this behaviour with /etc/modules.conf (/etc/modules.d/*) - I don't recall the precise syntax, but it goes something like:

```

alias eth0 eepro100

```

I do not recall how to force a specific one (of many) eepro100 to a given 'ethX' interface, but IIRC that's the right way to do it.

----------

## TGL

 *dswhite42 wrote:*   

> So if I'm reading this right, the rules ARE being processed and eth0 is supposed to be renamed to eth1 (and vice versa).  So why is it not actually happening?  Why does 00:50:8d:00:00:f4:a8:54 remain eth1, and 00:a0:cc:60:c8:43 remains eth0?

 

Probably because the MAC address is not setup yet in sysfs when udev process the rules, at coldplug time. This happened to me too, see this thread.

An udev level workaround is this rule, to be put somewhere before your renaming rules : 

```
ACTION=="add", SUBSYSTEM=="net", WAIT_FOR_SYSFS="device/driver"
```

As for the real fix, it is at kernel level (it makes the sysfs infos be exposed on time for udev to access them): 

```
--- linux/net/core/dev.c.orig

+++ linux/net/core/dev.c

@@ -3042,11 +3042,11 @@ void netdev_run_todo(void)

 

       switch(dev->reg_state) {

       case NETREG_REGISTERING:

+         dev->reg_state = NETREG_REGISTERED;

          err = netdev_register_sysfs(dev);

          if (err)

             printk(KERN_ERR "%s: failed sysfs registration (%d)\n",

                    dev->name, err);

-         dev->reg_state = NETREG_REGISTERED;

          break;

 

       case NETREG_UNREGISTERING:
```

 This patch is in 2.6.17_preSomething, and works fine for me on 2.6.16 too (don't know for your 2.6.15 though).

----------

## dswhite42

Thanks to everyone for their help.  TGL, I appreciate your udev ideas, but unfortunately I'm still stuck.

My /etc/udev/rules.d/05-udev-early.rules now contains these lines (the last 4 lines added by me):

```
# ignore these events until someone needs them

SUBSYSTEM=="drivers",   OPTIONS="ignore_device"

SUBSYSTEM=="module",    OPTIONS="ignore_device"

# sysfs is populated after the event is sent

ACTION=="add", DEVPATH=="/devices/*", ENV{PHYSDEVBUS}=="?*", WAIT_FOR_SYSFS="bus"

ACTION=="add", SUBSYSTEM=="scsi", WAIT_FOR_SYSFS="ioerr_cnt"

ACTION=="add", SUBSYSTEM=="net", WAIT_FOR_SYSFS="address"

ACTION=="add", SUBSYSTEM=="net", WAIT_FOR_SYSFS="device/driver"

KERNEL=="eth*", SYSFS{address}=="00:50:8d:f5:a8:54", NAME="eth0"

KERNEL=="eth*", SYSFS{address}=="00:a0:cc:60:c8:43", NAME="eth1"

KERNEL=="eth*", SYSFS{address}=="00:50:8d:00:00:f4:a8:54", NAME="eth2"

```

Unfortunately the problem still remains, and eth0/eth1 are still randomly assigned to either 00:50:8d:f5:a8:54 or 00:a0:cc:60:c8:43 .  I see the following text during the boot process now:

```
udevd-event[2528]: rename_net_if: error changing net interface name: File exists

udevd-event[2606]: rename_net_if: error changing net interface name: File exists

...

wait_for_sysfs: waiting for '/sys/class/net/lo/device/driver' failed

wait_for_sysfs: waiting for '/sys/class/net/eth2/device/driver' failed
```

I see that eth0 and eth1 don't seem to appear in that list of wait_for_sysfs errors - maybe that means that the wait_for_sysfs command is working for eth0/eth1, and yet something is still preventing them from being renamed?

Is there a way to have the udev process output more debugging info?  I don't think it's outputting any debugging info, and I'm almost certain it's not putting anything in any log file either (nothing in /var/log/messages, dmesg, no files in /var/log that have any kind of "udev" name...)

----------

## billk

The following suggestion (from above) worked for me.  Got an error on eaiting for LO, but didnt seem to affect anything.

ACTION=="add", SUBSYSTEM=="net", WAIT_FOR_SYSFS="device/driver"

BillK

----------

## dswhite42

I've installed gentoo-sources-2.6.16-gentoo-r4 , which have the dev.c patch (that TGL mentioned) applied.  It unfortunately hasn't changed a thing.  

Can't imagine why this started happening with udev 090.  Guess I'll have to give up and just use names other than eth0 and eth1...   :Sad: 

----------

## jsivak

 *dswhite42 wrote:*   

> I've installed gentoo-sources-2.6.16-gentoo-r4 , which have the dev.c patch (that TGL mentioned) applied.  It unfortunately hasn't changed a thing.  
> 
> Can't imagine why this started happening with udev 090.  Guess I'll have to give up and just use names other than eth0 and eth1...  

 

This might be "old school", but I just use an init.d script to rename the interfaces at boot time. I do this on a firewall where I want to be absolutely sure wich NIC is eth0, eth1, etc..

```

#!/sbin/runscript

#

# for this script to work do the following:

#   1. Update /etc/init.d/net.eth0 to include

#   "need nameif" prior to the "use hotplug .." line.

#

#   2. Reassign the existing eth0, eth1, etc to

#      "unused" names so that we can reassign

#      them. The kernel will not "overwrite" an

#      existing device name (e.g. eth1 can't be renamed to eth0

#      until eth0 is "removed"/renamed.)

start() {

        # First rename the existing eth0, ...

        # Motherboard

        /sbin/nameif -s foo0 00:0f:ea:d1:cf:7a

        # 3Com 3c905b #1

        /sbin/nameif -s foo1 00:50:04:73:7a:dc

        # 3Com 3c905b #2

        /sbin/nameif -s foo2 00:50:04:ce:a9:9a

        # Now assign the "standard" names in the

        # preferred order

        # Motherboard

        /sbin/nameif -s eth0 00:0f:ea:d1:cf:7a

        # 3Com 3c905b

        /sbin/nameif -s eth1 00:50:04:73:7a:dc

        # 3Com 3c905b #2

        /sbin/nameif -s eth2 00:50:04:ce:a9:9a

}

```

The only unpleasant thing is that you'll need to update net.lo to depend on this script as well..

```

depend() {

    need nameif

        use coldplug hotplug pcmcia usb isdn wlan isapnp

        # Load any custom depend functions for the given interface

        # For example, br0 may need eth0 and eth1

        local iface=${myservice##*.}

        [[ $( type -t depend_${iface} ) == "function" ]] && depend_${iface}

}

```

----------

## Corona688

 *dswhite42 wrote:*   

> Unfortunately the problem still remains, and eth0/eth1 are still randomly assigned to either 00:50:8d:f5:a8:54 or 00:a0:cc:60:c8:43 .  I see the following text during the boot process now:[code]udevd-event[2528]: rename_net_if: error changing net interface name: File exists
> 
> udevd-event[2606]: rename_net_if: error changing net interface name: File exists

  As already explained, it's name collision.  To avoid this, rename these interfaces to things the kernel isn't already trying to eat up...  I managed to "fix" the order of eth0 eth1 etc. in udev once, then swapped the cards, and it broke again!  It only ever works without collision under very, very specific and hard-to-reproduce circumstances.  Naming them something other than eth* prevents this.  Also, compile your network drivers as modules.

----------

## UberLord

 *jsivak wrote:*   

> The only unpleasant thing is that you'll need to update net.lo to depend on this script as well..

 

Actually you can get nameif to come before net.lo

```
depend() {

   before net.lo

}
```

Just make sure that nameif is then in the boot runlevel

----------

## jsivak

 *UberLord wrote:*   

> 
> 
> Actually you can get nameif to come before net.lo
> 
> ```
> ...

 

Sweet! Thanx for the info.

----------

## thepustule

As long as the two network interfaces on your system don't use the exact same driver, you should be able to specify the driver load order in /etc/modules.autoload.d/kernel-2.6

IIRC, the manual module load that reads this file gets processed before coldplug, so you get to specify before the whole automatic thing happens.

I normally go a step further and compile the driver I want for eth0 statically into the kernel, and the other ones as modules.  At least that way I know for sure which one will be eth0.  This normally works ok, unless I have five interfaces that are the exact same model.  One driver.  Oyyyyyy

----------

## Monkeh

 *thepustule wrote:*   

> As long as the two network interfaces on your system don't use the exact same driver, you should be able to specify the driver load order in /etc/modules.autoload.d/kernel-2.6
> 
> IIRC, the manual module load that reads this file gets processed before coldplug, so you get to specify before the whole automatic thing happens.

 

'fraid not. Tried that with my machine the other day, it just picked randomly. udev autoloads modules before the modules init script (which is what loads modules listed in /etc/modules.autoload.d/kernel-2.6, afaik) runs.

----------

## thepustule

 *Monkeh wrote:*   

>  udev autoloads modules before the modules init script (which is what loads modules listed in /etc/modules.autoload.d/kernel-2.6, afaik) runs.

 

Are you sure about that?  I don't believe it is the job of udev to load modules.  udev just populates the /dev tree.  If you remove coldplug from your default runlevel, and reboot, so that only udev and modules init runs, I believe you'll see that no modules get loaded other than what you specify in modules.autoload.d

<ADDED>

Oh the pain!  I see what's going on - there's a major change to udev coming down, which adds module autoloading into udev itself.  WHY!!!!!!

I guess this isn't the time to debate the craziness of running unstable udev and baselayout, but that is why I couldn't reproduce the problem you are having.  

It's strange that on the udev site itself it explains clearly in the FAQ that module autoloading is not the intended job of udev.  I wonder why the gentoo people would be going down this path then?  

Painful!

----------

## Monkeh

There's nothing crazy about ~amd64 udev and baselayout. They're utterly rock solid (as is my entire system).

The udev changes piss me off quite badly. It's unwanted behavior which, despite all my fiddling, I've been unable to change thus far..

----------

## thepustule

Is it possible in any way to lobby the devs NOT to combine autoloading into udev?

----------

## Monkeh

 *thepustule wrote:*   

> Is it possible in any way to lobby the devs NOT to combine autoloading into udev?

 

I just did a bit of extra reading, you can use module blacklists to disable it.. But I'd rather have it not there or be optional in the firstplace.

E: and infact I tried module blacklisting on this machine when I was trying to get my NICs the way I wanted them, and it didn't work.

----------

## thepustule

Yeah - that's scary.

Check out http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev-FAQ questions 4 and 5.  I can't understand why gentoo would go this way when it's specifically not intended by udev itself.

----------

## Genone

 *thepustule wrote:*   

>  *Monkeh wrote:*    udev autoloads modules before the modules init script (which is what loads modules listed in /etc/modules.autoload.d/kernel-2.6, afaik) runs. 
> 
> Are you sure about that?  I don't believe it is the job of udev to load modules.  udev just populates the /dev tree.  If you remove coldplug from your default runlevel, and reboot, so that only udev and modules init runs, I believe you'll see that no modules get loaded other than what you specify in modules.autoload.d
> 
> <ADDED>
> ...

 

It is really udev doing that automagic crap unfortunately.

----------

## thepustule

On the udev FAQ, question 4 and 5 specifically state that udev is NOT supposed to do that.  Why would gentoo go down a different path like this?

----------

## Genone

 *thepustule wrote:*   

> On the udev FAQ, question 4 and 5 specifically state that udev is NOT supposed to do that.  Why would gentoo go down a different path like this?

 

This isn't a Gentoo thing. FYI, the Gentoo udev maintainer is also the upstream udev author. You'll have to ask him.

----------

## thepustule

Aaaah.

Well, that's different, I guess...

If that's the way udev is really going, I guess we'll have to adapt.

----------

## Monkeh

 *thepustule wrote:*   

> Aaaah.
> 
> Well, that's different, I guess...
> 
> If that's the way udev is really going, I guess we'll have to adapt.

 

Or mask >=udev-089.

----------

## maKKus

This is also bringing met to the brink of madness, Why o why does the boot behavior change everytime udev is updated......

I do not want /etc/init.d/net.eth0 and /net/init.d/net.wlan0 to autostart. I'm in command of what is happening at boot. And if not I want to now who is and how I can disable it.

----------

