From b0d046a1afc1cfc3bdd8b2435e48f60744c0a0e6 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Fri, 26 Feb 2016 14:58:11 -0800 Subject: [PATCH] Remove all netlink/osl deps from ipam/ipamutils Currently ipam/ipamutils has a bunch of dependencies in osl and netlink which makes the ipam/ipamutils harder to use independently with other applications. This PR modularizes ipam/ipamutils into a standalone package with no OS level dependencies. Signed-off-by: Jana Radhakrishnan --- libnetwork/cmd/dnet/dnet.go | 4 +- libnetwork/drivers/bridge/bridge_test.go | 3 +- libnetwork/ipam/allocator.go | 7 -- libnetwork/ipam/allocator_test.go | 26 +---- libnetwork/ipamutils/utils_linux.go | 76 --------------- libnetwork/ipamutils/utils_test.go | 93 +----------------- libnetwork/netutils/utils.go | 7 -- .../{ipamutils => netutils}/utils_freebsd.go | 3 +- libnetwork/netutils/utils_linux.go | 67 +++++++++++++ libnetwork/netutils/utils_test.go | 96 ++++++++++++++++++- .../{ipamutils => netutils}/utils_windows.go | 3 +- libnetwork/network.go | 44 ++++++++- libnetwork/osl/sandbox_linux_test.go | 14 ++- libnetwork/resolvconf/resolvconf.go | 12 +-- libnetwork/resolvconf/resolvconf_test.go | 20 ++-- libnetwork/resolver.go | 8 +- libnetwork/sandbox.go | 3 +- libnetwork/sandbox_dns_unix.go | 7 +- libnetwork/types/types.go | 13 +++ 19 files changed, 262 insertions(+), 244 deletions(-) delete mode 100644 libnetwork/ipamutils/utils_linux.go rename libnetwork/{ipamutils => netutils}/utils_freebsd.go (89%) rename libnetwork/{ipamutils => netutils}/utils_windows.go (89%) diff --git a/libnetwork/cmd/dnet/dnet.go b/libnetwork/cmd/dnet/dnet.go index 27d1ffac89..d84e03291f 100644 --- a/libnetwork/cmd/dnet/dnet.go +++ b/libnetwork/cmd/dnet/dnet.go @@ -29,8 +29,8 @@ import ( "github.com/docker/libnetwork/config" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/driverapi" - "github.com/docker/libnetwork/ipamutils" "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/options" "github.com/docker/libnetwork/types" "github.com/gorilla/mux" @@ -429,7 +429,7 @@ func encodeData(data interface{}) (*bytes.Buffer, error) { } func ipamOption(bridgeName string) libnetwork.NetworkOption { - if nw, _, err := ipamutils.ElectInterfaceAddresses(bridgeName); err == nil { + if nw, _, err := netutils.ElectInterfaceAddresses(bridgeName); err == nil { ipamV4Conf := &libnetwork.IpamConf{PreferredPool: nw.String()} hip, _ := types.GetHostPartIP(nw.IP, nw.Mask) if hip.IsGlobalUnicast() { diff --git a/libnetwork/drivers/bridge/bridge_test.go b/libnetwork/drivers/bridge/bridge_test.go index 23610ad54f..2a4a2902b8 100644 --- a/libnetwork/drivers/bridge/bridge_test.go +++ b/libnetwork/drivers/bridge/bridge_test.go @@ -10,6 +10,7 @@ import ( "github.com/docker/libnetwork/ipamutils" "github.com/docker/libnetwork/iptables" "github.com/docker/libnetwork/netlabel" + "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/options" "github.com/docker/libnetwork/testutils" "github.com/docker/libnetwork/types" @@ -21,7 +22,7 @@ func init() { func getIPv4Data(t *testing.T) []driverapi.IPAMData { ipd := driverapi.IPAMData{AddressSpace: "full"} - nw, _, err := ipamutils.ElectInterfaceAddresses("") + nw, _, err := netutils.ElectInterfaceAddresses("") if err != nil { t.Fatal(err) } diff --git a/libnetwork/ipam/allocator.go b/libnetwork/ipam/allocator.go index 70fe06eba7..6641a4cc8b 100644 --- a/libnetwork/ipam/allocator.go +++ b/libnetwork/ipam/allocator.go @@ -401,13 +401,6 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) } if !aSpace.contains(as, nw) { - if as == localAddressSpace { - // Check if nw overlap with system routes, name servers - if _, err := ipamutils.FindAvailableNetwork([]*net.IPNet{nw}); err == nil { - return nw, nil - } - continue - } return nw, nil } } diff --git a/libnetwork/ipam/allocator_test.go b/libnetwork/ipam/allocator_test.go index 64ba358db3..c5c07e83d4 100644 --- a/libnetwork/ipam/allocator_test.go +++ b/libnetwork/ipam/allocator_test.go @@ -453,27 +453,11 @@ func TestPredefinedPool(t *testing.T) { t.Fatalf("Expected failure for non default addr space") } - exp, err := ipamutils.FindAvailableNetwork(a.predefined[localAddressSpace]) + pid, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false) if err != nil { t.Fatal(err) } - nw, err := a.getPredefinedPool(localAddressSpace, false) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(nw, exp) { - t.Fatalf("Unexpected default network returned: %s. Expected: %s", nw, exp) - } - - pid, nw, _, err := a.RequestPool(localAddressSpace, exp.String(), "", nil, false) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(nw, exp) { - t.Fatalf("Unexpected default network returned: %s. Expected: %s", nw, exp) - } - nw2, err := a.getPredefinedPool(localAddressSpace, false) if err != nil { t.Fatal(err) @@ -485,14 +469,6 @@ func TestPredefinedPool(t *testing.T) { if err := a.ReleasePool(pid); err != nil { t.Fatal(err) } - - nw, err = a.getPredefinedPool(localAddressSpace, false) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(nw, exp) { - t.Fatalf("Unexpected default network returned: %s. Expected %s", nw, exp) - } } func TestRemoveSubnet(t *testing.T) { diff --git a/libnetwork/ipamutils/utils_linux.go b/libnetwork/ipamutils/utils_linux.go deleted file mode 100644 index 056a234c8f..0000000000 --- a/libnetwork/ipamutils/utils_linux.go +++ /dev/null @@ -1,76 +0,0 @@ -// Package ipamutils provides utililty functions for ipam management -package ipamutils - -import ( - "fmt" - "net" - - "github.com/docker/libnetwork/netutils" - "github.com/docker/libnetwork/osl" - "github.com/docker/libnetwork/resolvconf" - "github.com/vishvananda/netlink" -) - -// 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 - ) - - InitNetworks() - - defer osl.InitOSContext()() - - link, _ := netlink.LinkByName(name) - if link != nil { - v4addr, err := netlink.AddrList(link, netlink.FAMILY_V4) - if err != nil { - return nil, nil, err - } - v6addr, err := netlink.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(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 := netutils.CheckNameserverOverlaps(nameservers, nw); err == nil { - if err := netutils.CheckRouteOverlaps(nw); err == nil { - return nw, nil - } - } - } - return nil, fmt.Errorf("no available network") -} diff --git a/libnetwork/ipamutils/utils_test.go b/libnetwork/ipamutils/utils_test.go index 8cddc505fa..215644336a 100644 --- a/libnetwork/ipamutils/utils_test.go +++ b/libnetwork/ipamutils/utils_test.go @@ -1,12 +1,9 @@ package ipamutils import ( - "net" "testing" - "github.com/docker/libnetwork/testutils" - "github.com/docker/libnetwork/types" - "github.com/vishvananda/netlink" + _ "github.com/docker/libnetwork/testutils" ) func init() { @@ -27,91 +24,3 @@ func TestGranularPredefined(t *testing.T) { } } - -func TestNetworkRequest(t *testing.T) { - defer testutils.SetupTestOSContext(t)() - _, exp, err := net.ParseCIDR("172.17.0.0/16") - if err != nil { - t.Fatal(err) - } - - nw, err := FindAvailableNetwork(PredefinedBroadNetworks) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(exp, nw) { - t.Fatalf("exected %s. got %s", exp, nw) - } - - _, exp, err = net.ParseCIDR("10.0.0.0/24") - if err != nil { - t.Fatal(err) - } - nw, err = FindAvailableNetwork(PredefinedGranularNetworks) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(exp, nw) { - t.Fatalf("exected %s. got %s", exp, nw) - } - - // Add iface and ssert returned address on request - createInterface(t, "test", "172.17.42.1/16") - - _, exp, err = net.ParseCIDR("172.18.0.0/16") - if err != nil { - t.Fatal(err) - } - nw, err = FindAvailableNetwork(PredefinedBroadNetworks) - if err != nil { - t.Fatal(err) - } - if !types.CompareIPNet(exp, nw) { - t.Fatalf("exected %s. got %s", exp, nw) - } -} - -func TestElectInterfaceAddress(t *testing.T) { - defer testutils.SetupTestOSContext(t)() - nws := "172.101.202.254/16" - createInterface(t, "test", nws) - - ipv4Nw, ipv6Nw, err := ElectInterfaceAddresses("test") - if err != nil { - t.Fatal(err) - } - - if ipv4Nw == nil { - t.Fatalf("unexpected empty ipv4 network addresses") - } - - if len(ipv6Nw) == 0 { - t.Fatalf("unexpected empty ipv4 network addresses") - } - - if nws != ipv4Nw.String() { - t.Fatalf("expected %s. got %s", nws, ipv4Nw) - } -} - -func createInterface(t *testing.T, name, nw string) { - // Add interface - link := &netlink.Bridge{ - LinkAttrs: netlink.LinkAttrs{ - Name: "test", - }, - } - bip, err := types.ParseCIDR(nw) - if err != nil { - t.Fatal(err) - } - if err = netlink.LinkAdd(link); err != nil { - t.Fatalf("Failed to create interface via netlink: %v", err) - } - if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: bip}); err != nil { - t.Fatal(err) - } - if err = netlink.LinkSetUp(link); err != nil { - t.Fatal(err) - } -} diff --git a/libnetwork/netutils/utils.go b/libnetwork/netutils/utils.go index 482e4f038f..62287efcc9 100644 --- a/libnetwork/netutils/utils.go +++ b/libnetwork/netutils/utils.go @@ -14,13 +14,6 @@ import ( "github.com/docker/libnetwork/types" ) -// constants for the IP address type -const ( - IP = iota // IPv4 and IPv6 - IPv4 - IPv6 -) - var ( // ErrNetworkOverlapsWithNameservers preformatted error ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver") diff --git a/libnetwork/ipamutils/utils_freebsd.go b/libnetwork/netutils/utils_freebsd.go similarity index 89% rename from libnetwork/ipamutils/utils_freebsd.go rename to libnetwork/netutils/utils_freebsd.go index 09eced12d1..f7a7ac75f5 100644 --- a/libnetwork/ipamutils/utils_freebsd.go +++ b/libnetwork/netutils/utils_freebsd.go @@ -1,5 +1,4 @@ -// Package ipamutils provides utililty functions for ipam management -package ipamutils +package netutils import ( "net" diff --git a/libnetwork/netutils/utils_linux.go b/libnetwork/netutils/utils_linux.go index 782e542a52..f1e73d2297 100644 --- a/libnetwork/netutils/utils_linux.go +++ b/libnetwork/netutils/utils_linux.go @@ -4,9 +4,13 @@ package netutils import ( + "fmt" "net" "strings" + "github.com/docker/libnetwork/ipamutils" + "github.com/docker/libnetwork/osl" + "github.com/docker/libnetwork/resolvconf" "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" ) @@ -48,3 +52,66 @@ func GenerateIfaceName(prefix string, len int) (string, error) { } 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, _ := netlink.LinkByName(name) + if link != nil { + v4addr, err := netlink.AddrList(link, netlink.FAMILY_V4) + if err != nil { + return nil, nil, err + } + v6addr, err := netlink.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") +} diff --git a/libnetwork/netutils/utils_test.go b/libnetwork/netutils/utils_test.go index 9b883d9422..961e8d48a2 100644 --- a/libnetwork/netutils/utils_test.go +++ b/libnetwork/netutils/utils_test.go @@ -5,7 +5,9 @@ import ( "net" "testing" - _ "github.com/docker/libnetwork/testutils" + "github.com/docker/libnetwork/ipamutils" + "github.com/docker/libnetwork/testutils" + "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" ) @@ -210,3 +212,95 @@ func TestUtilGenerateRandomMAC(t *testing.T) { t.Fatalf("mac1 %s should not equal mac2 %s", mac1, mac2) } } + +func TestNetworkRequest(t *testing.T) { + defer testutils.SetupTestOSContext(t)() + ipamutils.InitNetworks() + + _, exp, err := net.ParseCIDR("172.17.0.0/16") + if err != nil { + t.Fatal(err) + } + + nw, err := FindAvailableNetwork(ipamutils.PredefinedBroadNetworks) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(exp, nw) { + t.Fatalf("exected %s. got %s", exp, nw) + } + + _, exp, err = net.ParseCIDR("10.0.0.0/24") + if err != nil { + t.Fatal(err) + } + nw, err = FindAvailableNetwork(ipamutils.PredefinedGranularNetworks) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(exp, nw) { + t.Fatalf("exected %s. got %s", exp, nw) + } + + // Add iface and ssert returned address on request + createInterface(t, "test", "172.17.42.1/16") + + _, exp, err = net.ParseCIDR("172.18.0.0/16") + if err != nil { + t.Fatal(err) + } + nw, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks) + if err != nil { + t.Fatal(err) + } + if !types.CompareIPNet(exp, nw) { + t.Fatalf("exected %s. got %s", exp, nw) + } +} + +func TestElectInterfaceAddress(t *testing.T) { + defer testutils.SetupTestOSContext(t)() + ipamutils.InitNetworks() + + nws := "172.101.202.254/16" + createInterface(t, "test", nws) + + ipv4Nw, ipv6Nw, err := ElectInterfaceAddresses("test") + if err != nil { + t.Fatal(err) + } + + if ipv4Nw == nil { + t.Fatalf("unexpected empty ipv4 network addresses") + } + + if len(ipv6Nw) == 0 { + t.Fatalf("unexpected empty ipv4 network addresses") + } + + if nws != ipv4Nw.String() { + t.Fatalf("expected %s. got %s", nws, ipv4Nw) + } +} + +func createInterface(t *testing.T, name, nw string) { + // Add interface + link := &netlink.Bridge{ + LinkAttrs: netlink.LinkAttrs{ + Name: "test", + }, + } + bip, err := types.ParseCIDR(nw) + if err != nil { + t.Fatal(err) + } + if err = netlink.LinkAdd(link); err != nil { + t.Fatalf("Failed to create interface via netlink: %v", err) + } + if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: bip}); err != nil { + t.Fatal(err) + } + if err = netlink.LinkSetUp(link); err != nil { + t.Fatal(err) + } +} diff --git a/libnetwork/ipamutils/utils_windows.go b/libnetwork/netutils/utils_windows.go similarity index 89% rename from libnetwork/ipamutils/utils_windows.go rename to libnetwork/netutils/utils_windows.go index 4878ca2b86..3b4bb9d909 100644 --- a/libnetwork/ipamutils/utils_windows.go +++ b/libnetwork/netutils/utils_windows.go @@ -1,5 +1,4 @@ -// Package ipamutils provides utililty functions for ipam management -package ipamutils +package netutils import ( "net" diff --git a/libnetwork/network.go b/libnetwork/network.go index a14550cd7e..b8b3117eb6 100644 --- a/libnetwork/network.go +++ b/libnetwork/network.go @@ -1094,6 +1094,48 @@ func (n *network) ipamAllocate() error { return n.ipamAllocateVersion(6, ipam) } +func (n *network) requestPoolHelper(ipam ipamapi.Ipam, addressSpace, preferredPool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) { + for { + poolID, pool, meta, err := ipam.RequestPool(addressSpace, preferredPool, subPool, options, v6) + if err != nil { + return "", nil, nil, err + } + + // If the network belongs to global scope or the pool + // returned is invalid, no need to perform overlap + // check. + if n.Scope() == datastore.GlobalScope || !types.IsIPNetValid(pool) { + return poolID, pool, meta, nil + } + + // Check for overlap and if none found, we have found the right pool. + if _, err := netutils.FindAvailableNetwork([]*net.IPNet{pool}); err == nil { + return poolID, pool, meta, nil + } + + // Pool obtained in this iteration is + // overlapping. Hold onto the pool and don't release + // it yet, because we don't want ipam to give us back + // the same pool over again. But make sure we still do + // a deferred release when we have either obtained a + // non-overlapping pool or ran out of pre-defined + // pools. + defer func() { + if err := ipam.ReleasePool(poolID); err != nil { + log.Warnf("Failed to release overlapping pool %s while returning from pool request helper for network %s", pool, n.Name()) + } + }() + + // If this is a preferred pool request and the network + // is local scope and there is a overlap, we fail the + // network creation right here. The pool will be + // released in the defer. + if preferredPool != "" { + return "", nil, nil, fmt.Errorf("requested subnet %s overlaps in the host", preferredPool) + } + } +} + func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error { var ( cfgList *[]*IpamConf @@ -1130,7 +1172,7 @@ func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error { d := &IpamInfo{} (*infoList)[i] = d - d.PoolID, d.Pool, d.Meta, err = ipam.RequestPool(n.addrSpace, cfg.PreferredPool, cfg.SubPool, n.ipamOptions, ipVer == 6) + d.PoolID, d.Pool, d.Meta, err = n.requestPoolHelper(ipam, n.addrSpace, cfg.PreferredPool, cfg.SubPool, n.ipamOptions, ipVer == 6) if err != nil { return err } diff --git a/libnetwork/osl/sandbox_linux_test.go b/libnetwork/osl/sandbox_linux_test.go index 8343d76172..7414e0a5d8 100644 --- a/libnetwork/osl/sandbox_linux_test.go +++ b/libnetwork/osl/sandbox_linux_test.go @@ -1,6 +1,9 @@ package osl import ( + "crypto/rand" + "encoding/hex" + "io" "net" "os" "path/filepath" @@ -9,7 +12,6 @@ import ( "testing" "time" - "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/testutils" "github.com/docker/libnetwork/types" "github.com/vishvananda/netlink" @@ -25,8 +27,16 @@ const ( sboxIfaceName = "containername" ) +func generateRandomName(prefix string, size int) (string, error) { + id := make([]byte, 32) + if _, err := io.ReadFull(rand.Reader, id); err != nil { + return "", err + } + return prefix + hex.EncodeToString(id)[:size], nil +} + func newKey(t *testing.T) (string, error) { - name, err := netutils.GenerateRandomName("netns", 12) + name, err := generateRandomName("netns", 12) if err != nil { return "", err } diff --git a/libnetwork/resolvconf/resolvconf.go b/libnetwork/resolvconf/resolvconf.go index 507d9ef50d..017b413dfc 100644 --- a/libnetwork/resolvconf/resolvconf.go +++ b/libnetwork/resolvconf/resolvconf.go @@ -10,8 +10,8 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/ioutils" - "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/resolvconf/dns" + "github.com/docker/libnetwork/types" ) var ( @@ -122,7 +122,7 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) { } // if the resulting resolvConf has no more nameservers defined, add appropriate // default DNS servers for IPv4 and (optionally) IPv6 - if len(GetNameservers(cleanedResolvConf, netutils.IP)) == 0 { + if len(GetNameservers(cleanedResolvConf, types.IP)) == 0 { logrus.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers : %v", defaultIPv4Dns) dns := defaultIPv4Dns if ipv6Enabled { @@ -158,11 +158,11 @@ func GetNameservers(resolvConf []byte, kind int) []string { nameservers := []string{} for _, line := range getLines(resolvConf, []byte("#")) { var ns [][]byte - if kind == netutils.IP { + if kind == types.IP { ns = nsRegexp.FindSubmatch(line) - } else if kind == netutils.IPv4 { + } else if kind == types.IPv4 { ns = nsIPv4Regexpmatch.FindSubmatch(line) - } else if kind == netutils.IPv6 { + } else if kind == types.IPv6 { ns = nsIPv6Regexpmatch.FindSubmatch(line) } if len(ns) > 0 { @@ -177,7 +177,7 @@ func GetNameservers(resolvConf []byte, kind int) []string { // This function's output is intended for net.ParseCIDR func GetNameserversAsCIDR(resolvConf []byte) []string { nameservers := []string{} - for _, nameserver := range GetNameservers(resolvConf, netutils.IP) { + for _, nameserver := range GetNameservers(resolvConf, types.IP) { nameservers = append(nameservers, nameserver+"/32") } return nameservers diff --git a/libnetwork/resolvconf/resolvconf_test.go b/libnetwork/resolvconf/resolvconf_test.go index f0c2080cef..218191396b 100644 --- a/libnetwork/resolvconf/resolvconf_test.go +++ b/libnetwork/resolvconf/resolvconf_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/docker/docker/pkg/ioutils" - "github.com/docker/libnetwork/netutils" _ "github.com/docker/libnetwork/testutils" + "github.com/docker/libnetwork/types" ) func TestGet(t *testing.T) { @@ -49,7 +49,7 @@ nameserver 1.2.3.4 `search example.com nameserver 1.2.3.4 # not 4.3.2.1`: {"1.2.3.4"}, } { - test := GetNameservers([]byte(resolv), netutils.IP) + test := GetNameservers([]byte(resolv), types.IP) if !strSlicesEqual(test, result) { t.Fatalf("Wrong nameserver string {%s} should be %v. Input: %s", test, result, resolv) } @@ -84,11 +84,11 @@ func TestGetSearchDomains(t *testing.T) { for resolv, result := range map[string][]string{ `search example.com`: {"example.com"}, `search example.com # ignored`: {"example.com"}, - ` search example.com `: {"example.com"}, - ` search example.com # ignored`: {"example.com"}, + ` search example.com `: {"example.com"}, + ` search example.com # ignored`: {"example.com"}, `search foo.example.com example.com`: {"foo.example.com", "example.com"}, - ` search foo.example.com example.com `: {"foo.example.com", "example.com"}, - ` search foo.example.com example.com # ignored`: {"foo.example.com", "example.com"}, + ` search foo.example.com example.com `: {"foo.example.com", "example.com"}, + ` search foo.example.com example.com # ignored`: {"foo.example.com", "example.com"}, ``: {}, `# ignored`: {}, `nameserver 1.2.3.4 @@ -111,12 +111,12 @@ func TestGetOptions(t *testing.T) { for resolv, result := range map[string][]string{ `options opt1`: {"opt1"}, `options opt1 # ignored`: {"opt1"}, - ` options opt1 `: {"opt1"}, - ` options opt1 # ignored`: {"opt1"}, + ` options opt1 `: {"opt1"}, + ` options opt1 # ignored`: {"opt1"}, `options opt1 opt2 opt3`: {"opt1", "opt2", "opt3"}, `options opt1 opt2 opt3 # ignored`: {"opt1", "opt2", "opt3"}, - ` options opt1 opt2 opt3 `: {"opt1", "opt2", "opt3"}, - ` options opt1 opt2 opt3 # ignored`: {"opt1", "opt2", "opt3"}, + ` options opt1 opt2 opt3 `: {"opt1", "opt2", "opt3"}, + ` options opt1 opt2 opt3 # ignored`: {"opt1", "opt2", "opt3"}, ``: {}, `# ignored`: {}, `nameserver 1.2.3.4`: {}, diff --git a/libnetwork/resolver.go b/libnetwork/resolver.go index cff692fd1f..d4dec8e48a 100644 --- a/libnetwork/resolver.go +++ b/libnetwork/resolver.go @@ -10,7 +10,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/iptables" - "github.com/docker/libnetwork/netutils" + "github.com/docker/libnetwork/types" "github.com/miekg/dns" ) @@ -240,7 +240,7 @@ func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns. if len(addr) > 1 { addr = shuffleAddr(addr) } - if ipType == netutils.IPv4 { + if ipType == types.IPv4 { for _, ip := range addr { rr := new(dns.A) rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL} @@ -312,9 +312,9 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) { } name := query.Question[0].Name if query.Question[0].Qtype == dns.TypeA { - resp, err = r.handleIPQuery(name, query, netutils.IPv4) + resp, err = r.handleIPQuery(name, query, types.IPv4) } else if query.Question[0].Qtype == dns.TypeAAAA { - resp, err = r.handleIPQuery(name, query, netutils.IPv6) + resp, err = r.handleIPQuery(name, query, types.IPv6) } else if query.Question[0].Qtype == dns.TypePTR { resp, err = r.handlePTRQuery(name, query) } diff --git a/libnetwork/sandbox.go b/libnetwork/sandbox.go index 5517301bcc..0b98d8384e 100644 --- a/libnetwork/sandbox.go +++ b/libnetwork/sandbox.go @@ -12,7 +12,6 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/etchosts" "github.com/docker/libnetwork/netlabel" - "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/osl" "github.com/docker/libnetwork/types" ) @@ -522,7 +521,7 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin n.Lock() ip, ok = sr.svcMap[name] - if ipType == netutils.IPv6 { + if ipType == types.IPv6 { // If the name resolved to v4 address then its a valid name in // the docker network domain. If the network is not v6 enabled // set ipv6Miss to filter the DNS query from going to external diff --git a/libnetwork/sandbox_dns_unix.go b/libnetwork/sandbox_dns_unix.go index c8b595eb24..ac1f53c76e 100644 --- a/libnetwork/sandbox_dns_unix.go +++ b/libnetwork/sandbox_dns_unix.go @@ -11,7 +11,6 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/etchosts" - "github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/resolvconf" "github.com/docker/libnetwork/types" ) @@ -166,7 +165,7 @@ func (sb *sandbox) setupDNS() error { if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 { var ( err error - dnsList = resolvconf.GetNameservers(currRC.Content, netutils.IP) + dnsList = resolvconf.GetNameservers(currRC.Content, types.IP) dnsSearchList = resolvconf.GetSearchDomains(currRC.Content) dnsOptionsList = resolvconf.GetOptions(currRC.Content) ) @@ -275,7 +274,7 @@ func (sb *sandbox) rebuildDNS() error { // localhost entries have already been filtered out from the list // retain only the v4 servers in sb for forwarding the DNS queries - sb.extDNS = resolvconf.GetNameservers(currRC.Content, netutils.IPv4) + sb.extDNS = resolvconf.GetNameservers(currRC.Content, types.IPv4) var ( dnsList = []string{sb.resolver.NameServer()} @@ -284,7 +283,7 @@ func (sb *sandbox) rebuildDNS() error { ) // external v6 DNS servers has to be listed in resolv.conf - dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, netutils.IPv6)...) + dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, types.IPv6)...) // Resolver returns the options in the format resolv.conf expects dnsOptionsList = append(dnsOptionsList, sb.resolver.ResolverOptions()...) diff --git a/libnetwork/types/types.go b/libnetwork/types/types.go index 44ee563e69..f32919d6ea 100644 --- a/libnetwork/types/types.go +++ b/libnetwork/types/types.go @@ -9,6 +9,13 @@ import ( "strings" ) +// constants for the IP address type +const ( + IP = iota // IPv4 and IPv6 + IPv4 + IPv6 +) + // UUID represents a globally unique ID of various resources like network and endpoint type UUID string @@ -318,6 +325,12 @@ func GetMinimalIPNet(nw *net.IPNet) *net.IPNet { return nw } +// IsIPNetValid returns true if the ipnet is a valid network/mask +// combination. Otherwise returns false. +func IsIPNetValid(nw *net.IPNet) bool { + return nw.String() != "0.0.0.0/0" +} + var v4inV6MaskPrefix = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} // compareIPMask checks if the passed ip and mask are semantically compatible.