Exploring NetworkManager, D-Bus, systemd, and Raspberry Pi

Categories:

I had to create a new category named Hacking for this post. The end result is a Raspberry Pi outfitted with LEDs that will inform me of which network interfaces are activated. If you want to actually recreate what I’ve done you’re going to need:

A few days ago I was researching on Google and started off with this question: How do I get notified if a Linux network connection goes down? The top result on StackOverflow led me down the path of learning about technologies that, quite frankly, I hadn’t explored before. Those being:

Call me old-school, but I teethed on MkLinux and RedHat before there was a distribution called Fedora. /etc/sysconfig/network-scripts and /etc/init.d/network were the only game in town, and I simply hadn’t kept up with the latest in Linux-land.

Getting Started

You’re going to need a Raspberry Pi with Debian Jessie (or rather, Raspbian that is based upon Jessie). Head on over to the Raspbians download page and grab the release based upon Jessie. Hopefully this isn’t your first Raspberry rodeo, but if it is, once the .zip file is downloaded, go ahead and unzip 2015-09-24-raspbian-jessie.img.zip and then insert an SD card into your computer, determine what device it was associated with (hint: dmesg), and then:

Once the dd is complete, insert the SD card into your Raspberry Pi SD slot, connect it to your home router via Ethernet, and power it on. It should be visible shortly via Avahi and you can log in with:

As usual, the default password for the pi user is raspberry. Verify that you are indeed running Raspbian Jessie:

From here’s on I’m going to drop to the root user, so if a command fails due to lack of permissions, either sudo su or prepend the command with sudo. If you balk at running as root, see this post explaining why you’re a wimp.
Before proceeding, you might want to also run the following on your Pi:

to get the latest and greatest packages for Raspbian.

Installing NetworkManager

We want to manage our network interfaces with NetworkManager, so we need to install it. Now, the question is: why do we want to manage our network interface with NetworkManager? The answer is to take advantage of the messages NetworkManager places on the D-Bus when the status of “network” changes. After working with it a bit, I like to think of D-Bus as the Linux equivalent of the iOS and OS X NSNotificationCenter. When I want to listen for broadcasted events I subscribe to be notified when said events occur.
Let’s install NetworkManager then with:

While NetworkManager is installing, watch the console output. You’ll see at some point:

Now, this information is key. We are going to go into /etc/network/interfaces and remove a lot of information. Before that, let’s read a bit about how NetworkManager determines whether or not it (rather than something else), is going to manage interfaces.
Okay, three things to do to enable NetworkManager for our interfaces:

  • remove interface entries from /etc/network/interfaces
  • set managed=true in /etc/NetworkManager/NetworkManager.conf
  • /etc/init.d/network-manager restart

After this our files look like:

And then:

You will see in the systemd logs that NetworkManager is struggling with wlan0. We’ll fix that momentarily, but first, take a look at your interfaces with nmcli (NetworkManager CLI):

So far so good. Our Ethernet device is up and connected (which if it weren’t we would have gotten knocked out of our ssh session).

Configuring WiFi

I will confess that this next part took a little trial and error, but hey, that’s what hacking is all about. Without ever having been exposed to NetworkManager one expects to fiddle with the parameters a bit to make things work. Here we go:

Of course, replace MYSSID and MYPSK with your own SSID and pre-shared key.

All of this was sorted out by reading the RedHat documentation.
Before enabling the connection, kill any wpa_supplicant process that may have been hanging out.

and then start the connection with nmcli:

Using nmcli dev status once more:

Very handy indeed.

D-Bus Messages and python-networkmanager

Okay, now we’re getting somewhere! Another new command. On your Pi, run busctl monitor org.freedesktop.NetworkManager. You might see something like:

Now, this is neat! It looks like every time the signal strength of the WiFi connection changes there’s a message on the D-Bus. What happens if you pull the WiFi adapter out altogether? Two signals get emitted: AccessPointRemoved and DeviceRemoved, along with additional signals on other paths.

Now, this isn’t necessarily a D-Bus tutorial or complete NetworkManager tutorial, but, you might want to read up on the NetworkManager D-Bus API here.

