Browse Source

Generate container mac address based on IP

Currently we craete container mac address completely
randomly. But we probably need to generate based on
IP so that the mac address stays the same for a given
IP.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
Jana Radhakrishnan 10 years ago
parent
commit
fcca4484cb
1 changed files with 35 additions and 10 deletions
  1. 35 10
      libnetwork/drivers/bridge/bridge.go

+ 35 - 10
libnetwork/drivers/bridge/bridge.go

@@ -852,14 +852,6 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 		}
 	}()
 
-	// Set the sbox's MAC. If specified, use the one configured by user, otherwise use a random one
-	mac := electMacAddress(epConfig)
-	err = netlink.LinkSetHardwareAddr(sbox, mac)
-	if err != nil {
-		return err
-	}
-	endpoint.macAddress = mac
-
 	n.Lock()
 	config := n.config
 	n.Unlock()
@@ -889,6 +881,14 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	}
 	ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
 
+	// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
+	mac := electMacAddress(epConfig, ip4)
+	err = netlink.LinkSetHardwareAddr(sbox, mac)
+	if err != nil {
+		return err
+	}
+	endpoint.macAddress = mac
+
 	// v6 address for the sandbox side pipe interface
 	ipv6Addr = &net.IPNet{}
 	if config.EnableIPv6 {
@@ -1289,9 +1289,34 @@ func parseContainerOptions(cOptions map[string]interface{}) (*containerConfigura
 	}
 }
 
-func electMacAddress(epConfig *endpointConfiguration) net.HardwareAddr {
+// 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 netutils.GenerateRandomMAC()
+	return generateMacAddr(ip)
 }