Score:4

Debian: Where does a bridge interface store its MAC address and how can I change it?

gi flag

I have reinstalled a computer and since I need several similar computers, I duplicated the hard disk with dd. On the target systems I have adjusted /etc/hosts, /etc/hostname and /etc/network/interfaces.d/* accordingly.

So I got different machines with different host names and different IP addresses.

But while the hardware interfaces also have different MAC addresses, the bridge interface has the same MAC address on all target systems. Apparently it was copied along.

The bridge is "classically" defined in /etc/network/interfaces.d/bridge:

iface br0 inet static
  bridge_ports enp0s31f6
    address 192.168.1.20
    broadcast 192.168.1.255
    network 192.168.1.0
    netmask 255.255.255.0
    gateway 192.168.1.1

(Needless to say that I set address on each machine individually.)

As a trial I changed the file, removed the bridge interface, assigned the IP address directly to the ethernet interface, rebooted (worked: bridge was gone and the hardware interface had the correct IP address) and edited the bridge back in.

After that the bridge had its original address again...

Thanks a lot for your support!

Score:4
cl flag
A.B

The overall behavior is caused by systemd, even if systemd isn't configured to manage the system's network.


A bridge interface on Linux has two "modes" with its MAC address:

  • the implicit mode

    When creating a bridge interface without specifying its MAC address, it gets a temporary random MAC address (with private bit set). When an other interface is set as bridge port, the bridge inherits this interface's MAC address to replace the temporary one. I leave undefined what happens when a 2nd interface is added because behavior might have changed depending on kernel version. This mode can't exist anymore on a system with a recent systemd running.

  • the explicit mode

    When creating the bridge (ip link add ...) or changing it (ip link set dev ...) one can specify address xx:xx:xx:xx:xx:xx, changing the bridge's behavior: it won't inherit anything, its initial oper state will be down when administratively set up (because it has no connectivity yet) instead of unknown and a few similar things. For example by indirect effect such bridge won't have a link local IPv6 address created since it's in down oper state, until it has actual connectivity using an added bridge port itself with connectivity.


systemd

Recent versions of systemd choose to always explicitly assign a MAC address to virtual interfaces that were created without specifying the address (systemd tracks this. One can track what it does by running ip monitor link and see that the interfaces created without stating the MAC address immediately get their MAC address changed (by systemd)). systemd doesn't care (at least by default) if it's supposed to manage the interface or not.

This affects bridges. Because the algorithm choosing the MAC address depends on the system's machine-id UUID (and the interface name), if the system-cloning actions don't change the machine-id, two systems will keep the same MAC addresses on their virtual interfaces with the same name, such as br0. These two systems won't be able to communicate properly anymore over their LAN since there must be no same MAC address on an Ethernet LAN (and this might cause some switches in the path to complain and log flapping errors).

This systemd behavior is visible in the host initial network namespace but not in other network namespaces (unless they have systemd also running on it like would be the case in a system container managed by LXC), because systemd won't track other network namespaces.

Solutions

As systemd doesn't look like it will disappear soon, the best way is to stay compliant with what it does: have an unique machine-id provisioned on each cloned system. The method to change the setting for each clone is explained for example there (and is not specific to Debian, but to using systemd or one of its sub-components):

machine id and cloned systems, generating a new machine id

The machine id is something that is frequently missed to change when cloning a machine. A new machine-id can be generated by

rm -f /etc/machine-id /var/lib/dbus/machine-id
dbus-uuidgen --ensure=/etc/machine-id
dbus-uuidgen --ensure

Making /etc/machine-id a 0-byte file is considered to be the canonical way to clear it, rather than actually deleting it, because if systemd is running on a completely read-only root filesystem, it has code to create a machine ID on a tmpfs and bind-mount it over the top of the empty file.

So either execute the 3 commands above and have a way to automate this (eg: using ansible which could compare with the deployed id present by default), or just remove files and create an empty /etc/machine-id hoping systemd will do some randomization (if not R/O, no idea how this later method behaves).

Of course doing a manual assignment of the MAC address won't be overridden by systemd. So as long as the value is different on each system, one can set the address when creating the interface. With the ifupdown package and bridge-utils installed (because it provides additional functions to ifupdown, not really for the obsolete brctl command) you can use the function bridge_hw in the bridge stanza.

You can either copy the real interface's MAC:

    bridge_hw enp0s31f6

so that for example DHCP without DUID behaves the same as it would have without a bridge configuration, and as an added bonus, defer the choice of an unique MAC address to the hardware (ie: the NIC manufacturer or for virtual systems the hypervisor).

Or you can choose a different MAC address on each system:

    bridge_hw 12:34:56:78:9a:bc

For more details and reproducible examples about this "feature" of systemd and how it affects bridges and other virtual interfaces, see this UL SE Q/A where I made an answer:

How can I make Linux generate different MAC addresses for different bridge devices which are on different PCs?

Alek_A avatar
pe flag
Thanks for the explanation on systemd! Unfortunately I found out that `bridge_hw eth0` does not work, probably because I have `ifupdown2` installed, not `ifupdown`, so I had to specify actual address.
th0masrad avatar
gi flag
Incredibly good! Many, many, many thanks for this great detailed answer.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.