diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index 8fc05ae64f..39e5246a8b 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/libnetwork/drivers/bridge/bridge.go @@ -1381,34 +1381,9 @@ func parseContainerOptions(cOptions map[string]interface{}) (*containerConfigura } } -// Generate a IEEE802 compliant MAC address from the given IP address. -// -// The generator is guaranteed to be consistent: the same IP will always yield the same -// MAC address. This is to avoid ARP cache issues. -func generateMacAddr(ip net.IP) net.HardwareAddr { - hw := make(net.HardwareAddr, 6) - - // The first byte of the MAC address has to comply with these rules: - // 1. Unicast: Set the least-significant bit to 0. - // 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1. - // 3. As "small" as possible: The veth address has to be "smaller" than the bridge address. - hw[0] = 0x02 - - // The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI). - // Since this address is locally administered, we can do whatever we want as long as - // it doesn't conflict with other addresses. - hw[1] = 0x42 - - // Insert the IP address into the last 32 bits of the MAC address. - // This is a simple way to guarantee the address will be consistent and unique. - copy(hw[2:], ip.To4()) - - return hw -} - func electMacAddress(epConfig *endpointConfiguration, ip net.IP) net.HardwareAddr { if epConfig != nil && epConfig.MacAddress != nil { return epConfig.MacAddress } - return generateMacAddr(ip) + return netutils.GenerateMACFromIP(ip) } diff --git a/libnetwork/drivers/bridge/netlink_deprecated_linux.go b/libnetwork/drivers/bridge/netlink_deprecated_linux.go index 007ccb285a..6b49efa166 100644 --- a/libnetwork/drivers/bridge/netlink_deprecated_linux.go +++ b/libnetwork/drivers/bridge/netlink_deprecated_linux.go @@ -7,6 +7,8 @@ import ( "syscall" "time" "unsafe" + + "github.com/docker/libnetwork/netutils" ) const ( @@ -74,16 +76,6 @@ func ioctlAddToBridge(iface, master *net.Interface) error { return ifIoctBridge(iface, master, ioctlBrAddIf) } -func randMacAddr() string { - hw := make(net.HardwareAddr, 6) - for i := 0; i < 6; i++ { - hw[i] = byte(rnd.Intn(255)) - } - hw[0] &^= 0x1 // clear multicast bit - hw[0] |= 0x2 // set local assignment bit (IEEE802) - return hw.String() -} - func ioctlSetMacAddress(name, addr string) error { if len(name) >= ifNameSize { return fmt.Errorf("Interface name %s too long", name) @@ -133,7 +125,7 @@ func ioctlCreateBridge(name string, setMacAddr bool) error { return err } if setMacAddr { - return ioctlSetMacAddress(name, randMacAddr()) + return ioctlSetMacAddress(name, netutils.GenerateRandomMAC().String()) } return nil } diff --git a/libnetwork/netutils/utils.go b/libnetwork/netutils/utils.go index cb430eb03f..6ade406db4 100644 --- a/libnetwork/netutils/utils.go +++ b/libnetwork/netutils/utils.go @@ -122,26 +122,36 @@ func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) { return addrs4[0], addrs6, nil } -// GenerateRandomMAC returns a new 6-byte(48-bit) hardware address (MAC) -func GenerateRandomMAC() net.HardwareAddr { +func genMAC(ip net.IP) net.HardwareAddr { hw := make(net.HardwareAddr, 6) // The first byte of the MAC address has to comply with these rules: // 1. Unicast: Set the least-significant bit to 0. // 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1. - // 3. As "small" as possible: The veth address has to be "smaller" than the bridge address. hw[0] = 0x02 // The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI). // Since this address is locally administered, we can do whatever we want as long as // it doesn't conflict with other addresses. hw[1] = 0x42 - // Randomly generate the remaining 4 bytes (2^32) - _, err := rand.Read(hw[2:]) - if err != nil { - return nil + // Fill the remaining 4 bytes based on the input + if ip == nil { + rand.Read(hw[2:]) + } else { + copy(hw[2:], ip.To4()) } return hw } +// GenerateRandomMAC returns a new 6-byte(48-bit) hardware address (MAC) +func GenerateRandomMAC() net.HardwareAddr { + return genMAC(nil) +} + +// GenerateMACFromIP returns a locally administered MAC address where the 4 least +// significant bytes are derived from the IPv4 address. +func GenerateMACFromIP(ip net.IP) net.HardwareAddr { + return genMAC(ip) +} + // GenerateRandomName returns a new name joined with a prefix. This size // specified is used to truncate the randomly generated value func GenerateRandomName(prefix string, size int) (string, error) {