1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/libnetwork/netutils/utils_linux.go
Alessandro Boch 6d3fa9e0f2 Migrate libnetwork to use netlink.Handle
Signed-off-by: Alessandro Boch <aboch@docker.com>
2016-06-08 21:05:36 -07:00

125 lines
3.4 KiB
Go

// +build linux
// Network utility functions.
package netutils
import (
"fmt"
"net"
"strings"
"github.com/docker/libnetwork/ipamutils"
"github.com/docker/libnetwork/ns"
"github.com/docker/libnetwork/osl"
"github.com/docker/libnetwork/resolvconf"
"github.com/docker/libnetwork/types"
"github.com/vishvananda/netlink"
)
var (
networkGetRoutesFct func(netlink.Link, int) ([]netlink.Route, error)
)
// CheckRouteOverlaps checks whether the passed network overlaps with any existing routes
func CheckRouteOverlaps(toCheck *net.IPNet) error {
if networkGetRoutesFct == nil {
networkGetRoutesFct = ns.NlHandle().RouteList
}
networks, err := networkGetRoutesFct(nil, netlink.FAMILY_V4)
if err != nil {
return err
}
for _, network := range networks {
if network.Dst != nil && NetworkOverlaps(toCheck, network.Dst) {
return ErrNetworkOverlaps
}
}
return nil
}
// GenerateIfaceName returns an interface name using the passed in
// prefix and the length of random bytes. The api ensures that the
// there are is no interface which exists with that name.
func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, error) {
linkByName := netlink.LinkByName
if nlh != nil {
linkByName = nlh.LinkByName
}
for i := 0; i < 3; i++ {
name, err := GenerateRandomName(prefix, len)
if err != nil {
continue
}
_, err = linkByName(name)
if err != nil {
if strings.Contains(err.Error(), "not found") {
return name, nil
}
return "", err
}
}
return "", types.InternalErrorf("could not generate interface name")
}
// ElectInterfaceAddresses looks for an interface on the OS with the
// specified name and returns its IPv4 and IPv6 addresses in CIDR
// form. If the interface does not exist, it chooses from a predifined
// list the first IPv4 address which does not conflict with other
// interfaces on the system.
func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
var (
v4Net *net.IPNet
v6Nets []*net.IPNet
err error
)
defer osl.InitOSContext()()
link, _ := ns.NlHandle().LinkByName(name)
if link != nil {
v4addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V4)
if err != nil {
return nil, nil, err
}
v6addr, err := ns.NlHandle().AddrList(link, netlink.FAMILY_V6)
if err != nil {
return nil, nil, err
}
if len(v4addr) > 0 {
v4Net = v4addr[0].IPNet
}
for _, nlAddr := range v6addr {
v6Nets = append(v6Nets, nlAddr.IPNet)
}
}
if link == nil || v4Net == nil {
// Choose from predifined broad networks
v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
if err != nil {
return nil, nil, err
}
}
return v4Net, v6Nets, nil
}
// FindAvailableNetwork returns a network from the passed list which does not
// overlap with existing interfaces in the system
func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
// We don't check for an error here, because we don't really care if we
// can't read /etc/resolv.conf. So instead we skip the append if resolvConf
// is nil. It either doesn't exist, or we can't read it for some reason.
var nameservers []string
if rc, err := resolvconf.Get(); err == nil {
nameservers = resolvconf.GetNameserversAsCIDR(rc.Content)
}
for _, nw := range list {
if err := CheckNameserverOverlaps(nameservers, nw); err == nil {
if err := CheckRouteOverlaps(nw); err == nil {
return nw, nil
}
}
}
return nil, fmt.Errorf("no available network")
}