When working with Linux bridges, maintaining a stable MAC address is crucial for network stability. In traditional /etc/network/interfaces
configurations, we could use post-up
hooks to dynamically set the bridge's MAC address based on a member interface:
post-up ip link set br0 address cat /sys/class/net/wlan0/address
This ensures each system maintains its unique MAC address (from wlan0) while preventing MAC flapping when adding interfaces with lower MAC addresses.
systemd-networkd handles post-configuration differently than ifupdown. Instead of direct command hooks, it uses a more structured approach through service units. Here are two methods to achieve dynamic MAC configuration:
Method 1: Using systemd-networkd Directives
For simple cases, you can use MACAddress=
in your .netdev file:
[NetDev]
Name=br0
Kind=bridge
MACAddress=$(cat /sys/class/net/wlan0/address)
However, this requires environment variable expansion support which might not be available in all systemd versions.
Method 2: Creating a Custom Service Unit
For more control, create a service that runs after network configuration:
# /etc/systemd/system/set-bridge-mac.service
[Unit]
Description=Set bridge MAC address
After=sys-subsystem-net-devices-br0.device
BindsTo=sys-subsystem-net-devices-br0.device
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'ip link set br0 address $(cat /sys/class/net/wlan0/address)'
[Install]
WantedBy=multi-user.target
Then enable and start the service:
systemctl enable --now set-bridge-mac.service
For complex scenarios, consider networkd-dispatcher
which provides hook-like functionality:
# /etc/networkd-dispatcher/routable.d/10-set-bridge-mac
#!/bin/sh
if [ "$IFACE" = "br0" ]; then
ip link set br0 address $(cat /sys/class/net/wlan0/address)
fi
If your MAC address isn't persisting:
- Check service dependencies with
systemd-analyze verify set-bridge-mac.service
- Verify timing with
journalctl -u set-bridge-mac.service -b
- Ensure proper device naming in
/sys/class/net/
The service-based approach provides better integration with systemd's lifecycle management while maintaining the flexibility needed for dynamic network configuration.
When working with Linux bridges, maintaining a consistent MAC address is crucial for network stability. In traditional /etc/network/interfaces
configurations, we'd use post-up
commands to clone the MAC address from a physical interface:
# Traditional ifupdown approach
auto br0
iface br0 inet static
bridge_ports eth0 wlan0
post-up ip link set br0 address $(cat /sys/class/net/wlan0/address)
systemd-networkd handles this differently through its unit-based architecture. The equivalent functionality requires creating two unit files:
The NetDev Definition
# /etc/systemd/network/25-br0.netdev
[NetDev]
Name=br0
Kind=bridge
The Network Configuration
# /etc/systemd/network/25-br0.network
[Match]
Name=br0
[Network]
DHCP=no
To replicate the post-up
functionality, we create a service unit that executes after the bridge is up:
# /etc/systemd/system/set-bridge-mac.service
[Unit]
Description=Set bridge MAC address
After=network.target sys-subsystem-net-devices-br0.device
Requires=sys-subsystem-net-devices-br0.device
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'ip link set br0 address $(cat /sys/class/net/wlan0/address)'
[Install]
WantedBy=multi-user.target
For more complex scenarios, consider using systemd-networkd-wait-online
in your service:
# /etc/systemd/system/set-bridge-mac.service
[Unit]
Description=Set bridge MAC address
After=systemd-networkd-wait-online.service
Requires=systemd-networkd-wait-online.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'while ! ip link show br0 >/dev/null 2>&1; do sleep 1; done; ip link set br0 address $(cat /sys/class/net/wlan0/address)'
[Install]
WantedBy=multi-user.target
After implementing these changes:
- Enable the service:
systemctl enable set-bridge-mac.service
- Restart networkd:
systemctl restart systemd-networkd
- Verify with:
ip link show br0
and check the MAC matches wlan0
Remember that the bridge must be fully initialized before modifying its MAC address, which is why we use device or networkd-wait dependencies.