Merge pull request #44827 from corhere/libnw/drop-electinterfaceaddresses
libnetwork: reduce usage of shared mutable state in ipamutils
This commit is contained in:
commit
6c9dd8b650
14 changed files with 267 additions and 311 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 != "" {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
62
libnetwork/ipams/builtin/builtin.go
Normal file
62
libnetwork/ipams/builtin/builtin.go
Normal 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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"))
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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{
|
||||
|
|
Loading…
Add table
Reference in a new issue