NIC Naming

繁體中文版

Remember, not so long ago, the NIC names were eth0, eth1, etc. With the file /etc/udev/rules.d/70-persistent-net.rules, the MAC address of the NIC is tied to the name, like eth0. So if you have multiple NICs in your computer, every time you boot or reboot the computer you get a predictable and consistent names of the NICs. eth0 is always eth0, eth1 is always eth1 and so on.

Then systemd enters the picture. And now when you boot or reboot your computer, you do not get a predictable nor a consistent naming of the NICs. What used to be eth0 may now be called eth2. and what used to be eth1 may now be called eth0. What a total mess! The result is that nobody can connect to the internet. The file /etc/udev/rules.d/70-persistent-net.rules:

SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:0c:f1:73:93:51", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:26:5a:79:b5:9c", ATTR{type}=="1", KERNEL=="eth*", NAME="eth1"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:17:9a:bb:4e:7a", ATTR{type}=="1", KERNEL=="eth*", NAME="eth2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:19:5b:2e:fd:47", ATTR{type}=="1", KERNEL=="eth*", NAME="eth3"

is not working anymore and /etc/sysconfig/network-scripts/ifcfg.eth0 with an entry HWADDR=<mac-address> is just ignored.

Every time I reboot my server, I have to cross my fingers, hoping that at least eth0 will be setup correctly. At least, I can ssh to my server and try to fix the others. But often enough, I don't get the desired result.

So the developers came out with suggestions on how to get a predictable network interface names. In short, do not use the name eth anymore. Use names like wan0, lan1 or based on the location of the NIC on the motherboard, a horrid name like enp5s0.  I refuse to follow this suggestion as I have already setup my iptables rules using the names eth0, eth1, eth2 and eth3.

I am using Fedora 20, so what I describe below may not work in other distributions.

My server is a router for the student LANs and I am using 4 NICs:

eth0 is connected to the internet
eth1 (192.168.1.0/24) is NATed to eth0
eth2 (192.168.2.0/24) is NATed to eth0
eth3 (192.168.3.0/24) is NATed to eth0

So, as you can see, if the NIC names eth0, eth1, eth2 and eth3 get mixed up, then nobody can connect to the internet.

Fortunately eth0 is using the kernel module e1000 and the rest are using skge. So I created a file, I named nic.conf, with the content:

blacklist skge

and placed this file in /etc/modprobe.d/. This will blacklist skge kernel module. This means that the kernel module skge will not be loaded during boot. Now I have only one NIC, so eth0 will always be setup correctly. At least now I can ssh to this server every time I reboot. Then I ssh to the server and fix the other NICs. But this is still a very tedious work to do.

I have read a lot of articles in the internet on how to solve this problem. I tried the different suggestions but never found a solution that worked. Finally I found this article. I read and reread it many times until I found the one that talked about "Using the ethtool and ip programs." At first, I dismissed it as I didn't think it was workable. But that gave me an idea of what to do next.

Based on this suggestion, I wrote a bash script (I called it reneth) that first rename eth1 to not_eth1, eth2 to not_eth2 and eth3 to not_eth3. Then according to each NIC MAC address, I rename it back to either eth1, eth2 or eth3. And it works! To automate the process, I execute this script from /etc/rc.d/rc.local.

The script:

#!/bin/bash
#
# Module skge for eth1, eth2 and eth3 is blacklisted in /etc/modprobe.d/nic.conf
# to ensure that after a reboot, eth0 (using module e1000) is setup correctly.
# At least I can ssh to NATcr!
# The following script is named reneth.
# To automate this process after every reboot, execute this script from /etc/rc.d/rc.local.
# Get MAC address of current eth1, eth2 and eth3.
# Then rename:
# eth1 ==> not_eth1
# eth2 ==> not_eth2
# eth3 ==> not_eth3
# Based on the MAC address, find which MAC belongs to eth1, eth2 or eth3.
# and rename the NIC accordingly to eth1, eth2 or eth3.
#
# Fr. Visminlu Vicente L. Chua, S.J.
# 2014/07/23
#
# Install NIC module skge
#
/usr/sbin/modprobe skge

#
# Get current MAC address of eth1, eth2 and eth3.
#
eth_1=`grep -H . /sys/class/net/eth1/address`
eth_2=`grep -H . /sys/class/net/eth2/address`
eth_3=`grep -H . /sys/class/net/eth3/address`

#
# The correct MAC address of eth1, eth2 and eth3
#
eth1Mac="00:26:5a:79:b5:9c"
eth2Mac="00:17:9a:bb:4e:7a"
eth3Mac="00:19:5b:2e:fd:47"

#
# Rename eth1, eth2 and eth3 to not_eth1, not_eth2 and not_eth3
#
/usr/sbin/ip link set dev eth1 name not_eth1
/usr/sbin/ip link set dev eth2 name not_eth2
/usr/sbin/ip link set dev eth3 name not_eth3

#
# find eth1
#
if [[ $eth_1 == *$eth1Mac* ]] ; then
   /usr/sbin/ip link set dev not_eth1 name eth1
elif [[ $eth_1 == *$eth2Mac* ]] ; then
   /usr/sbin/ip link set dev not_eth2 name eth1
elif [[ $eth_1 == *$eth3Mac* ]] ; then
   /usr/sbin/ip link set dev not_eth3 name eth1
fi

#
# find eth2
#
if [[ $eth_2 == *$eth1Mac* ]] ; then
   /usr/sbin/ip link set dev not_eth1 name eth2
elif [[ $eth_2 == *$eth2Mac* ]] ; then
   /usr/sbin/ip link set dev not_eth2 name eth2
elif [[ $eth_2 == *$eth3Mac* ]] ; then
   /usr/sbin/ip link set dev not_eth3 name eth2
fi

#
# find eth3
#
if [[ $eth_3 == *$eth1Mac* ]] ; then
   /usr/sbin/ip link set dev not_eth1 name eth3
elif [[ $eth_3 == *$eth2Mac* ]] ; then
   /usr/sbin/ip link set dev not_eth2 name eth3
elif [[ $eth_3 == *$eth3Mac* ]] ; then
   /usr/sbin/ip link set dev not_eth3 name eth3
fi

This solves my problem and I am hoping this will also help you with your problem.

Fr. Visminlu Vicente L, Chua, S.J.
2014/07/26