Today, I was caught off guard by a change in Enterprise Linux 7.3. Apparently, systemd was assigning interface names like eno16780032 based on “garbage” data. I’m not really a fan of ANY of the names the modern schemes generate, what was the problem with eth#? But that’s beside the point. What hit me was that starting in 7.3 the garbage data is now being discarded and this results in a change in interface names. All this, in a point release. Here’s KB 2592561 that details the change. This applies to both Red Hat EL and CentOS, and presumably other members of the family based on RHEL 7.
The good news is that existing nodes that are updated are left alone. A file is generated to preserve the garbage data and your interface name. Unlike other udev rules, this one ONLY applies to existing systems that want to preserve the naming convention:
[root@kickstarted ~]# cat /etc/udev/rules.d/90-eno-fix.rules # This file was automatically generated on systemd update SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:50:56:95:de:4e", NAME="eno16780032"
As you can see, it’s based on the MAC. That’s the bad news. If you plan to use the node as a template to deploy other VMs, the resulting VMs will effectively receive “new” interfaces based on the new MAC, resulting in ens192 instead of eno16780032. This definitely introduces at least one minor issue: the eno16780032 configuration is left intact and the interface is missing, so every call to systemctl restart network generates an error. It can also cause other issues for you if you have scripts, tools, provisioning systems, etc., that are predicting your nodes will have interface names like ens192. This is not difficult to remedy, thankfully.
Fire up your golden image/template/whatever you call it. First, get rid of the udev “fix” rule, then rename the interface configuration file. Open that file and replace all references to the old device name with the new. In this example, the template is configured with DHCP, but whatever your file looks like, it’s the same process:
[root@kickstarted ~]# rm /etc/udev/rules.d/90-eno-fix.rules rm: remove regular file ‘/etc/udev/rules.d/90-eno-fix.rules’? y [root@kickstarted ~]# mv /etc/sysconfig/network-scripts/ifcfg-eno16780032 /etc/sysconfig/network-scripts/ifcfg-ens192 [root@kickstarted ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens192 # Generated by dracut initrd NAME="eno16780032" DEVICE="eno16780032" ONBOOT=yes NETBOOT=yes UUID="8eee2ae8-483f-4f86-842f-956f94085917" IPV6INIT=yes BOOTPROTO=dhcp TYPE=Ethernet [root@kickstarted ~]# vi /etc/sysconfig/network-scripts/ifcfg-ens192 [root@kickstarted ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens192 # Generated by dracut initrd NAME="ens192" DEVICE="ens192" ONBOOT=yes NETBOOT=yes UUID="8eee2ae8-483f-4f86-842f-956f94085917" IPV6INIT=yes BOOTPROTO=dhcp TYPE=Ethernet
If you are interested in disabling IPv6, be sure to refer to the new interface name or use all to disable it system-wide. Given the recent change, I decided not to rely on interface names:
[root@kickstarted ~]# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:50:56:95:de:4e brd ff:ff:ff:ff:ff:ff inet 1.2.3.4/26 brd 1.2.3.1 scope global dynamic ens192 valid_lft 43104sec preferred_lft 43104sec inet6 fe80::250:56ff:fe95:de4e/64 scope link valid_lft forever preferred_lft forever [root@kickstarted ~]# cat > /etc/sysctl.d/disableipv6.conf << EOF > net.ipv6.conf.all.disable_ipv6 = 1 > EOF [root@kickstarted ~]# sysctl -p [root@kickstarted ~]# systemctl restart network [root@kickstarted ~]# ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:50:56:95:de:4e brd ff:ff:ff:ff:ff:ff inet 1.2.3.4/26 brd 1.2.3.1 scope global dynamic ens192 valid_lft 43197sec preferred_lft 43197sec
You can now reboot the node and make sure it comes up alright before converting it back to a template.
Finally, don’t forget to update all references in documentation and external systems. If a script tries to look for /etc/sysconfig/network-scripts/ifcfg-eno16780032 it’s going to be very disappointed.
Again, this isn’t complicated, just tedious. Shame on Red Hat for making this change in a point release. It’s really odd, given their general insistence on sticking with EOL’ed software for a decade because that’s what was in the first GA release of the major version, like ruby 2.0.0 (EOL 3 years ago) or perl 5.16 (5.20 is the oldest supported). This was not the time to surprise people. Please, Red Hat, please have value for the time we’ve put into testing our own systems, much like we respect the time you’ve put into testing yours.
To me this doesn’t seem like a RHEL / systemd problem, it’s a Vmware problem (which one would know if they read the KB 2592561)
The underlying cause of the difference in names is due to the information passed up from the VMware bios (I don’t really know who to blame, since other OSes don’t seem to be confused, but whatever). The real issue is that RHEL broke the expected behavior in a point release. We normally only experience such behavior in major releases. It’s especially troublesome to me as nodes upgraded to 7.3 and nodes built with 7.3 have divergent behavior as well. This is not what I expect from point releases, though of course it’s Red Hat’s prerogative to make the changes.