What is the systemd-networkd equivalent of post-up? (dynamic bridge MAC configuration)

7,003

It turns out that due to the heavy modular concept of systemd and systemd-networkd the scripting question needs to be tackled from a different angle: instead of looking for scripting with the bridge .netdev definition, the systemd way is to have a (very small) one-shot .service unit that is wanted by the bridge .netdev.

As a side note: it seems that in more recent Linux kernels, the kernel bridges actually don't use the dynamically changing lowest MAC48 scheme for the bridge MAC48 anymore. Instead, they create a static MAC48 for the bridge itself. So, in the very strict sense this solution is not really needed anymore, unless one prefers to use a "real" hardware MAC48; which is what is done here in the following service unit.

The necessary new service unit (in lieu of the old post-up from /etc/network/interfaces) lives in /etc/systemd/system/bridge-stable-mac.service and assigns the MAC48 from (built-in, fixed) wlan0 to the bridge itself:

[Service]
Type=oneshot
ExecStart=/bin/bash -c "/bin/echo 'br0 available, setting MAC ' `/bin/cat /sys/class/net/wlan0/address`"
ExecStart=/bin/bash -c "/sbin/ip link set br0 address `/bin/cat /sys/class/net/wlan0/address`"

[Install]
WantedBy=sys-subsystem-net-devices-br0.device

The central point here is the WantedBy= clause: whenever br0 starts, then this service should be run (exactly once, Type=oneshot). Systemd is really neat here, as it doesn't need to edit the existing device definition in order to add our dependency, but instead calculates this dependency using our inverse WantedBy= link. This is really where I think that systemd does shine.

The service unit above assumes that your bridge is named br0. You should use a corresponding .netdev file to define this bridge br0. For instance, in /etc/systemd/network/10-br0.netdev:

[NetDev]
Name=br0
Kind=bridge

When it comes to hotplugging bridge ports, systemd actually does this already out-of-the-box, which is very neat; in /etc/systemd/network/10-br0-ports.network:

[Match]
Name=eth0 wlan0

[Network]
Bridge=br0

That's it!

Share:
7,003

Related videos on Youtube

TheDiveO
Author by

TheDiveO

Lorem ipsum superbus esse semper latinum labere.

Updated on September 18, 2022

Comments

  • TheDiveO
    TheDiveO over 1 year

    In Linux distributions that use /etc/network/interfaces (such as Debian) I could get a (kernel) bridge to use the MAC48 address of one of its static bridge slave interfaces, such as a built in wlan0, using post-up, as in:

     post-up ip link set br0 address `cat /sys/class/net/wlan0/address`
    

    This ensured that both 1) each cloned system used its very own unique MAC48 (the one from the unique wlan0), and 2) the bridge MAC kept stable even when hot-plugging further bridge interfaces with lower MAC48's.

    Does systemd-networkd support any kind of post-up commands that can be run after a network (or netdev) has been brought up? I've tried to find such a thing, but may have missed it.

    Or is the correct way in systemd completely different, i.e. to have a device unit, and a service that wraps the ip link... command and depends on the device unit? If so, how would the device unit and the service unit files look like?

  • iBug
    iBug over 2 years
    I wonder if RemainAfterExit=yes is needed for the service.