NetworkManager is bloat

Or how I came to love dhcpcd and iwd for all of my networking needs...

Background§

I have a weird fascination with running as little software as possible on my machines.

For whatever reason, minimizing RAM usage scratches some weird itch of mine. And no, it's not infected. At least, I hope not...

Anyways, after watching a video on installing Arch Linux for fun (don't judge me), the presenter Ermanno (who's videos I VERY HIGHLY RECOMMEND) covered a change to the install process that Arch Linux made recently.

Or I suppose a more accurate description is a change that Arch Linux made to how to connect to a wireless network when you're installing. Keep in mind that the standard Arch Linux install process doesn't have a GUI or any desktop environment with a graphical installer. There's no comfy icon to click on to configure networking, nothing.

Out of curiousity, I started looking into this new replacement sofware - iwd.

Once I started falling down that rabbit hole, I discovered just how unnecessary NetworkManager is in my setup.

Why this works for me§

Like I said, I run a minimal setup. This means I don't need nor want big fancy GUI's for my tools.

To give an example, I run:

  • A tiling window manager (i3, bspwm, sway, river are all on regular rotation...)
  • A CLI or ncurses-UI for connecting to wifi (this was nmtui when I was using NetworkManager).
  • A CLI VPN with no visual feedback or need to graphically configure said VPN.
  • I don't connect to esoteric modems like PPPOE, etc from my laptop or desktop.

With all this in mind, all of the "extra" features (read: bloat) of NetworkManager mean that I'm paying a pretty steep cost in terms of dependencies and memory usage for things I simply don't need.

Note that there are some GUI tools for dhcpcd and iwd at this point, so check those out on the Arch Wiki if you're really curious.

How to make the change§

If you want to make the change yourself, it's actually pretty easy. I recommend doing things in this order, because if you can't get iwd/dhcpcd to work to your liking, it's trivial to go back to NetworkManager.

Install iwd and dhcpcd (and openresolv)§

We need all three applications. In short, dhcpcd handles the DHCP handshake (and thus giving you an IP address) when a connection is established, like plugging in an ethernet cable or connecting to a wifi network with iwd. As stated iwd handles wireless connections, that's it.

Lastly, openresolv (a resolvconf implementation) handles the DNS configuration (mostly the maintenance of your /etc/hosts file). dhcpcd works with openresolv automatically, you can read its documentation for more details.

I did mess around with using systemd-resolvd to have one less dependency, but ran into several issues with DNS configuration reliability. Just use openresolv and you'll be much happier.

On Arch, I installed all necessary software with pacman like so:

# pacman -S iwd dhcpcd openresolv

Disable NetworkManager and wpa_supplicant§

Now that you've downloaded the necessary software, you've got to shutdown NetworkManager and wpa_supplicant to prevent conflicts between the two sets of software.

# systemctl stop NetworkManager wpa_supplicant

Note: Obviously, you'll lose internet at this point.

Start iwd and dhcpcd§

With NetworkManager and its wireless sidekick taken care of, spin up iwd and dhcpcd.

# systemctl start iwd dhcpcd

Wifi setup§

dhcpcd handles all wired connections automatically, so if you're already connected with an ethernet cable you're done.

But, if you need to connect to a wireless network (as I'd wager 99.99% of people reading this do...), you'll need to configured iwd to know about your wireless network.

To do so you can use the delightful companion for iwd - iwctl.

You can run iwctl directly, type help, and then follow the corresponding documentation. Alternatively, you can pass all of your commands directly to iwctl, as I demonstrate at the end of this section.

In my case, I simply needed to type the following:

$ iwctl
[iwd]# device list
wlan0 ...

I simply wanted to ensure that a wireless device was recognized, and it was. This isn't actually required to connect to an access point.

[iwd]# station wlan0 scan

Wait a few seconds as iwd looks up all the networks in your area...

[iwd]# station wlan0 connect "MyNetworkName"

Enter password when prompted and wait ~10 seconds to ensure you don't get an error back. If you do, you likely mistyped your password or your wifi is on the fritz.

Note that you can press Tab to autocomplete pretty much all commands, including the wireless name above.

[iwd]# quit

Exit out of the application.

Note that instead of using the iwctl REPL, you can just feed the associated commands directly to iwctl, like so:

$ iwctl station wlan0 connect "MyNetworkName"

I do like the REPL, as it holds your hand (if necessary), supports tab completion and just feels polished. Use whatever method you prefer.

Ensure you've got an IP address§

You may need to wait a few seconds as iwd and dhcpcd do their corresonding thaaangs, but you should receive an IP address that looks somewhat familiar. You can check this with the ip command.

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    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
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 60:e1:86:87:bc:89 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.217/24 brd 192.168.1.255 scope global dynamic noprefixroute wlan0
       valid_lft 33914sec preferred_lft 28514sec
    inet6 fd22:f6c3:4e66::a7e/128 scope global dynamic noprefixroute
       valid_lft 35181sec preferred_lft 35181sec
    inet6 2600:6c52:7b00:55aa::a7e/128 scope global dynamic noprefixroute
       valid_lft 35181sec preferred_lft 35181sec
    inet6 fd22:f6c3:4e66:0:dcb8:7af:18a1:8bd9/64 scope global mngtmpaddr noprefixroute
       valid_lft forever preferred_lft forever
    inet6 2600:6c52:7b00:55aa:9af:4ba4:ee9b:d32d/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 573699sec preferred_lft 573699sec
    inet6 fe80::1f0:1103:da4d:ee9b/64 scope link
       valid_lft forever preferred_lft forever

While that might seem like a wall of text, the 192.168.1.217 under wlan0 is what I'm looking for and tells me that I'm properly connected to my home network.

You can confirm network + DNS connectivity with a simple:

$ ping austindw.com

Or use google.com, whatever you want...

If everything looks good, you can make the switch permanent:

# systemctl enable dhcpcd iwd
# systemctl disable NetworkManager wpa_supplicant

Reboot, and you should come up with a perfectly working internet connection.

How to revert§

If you run into issues and you want to switch back, simply do:

# systemctl disable --now dhcpcd iwd
# systemctl enable --now NetworkManager wpa_supplicant

This will immediately stop dhcpcd and iwd, then start NetworkManager and wpa_supplicant. With these commands, you'll even be safe to reboot and still use NetworkManager.

Results§

"But Austin, I just replaced two networking programs with two more networking programs, how is this an improvement?"

Good question - if you measure the RAM usage before and after the switch, you should notice around a ~20MB reduction with the exact same end result.

Additionally, my wireless connections were much more stable with iwd than with NetworkManager. I used to have frequent disconnect/reconnect storms when I placed a decent amount of load on my wifi connection. I never quite tracked down the root cause, but the broader stroke of just replacing NetworkManager completely has yielded a much improved networking experience.

So I have less resource usage, and an extremely stable wireless network connection.

I'm never going back to NetworkManager if I can help it.

Hopefully this has helped convert you. Give it a try, and you just might be sold on the iwd + dhcpcd power couple for life.