Xen/XCP-ng Hypervisor Network Interface Controller Solution to Set Static MAC Assignments to Prevent Out-of-Order / Re-ordering of NIC Numbering
Problem Description
XCP-ng can sometimes skip NIC numbers (e.g., having eth0-4, then eth6-7, missing eth5) or renumber NICs after hardware changes, BIOS updates, or system updates. This causes:
- Inconsistent NIC naming with gaps in numbering
- Broken network configurations after reboots
- VMs losing network connectivity
- Duplicate NICs with the same MAC address appearing
- Management interface becoming unreachable
Step-by-Step Solution to Set Static MAC Assignments
Step 1: Create Static Rules for All Interfaces
First, backup the current configuration:
cp -r /etc/sysconfig/network-scripts/interface-rename-data /root/interface-rename-backup-$(date +%Y%m%d)
Get your current MAC addresses:
# List all current NICs with their MAC addresses
xe pif-list params=device,MAC
Then edit the static rules file:
vi /etc/sysconfig/network-scripts/interface-rename-data/static-rules.conf
Add these rules based on your current MAC addresses (replace with YOUR actual MACs):
# Static rules to ensure consistent NIC naming
eth0: mac = "aa:bb:cc:dd:ee:00"
eth1: mac = "aa:bb:cc:dd:ee:01"
eth2: mac = "aa:bb:cc:dd:ee:02"
eth3: mac = "aa:bb:cc:dd:ee:03"
eth4: mac = "aa:bb:cc:dd:ee:04"
eth5: mac = "aa:bb:cc:dd:ee:05"
eth6: mac = "aa:bb:cc:dd:ee:06"
Note: If you’re fixing a gap in numbering (e.g., you have eth6 and eth7 but no eth5), map the MAC from eth6 to eth5, and eth7 to eth6 in your static rules.
Step 2: Clear Dynamic Rules
Clear the dynamic rules to prevent conflicts:
echo '{"lastboot": [], "old": []}' > /etc/sysconfig/network-scripts/interface-rename-data/dynamic-rules.json
Step 3: Regenerate udev Rules
Regenerate the network naming rules:
/etc/sysconfig/network-scripts/interface-rename.py --update-udev-rules
Step 4: Update XCP-ng Database
Before rebooting, you may need to update the XCP-ng database to reflect the changes. First, put the host in maintenance mode if it’s in a pool:
xe host-disable uuid=$(xe host-list name-label=$(hostname) --minimal)
Step 5: Reboot
Reboot the host for the changes to take effect:
reboot
Step 6: Verify After Reboot
After reboot, verify the new naming:
xe pif-list params=uuid,device,MAC,host-name-label
ip link show
Handling Stale or Duplicate NICs After Reboot
If after reboot you see duplicate NICs (both showing the same MAC address), you need to remove the stale entries.
Identify and Remove Duplicates
# Find PIFs with duplicate MACs
xe pif-list params=uuid,device,MAC
# Look for entries where two different devices show the same MAC
# Remove the stale PIF using its UUID
xe pif-forget uuid=<STALE-PIF-UUID>
# Rescan PIFs
xe pif-scan host-uuid=$(xe host-list name-label=$(hostname) --minimal)
# Reboot again
reboot
Complete Verification Process
After the final reboot, perform these verification steps:
1. Verify Current NIC Configuration
First, check that all NICs are properly numbered without gaps:
# Check all PIFs with their device names and MACs
xe pif-list params=device,MAC,host-name-label | grep -E "device|MAC|host-name" | paste - - - | sort
# Check that you have eth0 through eth6 (no gaps)
for i in {0..6}; do
echo -n "eth$i: "
xe pif-list device=eth$i params=MAC --minimal
done
2. Verify No Duplicate MACs
Check for any duplicate MAC addresses:
# List all MACs and check for duplicates
xe pif-list params=MAC --minimal | tr ',' '\n' | sort | uniq -d
This should return nothing if there are no duplicates.
3. Verify Static Rules Are In Place
Check that your static rules are properly configured:
# View the static rules
cat /etc/sysconfig/network-scripts/interface-rename-data/static-rules.conf
# Verify the rules match your current configuration
echo "=== Comparing static rules to actual MACs ==="
for i in {0..6}; do
actual_mac=$(xe pif-list device=eth$i params=MAC --minimal 2>/dev/null)
static_mac=$(grep "^eth$i:" /etc/sysconfig/network-scripts/interface-rename-data/static-rules.conf | awk -F'"' '{print $2}')
echo "eth$i: static=$static_mac actual=$actual_mac $([ "$static_mac" = "$actual_mac" ] && echo "✓ MATCH" || echo "✗ MISMATCH")"
done
4. Check udev Rules
Verify the udev rules were regenerated correctly:
# Check the timestamp to ensure it was recently updated
ls -la /etc/udev/rules.d/60-net.rules
# View the generated rules
cat /etc/udev/rules.d/60-net.rules
5. Verify Network Bonds/VLANs (if applicable)
If you have any bonds or VLANs configured, verify they’re still associated with the correct PIFs:
# Check bonds
xe bond-list params=uuid,master,slaves
# Check VLANs
xe vlan-list params=uuid,tagged-PIF,untagged-PIF,tag
Expected Results
After successful configuration, you should see:
- Sequential NICs: eth0, eth1, eth2, eth3, eth4, eth5, eth6 (no gaps)
- No duplicates: Each NIC has a unique MAC address
- Static rules match: All static rules in the config file match actual NICs
- Persistent naming: NICs maintain their names after reboots
Example of correct output:
eth0: aa:bb:cc:dd:ee:00
eth1: aa:bb:cc:dd:ee:01
eth2: aa:bb:cc:dd:ee:02
eth3: aa:bb:cc:dd:ee:03
eth4: aa:bb:cc:dd:ee:04
eth5: aa:bb:cc:dd:ee:05
eth6: aa:bb:cc:dd:ee:06
Important Files
/etc/sysconfig/network-scripts/interface-rename-data/static-rules.conf
- Contains MAC-to-interface name mappings
- Overrides dynamic detection
- Persists across reboots and updates
/etc/sysconfig/network-scripts/interface-rename-data/dynamic-rules.json
- Contains boot-time detected mappings
- Should be cleared when setting static rules
- Automatically regenerated each boot
/etc/udev/rules.d/60-net.rules
- Generated udev rules for network naming
- Created from static and dynamic rules
- Applied during boot process
Troubleshooting
Issue: NIC numbers still have gaps after reboot
- Verify static rules file has correct MAC addresses
- Ensure dynamic rules were cleared
- Check for typos in MAC addresses (must be lowercase)
- Regenerate udev rules and reboot again
Issue: Duplicate MACs persist after xe pif-forget
- List all PIFs to find all duplicates:
xe pif-list params=uuid,device,MAC
- Remove ALL duplicate PIFs except one
- Run
xe pif-scan
to rescan - Reboot the host
Issue: Lost management interface after changes
- Access via physical console or IPMI
- Run
xsconsole
from command line - Navigate to “Network and Management Interface”
- Reconfigure management interface on correct NIC
Issue: NICs revert to old naming after XCP-ng update
- Check if static rules file still exists
- Verify
/etc/sysconfig/network-scripts/interface-rename.py
hasn’t been replaced - Regenerate udev rules
- Reboot
Additional Notes
Some hardware (Intel X550, X710, Broadcom mezzanine cards) may present ports out of physical order. Static MAC rules will let you map them to match physical port layout if desired.
This guide only affects OS-level NIC naming in XCP-ng. It does not change BIOS/UEFI boot order or IPMI/iDRAC/iLO port assignments.
Why This Works
Static MAC-based rules provide reliable NIC naming because:
- MAC addresses are unique and don’t change
- Static rules override boot-time detection order
- Rules persist through all system updates and hardware changes
- Uses XCP-ng’s native interface rename system
Conclusion
Once static MAC-based rules are configured, your NICs will maintain consistent names regardless of system changes. The key is mapping each physical NIC’s MAC address to a specific ethX name in the static rules file. If you want to remove a NIC (or move it to a different slot) and you have Network Appliances or Storage Servers running in VMs (eg pfSense/OPNsense, WAZUH, NFS/SMB, etc) then you may have noticed the NIC ordering can change, cause chaos and headaches in your VMs. Hopefully, this guide helps!