blob: 62e4f61a6534fd636669c9351453b468d64bb8ea [file] [log] [blame]
package cluster // import "github.com/docker/docker/daemon/cluster"
import (
"net"
"github.com/vishvananda/netlink"
)
func (c *Cluster) resolveSystemAddr() (net.IP, error) {
// Use the system's only device IP address, or fail if there are
// multiple addresses to choose from.
interfaces, err := netlink.LinkList()
if err != nil {
return nil, err
}
var (
systemAddr net.IP
systemInterface string
deviceFound bool
)
for _, intf := range interfaces {
// Skip non device or inactive interfaces
if intf.Type() != "device" || intf.Attrs().Flags&net.FlagUp == 0 {
continue
}
addrs, err := netlink.AddrList(intf, netlink.FAMILY_ALL)
if err != nil {
continue
}
var interfaceAddr4, interfaceAddr6 net.IP
for _, addr := range addrs {
ipAddr := addr.IPNet.IP
// Skip loopback and link-local addresses
if !ipAddr.IsGlobalUnicast() {
continue
}
// At least one non-loopback device is found and it is administratively up
deviceFound = true
if ipAddr.To4() != nil {
if interfaceAddr4 != nil {
return nil, errMultipleIPs(intf.Attrs().Name, intf.Attrs().Name, interfaceAddr4, ipAddr)
}
interfaceAddr4 = ipAddr
} else {
if interfaceAddr6 != nil {
return nil, errMultipleIPs(intf.Attrs().Name, intf.Attrs().Name, interfaceAddr6, ipAddr)
}
interfaceAddr6 = ipAddr
}
}
// In the case that this interface has exactly one IPv4 address
// and exactly one IPv6 address, favor IPv4 over IPv6.
if interfaceAddr4 != nil {
if systemAddr != nil {
return nil, errMultipleIPs(systemInterface, intf.Attrs().Name, systemAddr, interfaceAddr4)
}
systemAddr = interfaceAddr4
systemInterface = intf.Attrs().Name
} else if interfaceAddr6 != nil {
if systemAddr != nil {
return nil, errMultipleIPs(systemInterface, intf.Attrs().Name, systemAddr, interfaceAddr6)
}
systemAddr = interfaceAddr6
systemInterface = intf.Attrs().Name
}
}
if systemAddr == nil {
if !deviceFound {
// If no non-loopback device type interface is found,
// fall back to the regular auto-detection mechanism.
// This is to cover the case where docker is running
// inside a container (eths are in fact veths).
return c.resolveSystemAddrViaSubnetCheck()
}
return nil, errNoIP
}
return systemAddr, nil
}