From fcca4484cbd1aca15f3b0dc65573ad71896cd2e9 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 10 Jun 2015 14:21:24 -0700 Subject: [PATCH] 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 --- libnetwork/drivers/bridge/bridge.go | 45 ++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/libnetwork/drivers/bridge/bridge.go b/libnetwork/drivers/bridge/bridge.go index d64733eba6..87bd7e3901 100644 --- a/libnetwork/drivers/bridge/bridge.go +++ b/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) }