| // +build linux |
| |
| package 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 |
| } |