Modern Linux distributions using systemd and udev often experience interface naming inconsistencies across reboots. The traditional eth0, eth1 convention becomes unreliable when:
- Multiple NICs of different types exist (GbE, 10GbE, etc.)
- Hardware detection order varies during boot
- NetworkManager attempts to manage multiple interfaces
The most robust approach is creating udev rules to bind physical NICs to specific interface names. Here's how:
# First identify your NIC's MAC address and PCI bus info
$ ip link show
$ ethtool -i eth0 | grep bus-info
# Create a custom udev rule
$ sudo vim /etc/udev/rules.d/70-persistent-net.rules
Example rule content:
# For built-in GbE controller (main NIC)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*",
ATTR{address}=="00:11:22:33:44:55", ATTR{type}=="1", NAME="eth0"
# Second GbE NIC
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*",
ATTR{address}=="00:11:22:33:44:56", NAME="eth1"
# 10GbE card
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*",
ATTR{address}=="00:11:22:33:44:57", NAME="eth2"
Some distributions (like RHEL/CentOS) include biosdevname which provides consistent naming based on BIOS information:
# Install biosdevname if not present
$ sudo apt install biosdevname # Debian/Ubuntu
$ sudo yum install biosdevname # RHEL/CentOS
# Add to kernel boot parameters
$ sudo vim /etc/default/grub
GRUB_CMDLINE_LINUX="biosdevname=1 net.ifnames=0"
$ sudo update-grub
For systems using NetworkManager, you can create connection profiles tied to specific interfaces:
# Example connection profile for eth0
$ sudo nmcli con add con-name "eth0-static" ifname eth0 type ethernet \
ip4 192.168.1.100/24 gw4 192.168.1.1
After making changes:
# Reload udev rules
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger
# Check interface naming
$ ip link show
# Test persistent naming across reboots
$ sudo reboot
- Race conditions: Add
WAIT_FOR="eth0"
to dependent services - MAC address changes: Some NICs (especially USB) may have mutable MACs
- Virtual interfaces: Apply different rules for virtual interfaces (veth*, tap*)
When dealing with multiple network interfaces (especially mixed-speed configurations like 1GbE and 10GbE), Linux systems may assign interface names (eth0, eth1, etc.) unpredictably across reboots. This becomes particularly problematic when:
- You have static IP configurations tied to specific interfaces
- Different networks are accessed through different physical ports
- NetworkManager or other services expect consistent device naming
The traditional approach using udev rules has been largely superseded by more robust methods:
# Check current naming scheme
$ sudo dmesg | grep -i "renamed network"
# Or alternatively:
$ ip -o link show | awk -F': ' '{print $2}'
Modern Linux distributions (systemd-based) use predictable naming schemes:
# List all available naming schemes
$ sudo networkctl list
# Example output showing physical locations:
eno1 ethernet onboard
enp3s0 ethernet PCI slot 3
enx78e7d1ea46da ethernet MAC-based
For legacy systems or specific requirements, create udev rules:
# Create a new udev rule file
$ sudo nano /etc/udev/rules.d/70-persistent-net.rules
# Example content:
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*",
ATTR{address}=="00:1a:4b:12:34:56", NAME="eth0"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*",
ATTR{address}=="00:1a:4b:12:34:57", NAME="eth1"
For systems using NetworkManager, create connection profiles with explicit interface names:
# Example nmcli command to create a connection
$ sudo nmcli con add con-name "corp-net" ifname eth0 type ethernet \
ip4 192.168.1.100/24 gw4 192.168.1.1
# Verify the configuration
$ nmcli con show "corp-net" | grep interface-name
When implementing these solutions, watch for:
- MAC address changes (especially with virtual machines)
- Conflicts between different naming methods
- Driver loading order affecting device detection
After making changes, test with:
# Bring interfaces down and up
$ sudo ip link set eth0 down && sudo ip link set eth0 up
# Check interface status
$ ip addr show eth0
# Verify NetworkManager connections
$ nmcli device status