Merge pull request #44827 from corhere/libnw/drop-electinterfaceaddresses

libnetwork: reduce usage of shared mutable state in ipamutils
This commit is contained in:
Cory Snider 2023-01-26 16:42:04 -05:00 committed by GitHub
commit 6c9dd8b650
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 267 additions and 311 deletions

View file

@ -4,16 +4,19 @@ import (
"bufio"
"fmt"
"io"
"net"
"os"
"regexp"
"strings"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/libnetwork/ns"
"github.com/docker/docker/libnetwork/resolvconf"
"github.com/moby/sys/mount"
"github.com/moby/sys/mountinfo"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
)
// On Linux, plugins use a static path for storing execution state,
@ -141,3 +144,41 @@ func setupResolvConf(config *config.Config) {
}
config.ResolvConf = resolvconf.Path()
}
// ifaceAddrs returns the IPv4 and IPv6 addresses assigned to the network
// interface with name linkName.
//
// No error is returned if the named interface does not exist.
func ifaceAddrs(linkName string) (v4, v6 []*net.IPNet, err error) {
nl := ns.NlHandle()
link, err := nl.LinkByName(linkName)
if err != nil {
if !errors.As(err, new(netlink.LinkNotFoundError)) {
return nil, nil, err
}
return nil, nil, nil
}
get := func(family int) ([]*net.IPNet, error) {
addrs, err := nl.AddrList(link, family)
if err != nil {
return nil, err
}
ipnets := make([]*net.IPNet, len(addrs))
for i := range addrs {
ipnets[i] = addrs[i].IPNet
}
return ipnets, nil
}
v4, err = get(netlink.FAMILY_V4)
if err != nil {
return nil, nil, err
}
v6, err = get(netlink.FAMILY_V6)
if err != nil {
return nil, nil, err
}
return v4, v6, nil
}

View file

@ -4,6 +4,7 @@
package daemon // import "github.com/docker/docker/daemon"
import (
"net"
"os"
"path/filepath"
"strings"
@ -11,8 +12,12 @@ import (
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/libnetwork/testutils"
"github.com/docker/docker/libnetwork/types"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/moby/sys/mount"
"github.com/moby/sys/mountinfo"
"github.com/vishvananda/netlink"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
@ -343,3 +348,66 @@ func TestRootMountCleanup(t *testing.T) {
assert.Assert(t, d.cleanupMounts())
})
}
func TestIfaceAddrs(t *testing.T) {
CIDR := func(cidr string) *net.IPNet {
t.Helper()
nw, err := types.ParseCIDR(cidr)
assert.NilError(t, err)
return nw
}
for _, tt := range []struct {
name string
nws []*net.IPNet
}{
{
name: "Single",
nws: []*net.IPNet{CIDR("172.101.202.254/16")},
},
{
name: "Multiple",
nws: []*net.IPNet{
CIDR("172.101.202.254/16"),
CIDR("172.102.202.254/16"),
},
},
} {
t.Run(tt.name, func(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
createBridge(t, "test", tt.nws...)
ipv4Nw, ipv6Nw, err := ifaceAddrs("test")
if err != nil {
t.Fatal(err)
}
assert.Check(t, is.DeepEqual(tt.nws, ipv4Nw,
cmpopts.SortSlices(func(a, b *net.IPNet) bool { return a.String() < b.String() })))
// IPv6 link-local address
assert.Check(t, is.Len(ipv6Nw, 1))
})
}
}
func createBridge(t *testing.T, name string, bips ...*net.IPNet) {
t.Helper()
link := &netlink.Bridge{
LinkAttrs: netlink.LinkAttrs{
Name: name,
},
}
if err := netlink.LinkAdd(link); err != nil {
t.Fatalf("Failed to create interface via netlink: %v", err)
}
for _, bip := range bips {
if err := netlink.AddrAdd(link, &netlink.Addr{IPNet: bip}); err != nil {
t.Fatal(err)
}
}
if err := netlink.LinkSetUp(link); err != nil {
t.Fatal(err)
}
}

View file

