Docker MAC Address Generation
Asked Answered
P

1

17

I had a question about applications running within Docker containers and UUID generation.

Here’s our scenario:

  • Currently our applications are using an event driven framework.

  • For the events we generate the UUID’s based on mac address, pid,
    time-stamp and counter.

  • For running containers on a distributed system like CoreOS (while a very very very low chance), there is no guarantee that all those parameters used to generate a UUID would be unique for each container as one container on one server in the cluster could generate a UUID using the same mac, pid, time-stamp and counter as another container on the cluster.

  • In essence if these two UUID’s were both to generate an event and send it to our messaging bus, then obviously there would be a conflict.

In our analysis, this scenario seems to boil down to the uniqueness of mac addresses on each Docker container.

So to be frank:

  • How unique are the mac addresses within containers?
  • How are mac addresses generated if they are not manually set?
Pygmy answered 15/10, 2014 at 14:37 Comment(0)
W
9

From my reading of generateMacAddr function (edit: answer concerned 1.3.0-dev, but is still correct for 17.05), MAC addresses generated by docker are essentially the IPv4 address of the container's interface on the docker0 bridge: they are guaranteed to be consistent with the IP address.

The docker0 bridge's subnet you have to operate in, usually 255.255.0.0 as per this example of 172.17.42.1/16, has 65,534 routable addresses. This does reduce entropy for UUID generation, but MAC address collision isn't possible as IPs must be unique, and the scenario of identical MAC, PID, time and counter in two containers on the same docker server/CoreOS host should not be a possibility.

However two CoreOS hosts (each running one docker server) could potentially choose the same random subnet, resulting in the possibility of duplicated MACs for containers on different hosts. You could evade this by setting a fixed CIDR for the docker server on each host:

--fixed-cidr=CIDR — restrict the IP range from the docker0 subnet, using the standard CIDR notation like 172.167.1.0/28. This range must be and IPv4 range for fixed IPs (ex: 10.20.0.0/16) and must be a subset of the bridge IP range (docker0 or set using --bridge). For example with --fixed-cidr=192.168.1.0/25, IPs for your containers will be chosen from the first half of 192.168.1.0/24 subnet.

This should ensure unique MAC addresses across the cluster.

The original IEEE 802 MAC address comes from the original Xerox Ethernet addressing scheme. This 48-bit address space contains potentially 248 or 281,474,976,710,656 possible MAC addresses.

source

If you are concerned about lack of entropy (the IP to MAC mapping reduces it considerably), a better option may be to use a different mechanism for UUID generation. UUID versions 3, 4 and 5 do not take MAC address into account. Alternatively you could include the host machine's MAC in UUID generation.

Of course, whether this "considerable MAC space reduction" will have any impact of UUID generation should probably be tested before any code is changed.

Source linked to above:

// 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
}
Wieland answered 27/10, 2014 at 17:52 Comment(2)
Thanks for the answer! This actually confirms that we may want to rethink our implementation.Pygmy
Additionally, could you please clarify if it is the IPv4 address of the container or of the host? Docker IP addresses are NAT'd to the IP address of the host. Theoretically docker containers on two different hosts could be operating within the same subnet which means MAC address collision is indeed possible in this scenario.Pygmy

© 2022 - 2024 — McMap. All rights reserved.