Although numerous and significant changes have been introduced in recent versions of Red Hat Enterprise Linux/CentOS, one of the most hotly contested topics seems to center around network configuration. In older versions of RHEL/CentOS, the default means of configuring network interfaces was via network scripts and use of the Network Administration Tool, which is now deprecated. Additionally, the well-known net-tools are also considered obsolete, replaced by the less-familiar ip commands. From RHEL/CentOS 6 onward, emphasis is now placed on using NetworkManager for network configuration, as well as the aforementioned ip command set. As of RHEL/CentOS 7, NetworkManager is considered the default method for managing network configurations, though the RHEL development teams paid careful attention to ensure that the network scrips would still function, and that they play nice with NetworkManager. Note this passage from the RHEL Networking Guide describing the relationship between NetworkManager and the older networking scripts:
“Note that in Red Hat Enterprise Linux 7, NetworkManager is started first, and /etc/init.d/network checks with NetworkManager to avoid tampering with NetworkManager’s connections. NetworkManager is intended to be the primary application using sysconfig configuration files and /etc/init.d/network is intended to be secondary, playing a fallback role.”
Old habits die hard, however, and you’ll likely see a number of articles across the Internet that detail methods to workaround NetworkManager, describe NetworkManager as, “the devil,” or “the plague,” and claim that most of the difficulties that arise with network configuration in RHEL/CentOS 7 are due to NetworkManager. While I haven’t seen any catastrophic effects from NetworkManager’s use, if it isn’t properly configured or if you aren’t well versed in its syntax, it can certainly be confusing and produce unintended results. In this article we’ll attempt to reserve judgement, and walk you through both methods of network configuration and let you decide which you prefer. First, let’s begin with NetworkManager and some of the tools used for configuration.
NetworkManager
NetworkManager is described as a “dynamic network control and configuration daemon.” Though the traditional ifcfg scripts are supported, NetworkManager is intended to the be the default mechanism for network configuration in RHEL/CentOS 7. It offers fairly extensive control of a variety of network interface types, including more modern connectivity such as Wi-Fi, mobile broadband, infiniband, as well as traditional Ethernet connections. At Teknophiles, we primarily deal with server environments in which our primary concern is the latter – traditional static Ethernet configurations. As such, much of the added functionality that NetworkManager offers will be superfluous to our discussion here. More detail on NetworkManager can be found here.
nmcli
In a server environment, NetworkManager is primarily managed by two user interfaces, nmcli (command-line interface) and nmtui (text user interface). We’ll first detail nmcli, since that’s what many administrators will prefer. Additionally, we feel strongly that understanding the cli is important since it helps to understand what is being invoked behind the scenes when using the tui. In its simplest form nmcli produces basic interface information and DNS configuration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# nmcli eth0: connected to Wired connection 1 "eth0" ethernet (hv_netvsc), 00:15:5D:4C:16:16, hw, mtu 1500 ip4 default inet4 10.0.1.175/24 inet6 fe80::53f0:dfc9:b4d:bf95/64 lo: unmanaged "lo" loopback (unknown), 00:00:00:00:00:00, sw, mtu 65536 DNS configuration: servers: 10.0.0.11 10.0.0.21 domains: domain.com interface: eth0 |
More detail can be had by looking at a specific network device. This command is shorthand for “nmcli device show.” Note the connection name, “Wired connection 1”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# nmcli dev sh eth0 GENERAL.DEVICE: eth0 GENERAL.TYPE: ethernet GENERAL.HWADDR: 00:15:5D:4C:16:16 GENERAL.MTU: 1500 GENERAL.STATE: 100 (connected) GENERAL.CONNECTION: Wired connection 1 GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/1 WIRED-PROPERTIES.CARRIER: on IP4.ADDRESS[1]: 10.0.1.175/24 IP4.GATEWAY: 10.0.1.1 IP4.DNS[1]: 10.0.0.11 IP4.DNS[2]: 10.0.0.21 IP4.DOMAIN[1]: domain.com IP6.ADDRESS[1]: fe80::53f0:dfc9:b4d:bf95/64 IP6.GATEWAY: -- |
Using the connection name, we can also look at the connection detail, which produces quite a bit of output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# nmcli con sh "Wired connection 1" connection.id: Wired connection 1 connection.uuid: a1320e99-49df-39f5-8eaf-49c1ac44c76c connection.stable-id: -- connection.interface-name: -- connection.type: 802-3-ethernet connection.autoconnect: yes connection.autoconnect-priority: -999 connection.autoconnect-retries: -1 (default) connection.timestamp: 1522614721 connection.read-only: no connection.permissions: -- connection.zone: -- connection.master: -- connection.slave-type: -- connection.autoconnect-slaves: -1 (default) connection.secondaries: -- connection.gateway-ping-timeout: 0 connection.metered: unknown connection.lldp: -1 (default) 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- 802-3-ethernet.auto-negotiate: no 802-3-ethernet.mac-address: 00:15:5D:4C:16:16 802-3-ethernet.cloned-mac-address: -- 802-3-ethernet.generate-mac-address-mask:-- 802-3-ethernet.mac-address-blacklist: -- 802-3-ethernet.mtu: auto 802-3-ethernet.s390-subchannels: -- 802-3-ethernet.s390-nettype: -- 802-3-ethernet.s390-options: -- 802-3-ethernet.wake-on-lan: 1 (default) 802-3-ethernet.wake-on-lan-password: -- ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- ipv4.dns-options: (default) ipv4.dns-priority: 0 ipv4.addresses: -- ipv4.gateway: -- ipv4.routes: -- ipv4.route-metric: -1 ipv4.ignore-auto-routes: no ipv4.ignore-auto-dns: no ipv4.dhcp-client-id: -- ipv4.dhcp-timeout: 0 ipv4.dhcp-send-hostname: yes ipv4.dhcp-hostname: -- ipv4.dhcp-fqdn: -- ipv4.never-default: no ipv4.may-fail: yes ipv4.dad-timeout: -1 (default) ipv6.method: auto ipv6.dns: -- ipv6.dns-search: -- ipv6.dns-options: (default) ipv6.dns-priority: 0 ipv6.addresses: -- ipv6.gateway: -- ipv6.routes: -- ipv6.route-metric: -1 ipv6.ignore-auto-routes: no ipv6.ignore-auto-dns: no ipv6.never-default: no ipv6.may-fail: yes ipv6.ip6-privacy: -1 (unknown) ipv6.addr-gen-mode: stable-privacy ipv6.dhcp-send-hostname: yes ipv6.dhcp-hostname: -- ipv6.token: -- proxy.method: none proxy.browser-only: no proxy.pac-url: -- proxy.pac-script: -- GENERAL.NAME: Wired connection 1 GENERAL.UUID: a1320e99-49df-39f5-8eaf-49c1ac44c76c GENERAL.DEVICES: eth0 GENERAL.STATE: activated GENERAL.DEFAULT: yes GENERAL.DEFAULT6: no GENERAL.VPN: no GENERAL.ZONE: -- GENERAL.DBUS-PATH: /org/freedesktop/NetworkManager/ActiveConnection/1 GENERAL.CON-PATH: /org/freedesktop/NetworkManager/Settings/1 GENERAL.SPEC-OBJECT: -- GENERAL.MASTER-PATH: -- IP4.ADDRESS[1]: 10.0.1.175/24 IP4.GATEWAY: 10.0.1.1 IP4.DNS[1]: 10.0.0.11 IP4.DNS[2]: 10.0.0.21 IP4.DOMAIN[1]: domain.com DHCP4.OPTION[1]: requested_classless_static_routes = 1 DHCP4.OPTION[2]: requested_rfc3442_classless_static_routes = 1 DHCP4.OPTION[3]: subnet_mask = 255.255.255.0 DHCP4.OPTION[4]: requested_subnet_mask = 1 DHCP4.OPTION[5]: domain_name_servers = 10.0.0.11 10.0.0.21 DHCP4.OPTION[6]: ip_address = 10.0.1.175 DHCP4.OPTION[7]: requested_static_routes = 1 DHCP4.OPTION[8]: dhcp_server_identifier = 10.0.0.11 DHCP4.OPTION[9]: requested_nis_servers = 1 DHCP4.OPTION[10]: requested_time_offset = 1 DHCP4.OPTION[11]: broadcast_address = 10.0.1.255 DHCP4.OPTION[12]: requested_interface_mtu = 1 DHCP4.OPTION[13]: dhcp_rebinding_time = 453600 DHCP4.OPTION[14]: requested_domain_name_servers = 1 DHCP4.OPTION[15]: dhcp_message_type = 5 DHCP4.OPTION[16]: requested_broadcast_address = 1 DHCP4.OPTION[17]: routers = 10.0.1.1 DHCP4.OPTION[18]: dhcp_renewal_time = 259200 DHCP4.OPTION[19]: requested_domain_name = 1 DHCP4.OPTION[20]: domain_name = domain.com DHCP4.OPTION[21]: requested_routers = 1 DHCP4.OPTION[22]: expiry = 1523125322 DHCP4.OPTION[23]: requested_wpad = 1 DHCP4.OPTION[24]: requested_nis_domain = 1 DHCP4.OPTION[25]: requested_ms_classless_static_routes = 1 DHCP4.OPTION[26]: network_number = 10.0.1.0 DHCP4.OPTION[27]: requested_domain_search = 1 DHCP4.OPTION[28]: next_server = 0.0.0.0 DHCP4.OPTION[29]: requested_ntp_servers = 1 DHCP4.OPTION[30]: requested_host_name = 1 DHCP4.OPTION[31]: dhcp_lease_time = 518400 IP6.ADDRESS[1]: fe80::53f0:dfc9:b4d:bf95/64 IP6.GATEWAY: -- |
This is a pretty typical configuration for a RHEL/CentOS box in its default configuration. From this output we can determine a good bit of useful information which we’ll need to configure a static IP on our server. Note that these attributes all take the format “setting.property”, with the property value listed in the right-hand column. We can see here that the connection has a human-readable ID, called “connection.id,” which is arguably somewhat unwieldy:
1 2 3 |
connection.id: Wired connection 1 |
We can also see that the interface device is eth0, the connection type is Ethernet (802-3-ethernet), and this configuration was set by DHCP (auto).
1 2 3 4 5 |
GENERAL.DEVICES: eth0 connection.type: 802-3-ethernet ipv4.method: auto |
In a typical server configuration, you’ll likely want to change several of these parameters to match your environment or standard practices. We can use the nmcli command to bring up an interactive command line tool to edit an existing connection.
1 2 3 4 5 6 7 8 9 10 11 12 |
# nmcli con edit "Wired connection 1" ===| nmcli interactive connection editor |=== Editing existing '802-3-ethernet' connection: 'Wired connection 1' Type 'help' or '?' for available commands. Type 'describe [.]' for detailed property description. You may edit the following settings: connection, 802-3-ethernet (ethernet), 802-1x, dcb, ipv4, ipv6, proxy |
The “?”, “help”, or “h” command will bring up a quick reference of available commands.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
nmcli> ? ------------------------------------------------------------------------------ ---[ Main menu ]--- goto [ | ] :: go to a setting or property remove [.] | :: remove setting or reset property value set [. ] :: set property value describe [.] :: describe property print [all | [.]] :: print the connection verify [all | fix] :: verify the connection save [persistent|temporary] :: save the connection activate [] [/|] :: activate the connection back :: go one level up (back) help/? [<command></command>] :: print this help nmcli :: nmcli configuration quit :: exit nmcli ------------------------------------------------------------------------------ |
First, let’s create a more friendly connection name. Since we know this is a “connection” setting, type “goto connection” to enter the connection setting menu. Typing “print” or “p” will display the current values of this setting. The print command is contextual – it will display the values for your current location, in this case the connection menu.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
nmcli> goto connection You may edit the following properties: id, uuid, interface-name, type, permissions, autoconnect, autoconnect-priority, autoconnect-retries, timestamp, read-only, zone, master, slave-type, autoconnect-slaves, secondaries, gateway-ping-timeout, metered, lldp, stable-id nmcli connection> p ['connection' setting values] connection.id: Wired connection 1 connection.uuid: a1320e99-49df-39f5-8eaf-49c1ac44c76c connection.stable-id: -- connection.interface-name: -- connection.type: 802-3-ethernet connection.autoconnect: yes connection.autoconnect-priority: -999 connection.autoconnect-retries: -1 (default) connection.timestamp: 1522615921 connection.read-only: no connection.permissions: -- connection.zone: -- connection.master: -- connection.slave-type: -- connection.autoconnect-slaves: -1 (default) connection.secondaries: -- connection.gateway-ping-timeout: 0 connection.metered: unknown connection.lldp: -1 (default) |
We can now change connection.id value with the “set” command. Since the commands are contextual, we simply need to invoke the command as shown below. If we were not in the connection sub-menu, we would have to use the full setting.property format, connection.id, in our command.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
nmcli connection> set id static-eth0 nmcli connection> p ['connection' setting values] connection.id: static-eth0 connection.uuid: a1320e99-49df-39f5-8eaf-49c1ac44c76c connection.stable-id: -- connection.interface-name: -- connection.type: 802-3-ethernet connection.autoconnect: yes connection.autoconnect-priority: -999 connection.autoconnect-retries: -1 (default) connection.timestamp: 1522615921 connection.read-only: no connection.permissions: -- connection.zone: -- connection.master: -- connection.slave-type: -- connection.autoconnect-slaves: -1 (default) connection.secondaries: -- connection.gateway-ping-timeout: 0 connection.metered: unknown connection.lldp: -1 (default) |
We can see that our connection.id is now static-eth0, which is much easier to type or call in scripts, since it now lacks spaces and is much less generic. Before we continue, however, there’s one more important step. If you’ve ever configured a Cisco or other enterprise switch, you know that simply updating a config and walking away can be disastrous if you do not commit the running configuration. NetworkManager’s interactive configuration works much the same way – though you’ll see the changes to your interfaces immediately, those settings will not survive a restart unless you save the configuration. This is done with a simple “save” command.
1 2 3 4 5 |
nmcli connection> save persistent nmcli connection> quit |
Now let’s activate the changes and take a look at the results by looking at the connection properties again.
1 2 3 4 5 6 7 |
# nmcli con up id static-eth0 Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/2) # nmcli con sh static-eth0 | grep connection.id connection.id: static-eth0 |
If you’d prefer not to use the interactive editor, this can also be accomplished via the nmcli in a single command as follows.
1 2 3 |
# nmcli con modify "Wireless connection 1" connection.id static-eth0 |
Let’s move on to setting the interface to use a static IPv4 address. We’ll also disable IPv6 with this command as well.
1 2 3 |
# nmcli con modify static-eth0 ipv4.method manual ipv4.address 10.0.1.155/24 ipv4.gateway 10.0.1.1 ipv4.dns 10.0.0.11,10.0.0.21 ipv4.dns-search domain.com ipv6.method ignore |
As you can see, nmcli is quite powerful. With a single command, we can very quickly modify our network configuration, without the need for modifying networks scripts or other complicated configurations.
nmtui
The nmtui utility is a text user interface designed to perform many of the same functions as nmcli. Though some Linux sysadmins distrust UIs (we’ve seen bugginess in some UIs ourselves), nmtui provides a quick way to configure a network interface via NetworkManager.
1 2 3 |
# nmtui |
First, select the option to, “Edit a configuration,” then select, “Wired connection 1” from the list of Ethernet connections.
Next, edit the profile name, then highlight <Show> next to = IPv4 CONFIGURATION and press ENTER.
Set the following items, according to your environment:
Highlight <OK> when done and press ENTER.
Now go back to the initial NetworkManager TUI menu and select “Quit” to exit to the shell. Activate the new configuration as follows.
1 2 3 |
# nmcli con up id static-eth0 |
Finally, take a quick look at /etc/resolv.conf. You’ll notice that NetworkManager was kind enough to edit these values for you.
1 2 3 4 5 6 |
# Generated by NetworkManager search domain.com nameserver 10.0.0.11 nameserver 10.0.0.21 |
No School Like the Old School
As we previously stated, there’s still a great deal of loyalty to the old network scripts method for configuring networking in RHEL/CentOS 7. Since the RHEL devs made sure that network scripts still function as expected, there’s a fairly straightforward means of circumventing NetworkManager and using the network scripts. This is a boon to many sysadmins, who already have well-documented and streamlined processes in place for network configuration. To use the network scripts for configuring networking in RHEL/CentOS 7, first disable the NetworkManager.service.
1 2 3 4 5 6 7 8 |
# systemctl disable NetworkManager.service Removed symlink /etc/systemd/system/multi-user.target.wants/NetworkManager.service. Removed symlink /etc/systemd/system/dbus-org.freedesktop.NetworkManager.service. Removed symlink /etc/systemd/system/dbus-org.freedesktop.nm-dispatcher.service. # systemctl stop NetworkManager.service |
You may also elect to use the “systemctl mask” command, but this might make swapping back and forth to test each method a bit less trivial. If you’ve settled on using the network scripts for network management, we do recommend using “systemctl mask NetworkManager.service” in your final configuration.
Now that the NetworkManager daemon won’t restart upon reboot and won’t interfere with our manual configuration, we can configure our eth0 interface by creating or modifying the appropriate network script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# ifconfig eth0 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 10.0.1.152 netmask 255.255.255.0 broadcast 10.0.1.255 inet6 fe80::215:5dff:fe4c:1616 prefixlen 64 scopeid 0x20 ether 00:15:5d:4c:16:16 txqueuelen 1000 (Ethernet) RX packets 1901 bytes 258986 (252.9 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 862 bytes 196629 (192.0 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 # vi /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 NM_CONTROLLED=no ONBOOT=yes TYPE=Ethernet BOOTPROTO=static DEFROUTE=yes IPV4_FAILURE_FATAL=yes IPV6INIT=no IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_PEERDNS=yes IPV6_PEERROUTES=yes IPV6_FAILURE_FATAL=no HWADDR=00:15:5D:4C:16:16 IPADDR=10.0.1.155 PREFIX=24 GATEWAY=10.0.1.1 DNS1=10.0.0.11 DNS2=10.0.0.21 SEARCH=domain.com |
Make sure this is the ONLY network script that references this device and/or MAC address. This is especially relevant if NetworkManager has been previously running things and you have made manual changes.
After saving the configuration file, restart the network service.
1 2 3 |
# systemctl restart network |
Alternatively, bounce the network interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# ifdown eth0 && ifup eth0 # ifconfig eth0 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 10.0.1.155 netmask 255.255.255.0 broadcast 10.0.1.255 inet6 fe80::215:5dff:fe4c:1616 prefixlen 64 scopeid 0x20 ether 00:15:5d:4c:16:16 txqueuelen 1000 (Ethernet) RX packets 282 bytes 38878 (37.9 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 225 bytes 32272 (31.5 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 |
net-tools vs. ip
Lastly, we’ll complete the discussion by looking at the old net-tools vs the ip command. There’s really not much to say here, as the net-tools have been deprecated and haven’t been updated in ages. Yet I’m sure there are those to will cling to the old tools for quite some time – I certainly find myself still relying on ifconfig and route quite a bit. On the surface each tool offers much of the same information, though truth be told, to my over-40 eyes, the old tools do provide more pleasing output.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# ifconfig eth0 eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 10.0.1.155 netmask 255.255.255.0 broadcast 10.0.1.255 inet6 fe80::215:5dff:fe4c:1616 prefixlen 64 scopeid 0x20 ether 00:15:5d:4c:16:16 txqueuelen 1000 (Ethernet) RX packets 282 bytes 38878 (37.9 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 225 bytes 32272 (31.5 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 # ip a sh eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:15:5d:4c:16:16 brd ff:ff:ff:ff:ff:ff inet 10.0.1.155/24 brd 10.0.1.255 scope global eth0 valid_lft forever preferred_lft forever # route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default gateway 0.0.0.0 UG 100 0 0 eth0 10.0.1.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0 # ip r default via 10.0.1.1 dev eth0 proto static metric 100 10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.155 metric 100 |
Conclusion
As with most things Linux, there’s more than one way to skin the proverbial cat. Network configuration is no exception. Sometimes it’s difficult to let go of old methodologies and embrace the new, especially when you’ve been doing something the same way for many years. I think this is probably the case with some of the bad press surrounding NetworkManager, especially in server environments. On the other hand, older, simpler methods are sometimes faster and less error-prone than newer, less-familiar ones. In the end, it’s up to you decide which method you prefer, but both network scripts and NetworkManager should provide you the tools you need to successfully manage your Linux network configurations.