Recall that the original question that started me down this hacking journey was how to get notified about changes in network availability. Well, reading D-Bus messages from NetworkManager is the answer, but before we tie everything together we’ll install a Python library that is going to make this much easier. That library is python-networkmanager.

python-networkmanager documentation is a little sparse, but much of the functionality can be gleaned from the examples.

Signals We’re Interested In

After a little trial and error I determined that we’re interested in two NetworkManager signals:

  • DeviceAdded
  • DeviceRemoved

and we’re interested in the StatusChanged signal for a given device.

This is important! The top-level StatusChanged signal for the NetworkManager is the overall status, and we are interested specifically in status changes for each device.

With python-networkmanager we code this as follows:

First, we “connect” (or subscribe) to the DeviceAdded and DeviceRemoved signals. The second argument to connect_to_signal is a callback, which we’ll define later on. Next, we use the GetDevices() method to give us all of the current devices.

For each device we connect to the StateChanged signal. This is how we’ll know whether there was a state change for that specific device. Then, using the python-networkmanager API we get the type of connection (Wired, Wireless, etc.), and determine whether NetworkManager reports the connection as activated (i.e., up and with an address). If all is well we stash this information in our Devices table and call something like ethernet(True) (more on this later).

Now, for a look at our add/remove and state change functions:

Work through this code on your own; hopefully it isn’t too obtuse, but to be fair, none of this will run without filling in the gaps. Like, what does ethernet do? Fear not, the entire code resides in a single file called watchnet.py. Here you will find the ethernet and wifi functions, which simply raise/lower GPIO pins. If you have the GPIO pins connected to LEDs you get a nice visual display of what interface is up/down at the moment. In the first pic both LEDs are lit, thus indicating that both the Ethernet and WiFi connections are up.

bothconnected
Both Network Interfaces Connected

In the second pic I’ve removed the Wireless USB Adapter, and the yellow LED goes out.

WiFi Disconnected
WiFi Disconnected

I am using GPIO pins 23 and 24 on the Raspberry Pi and carrying them out to a green and yellow LED. If you’ve never used the Pi to drive LEDs, have a look at this tutorial, but realize I am using the /sys/class/gpio “method” of setting the pins, and my circuit omits the resistors (I like to live dangerously).

Life cycle of the Wired and Wireless Devices

Now, I’m by no means an expert on NetworkManager and I’m sure there may be some additional states lurking in the machine that I haven’t seen, but what I can gather here is what you should expect for a “normal” sequence for both a Wired and Wireless device:

states

In contrast, a Wireless device has some additional steps to obtain credentials for the connection:

wireless_states

If you don’t have any LEDs lying around (what kind of hacker are you?!) run the watchnet.py script in the foreground and take note of the logs:

In this example the Wireless USB Adapter was pulled (Device removed, which coincidentally you will not see for pulling an Ethernet cable).

But seriously, it’s more fun with LEDs.

Wrapping It Up

Now, to wrap everything up into a nice “no touch” environment, we turn to writing a systemd unit. In /etc/systemd/system/watchnet.service add the contents:

Enable the service:

Of course, make sure watchnet.py is in /home/pi and the execute bit (chmod +x watchnet.py) is set!

Now, for some fun:

  • Pull the power to the Pi
  • Disconnect all of the network interfaces
  • Choose either the Ethernet cable or Wireless USB Adapter and plug it in

The appropriate LED should light up! Plug in the “other” device and its LED will light up as well. So, at a glance, you can see what network interface(s) are connected on your Pi.

Next Time

I’m itching to buy a Adafruit Character LCD for the Pi. Imagine displaying in text various status messages, or changing colors based upon the WiFi signal strength. Next time!

2 thoughts on “Exploring NetworkManager, D-Bus, systemd, and Raspberry Pi”

  1. Hi,

    i’m following your article.

    but …. busctl command is missing in raspbian…how to add?

  2. busctl I believe is included with the systemd package. You may be on a version of Raspbian which is SysVInit-based (in which case you may have to decide whether or not install portions of systemd or switch to a flavor which includes it).

Leave a Reply

Your email address will not be published. Required fields are marked *