Persistent Network Interface Naming: How to Fix eth0/eth1 Swapping on Reboot in Linux


2 views

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