diff --git a/hack/vendor.sh b/hack/vendor.sh index 6c6c6eb7f5..d5048f52f7 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -55,7 +55,7 @@ clone hg code.google.com/p/go.net 84a4013f96e0 clone hg code.google.com/p/gosqlite 74691fb6f837 #get libnetwork packages -clone git github.com/docker/libnetwork ace6b576239cd671d1645d82520b16791737f60d +clone git github.com/docker/libnetwork 90638ec9cf7fa7b7f5d0e96b0854f136d66bff92 clone git github.com/vishvananda/netns 5478c060110032f972e86a1f844fdb9a2f008f2c clone git github.com/vishvananda/netlink 8eb64238879fed52fd51c5b30ad20b928fb4c36c diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go index 05b1535dd0..8896bd8483 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -498,14 +498,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 - // Add bridge inherited attributes to pipe interfaces if config.Mtu != 0 { err = netlink.LinkSetMTU(host, config.Mtu) @@ -531,6 +523,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 { @@ -926,11 +926,36 @@ 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) } // Generates a name to be used for a virtual ethernet diff --git a/vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go b/vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go index 22d5fe279d..f8bb5716e3 100644 --- a/vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go +++ b/vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go @@ -103,12 +103,20 @@ func removeFromGarbagePaths(path string) { // GC triggers garbage collection of namespace path right away // and waits for it. func GC() { + gpmLock.Lock() + if len(garbagePathMap) == 0 { + // No need for GC if map is empty + gpmLock.Unlock() + return + } + gpmLock.Unlock() + + // if content exists in the garbage paths + // we can trigger GC to run, providing a + // channel to be notified on completion waitGC := make(chan struct{}) - - // Trigger GC now gpmChan <- waitGC - - // wait for gc to complete + // wait for GC completion <-waitGC }