Skip to content
This repository has been archived by the owner on Dec 7, 2023. It is now read-only.

Commit

Permalink
Assign a random MAC address to the bridge
Browse files Browse the repository at this point in the history
If we don't do this it will adopt the lowest address of an attached
device, hence change over time.

Remove the previous work-around of getting and setting the random MAC
that Linux assigned, also getting and setting the TUN address since
that doesn't change if you set the bridge address.
  • Loading branch information
bboreham committed Jan 14, 2021
1 parent 08493ac commit 6e2f25c
Showing 1 changed file with 23 additions and 30 deletions.
53 changes: 23 additions & 30 deletions pkg/container/network.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package container

import (
"crypto/rand"
"fmt"
"net"
"time"
Expand Down Expand Up @@ -224,6 +225,14 @@ func createBridge(bridgeName string) (*netlink.Bridge, error) {
la := netlink.NewLinkAttrs()
la.Name = bridgeName

// Assign a specific mac to the bridge - if we don't do this it will adopt
// the lowest address of an attached device, hence change over time.
mac, err := randomMAC()
if err != nil {
return nil, err
}
la.HardwareAddr = mac

// Disable MAC address age tracking. This causes issues in the container,
// the bridge is unable to resolve MACs from outside resulting in it never
// establishing the internal routes. This "optimization" is only really useful
Expand All @@ -243,45 +252,29 @@ func addLink(link netlink.Link) (err error) {
return
}

// This is a MAC address persistence workaround, netlink.LinkSetMaster{,ByIndex}()
// has a bug that arbitrarily changes the MAC addresses of the bridge and virtual
// device to be bound to it. TODO: Remove when fixed upstream
func setMaster(master netlink.Link, links ...netlink.Link) error {
masterIndex := master.Attrs().Index
masterMAC, err := getMAC(master)
if err != nil {
return err
func randomMAC() (net.HardwareAddr, error) {
mac := make([]byte, 6)
if _, err := rand.Read(mac); err != nil {
return nil, err
}

for _, link := range links {
mac, err := getMAC(link)
if err != nil {
return err
}
// In the first byte of the MAC, the 'multicast' bit should be
// clear and 'locally administered' bit should be set.
mac[0] = (mac[0] & 0xFE) | 0x02

if err = netlink.LinkSetMasterByIndex(link, masterIndex); err != nil {
return err
return net.HardwareAddr(mac), nil
}

if err = netlink.LinkSetHardwareAddr(link, mac); err != nil {
func setMaster(master netlink.Link, links ...netlink.Link) error {
masterIndex := master.Attrs().Index

for _, link := range links {
if err := netlink.LinkSetMasterByIndex(link, masterIndex); err != nil {
return err
}
}

return netlink.LinkSetHardwareAddr(master, masterMAC)
}

// getMAC fetches the generated MAC address for the given link
func getMAC(link netlink.Link) (addr net.HardwareAddr, err error) {
// The attributes of the netlink.Link passed to this function do not contain HardwareAddr
// as it is expected to be generated by the networking subsystem. Thus, "reload" the Link
// by querying it to retrieve the generated attributes after the link has been created.
if link, err = netlink.LinkByIndex(link.Attrs().Index); err != nil {
return
}

addr = link.Attrs().HardwareAddr
return
return nil
}

func maskString(mask net.IPMask) string {
Expand Down

0 comments on commit 6e2f25c

Please sign in to comment.