@ -35,7 +35,6 @@ import (
nwconfig "github.com/docker/docker/libnetwork/config"
"github.com/docker/docker/libnetwork/drivers/bridge"
"github.com/docker/docker/libnetwork/netlabel"
"github.com/docker/docker/libnetwork/netutils"
"github.com/docker/docker/libnetwork/options"
lntypes "github.com/docker/docker/libnetwork/types"
"github.com/docker/docker/opts"
@ -950,30 +949,37 @@ func initBridgeDriver(controller *libnetwork.Controller, config *config.Config)
ipamV4Conf := &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
nwList, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName)
// By default, libnetwork will request an arbitrary available address
// pool for the network from the configured IPAM allocator.
// Configure it to use the IPv4 network ranges of the existing bridge
// interface if one exists with IPv4 addresses assigned to it.
nwList, nw6List, err := ifaceAddrs(bridgeName)
if err != nil {
return errors.Wrap(err, "list bridge addresses failed")
}
nw := nwList[0]
if len(nwList) > 1 && config.BridgeConfig.FixedCIDR != "" {
_, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR)
if err != nil {
return errors.Wrap(err, "parse CIDR failed")
}
// Iterate through in case there are multiple addresses for the bridge
for _, entry := range nwList {
if fCIDR.Contains(entry.IP) {
nw = entry
break
if len(nwList) > 0 {
nw := nwList[0]
if len(nwList) > 1 && config.BridgeConfig.FixedCIDR != "" {
_, fCIDR, err := net.ParseCIDR(config.BridgeConfig.FixedCIDR)
if err != nil {
return errors.Wrap(err, "parse CIDR failed")
}
// Iterate through in case there are multiple addresses for the bridge
for _, entry := range nwList {
if fCIDR.Contains(entry.IP) {
nw = entry
break
}
}
}
}
ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String()
hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask)
if hip.IsGlobalUnicast() {
ipamV4Conf.Gateway = nw.IP.String()
ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String()
hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask)
if hip.IsGlobalUnicast() {
ipamV4Conf.Gateway = nw.IP.String()
}
}
if config.BridgeConfig.IP != "" {

View file

@ -13,6 +13,7 @@ import (
"testing"
"github.com/docker/docker/libnetwork/driverapi"
"github.com/docker/docker/libnetwork/ipamutils"
"github.com/docker/docker/libnetwork/iptables"
"github.com/docker/docker/libnetwork/netlabel"
"github.com/docker/docker/libnetwork/netutils"
@ -169,13 +170,13 @@ func compareBindings(a, b []types.PortBinding) bool {
func getIPv4Data(t *testing.T, iface string) []driverapi.IPAMData {
ipd := driverapi.IPAMData{AddressSpace: "full"}
nws, _, err := netutils.ElectInterfaceAddresses(iface)
nw, err := netutils.FindAvailableNetwork(ipamutils.GetLocalScopeDefaultNetworks())
if err != nil {
t.Fatal(err)
}
ipd.Pool = nws[0]
ipd.Pool = nw
// Set network gateway to X.X.X.1
ipd.Gateway = types.GetIPNetCopy(nws[0])
ipd.Gateway = types.GetIPNetCopy(nw)
ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1
return []driverapi.IPAMData{ipd}
}
@ -1049,7 +1050,15 @@ func TestCreateWithExistingBridge(t *testing.T) {
genericOption := make(map[string]interface{})
genericOption[netlabel.GenericData] = netconfig
if err := d.CreateNetwork(brName, genericOption, nil, getIPv4Data(t, brName), nil); err != nil {
ipv4Data := []driverapi.IPAMData{{
AddressSpace: "full",
Pool: types.GetIPNetCopy(addr.IPNet),
Gateway: types.GetIPNetCopy(addr.IPNet),
}}
// Set network gateway to X.X.X.1
ipv4Data[0].Gateway.IP[len(ipv4Data[0].Gateway.IP)-1] = 1
if err := d.CreateNetwork(brName, genericOption, nil, ipv4Data, nil); err != nil {
t.Fatalf("Failed to create bridge network: %v", err)
}

View file

@ -10,7 +10,12 @@ import (
)
func initIPAMDrivers(r *drvregistry.DrvRegistry, lDs, gDs interface{}, addressPool []*ipamutils.NetworkToSplit) error {
builtinIpam.SetDefaultIPAddressPool(addressPool)
// TODO: pass address pools as arguments to builtinIpam.Init instead of
// indirectly through global mutable state. Swarmkit references that
// function so changing its signature breaks the build.
if err := builtinIpam.SetDefaultIPAddressPool(addressPool); err != nil {
return err
}
for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
builtinIpam.Init,
remoteIpam.Init,

View file

@ -10,7 +10,6 @@ import (
"github.com/docker/docker/libnetwork/datastore"
"github.com/docker/docker/libnetwork/discoverapi"
"github.com/docker/docker/libnetwork/ipamapi"
"github.com/docker/docker/libnetwork/ipamutils"
"github.com/docker/docker/libnetwork/types"
"github.com/sirupsen/logrus"
)
@ -38,14 +37,14 @@ type Allocator struct {
}
// NewAllocator returns an instance of libnetwork ipam
func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
func NewAllocator(lcDs, glDs datastore.DataStore, lcAs, glAs []*net.IPNet) (*Allocator, error) {
a := &Allocator{}
// Load predefined subnet pools
a.predefined = map[string][]*net.IPNet{
localAddressSpace: ipamutils.GetLocalScopeDefaultNetworks(),
globalAddressSpace: ipamutils.GetGlobalScopeDefaultNetworks(),
localAddressSpace: lcAs,
globalAddressSpace: glAs,
}
// Initialize asIndices map

View file

@ -16,6 +16,7 @@ import (
"github.com/docker/docker/libnetwork/bitseq"
"github.com/docker/docker/libnetwork/datastore"
"github.com/docker/docker/libnetwork/ipamapi"
"github.com/docker/docker/libnetwork/ipamutils"
"github.com/docker/docker/libnetwork/types"
"github.com/docker/libkv/store"
"github.com/docker/libkv/store/boltdb"
@ -61,7 +62,7 @@ func getAllocator(store bool) (*Allocator, error) {
if err != nil {
return nil, err
}
return NewAllocator(ds, nil)
return NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
}
func TestInt2IP2IntConversion(t *testing.T) {
@ -1287,7 +1288,7 @@ func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, s
ds, err := randomLocalStore(store)
assert.NilError(t, err)
a, err := NewAllocator(ds, nil)
a, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
if err != nil {
t.Fatal(err)
}
@ -1355,7 +1356,7 @@ func TestRetrieveFromStore(t *testing.T) {
if err != nil {
t.Fatal(err)
}
a, err := NewAllocator(ds, nil)
a, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
if err != nil {
t.Fatal(err)
}
@ -1370,7 +1371,7 @@ func TestRetrieveFromStore(t *testing.T) {
}
// Restore
a1, err := NewAllocator(ds, nil)
a1, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
if err != nil {
t.Fatal(err)
}
@ -1392,7 +1393,7 @@ func TestRetrieveFromStore(t *testing.T) {
}
// Restore
a2, err := NewAllocator(ds, nil)
a2, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
if err != nil {
t.Fatal(err)
}
@ -1409,7 +1410,7 @@ func TestRetrieveFromStore(t *testing.T) {
}
// Restore
a3, err := NewAllocator(ds, nil)
a3, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
if err != nil {
t.Fatal(err)
}
@ -1426,7 +1427,7 @@ func TestRetrieveFromStore(t *testing.T) {
}
// Restore
a4, err := NewAllocator(ds, nil)
a4, err := NewAllocator(ds, nil, ipamutils.GetLocalScopeDefaultNetworks(), ipamutils.GetGlobalScopeDefaultNetworks())
if err != nil {
t.Fatal(err)
}

View file

@ -0,0 +1,62 @@
package builtin
import (
"errors"
"net"
"github.com/docker/docker/libnetwork/datastore"
"github.com/docker/docker/libnetwork/ipam"
"github.com/docker/docker/libnetwork/ipamapi"
"github.com/docker/docker/libnetwork/ipamutils"
)
var (
// defaultAddressPool Stores user configured subnet list
defaultAddressPool []*net.IPNet
)
// initBuiltin registers the built-in ipam service with libnetwork
func initBuiltin(ic ipamapi.Callback, l, g interface{}) error {
var (
ok bool
localDs, globalDs datastore.DataStore
)
if l != nil {
if localDs, ok = l.(datastore.DataStore); !ok {
return errors.New("incorrect local datastore passed to built-in ipam init")
}
}
if g != nil {
if globalDs, ok = g.(datastore.DataStore); !ok {
return errors.New("incorrect global datastore passed to built-in ipam init")
}
}
var localAddressPool []*net.IPNet
if len(defaultAddressPool) > 0 {
localAddressPool = append([]*net.IPNet(nil), defaultAddressPool...)
} else {
localAddressPool = ipamutils.GetLocalScopeDefaultNetworks()
}
a, err := ipam.NewAllocator(localDs, globalDs, localAddressPool, ipamutils.GetGlobalScopeDefaultNetworks())
if err != nil {
return err
}
cps := &ipamapi.Capability{RequiresRequestReplay: true}
return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps)
}
// SetDefaultIPAddressPool stores default address pool.
func SetDefaultIPAddressPool(addressPool []*ipamutils.NetworkToSplit) error {
nets, err := ipamutils.SplitNetworks(addressPool)
if err != nil {
return err
}
defaultAddressPool = nets
return nil
}

View file

@ -3,60 +3,9 @@
package builtin
import (
"errors"
"github.com/docker/docker/libnetwork/datastore"
"github.com/docker/docker/libnetwork/ipam"
"github.com/docker/docker/libnetwork/ipamapi"
"github.com/docker/docker/libnetwork/ipamutils"
)
var (
// defaultAddressPool Stores user configured subnet list
defaultAddressPool []*ipamutils.NetworkToSplit
)
import "github.com/docker/docker/libnetwork/ipamapi"
// Init registers the built-in ipam service with libnetwork
func Init(ic ipamapi.Callback, l, g interface{}) error {
var (
ok bool
localDs, globalDs datastore.DataStore
)
if l != nil {
if localDs, ok = l.(datastore.DataStore); !ok {
return errors.New("incorrect local datastore passed to built-in ipam init")
}
}
if g != nil {
if globalDs, ok = g.(datastore.DataStore); !ok {
return errors.New("incorrect global datastore passed to built-in ipam init")
}
}
err := ipamutils.ConfigLocalScopeDefaultNetworks(GetDefaultIPAddressPool())
if err != nil {
return err
}
a, err := ipam.NewAllocator(localDs, globalDs)
if err != nil {
return err
}
cps := &ipamapi.Capability{RequiresRequestReplay: true}
return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps)
}
// SetDefaultIPAddressPool stores default address pool.
func SetDefaultIPAddressPool(addressPool []*ipamutils.NetworkToSplit) {
defaultAddressPool = addressPool
}
// GetDefaultIPAddressPool returns default address pool.
func GetDefaultIPAddressPool() []*ipamutils.NetworkToSplit {
return defaultAddressPool
return initBuiltin(ic, l, g)
}

View file

@ -4,70 +4,18 @@
package builtin
import (
"errors"
"github.com/docker/docker/libnetwork/datastore"
"github.com/docker/docker/libnetwork/ipam"
"github.com/docker/docker/libnetwork/ipamapi"
"github.com/docker/docker/libnetwork/ipamutils"
windowsipam "github.com/docker/docker/libnetwork/ipams/windowsipam"
"github.com/docker/docker/libnetwork/ipams/windowsipam"
)
var (
// defaultAddressPool Stores user configured subnet list
defaultAddressPool []*ipamutils.NetworkToSplit
)
// InitDockerDefault registers the built-in ipam service with libnetwork
func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error {
var (
ok bool
localDs, globalDs datastore.DataStore
)
if l != nil {
if localDs, ok = l.(datastore.DataStore); !ok {
return errors.New("incorrect local datastore passed to built-in ipam init")
}
}
if g != nil {
if globalDs, ok = g.(datastore.DataStore); !ok {
return errors.New("incorrect global datastore passed to built-in ipam init")
}
}
ipamutils.ConfigLocalScopeDefaultNetworks(nil)
a, err := ipam.NewAllocator(localDs, globalDs)
if err != nil {
return err
}
cps := &ipamapi.Capability{RequiresRequestReplay: true}
return ic.RegisterIpamDriverWithCapabilities(ipamapi.DefaultIPAM, a, cps)
}
// Init registers the built-in ipam service with libnetwork
func Init(ic ipamapi.Callback, l, g interface{}) error {
initFunc := windowsipam.GetInit(windowsipam.DefaultIPAM)
err := InitDockerDefault(ic, l, g)
err := initBuiltin(ic, l, g)
if err != nil {
return err
}
return initFunc(ic, l, g)
}
// SetDefaultIPAddressPool stores default address pool .
func SetDefaultIPAddressPool(addressPool []*ipamutils.NetworkToSplit) {
defaultAddressPool = addressPool
}
// GetDefaultIPAddressPool returns default address pool .
func GetDefaultIPAddressPool() []*ipamutils.NetworkToSplit {
return defaultAddressPool
}

View file

@ -8,12 +8,12 @@ import (
)
var (
// PredefinedLocalScopeDefaultNetworks contains a list of 31 IPv4 private networks with host size 16 and 12
// predefinedLocalScopeDefaultNetworks contains a list of 31 IPv4 private networks with host size 16 and 12
// (172.17-31.x.x/16, 192.168.x.x/20) which do not overlap with the networks in `PredefinedGlobalScopeDefaultNetworks`
PredefinedLocalScopeDefaultNetworks []*net.IPNet
// PredefinedGlobalScopeDefaultNetworks contains a list of 64K IPv4 private networks with host size 8
predefinedLocalScopeDefaultNetworks []*net.IPNet
// predefinedGlobalScopeDefaultNetworks contains a list of 64K IPv4 private networks with host size 8
// (10.x.x.x/24) which do not overlap with the networks in `PredefinedLocalScopeDefaultNetworks`
PredefinedGlobalScopeDefaultNetworks []*net.IPNet
predefinedGlobalScopeDefaultNetworks []*net.IPNet
mutex sync.Mutex
localScopeDefaultNetworks = []*NetworkToSplit{{"172.17.0.0/16", 16}, {"172.18.0.0/16", 16}, {"172.19.0.0/16", 16},
{"172.20.0.0/14", 16}, {"172.24.0.0/14", 16}, {"172.28.0.0/14", 16},
@ -33,61 +33,45 @@ type NetworkToSplit struct {
func init() {
var err error
if PredefinedGlobalScopeDefaultNetworks, err = splitNetworks(globalScopeDefaultNetworks); err != nil {
if predefinedGlobalScopeDefaultNetworks, err = SplitNetworks(globalScopeDefaultNetworks); err != nil {
panic("failed to initialize the global scope default address pool: " + err.Error())
}
if PredefinedLocalScopeDefaultNetworks, err = splitNetworks(localScopeDefaultNetworks); err != nil {
if predefinedLocalScopeDefaultNetworks, err = SplitNetworks(localScopeDefaultNetworks); err != nil {
panic("failed to initialize the local scope default address pool: " + err.Error())
}
}
// configDefaultNetworks configures local as well global default pool based on input
func configDefaultNetworks(defaultAddressPool []*NetworkToSplit, result *[]*net.IPNet) error {
mutex.Lock()
defer mutex.Unlock()
defaultNetworks, err := splitNetworks(defaultAddressPool)
if err != nil {
return err
}
*result = defaultNetworks
return nil
}
// GetGlobalScopeDefaultNetworks returns PredefinedGlobalScopeDefaultNetworks
func GetGlobalScopeDefaultNetworks() []*net.IPNet {
mutex.Lock()
defer mutex.Unlock()
return PredefinedGlobalScopeDefaultNetworks
}
// GetLocalScopeDefaultNetworks returns PredefinedLocalScopeDefaultNetworks
func GetLocalScopeDefaultNetworks() []*net.IPNet {
mutex.Lock()
defer mutex.Unlock()
return PredefinedLocalScopeDefaultNetworks
}
// ConfigGlobalScopeDefaultNetworks configures global default pool.
// Ideally this will be called from SwarmKit as part of swarm init
func ConfigGlobalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
if defaultAddressPool == nil {
defaultAddressPool = globalScopeDefaultNetworks
}
return configDefaultNetworks(defaultAddressPool, &PredefinedGlobalScopeDefaultNetworks)
}
// ConfigLocalScopeDefaultNetworks configures local default pool.
// Ideally this will be called during libnetwork init
func ConfigLocalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
if defaultAddressPool == nil {
return nil
}
return configDefaultNetworks(defaultAddressPool, &PredefinedLocalScopeDefaultNetworks)
mutex.Lock()
defer mutex.Unlock()
defaultNetworks, err := SplitNetworks(defaultAddressPool)
if err != nil {
return err
}
predefinedGlobalScopeDefaultNetworks = defaultNetworks
return nil
}
// splitNetworks takes a slice of networks, split them accordingly and returns them
func splitNetworks(list []*NetworkToSplit) ([]*net.IPNet, error) {
// GetGlobalScopeDefaultNetworks returns a copy of the global-sopce network list.
func GetGlobalScopeDefaultNetworks() []*net.IPNet {
mutex.Lock()
defer mutex.Unlock()
return append([]*net.IPNet(nil), predefinedGlobalScopeDefaultNetworks...)
}
// GetLocalScopeDefaultNetworks returns a copy of the default local-scope network list.
func GetLocalScopeDefaultNetworks() []*net.IPNet {
return append([]*net.IPNet(nil), predefinedLocalScopeDefaultNetworks...)
}
// SplitNetworks takes a slice of networks, split them accordingly and returns them
func SplitNetworks(list []*NetworkToSplit) ([]*net.IPNet, error) {
localPools := make([]*net.IPNet, 0, len(list))
for _, p := range list {

View file

@ -44,13 +44,13 @@ func initGlobalScopeNetworks() []*net.IPNet {
}
func TestDefaultNetwork(t *testing.T) {
for _, nw := range PredefinedGlobalScopeDefaultNetworks {
for _, nw := range GetGlobalScopeDefaultNetworks() {
if ones, bits := nw.Mask.Size(); bits != 32 || ones != 24 {
t.Fatalf("Unexpected size for network in granular list: %v", nw)
}
}
for _, nw := range PredefinedLocalScopeDefaultNetworks {
for _, nw := range GetLocalScopeDefaultNetworks() {
if ones, bits := nw.Mask.Size(); bits != 32 || (ones != 20 && ones != 16) {
t.Fatalf("Unexpected size for network in broad list: %v", nw)
}
@ -61,7 +61,7 @@ func TestDefaultNetwork(t *testing.T) {
for _, v := range originalBroadNets {
m[v.String()] = true
}
for _, nw := range PredefinedLocalScopeDefaultNetworks {
for _, nw := range GetLocalScopeDefaultNetworks() {
_, ok := m[nw.String()]
assert.Check(t, ok)
delete(m, nw.String())
@ -75,7 +75,7 @@ func TestDefaultNetwork(t *testing.T) {
for _, v := range originalGranularNets {
m[v.String()] = true
}
for _, nw := range PredefinedGlobalScopeDefaultNetworks {
for _, nw := range GetGlobalScopeDefaultNetworks() {
_, ok := m[nw.String()]
assert.Check(t, ok)
delete(m, nw.String())
@ -93,7 +93,7 @@ func TestConfigGlobalScopeDefaultNetworks(t *testing.T) {
for _, v := range originalGlobalScopeNetworks {
m[v.String()] = true
}
for _, nw := range PredefinedGlobalScopeDefaultNetworks {
for _, nw := range GetGlobalScopeDefaultNetworks() {
_, ok := m[nw.String()]
assert.Check(t, ok)
delete(m, nw.String())
@ -101,17 +101,3 @@ func TestConfigGlobalScopeDefaultNetworks(t *testing.T) {
assert.Check(t, is.Len(m, 0))
}
func TestInitAddressPools(t *testing.T) {
err := ConfigLocalScopeDefaultNetworks([]*NetworkToSplit{{"172.80.0.0/16", 24}, {"172.90.0.0/16", 24}})
assert.NilError(t, err)
// Check for Random IPAddresses in PredefinedLocalScopeDefaultNetworks ex: first , last and middle
assert.Check(t, is.Len(PredefinedLocalScopeDefaultNetworks, 512), "Failed to find PredefinedLocalScopeDefaultNetworks")
assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[0].String(), "172.80.0.0/24"))
assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[127].String(), "172.80.127.0/24"))
assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[255].String(), "172.80.255.0/24"))
assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[256].String(), "172.90.0.0/24"))
assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[383].String(), "172.90.127.0/24"))
assert.Check(t, is.Equal(PredefinedLocalScopeDefaultNetworks[511].String(), "172.90.255.0/24"))
}

View file

@ -9,7 +9,6 @@ import (
"net"
"os"
"github.com/docker/docker/libnetwork/ipamutils"
"github.com/docker/docker/libnetwork/ns"
"github.com/docker/docker/libnetwork/resolvconf"
"github.com/docker/docker/libnetwork/types"
@ -61,46 +60,6 @@ func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, err
return "", types.InternalErrorf("could not generate interface name")
}
// ElectInterfaceAddresses looks for an interface on the OS with the
// specified name and returns returns all its IPv4 and IPv6 addresses in CIDR notation.
// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned.
// If the interface does not exist, it chooses from a predefined
// 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 v4Nets, v6Nets []*net.IPNet
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
}
for _, nlAddr := range v4addr {
v4Nets = append(v4Nets, nlAddr.IPNet)
}
for _, nlAddr := range v6addr {
v6Nets = append(v6Nets, nlAddr.IPNet)
}
}
if link == nil || len(v4Nets) == 0 {
// Choose from predefined local scope networks
v4Net, err := FindAvailableNetwork(ipamutils.PredefinedLocalScopeDefaultNetworks)
if err != nil {
return nil, nil, errors.Wrapf(err, "PredefinedLocalScopeDefaultNetworks List: %+v",
ipamutils.PredefinedLocalScopeDefaultNetworks)
}
v4Nets = append(v4Nets, v4Net)
}
return v4Nets, 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) {

View file

@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"net"
"sort"
"strings"
"testing"
@ -250,13 +249,13 @@ func TestUtilGenerateRandomMAC(t *testing.T) {
func TestNetworkRequest(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
nw, err := FindAvailableNetwork(ipamutils.PredefinedLocalScopeDefaultNetworks)
nw, err := FindAvailableNetwork(ipamutils.GetLocalScopeDefaultNetworks())
if err != nil {
t.Fatal(err)
}
var found bool
for _, exp := range ipamutils.PredefinedLocalScopeDefaultNetworks {
for _, exp := range ipamutils.GetLocalScopeDefaultNetworks() {
if types.CompareIPNet(exp, nw) {
found = true
break
@ -267,13 +266,13 @@ func TestNetworkRequest(t *testing.T) {
t.Fatalf("Found unexpected broad network %s", nw)
}
nw, err = FindAvailableNetwork(ipamutils.PredefinedGlobalScopeDefaultNetworks)
nw, err = FindAvailableNetwork(ipamutils.GetGlobalScopeDefaultNetworks())
if err != nil {
t.Fatal(err)
}
found = false
for _, exp := range ipamutils.PredefinedGlobalScopeDefaultNetworks {
for _, exp := range ipamutils.GetGlobalScopeDefaultNetworks() {
if types.CompareIPNet(exp, nw) {
found = true
break
@ -291,7 +290,7 @@ func TestNetworkRequest(t *testing.T) {
if err != nil {
t.Fatal(err)
}
nw, err = FindAvailableNetwork(ipamutils.PredefinedLocalScopeDefaultNetworks)
nw, err = FindAvailableNetwork(ipamutils.GetLocalScopeDefaultNetworks())
if err != nil {
t.Fatal(err)
}
@ -300,66 +299,6 @@ func TestNetworkRequest(t *testing.T) {
}
}
func TestElectInterfaceAddressMultipleAddresses(t *testing.T) {
defer testutils.SetupTestOSContext(t)()
nws := []string{"172.101.202.254/16", "172.102.202.254/16"}
createInterface(t, "test", nws...)
ipv4NwList, ipv6NwList, err := ElectInterfaceAddresses("test")
if err != nil {
t.Fatal(err)
}
if len(ipv4NwList) == 0 {
t.Fatal("unexpected empty ipv4 network addresses")
}
if len(ipv6NwList) == 0 {
t.Fatal("unexpected empty ipv6 network addresses")
}
nwList := []string{}
for _, ipv4Nw := range ipv4NwList {
nwList = append(nwList, ipv4Nw.String())
}
sort.Strings(nws)
sort.Strings(nwList)
if len(nws) != len(nwList) {
t.Fatalf("expected %v. got %v", nws, nwList)
}
for i, nw := range nws {
if nw != nwList[i] {
t.Fatalf("expected %v. got %v", nw, nwList[i])
}
}
}
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 len(ipv4Nw) == 0 {
t.Fatal("unexpected empty ipv4 network addresses")
}
if len(ipv6Nw) == 0 {
t.Fatal("unexpected empty ipv6 network addresses")
}
if nws != ipv4Nw[0].String() {
t.Fatalf("expected %s. got %s", nws, ipv4Nw[0])
}
}
func createInterface(t *testing.T, name string, nws ...string) {
// Add interface
link := &netlink.Bridge{