1

My dual-stack network at home uses router advertisements for IPv6 configuration, with a (mostly fixed) delegated /56 prefix from my ISP. All my machines therefore have a predictable global IPv6 address that they get via router advertisements, some are published on DNS when the prefix changes. All working fine.

Recently, I changed the configuration of one machine, and bridged the main eth0 interface so that I can start LXD containers on this bridge, and their network would also be configured in the same way (also getting a global IPv6 address).

With this configuration, it is not my eth0 interface that gets SLAAC configured anymore, but the br0 bridge. And when containers start, the veth interfaces that get added to the bridge change its setup, and the MAC address used for IPv6 address assigning is not always the one of my eth0, so the predictable global IPv6 of the main machine sometimes disappears...

I can force the MAC address of the container's interface (allowing a predictable public IPv6 for hat container), but the one that is added to the bridge is the other side of the pair, with a MAC address random generated by the kernel if I understand correctly. I also thought forcing the MAC address of eth0 to be "low-numbered", as it seems the bridge will chose the "lowest" MAC, but I am not sure this will work either, and what MAC address to chose that would always be lower than a kernel-generated one...

How can I keep one global IPv6 address on that machine ?

Note that machine is running Alpine Linux, so no systemd-networkd solutions will help.

1 Answer 1

1

You can force manually the MAC address of the bridge, just like most other virtual Ethernet-like interfaces. Once manually set, the MAC address won't change anymore: the dynamic change depending on the interface(s) set as bridge port won't happen anymore.

At the low level this can be done at creation:

ip link add name br0 address 12:34:56:78:9a:bc type bridge

or later:

ip link set dev br0 address 12:34:56:78:9a:bc

Older kernels might require the interface to be down before being able to change its MAC address.

I guess you can reuse the MAC address of the physical interface if you want to keep a compatible setting, but in this case you should:

  • do it before setting eth0 as bridge port

    or this won't be considered as having manually set the MAC address (and will stay in dynamic mode) because the command wouldn't actually change the MAC address since it would be the same as the (dynamic) inherited one. Details are described in this SU Q/A's answer of mine: How does Linux determine the default MAC address of a bridge device?.

    UPDATE: as OP found ifupdown accepts (depending on its exact variant) the keywords bridge-hw or bridge_hw which are intended for such usage and are supposed to handle properly the order of operations to avoid the bridge to stay in dynamic/inherited mode.

    Without such dedicated option, pre-up might be used but then a pre-up command to create the bridge first might be needed in case this virtual interface doesn't exist in the pre-up phase. One must verify the ordering so the MAC address is set on the bridge before the physical interface is set as bridge port. Sprinkling a few || true at the end of such pre-up entries to make the effect idempotent might be a good idea.

  • enforce disabling IPv6 on the eth0 interface - now a bridge port and not an independent interface anymore:

    systemctl -w net.ipv6.conf.eth0.disable_ipv6=1
    

    to be sure no part of the system will be confused.

Additional note: The dynamic behavior depending on interface's MAC address doesn't happen on a recent system running systemd because systemd assigns on-the-fly a "random stable" MAC address on all virtual interfaces whenever it detected their creation (whatever the command creating it) including bridges, switching the bridge's behavior to manual mode. Details are described in my answer there: How can I make Linux generate different MAC addresses for different bridge devices which are on different PCs?. If Alpine is running OpenRC, then the default dynamic behavior depending on interfaces should still happen (and thus needs to be overridden by a manual assignment, before setting eth0 as bridge port if its own MAC address is reused).

8
  • Thank you for this very elaborate response. This worked for me at first (disabling ipv6 on eth0 and setting hwaddress on bridge in pre-up), but then I restarted the container a couple of times until the veth MAC address was lower, and the bridge changed as well.
    – philfr
    Oct 26, 2023 at 8:22
  • That means the MAC address was changed after eth0 was enslaved, as I warned this would cause a problem. If you have a remote console you can test manually: detach eth0, change the MAC and reattach eth0. You'd better choose an other MAC address to avoid this problem.
    – A.B
    Oct 26, 2023 at 8:26
  • The easiest to overcome this would be to not use the bridge plugins and configure everything manually in pre-up, in the right order. Even Alpine's wiki documents this method for bridge: wiki.alpinelinux.org/wiki/Bridge#Using_pre-up.2Fpost-down (but you should forget brctl and use ip link ... type bridge and/or bridge ... instead.)
    – A.B
    Oct 26, 2023 at 8:30
  • 1
    Yes ! Finally got it working with a manual (pre-up/up) configuration. Thanks
    – philfr
    Oct 26, 2023 at 10:09
  • 1
    And to complete the answer, I found the Alpine way of specifying the MAC address of the bridge in the interfaces file is with the keyword bridge-hw, not hwaddress like on Debian, that I tried unsuccessfully. Now it works fine like that as well, and the configuration is simpler.
    – philfr
    Oct 26, 2023 at 11:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .