Prechádzať zdrojové kódy

Phase-2 bridge driver changes to support IPAM

- Set bridge ipv4 address when bridge is present
- IPv6 changes for bridge
- Convert unit tests to the new model

Signed-off-by: Alessandro Boch <aboch@docker.com>
Alessandro Boch 9 rokov pred
rodič
commit
af3eb25d44

+ 33 - 0
libnetwork/bitseq/sequence.go

@@ -5,6 +5,7 @@ package bitseq
 
 
 import (
 import (
 	"encoding/binary"
 	"encoding/binary"
+	"encoding/json"
 	"fmt"
 	"fmt"
 	"sync"
 	"sync"
 
 
@@ -392,6 +393,38 @@ func (h *Handle) String() string {
 		h.app, h.id, h.dbIndex, h.bits, h.unselected, h.head.toString())
 		h.app, h.id, h.dbIndex, h.bits, h.unselected, h.head.toString())
 }
 }
 
 
+// MarshalJSON encodes Handle into json message
+func (h *Handle) MarshalJSON() ([]byte, error) {
+	m := map[string]interface{}{
+		"id": h.id,
+	}
+
+	b, err := h.ToByteArray()
+	if err != nil {
+		return nil, err
+	}
+	m["sequence"] = b
+	return json.Marshal(m)
+}
+
+// UnmarshalJSON decodes json message into Handle
+func (h *Handle) UnmarshalJSON(data []byte) error {
+	var (
+		m   map[string]interface{}
+		b   []byte
+		err error
+	)
+	if err = json.Unmarshal(data, &m); err != nil {
+		return err
+	}
+	h.id = m["id"].(string)
+	bi, _ := json.Marshal(m["sequence"])
+	if err := json.Unmarshal(bi, &b); err != nil {
+		return err
+	}
+	return h.FromByteArray(b)
+}
+
 // getFirstAvailable looks for the first unset bit in passed mask starting from start
 // getFirstAvailable looks for the first unset bit in passed mask starting from start
 func getFirstAvailable(head *sequence, start uint32) (uint32, uint32, error) {
 func getFirstAvailable(head *sequence, start uint32) (uint32, uint32, error) {
 	// Find sequence which contains the start bit
 	// Find sequence which contains the start bit

+ 4 - 17
libnetwork/bitseq/store.go

@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 
 
-	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/types"
 	"github.com/docker/libnetwork/types"
 )
 )
@@ -25,27 +24,16 @@ func (h *Handle) KeyPrefix() []string {
 
 
 // Value marshals the data to be stored in the KV store
 // Value marshals the data to be stored in the KV store
 func (h *Handle) Value() []byte {
 func (h *Handle) Value() []byte {
-	b, err := h.ToByteArray()
+	b, err := json.Marshal(h)
 	if err != nil {
 	if err != nil {
-		log.Warnf("Failed to serialize Handle: %v", err)
-		b = []byte{}
-	}
-	jv, err := json.Marshal(b)
-	if err != nil {
-		log.Warnf("Failed to json encode bitseq handler byte array: %v", err)
-		return []byte{}
+		return nil
 	}
 	}
-	return jv
+	return b
 }
 }
 
 
 // SetValue unmarshals the data from the KV store
 // SetValue unmarshals the data from the KV store
 func (h *Handle) SetValue(value []byte) error {
 func (h *Handle) SetValue(value []byte) error {
-	var b []byte
-	if err := json.Unmarshal(value, &b); err != nil {
-		return err
-	}
-
-	return h.FromByteArray(b)
+	return json.Unmarshal(value, h)
 }
 }
 
 
 // Index returns the latest DB Index as seen by this object
 // Index returns the latest DB Index as seen by this object
@@ -77,7 +65,6 @@ func (h *Handle) New() datastore.KVObject {
 
 
 	return &Handle{
 	return &Handle{
 		app:   h.app,
 		app:   h.app,
-		id:    h.id,
 		store: h.store,
 		store: h.store,
 	}
 	}
 }
 }

+ 20 - 1
libnetwork/cmd/dnet/dnet.go

@@ -29,8 +29,10 @@ import (
 	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/ipamutils"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
 	"github.com/gorilla/mux"
 	"github.com/gorilla/mux"
 )
 )
 
 
@@ -187,7 +189,12 @@ func createDefaultNetwork(c libnetwork.NetworkController) {
 			}
 			}
 			createOptions = append(createOptions,
 			createOptions = append(createOptions,
 				libnetwork.NetworkOptionGeneric(genericOption),
 				libnetwork.NetworkOptionGeneric(genericOption),
-				libnetwork.NetworkOptionPersist(false))
+				ipamOption(nw))
+		}
+
+		if _, err := c.NetworkByName(nw); err == nil {
+			logrus.Debugf("Default network %s already present", nw)
+			return
 		}
 		}
 		_, err := c.NewNetwork(d, nw, createOptions...)
 		_, err := c.NewNetwork(d, nw, createOptions...)
 		if err != nil {
 		if err != nil {
@@ -405,3 +412,15 @@ func encodeData(data interface{}) (*bytes.Buffer, error) {
 	}
 	}
 	return params, nil
 	return params, nil
 }
 }
+
+func ipamOption(bridgeName string) libnetwork.NetworkOption {
+	if nw, _, err := ipamutils.ElectInterfaceAddresses(bridgeName); err == nil {
+		ipamV4Conf := &libnetwork.IpamConf{PreferredPool: nw.String()}
+		hip, _ := types.GetHostPartIP(nw.IP, nw.Mask)
+		if hip.IsGlobalUnicast() {
+			ipamV4Conf.Gateway = nw.IP.String()
+		}
+		return libnetwork.NetworkOptionIpam("default", "", []*libnetwork.IpamConf{ipamV4Conf}, nil)
+	}
+	return nil
+}

+ 64 - 47
libnetwork/drivers/bridge/bridge.go

@@ -56,15 +56,17 @@ type configuration struct {
 // networkConfiguration for network specific configuration
 // networkConfiguration for network specific configuration
 type networkConfiguration struct {
 type networkConfiguration struct {
 	BridgeName         string
 	BridgeName         string
-	AddressIPv4        *net.IPNet
 	EnableIPv6         bool
 	EnableIPv6         bool
 	EnableIPMasquerade bool
 	EnableIPMasquerade bool
 	EnableICC          bool
 	EnableICC          bool
 	Mtu                int
 	Mtu                int
-	DefaultGatewayIPv4 net.IP
-	DefaultGatewayIPv6 net.IP
 	DefaultBindingIP   net.IP
 	DefaultBindingIP   net.IP
 	DefaultBridge      bool
 	DefaultBridge      bool
+	// Internal fields set after ipam data parsing
+	AddressIPv4        *net.IPNet
+	AddressIPv6        *net.IPNet
+	DefaultGatewayIPv4 net.IP
+	DefaultGatewayIPv6 net.IP
 }
 }
 
 
 // endpointConfiguration represents the user specified configuration for the sandbox endpoint
 // endpointConfiguration represents the user specified configuration for the sandbox endpoint
@@ -161,27 +163,39 @@ func (c *networkConfiguration) Validate() error {
 		}
 		}
 	}
 	}
 
 
+	// If default v6 gw is specified, AddressIPv6 must be specified and gw must belong to AddressIPv6 subnet
+	if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
+		if c.AddressIPv6 == nil || !c.AddressIPv6.Contains(c.DefaultGatewayIPv6) {
+			return &ErrInvalidGateway{}
+		}
+	}
 	return nil
 	return nil
 }
 }
 
 
 // Conflicts check if two NetworkConfiguration objects overlap
 // Conflicts check if two NetworkConfiguration objects overlap
-func (c *networkConfiguration) Conflicts(o *networkConfiguration) bool {
+func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
 	if o == nil {
 	if o == nil {
-		return false
+		return fmt.Errorf("same configuration")
 	}
 	}
 
 
 	// Also empty, becasue only one network with empty name is allowed
 	// Also empty, becasue only one network with empty name is allowed
 	if c.BridgeName == o.BridgeName {
 	if c.BridgeName == o.BridgeName {
-		return true
+		return fmt.Errorf("networks have same name")
 	}
 	}
 
 
 	// They must be in different subnets
 	// They must be in different subnets
 	if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) &&
 	if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) &&
 		(c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
 		(c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
-		return true
+		return fmt.Errorf("networks have overlapping IPv4")
+	}
+
+	// They must be in different v6 subnets
+	if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) &&
+		(c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) {
+		return fmt.Errorf("networks have overlapping IPv6")
 	}
 	}
 
 
-	return false
+	return nil
 }
 }
 
 
 // fromMap retrieve the configuration data from the map form.
 // fromMap retrieve the configuration data from the map form.
@@ -456,18 +470,18 @@ func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []d
 		c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway)
 		c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway)
 	}
 	}
 
 
-	if c.EnableIPv6 && len(ipamV6Data) == 0 {
-		return types.BadRequestErrorf("bridge network %s requires ipv6 configuration", id)
-	}
-
-	gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]
-	if ok {
+	if gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]; ok {
 		c.DefaultGatewayIPv4 = gw.IP
 		c.DefaultGatewayIPv4 = gw.IP
 	}
 	}
 
 
-	gw, ok = ipamV4Data[0].AuxAddresses[DefaultGatewayV6AuxKey]
-	if ok {
-		c.DefaultGatewayIPv6 = gw.IP
+	if len(ipamV6Data) > 0 {
+		if ipamV6Data[0].Gateway != nil {
+			c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway)
+		}
+
+		if gw, ok := ipamV6Data[0].AuxAddresses[DefaultGatewayV6AuxKey]; ok {
+			c.DefaultGatewayIPv6 = gw.IP
+		}
 	}
 	}
 
 
 	return nil
 	return nil
@@ -502,6 +516,9 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati
 
 
 // Returns the non link-local IPv6 subnet for the containers attached to this bridge if found, nil otherwise
 // Returns the non link-local IPv6 subnet for the containers attached to this bridge if found, nil otherwise
 func getV6Network(config *networkConfiguration, i *bridgeInterface) *net.IPNet {
 func getV6Network(config *networkConfiguration, i *bridgeInterface) *net.IPNet {
+	if config.AddressIPv6 != nil {
+		return config.AddressIPv6
+	}
 	if i.bridgeIPv6 != nil && i.bridgeIPv6.IP != nil && !i.bridgeIPv6.IP.IsLinkLocalUnicast() {
 	if i.bridgeIPv6 != nil && i.bridgeIPv6.IP != nil && !i.bridgeIPv6.IP.IsLinkLocalUnicast() {
 		return i.bridgeIPv6
 		return i.bridgeIPv6
 	}
 	}
@@ -551,8 +568,9 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
 		nw.Lock()
 		nw.Lock()
 		nwConfig := nw.config
 		nwConfig := nw.config
 		nw.Unlock()
 		nw.Unlock()
-		if nwConfig.Conflicts(config) {
-			return types.ForbiddenErrorf("conflicts with network %s (%s)", nw.id, nw.config.BridgeName)
+		if err := nwConfig.Conflicts(config); err != nil {
+			return types.ForbiddenErrorf("cannot create network %s (%s): conflicts with network %s (%s): %s",
+				nwConfig.BridgeName, id, nw.id, nw.config.BridgeName, err.Error())
 		}
 		}
 	}
 	}
 
 
@@ -613,10 +631,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
 	// Even if a bridge exists try to setup IPv4.
 	// Even if a bridge exists try to setup IPv4.
 	bridgeSetup.queueStep(setupBridgeIPv4)
 	bridgeSetup.queueStep(setupBridgeIPv4)
 
 
-	enableIPv6Forwarding := false
-	if d.config.EnableIPForwarding {
-		enableIPv6Forwarding = true
-	}
+	enableIPv6Forwarding := d.config.EnableIPForwarding && config.AddressIPv6 != nil
 
 
 	// Conditionally queue setup steps depending on configuration values.
 	// Conditionally queue setup steps depending on configuration values.
 	for _, step := range []struct {
 	for _, step := range []struct {
@@ -797,11 +812,6 @@ func setHairpinMode(link netlink.Link, enable bool) error {
 }
 }
 
 
 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
-	var (
-		ipv6Addr *net.IPNet
-		err      error
-	)
-
 	defer osl.InitOSContext()()
 	defer osl.InitOSContext()()
 
 
 	if ifInfo == nil {
 	if ifInfo == nil {
@@ -931,7 +941,11 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 		}
 		}
 	}
 	}
 
 
-	ipv4Addr := ifInfo.Address()
+	// Create the sandbox side pipe interface
+	endpoint.srcName = containerIfName
+	endpoint.macAddress = ifInfo.MacAddress()
+	endpoint.addr = ifInfo.Address()
+	endpoint.addrv6 = ifInfo.AddressIPv6()
 
 
 	// Down the interface before configuring mac address.
 	// Down the interface before configuring mac address.
 	if err = netlink.LinkSetDown(sbox); err != nil {
 	if err = netlink.LinkSetDown(sbox); err != nil {
@@ -939,28 +953,38 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 	}
 	}
 
 
 	// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
 	// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
-	mac := ifInfo.MacAddress()
-	if mac == nil {
-		mac = electMacAddress(epConfig, ipv4Addr.IP)
+	if endpoint.macAddress == nil {
+		endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP)
+		if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
+			return err
+		}
 	}
 	}
-	err = netlink.LinkSetHardwareAddr(sbox, mac)
+	err = netlink.LinkSetHardwareAddr(sbox, endpoint.macAddress)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err)
 		return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err)
 	}
 	}
-	endpoint.macAddress = mac
 
 
 	// Up the host interface after finishing all netlink configuration
 	// Up the host interface after finishing all netlink configuration
 	if err = netlink.LinkSetUp(host); err != nil {
 	if err = netlink.LinkSetUp(host); err != nil {
 		return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
 		return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
 	}
 	}
 
 
-	ipv6Addr = ifInfo.AddressIPv6()
-	// Create the sandbox side pipe interface
-	endpoint.srcName = containerIfName
-	endpoint.addr = ipv4Addr
+	if endpoint.addrv6 == nil && config.EnableIPv6 {
+		var ip6 net.IP
+		network := n.bridge.bridgeIPv6
+		ones, _ := network.Mask.Size()
+		if ones <= 80 {
+			ip6 = make(net.IP, len(network.IP))
+			copy(ip6, network.IP)
+			for i, h := range endpoint.macAddress {
+				ip6[i+10] = h
+			}
+		}
 
 
-	if config.EnableIPv6 {
-		endpoint.addrv6 = ipv6Addr
+		endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
+		if err := ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
+			return err
+		}
 	}
 	}
 
 
 	// Program any required port mapping and store them in the endpoint
 	// Program any required port mapping and store them in the endpoint
@@ -969,13 +993,6 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 		return err
 		return err
 	}
 	}
 
 
-	if ifInfo.MacAddress() == nil {
-		err = ifInfo.SetMacAddress(endpoint.macAddress)
-		if err != nil {
-			return err
-		}
-	}
-
 	return nil
 	return nil
 }
 }
 
 

+ 80 - 42
libnetwork/drivers/bridge/bridge_test.go

@@ -8,14 +8,27 @@ import (
 	"testing"
 	"testing"
 
 
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/ipamutils"
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/testutils"
 	"github.com/docker/libnetwork/testutils"
 	"github.com/docker/libnetwork/types"
 	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink"
 )
 )
 
 
+func getIPv4Data(t *testing.T) []driverapi.IPAMData {
+	ipd := driverapi.IPAMData{AddressSpace: "full"}
+	nw, _, err := ipamutils.ElectInterfaceAddresses("")
+	if err != nil {
+		t.Fatal(err)
+	}
+	ipd.Pool = nw
+	// Set network gateway to X.X.X.1
+	ipd.Gateway = types.GetIPNetCopy(nw)
+	ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1
+	return []driverapi.IPAMData{ipd}
+}
+
 func TestCreateFullOptions(t *testing.T) {
 func TestCreateFullOptions(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
 	defer testutils.SetupTestOSContext(t)()
 	d := newDriver()
 	d := newDriver()
@@ -27,17 +40,14 @@ func TestCreateFullOptions(t *testing.T) {
 
 
 	// Test this scenario: Default gw address does not belong to
 	// Test this scenario: Default gw address does not belong to
 	// container network and it's greater than bridge address
 	// container network and it's greater than bridge address
-	cip, cnw, _ := net.ParseCIDR("172.16.122.0/24")
-	cnw.IP = cip
-	ip, nw, _ := net.ParseCIDR("172.16.0.10/16")
-	nw.IP = ip
-	gw := net.ParseIP("172.16.0.1")
+	cnw, _ := types.ParseCIDR("172.16.122.0/24")
+	bnw, _ := types.ParseCIDR("172.16.0.0/24")
+	br, _ := types.ParseCIDR("172.16.0.1/16")
+	defgw, _ := types.ParseCIDR("172.16.0.100/16")
 
 
 	netConfig := &networkConfiguration{
 	netConfig := &networkConfiguration{
-		BridgeName:         DefaultBridgeName,
-		AddressIPv4:        nw,
-		DefaultGatewayIPv4: gw,
-		EnableIPv6:         true,
+		BridgeName: DefaultBridgeName,
+		EnableIPv6: true,
 	}
 	}
 	genericOption := make(map[string]interface{})
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = config
 	genericOption[netlabel.GenericData] = config
@@ -49,14 +59,21 @@ func TestCreateFullOptions(t *testing.T) {
 	netOption := make(map[string]interface{})
 	netOption := make(map[string]interface{})
 	netOption[netlabel.GenericData] = netConfig
 	netOption[netlabel.GenericData] = netConfig
 
 
-	err := d.CreateNetwork("dummy", netOption, nil, nil)
+	ipdList := []driverapi.IPAMData{
+		driverapi.IPAMData{
+			Pool:         bnw,
+			Gateway:      br,
+			AuxAddresses: map[string]*net.IPNet{DefaultGatewayV4AuxKey: defgw},
+		},
+	}
+	err := d.CreateNetwork("dummy", netOption, ipdList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
 	// Verify the IP address allocated for the endpoint belongs to the container network
 	// Verify the IP address allocated for the endpoint belongs to the container network
 	epOptions := make(map[string]interface{})
 	epOptions := make(map[string]interface{})
-	te := &testEndpoint{iface: &testInterface{}}
+	te := newTestEndpoint(cnw, 10)
 	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
 	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create an endpoint : %s", err.Error())
 		t.Fatalf("Failed to create an endpoint : %s", err.Error())
@@ -75,7 +92,7 @@ func TestCreateNoConfig(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = netconfig
 	genericOption[netlabel.GenericData] = netconfig
 
 
-	if err := d.CreateNetwork("dummy", genericOption, nil, nil); err != nil {
+	if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 }
 }
@@ -92,11 +109,11 @@ func TestCreate(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = netconfig
 	genericOption[netlabel.GenericData] = netconfig
 
 
-	if err := d.CreateNetwork("dummy", genericOption, nil, nil); err != nil {
+	if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
-	err := d.CreateNetwork("dummy", genericOption, nil, nil)
+	err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil)
 	if err == nil {
 	if err == nil {
 		t.Fatalf("Expected bridge driver to refuse creation of second network with default name")
 		t.Fatalf("Expected bridge driver to refuse creation of second network with default name")
 	}
 	}
@@ -125,7 +142,7 @@ func TestCreateFail(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = netconfig
 	genericOption[netlabel.GenericData] = netconfig
 
 
-	if err := d.CreateNetwork("dummy", genericOption, nil, nil); err == nil {
+	if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err == nil {
 		t.Fatal("Bridge creation was expected to fail")
 		t.Fatal("Bridge creation was expected to fail")
 	}
 	}
 }
 }
@@ -147,19 +164,19 @@ func TestCreateMultipleNetworks(t *testing.T) {
 	config1 := &networkConfiguration{BridgeName: "net_test_1"}
 	config1 := &networkConfiguration{BridgeName: "net_test_1"}
 	genericOption = make(map[string]interface{})
 	genericOption = make(map[string]interface{})
 	genericOption[netlabel.GenericData] = config1
 	genericOption[netlabel.GenericData] = config1
-	if err := d.CreateNetwork("1", genericOption, nil, nil); err != nil {
+	if err := d.CreateNetwork("1", genericOption, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
 	config2 := &networkConfiguration{BridgeName: "net_test_2"}
 	config2 := &networkConfiguration{BridgeName: "net_test_2"}
 	genericOption[netlabel.GenericData] = config2
 	genericOption[netlabel.GenericData] = config2
-	if err := d.CreateNetwork("2", genericOption, nil, nil); err != nil {
+	if err := d.CreateNetwork("2", genericOption, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
 	config3 := &networkConfiguration{BridgeName: "net_test_3"}
 	config3 := &networkConfiguration{BridgeName: "net_test_3"}
 	genericOption[netlabel.GenericData] = config3
 	genericOption[netlabel.GenericData] = config3
-	if err := d.CreateNetwork("3", genericOption, nil, nil); err != nil {
+	if err := d.CreateNetwork("3", genericOption, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
@@ -168,7 +185,7 @@ func TestCreateMultipleNetworks(t *testing.T) {
 
 
 	config4 := &networkConfiguration{BridgeName: "net_test_4"}
 	config4 := &networkConfiguration{BridgeName: "net_test_4"}
 	genericOption[netlabel.GenericData] = config4
 	genericOption[netlabel.GenericData] = config4
-	if err := d.CreateNetwork("4", genericOption, nil, nil); err != nil {
+	if err := d.CreateNetwork("4", genericOption, getIPv4Data(t), nil); err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
@@ -221,6 +238,12 @@ type testEndpoint struct {
 	routes         []types.StaticRoute
 	routes         []types.StaticRoute
 }
 }
 
 
+func newTestEndpoint(nw *net.IPNet, ordinal byte) *testEndpoint {
+	addr := types.GetIPNetCopy(nw)
+	addr.IP[len(addr.IP)-1] = ordinal
+	return &testEndpoint{iface: &testInterface{addr: addr}}
+}
+
 func (te *testEndpoint) Interface() driverapi.InterfaceInfo {
 func (te *testEndpoint) Interface() driverapi.InterfaceInfo {
 	if te.iface != nil {
 	if te.iface != nil {
 		return te.iface
 		return te.iface
@@ -329,7 +352,8 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
 	genericOption = make(map[string]interface{})
 	genericOption = make(map[string]interface{})
 	genericOption[netlabel.GenericData] = netconfig
 	genericOption[netlabel.GenericData] = netconfig
 
 
-	err := d.CreateNetwork("net1", genericOption, nil, nil)
+	ipdList := getIPv4Data(t)
+	err := d.CreateNetwork("net1", genericOption, ipdList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
@@ -338,7 +362,7 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
 	epOptions := make(map[string]interface{})
 	epOptions := make(map[string]interface{})
 	epOptions[netlabel.PortMap] = portMappings
 	epOptions[netlabel.PortMap] = portMappings
 
 
-	te := &testEndpoint{iface: &testInterface{}}
+	te := newTestEndpoint(ipdList[0].Pool, 11)
 	err = d.CreateEndpoint("net1", "ep1", te.Interface(), epOptions)
 	err = d.CreateEndpoint("net1", "ep1", te.Interface(), epOptions)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create an endpoint : %s", err.Error())
 		t.Fatalf("Failed to create an endpoint : %s", err.Error())
@@ -389,7 +413,8 @@ func TestCreateLinkWithOptions(t *testing.T) {
 	netOptions := make(map[string]interface{})
 	netOptions := make(map[string]interface{})
 	netOptions[netlabel.GenericData] = netconfig
 	netOptions[netlabel.GenericData] = netconfig
 
 
-	err := d.CreateNetwork("net1", netOptions, nil, nil)
+	ipdList := getIPv4Data(t)
+	err := d.CreateNetwork("net1", netOptions, ipdList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
@@ -398,7 +423,7 @@ func TestCreateLinkWithOptions(t *testing.T) {
 	epOptions := make(map[string]interface{})
 	epOptions := make(map[string]interface{})
 	epOptions[netlabel.MacAddress] = mac
 	epOptions[netlabel.MacAddress] = mac
 
 
-	te := &testEndpoint{iface: &testInterface{}}
+	te := newTestEndpoint(ipdList[0].Pool, 11)
 	err = d.CreateEndpoint("net1", "ep", te.Interface(), epOptions)
 	err = d.CreateEndpoint("net1", "ep", te.Interface(), epOptions)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create an endpoint: %s", err.Error())
 		t.Fatalf("Failed to create an endpoint: %s", err.Error())
@@ -458,7 +483,8 @@ func TestLinkContainers(t *testing.T) {
 	genericOption = make(map[string]interface{})
 	genericOption = make(map[string]interface{})
 	genericOption[netlabel.GenericData] = netconfig
 	genericOption[netlabel.GenericData] = netconfig
 
 
-	err := d.CreateNetwork("net1", genericOption, nil, nil)
+	ipdList := getIPv4Data(t)
+	err := d.CreateNetwork("net1", genericOption, ipdList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
@@ -467,7 +493,7 @@ func TestLinkContainers(t *testing.T) {
 	epOptions := make(map[string]interface{})
 	epOptions := make(map[string]interface{})
 	epOptions[netlabel.ExposedPorts] = exposedPorts
 	epOptions[netlabel.ExposedPorts] = exposedPorts
 
 
-	te1 := &testEndpoint{iface: &testInterface{}}
+	te1 := newTestEndpoint(ipdList[0].Pool, 11)
 	err = d.CreateEndpoint("net1", "ep1", te1.Interface(), epOptions)
 	err = d.CreateEndpoint("net1", "ep1", te1.Interface(), epOptions)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create an endpoint : %s", err.Error())
 		t.Fatalf("Failed to create an endpoint : %s", err.Error())
@@ -478,7 +504,7 @@ func TestLinkContainers(t *testing.T) {
 		t.Fatalf("No Ipv4 address assigned to the endpoint:  ep1")
 		t.Fatalf("No Ipv4 address assigned to the endpoint:  ep1")
 	}
 	}
 
 
-	te2 := &testEndpoint{iface: &testInterface{}}
+	te2 := newTestEndpoint(ipdList[0].Pool, 22)
 	err = d.CreateEndpoint("net1", "ep2", te2.Interface(), nil)
 	err = d.CreateEndpoint("net1", "ep2", te2.Interface(), nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create an endpoint : %s", err.Error())
 		t.Fatalf("Failed to create an endpoint : %s", err.Error())
@@ -581,6 +607,14 @@ func TestValidateConfig(t *testing.T) {
 
 
 	// Bridge network
 	// Bridge network
 	_, network, _ := net.ParseCIDR("172.28.0.0/16")
 	_, network, _ := net.ParseCIDR("172.28.0.0/16")
+	c = networkConfiguration{
+		AddressIPv4: network,
+	}
+
+	err = c.Validate()
+	if err != nil {
+		t.Fatal(err)
+	}
 
 
 	// Test v4 gw
 	// Test v4 gw
 	c.DefaultGatewayIPv4 = net.ParseIP("172.27.30.234")
 	c.DefaultGatewayIPv4 = net.ParseIP("172.27.30.234")
@@ -596,9 +630,10 @@ func TestValidateConfig(t *testing.T) {
 	}
 	}
 
 
 	// Test v6 gw
 	// Test v6 gw
-	_, containerSubnet, _ = net.ParseCIDR("2001:1234:ae:b004::/64")
+	_, v6nw, _ := net.ParseCIDR("2001:1234:ae:b004::/64")
 	c = networkConfiguration{
 	c = networkConfiguration{
 		EnableIPv6:         true,
 		EnableIPv6:         true,
+		AddressIPv6:        v6nw,
 		DefaultGatewayIPv6: net.ParseIP("2001:1234:ac:b004::bad:a55"),
 		DefaultGatewayIPv6: net.ParseIP("2001:1234:ac:b004::bad:a55"),
 	}
 	}
 	err = c.Validate()
 	err = c.Validate()
@@ -611,6 +646,18 @@ func TestValidateConfig(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Unexpected validation error on v6 default gateway")
 		t.Fatalf("Unexpected validation error on v6 default gateway")
 	}
 	}
+
+	c.AddressIPv6 = nil
+	err = c.Validate()
+	if err == nil {
+		t.Fatalf("Failed to detect invalid v6 default gateway")
+	}
+
+	c.AddressIPv6 = nil
+	err = c.Validate()
+	if err == nil {
+		t.Fatalf("Failed to detect invalid v6 default gateway")
+	}
 }
 }
 
 
 func TestSetDefaultGw(t *testing.T) {
 func TestSetDefaultGw(t *testing.T) {
@@ -623,24 +670,15 @@ func TestSetDefaultGw(t *testing.T) {
 
 
 	_, subnetv6, _ := net.ParseCIDR("2001:db8:ea9:9abc:b0c4::/80")
 	_, subnetv6, _ := net.ParseCIDR("2001:db8:ea9:9abc:b0c4::/80")
 
 
-	var nw *net.IPNet
-	for _, n := range bridgeNetworks {
-		if err := netutils.CheckRouteOverlaps(n); err == nil {
-			nw = n
-			break
-		}
-	}
-	if nw == nil {
-		t.Skipf("Skip as no more automatic networks available")
-	}
-
-	gw4 := types.GetIPCopy(nw.IP).To4()
+	ipdList := getIPv4Data(t)
+	gw4 := types.GetIPCopy(ipdList[0].Pool.IP).To4()
 	gw4[3] = 254
 	gw4[3] = 254
 	gw6 := net.ParseIP("2001:db8:ea9:9abc:b0c4::254")
 	gw6 := net.ParseIP("2001:db8:ea9:9abc:b0c4::254")
 
 
 	config := &networkConfiguration{
 	config := &networkConfiguration{
 		BridgeName:         DefaultBridgeName,
 		BridgeName:         DefaultBridgeName,
 		EnableIPv6:         true,
 		EnableIPv6:         true,
+		AddressIPv6:        subnetv6,
 		DefaultGatewayIPv4: gw4,
 		DefaultGatewayIPv4: gw4,
 		DefaultGatewayIPv6: gw6,
 		DefaultGatewayIPv6: gw6,
 	}
 	}
@@ -648,12 +686,12 @@ func TestSetDefaultGw(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = config
 	genericOption[netlabel.GenericData] = config
 
 
-	err := d.CreateNetwork("dummy", genericOption, nil, nil)
+	err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
-	te := &testEndpoint{iface: &testInterface{}}
+	te := newTestEndpoint(ipdList[0].Pool, 10)
 	err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
 	err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create endpoint: %v", err)
 		t.Fatalf("Failed to create endpoint: %v", err)

+ 14 - 11
libnetwork/drivers/bridge/network_test.go

@@ -26,12 +26,13 @@ func TestLinkCreate(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = config
 	genericOption[netlabel.GenericData] = config
 
 
-	err := d.CreateNetwork("dummy", genericOption, nil, nil)
+	ipdList := getIPv4Data(t)
+	err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
-	te := &testEndpoint{iface: &testInterface{}}
+	te := newTestEndpoint(ipdList[0].Pool, 10)
 	err = d.CreateEndpoint("dummy", "", te.Interface(), nil)
 	err = d.CreateEndpoint("dummy", "", te.Interface(), nil)
 	if err != nil {
 	if err != nil {
 		if _, ok := err.(InvalidEndpointIDError); !ok {
 		if _, ok := err.(InvalidEndpointIDError); !ok {
@@ -63,7 +64,7 @@ func TestLinkCreate(t *testing.T) {
 	// TODO: if we could get peer name from (sboxLnk.(*netlink.Veth)).PeerName
 	// TODO: if we could get peer name from (sboxLnk.(*netlink.Veth)).PeerName
 	// then we could check the MTU on hostLnk as well.
 	// then we could check the MTU on hostLnk as well.
 
 
-	te1 := &testEndpoint{iface: &testInterface{}}
+	te1 := newTestEndpoint(ipdList[0].Pool, 11)
 	err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil)
 	err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil)
 	if err == nil {
 	if err == nil {
 		t.Fatalf("Failed to detect duplicate endpoint id on same network")
 		t.Fatalf("Failed to detect duplicate endpoint id on same network")
@@ -117,18 +118,19 @@ func TestLinkCreateTwo(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = config
 	genericOption[netlabel.GenericData] = config
 
 
-	err := d.CreateNetwork("dummy", genericOption, nil, nil)
+	ipdList := getIPv4Data(t)
+	err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
-	te1 := &testEndpoint{iface: &testInterface{}}
+	te1 := newTestEndpoint(ipdList[0].Pool, 11)
 	err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil)
 	err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create a link: %s", err.Error())
 		t.Fatalf("Failed to create a link: %s", err.Error())
 	}
 	}
 
 
-	te2 := &testEndpoint{iface: &testInterface{}}
+	te2 := newTestEndpoint(ipdList[0].Pool, 12)
 	err = d.CreateEndpoint("dummy", "ep", te2.Interface(), nil)
 	err = d.CreateEndpoint("dummy", "ep", te2.Interface(), nil)
 	if err != nil {
 	if err != nil {
 		if _, ok := err.(driverapi.ErrEndpointExists); !ok {
 		if _, ok := err.(driverapi.ErrEndpointExists); !ok {
@@ -152,12 +154,12 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = config
 	genericOption[netlabel.GenericData] = config
 
 
-	err := d.CreateNetwork("dummy", genericOption, nil, nil)
+	ipdList := getIPv4Data(t)
+	err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
-
-	te := &testEndpoint{iface: &testInterface{}}
+	te := newTestEndpoint(ipdList[0].Pool, 30)
 	err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
 	err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create a link: %s", err.Error())
 		t.Fatalf("Failed to create a link: %s", err.Error())
@@ -187,12 +189,13 @@ func TestLinkDelete(t *testing.T) {
 	genericOption := make(map[string]interface{})
 	genericOption := make(map[string]interface{})
 	genericOption[netlabel.GenericData] = config
 	genericOption[netlabel.GenericData] = config
 
 
-	err := d.CreateNetwork("dummy", genericOption, nil, nil)
+	ipdList := getIPv4Data(t)
+	err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
-	te := &testEndpoint{iface: &testInterface{}}
+	te := newTestEndpoint(ipdList[0].Pool, 30)
 	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), nil)
 	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create a link: %s", err.Error())
 		t.Fatalf("Failed to create a link: %s", err.Error())

+ 3 - 2
libnetwork/drivers/bridge/port_mapping_test.go

@@ -44,12 +44,13 @@ func TestPortMappingConfig(t *testing.T) {
 	netOptions := make(map[string]interface{})
 	netOptions := make(map[string]interface{})
 	netOptions[netlabel.GenericData] = netConfig
 	netOptions[netlabel.GenericData] = netConfig
 
 
-	err := d.CreateNetwork("dummy", netOptions, nil, nil)
+	ipdList := getIPv4Data(t)
+	err := d.CreateNetwork("dummy", netOptions, ipdList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create bridge: %v", err)
 		t.Fatalf("Failed to create bridge: %v", err)
 	}
 	}
 
 
-	te := &testEndpoint{iface: &testInterface{}}
+	te := newTestEndpoint(ipdList[0].Pool, 11)
 	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
 	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
 	if err != nil {
 	if err != nil {
 		t.Fatalf("Failed to create the endpoint: %s", err.Error())
 		t.Fatalf("Failed to create the endpoint: %s", err.Error())

+ 1 - 1
libnetwork/drivers/bridge/setup_bridgenetfiltering.go

@@ -22,7 +22,7 @@ const (
 //Gets the IP version in use ( [ipv4], [ipv6] or [ipv4 and ipv6] )
 //Gets the IP version in use ( [ipv4], [ipv6] or [ipv4 and ipv6] )
 func getIPVersion(config *networkConfiguration) ipVersion {
 func getIPVersion(config *networkConfiguration) ipVersion {
 	ipVersion := ipv4
 	ipVersion := ipv4
-	if config.EnableIPv6 {
+	if config.AddressIPv6 != nil || config.EnableIPv6 {
 		ipVersion |= ipv6
 		ipVersion |= ipv6
 	}
 	}
 	return ipVersion
 	return ipVersion

+ 14 - 79
libnetwork/drivers/bridge/setup_ipv4.go

@@ -3,103 +3,38 @@ package bridge
 import (
 import (
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
-	"net"
 	"path/filepath"
 	"path/filepath"
 
 
 	log "github.com/Sirupsen/logrus"
 	log "github.com/Sirupsen/logrus"
-	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink"
 )
 )
 
 
-var bridgeNetworks []*net.IPNet
-
-func init() {
-	// Here we don't follow the convention of using the 1st IP of the range for the gateway.
-	// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
-	// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
-	// on the internal addressing or other stupid things like that.
-	// They shouldn't, but hey, let's not break them unless we really have to.
-	// Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
-
-	// 172.[17-31].42.1/16
-	mask := []byte{255, 255, 0, 0}
-	for i := 17; i < 32; i++ {
-		bridgeNetworks = append(bridgeNetworks, &net.IPNet{IP: []byte{172, byte(i), 42, 1}, Mask: mask})
-	}
-	// 10.[0-255].42.1/16
-	for i := 0; i < 256; i++ {
-		bridgeNetworks = append(bridgeNetworks, &net.IPNet{IP: []byte{10, byte(i), 42, 1}, Mask: mask})
-	}
-	// 192.168.[42-44].1/24
-	mask24 := []byte{255, 255, 255, 0}
-	for i := 42; i < 45; i++ {
-		bridgeNetworks = append(bridgeNetworks, &net.IPNet{IP: []byte{192, 168, byte(i), 1}, Mask: mask24})
-	}
-}
-
 func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error {
 func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error {
 	addrv4, _, err := i.addresses()
 	addrv4, _, err := i.addresses()
 	if err != nil {
 	if err != nil {
-		return err
-	}
-
-	// Check if we have an IP address already on the bridge.
-	if addrv4.IPNet != nil {
-		// Make sure to store bridge network and default gateway before getting out.
-		i.bridgeIPv4 = addrv4.IPNet
-		i.gatewayIPv4 = addrv4.IPNet.IP
-		return nil
-	}
-
-	// Do not try to configure IPv4 on a non-default bridge unless you are
-	// specifically asked to do so.
-	if config.BridgeName != DefaultBridgeName && config.DefaultBridge {
-		return NonDefaultBridgeNeedsIPError(config.BridgeName)
-	}
-
-	bridgeIPv4, err := electBridgeIPv4(config)
-	if err != nil {
-		return err
+		return fmt.Errorf("failed to retrieve bridge interface addresses: %v", err)
 	}
 	}
 
 
-	log.Debugf("Creating bridge interface %s with network %s", config.BridgeName, bridgeIPv4)
-	if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: bridgeIPv4}); err != nil {
-		return &IPv4AddrAddError{IP: bridgeIPv4, Err: err}
+	if !types.CompareIPNet(addrv4.IPNet, config.AddressIPv4) {
+		if addrv4.IPNet != nil {
+			if err := netlink.AddrDel(i.Link, &addrv4); err != nil {
+				return fmt.Errorf("failed to remove current ip address from bridge: %v", err)
+			}
+		}
+		log.Debugf("Assigning address to bridge interface %s: %s", config.BridgeName, config.AddressIPv4)
+		if err := netlink.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
+			return &IPv4AddrAddError{IP: config.AddressIPv4, Err: err}
+		}
 	}
 	}
 
 
 	// Store bridge network and default gateway
 	// Store bridge network and default gateway
-	i.bridgeIPv4 = bridgeIPv4
-	i.gatewayIPv4 = i.bridgeIPv4.IP
+	i.bridgeIPv4 = config.AddressIPv4
+	i.gatewayIPv4 = config.AddressIPv4.IP
 
 
 	return nil
 	return nil
 }
 }
 
 
-func electBridgeIPv4(config *networkConfiguration) (*net.IPNet, error) {
-	// Use the requested IPv4 CIDR when available.
-	if config.AddressIPv4 != nil {
-		return config.AddressIPv4, nil
-	}
-
-	// 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.
-	nameservers := []string{}
-	if resolvConf, _ := readResolvConf(); resolvConf != nil {
-		nameservers = append(nameservers, getNameserversAsCIDR(resolvConf)...)
-	}
-
-	// Try to automatically elect appropriate bridge IPv4 settings.
-	for _, n := range bridgeNetworks {
-		if err := netutils.CheckNameserverOverlaps(nameservers, n); err == nil {
-			if err := netutils.CheckRouteOverlaps(n); err == nil {
-				return n, nil
-			}
-		}
-	}
-
-	return nil, IPv4AddrRangeError(config.BridgeName)
-}
-
 func setupGatewayIPv4(config *networkConfiguration, i *bridgeInterface) error {
 func setupGatewayIPv4(config *networkConfiguration, i *bridgeInterface) error {
 	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
 	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
 		return &ErrInvalidGateway{}
 		return &ErrInvalidGateway{}

+ 0 - 49
libnetwork/drivers/bridge/setup_ipv4_test.go

@@ -4,7 +4,6 @@ import (
 	"net"
 	"net"
 	"testing"
 	"testing"
 
 
-	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/testutils"
 	"github.com/docker/libnetwork/testutils"
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink"
 )
 )
@@ -52,43 +51,6 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) {
 	}
 	}
 }
 }
 
 
-func TestSetupBridgeIPv4Auto(t *testing.T) {
-	defer testutils.SetupTestOSContext(t)()
-
-	var toBeChosen *net.IPNet
-	for _, n := range bridgeNetworks {
-		if err := netutils.CheckRouteOverlaps(n); err == nil {
-			toBeChosen = n
-			break
-		}
-	}
-	if toBeChosen == nil {
-		t.Skipf("Skip as no more automatic networks available")
-	}
-
-	config, br := setupTestInterface(t)
-	if err := setupBridgeIPv4(config, br); err != nil {
-		t.Fatalf("Failed to setup bridge IPv4: %v", err)
-	}
-
-	addrsv4, err := netlink.AddrList(br.Link, netlink.FAMILY_V4)
-	if err != nil {
-		t.Fatalf("Failed to list device IPv4 addresses: %v", err)
-	}
-
-	var found bool
-	for _, addr := range addrsv4 {
-		if toBeChosen.String() == addr.IPNet.String() {
-			found = true
-			break
-		}
-	}
-
-	if !found {
-		t.Fatalf("Bridge device does not have the automatic IPv4 address %s", toBeChosen.String())
-	}
-}
-
 func TestSetupGatewayIPv4(t *testing.T) {
 func TestSetupGatewayIPv4(t *testing.T) {
 	defer testutils.SetupTestOSContext(t)()
 	defer testutils.SetupTestOSContext(t)()
 
 
@@ -110,14 +72,3 @@ func TestSetupGatewayIPv4(t *testing.T) {
 		t.Fatalf("Set Default Gateway failed. Expected %v, Found %v", gw, br.gatewayIPv4)
 		t.Fatalf("Set Default Gateway failed. Expected %v, Found %v", gw, br.gatewayIPv4)
 	}
 	}
 }
 }
-
-func TestCheckPreallocatedBridgeNetworks(t *testing.T) {
-	// Just make sure the bridge networks are created the way we want (172.17.x.x/16)
-	for i := 0; i < len(bridgeNetworks); i++ {
-		fb := bridgeNetworks[i].IP[0]
-		ones, _ := bridgeNetworks[i].Mask.Size()
-		if ((fb == 172 || fb == 10) && ones != 16) || (fb == 192 && ones != 24) {
-			t.Fatalf("Wrong mask for preallocated bridge network: %s", bridgeNetworks[i].String())
-		}
-	}
-}

+ 24 - 0
libnetwork/drivers/bridge/setup_ipv6.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"net"
 	"net"
+	"os"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink"
@@ -57,12 +58,35 @@ func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
 	i.bridgeIPv6 = bridgeIPv6
 	i.bridgeIPv6 = bridgeIPv6
 	i.gatewayIPv6 = i.bridgeIPv6.IP
 	i.gatewayIPv6 = i.bridgeIPv6.IP
 
 
+	if config.AddressIPv6 == nil {
+		return nil
+	}
+
+	// Setting route to global IPv6 subnet
+	logrus.Debugf("Adding route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName)
+	err = netlink.RouteAdd(&netlink.Route{
+		Scope:     netlink.SCOPE_UNIVERSE,
+		LinkIndex: i.Link.Attrs().Index,
+		Dst:       config.AddressIPv6,
+	})
+	if err != nil && !os.IsExist(err) {
+		logrus.Errorf("Could not add route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName)
+	}
+
 	return nil
 	return nil
 }
 }
 
 
 func setupGatewayIPv6(config *networkConfiguration, i *bridgeInterface) error {
 func setupGatewayIPv6(config *networkConfiguration, i *bridgeInterface) error {
+	if config.AddressIPv6 == nil {
+		return &ErrInvalidContainerSubnet{}
+	}
+	if !config.AddressIPv6.Contains(config.DefaultGatewayIPv6) {
+		return &ErrInvalidGateway{}
+	}
+
 	// Store requested default gateway
 	// Store requested default gateway
 	i.gatewayIPv6 = config.DefaultGatewayIPv6
 	i.gatewayIPv6 = config.DefaultGatewayIPv6
+
 	return nil
 	return nil
 }
 }
 
 

+ 1 - 0
libnetwork/drivers/bridge/setup_ipv6_test.go

@@ -55,6 +55,7 @@ func TestSetupGatewayIPv6(t *testing.T) {
 
 
 	config := &networkConfiguration{
 	config := &networkConfiguration{
 		BridgeName:         DefaultBridgeName,
 		BridgeName:         DefaultBridgeName,
+		AddressIPv6:        nw,
 		DefaultGatewayIPv6: gw}
 		DefaultGatewayIPv6: gw}
 
 
 	br := &bridgeInterface{}
 	br := &bridgeInterface{}

+ 7 - 0
libnetwork/endpoint.go

@@ -622,10 +622,14 @@ func (ep *endpoint) assignAddress() error {
 		ipam ipamapi.Ipam
 		ipam ipamapi.Ipam
 		err  error
 		err  error
 	)
 	)
+
 	n := ep.getNetwork()
 	n := ep.getNetwork()
 	if n.Type() == "host" || n.Type() == "null" {
 	if n.Type() == "host" || n.Type() == "null" {
 		return nil
 		return nil
 	}
 	}
+
+	log.Debugf("Assigning addresses for endpoint %s's interface on network %s", ep.Name(), n.Name())
+
 	ipam, err = n.getController().getIpamDriver(n.ipamType)
 	ipam, err = n.getController().getIpamDriver(n.ipamType)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -683,6 +687,9 @@ func (ep *endpoint) releaseAddress() {
 	if n.Type() == "host" || n.Type() == "null" {
 	if n.Type() == "host" || n.Type() == "null" {
 		return
 		return
 	}
 	}
+
+	log.Debugf("Releasing addresses for endpoint %s's interface on network %s", ep.Name(), n.Name())
+
 	ipam, err := n.getController().getIpamDriver(n.ipamType)
 	ipam, err := n.getController().getIpamDriver(n.ipamType)
 	if err != nil {
 	if err != nil {
 		log.Warnf("Failed to retrieve ipam driver to release interface address on delete of endpoint %s (%s): %v", ep.Name(), ep.ID(), err)
 		log.Warnf("Failed to retrieve ipam driver to release interface address on delete of endpoint %s (%s): %v", ep.Name(), ep.ID(), err)

+ 7 - 2
libnetwork/ipam/allocator.go

@@ -102,8 +102,9 @@ func (a *Allocator) updateBitMasks(aSpace *addrSpace) error {
 	aSpace.Lock()
 	aSpace.Lock()
 	for k, v := range aSpace.subnets {
 	for k, v := range aSpace.subnets {
 		if v.Range == nil {
 		if v.Range == nil {
-			inserterList = append(inserterList,
-				func() error { return a.insertBitMask(k, v.Pool) })
+			kk := k
+			vv := v
+			inserterList = append(inserterList, func() error { return a.insertBitMask(kk, vv.Pool) })
 		}
 		}
 	}
 	}
 	aSpace.Unlock()
 	aSpace.Unlock()
@@ -127,6 +128,7 @@ func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) {
 
 
 // RequestPool returns an address pool along with its unique id.
 // RequestPool returns an address pool along with its unique id.
 func (a *Allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
 func (a *Allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
+	log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6)
 	k, nw, aw, ipr, err := a.parsePoolRequest(addressSpace, pool, subPool, v6)
 	k, nw, aw, ipr, err := a.parsePoolRequest(addressSpace, pool, subPool, v6)
 	if err != nil {
 	if err != nil {
 		return "", nil, nil, ipamapi.ErrInvalidPool
 		return "", nil, nil, ipamapi.ErrInvalidPool
@@ -160,6 +162,7 @@ retry:
 
 
 // ReleasePool releases the address pool identified by the passed id
 // ReleasePool releases the address pool identified by the passed id
 func (a *Allocator) ReleasePool(poolID string) error {
 func (a *Allocator) ReleasePool(poolID string) error {
+	log.Debugf("ReleasePool(%s)", poolID)
 	k := SubnetKey{}
 	k := SubnetKey{}
 	if err := k.FromString(poolID); err != nil {
 	if err := k.FromString(poolID); err != nil {
 		return types.BadRequestErrorf("invalid pool id: %s", poolID)
 		return types.BadRequestErrorf("invalid pool id: %s", poolID)
@@ -343,6 +346,7 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error)
 
 
 // RequestAddress returns an address from the specified pool ID
 // RequestAddress returns an address from the specified pool ID
 func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
 func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
+	log.Debugf("RequestAddress(%s, %v, %v)", poolID, prefAddress, opts)
 	k := SubnetKey{}
 	k := SubnetKey{}
 	if err := k.FromString(poolID); err != nil {
 	if err := k.FromString(poolID); err != nil {
 		return nil, nil, types.BadRequestErrorf("invalid pool id: %s", poolID)
 		return nil, nil, types.BadRequestErrorf("invalid pool id: %s", poolID)
@@ -391,6 +395,7 @@ func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[s
 
 
 // ReleaseAddress releases the address from the specified pool ID
 // ReleaseAddress releases the address from the specified pool ID
 func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
 func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
+	log.Debugf("ReleaseAddress(%s, %v)", poolID, address)
 	k := SubnetKey{}
 	k := SubnetKey{}
 	if err := k.FromString(poolID); err != nil {
 	if err := k.FromString(poolID); err != nil {
 		return types.BadRequestErrorf("invalid pool id: %s", poolID)
 		return types.BadRequestErrorf("invalid pool id: %s", poolID)

+ 20 - 23
libnetwork/ipam/allocator_test.go

@@ -13,7 +13,7 @@ import (
 	"github.com/docker/libnetwork/bitseq"
 	"github.com/docker/libnetwork/bitseq"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/ipamapi"
 	"github.com/docker/libnetwork/ipamapi"
-	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/ipamutils"
 	_ "github.com/docker/libnetwork/testutils"
 	_ "github.com/docker/libnetwork/testutils"
 	"github.com/docker/libnetwork/types"
 	"github.com/docker/libnetwork/types"
 )
 )
@@ -461,22 +461,33 @@ func TestPredefinedPool(t *testing.T) {
 		t.Fatalf("Expected failure for non default addr space")
 		t.Fatalf("Expected failure for non default addr space")
 	}
 	}
 
 
-	i, available, err := getFirstAvailablePool(a, localAddressSpace, 2)
+	exp, err := ipamutils.FindAvailableNetwork(a.predefined[localAddressSpace])
 	if err != nil {
 	if err != nil {
-		t.Skip(err)
+		t.Fatal(err)
 	}
 	}
 
 
-	pid, _, _, err := a.RequestPool(localAddressSpace, available.String(), "", nil, false)
+	nw, err := a.getPredefinedPool(localAddressSpace, false)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
+	if !types.CompareIPNet(nw, exp) {
+		t.Fatalf("Unexpected default network returned: %s. Expected: %s", nw, exp)
+	}
 
 
-	nw, err := a.getPredefinedPool(localAddressSpace, false)
+	pid, nw, _, err := a.RequestPool(localAddressSpace, exp.String(), "", nil, false)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	if nw != a.predefined[localAddressSpace][i+1] {
-		t.Fatalf("Unexpected default network returned: %s", nw)
+	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)
+	}
+	if types.CompareIPNet(nw, nw2) {
+		t.Fatalf("Unexpected default network returned: %s = %s", nw2, nw)
 	}
 	}
 
 
 	if err := a.ReleasePool(pid); err != nil {
 	if err := a.ReleasePool(pid); err != nil {
@@ -487,23 +498,9 @@ func TestPredefinedPool(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	if nw != a.predefined[localAddressSpace][i] {
-		t.Fatalf("Unexpected default network returned: %s", nw)
-	}
-}
-
-func getFirstAvailablePool(a *Allocator, as string, atLeast int) (int, *net.IPNet, error) {
-	i := 0
-	for i < len(a.predefined[as])-1 {
-		if err := netutils.CheckRouteOverlaps(a.predefined[as][i]); err == nil {
-			break
-		}
-		i++
-	}
-	if i > len(a.predefined[as])-1-atLeast {
-		return 0, nil, fmt.Errorf("Not enough non-overlapping networks to run the test")
+	if !types.CompareIPNet(nw, exp) {
+		t.Fatalf("Unexpected default network returned: %s. Expected %s", nw, exp)
 	}
 	}
-	return i, a.predefined[as][i], nil
 }
 }
 
 
 func TestAdjustAndCheckSubnet(t *testing.T) {
 func TestAdjustAndCheckSubnet(t *testing.T) {

+ 38 - 51
libnetwork/libnetwork_test.go

@@ -23,6 +23,7 @@ import (
 	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/ipamapi"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/osl"
@@ -82,14 +83,10 @@ func createController() error {
 	return nil
 	return nil
 }
 }
 
 
-func createTestNetwork(networkType, networkName string, netOption options.Generic) (libnetwork.Network, error) {
-	network, err := controller.NewNetwork(networkType, networkName,
-		libnetwork.NetworkOptionGeneric(netOption))
-	if err != nil {
-		return nil, err
-	}
-
-	return network, nil
+func createTestNetwork(networkType, networkName string, netOption options.Generic, ipamV4Configs, ipamV6Configs []*libnetwork.IpamConf) (libnetwork.Network, error) {
+	return controller.NewNetwork(networkType, networkName,
+		libnetwork.NetworkOptionGeneric(netOption),
+		libnetwork.NetworkOptionIpam(ipamapi.DefaultIPAM, "", ipamV4Configs, ipamV6Configs))
 }
 }
 
 
 func getEmptyGenericOption() map[string]interface{} {
 func getEmptyGenericOption() map[string]interface{} {
@@ -117,7 +114,7 @@ func TestNull(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	network, err := createTestNetwork("null", "testnull", options.Generic{})
+	network, err := createTestNetwork("null", "testnull", options.Generic{}, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -184,7 +181,7 @@ func TestHost(t *testing.T) {
 		}
 		}
 	}()
 	}()
 
 
-	network, err := createTestNetwork("host", "testhost", options.Generic{})
+	network, err := createTestNetwork("host", "testhost", options.Generic{}, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -270,24 +267,18 @@ func TestBridge(t *testing.T) {
 		defer testutils.SetupTestOSContext(t)()
 		defer testutils.SetupTestOSContext(t)()
 	}
 	}
 
 
-	subnet, err := types.ParseCIDR("192.168.100.1/24")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	log.Debug("Adding a bridge")
-
 	netOption := options.Generic{
 	netOption := options.Generic{
 		netlabel.GenericData: options.Generic{
 		netlabel.GenericData: options.Generic{
 			"BridgeName":         "testnetwork",
 			"BridgeName":         "testnetwork",
-			"AddressIPv4":        subnet,
 			"EnableIPv6":         true,
 			"EnableIPv6":         true,
 			"EnableICC":          true,
 			"EnableICC":          true,
 			"EnableIPMasquerade": true,
 			"EnableIPMasquerade": true,
 		},
 		},
 	}
 	}
+	ipamV4ConfList := []*libnetwork.IpamConf{&libnetwork.IpamConf{PreferredPool: "192.168.100.0/24", Gateway: "192.168.100.1"}}
+	ipamV6ConfList := []*libnetwork.IpamConf{&libnetwork.IpamConf{PreferredPool: "fe90::/98", Gateway: "fe90::22"}}
 
 
-	network, err := createTestNetwork(bridgeNetType, "testnetwork", netOption)
+	network, err := createTestNetwork(bridgeNetType, "testnetwork", netOption, ipamV4ConfList, ipamV6ConfList)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -327,7 +318,7 @@ func TestUnknownDriver(t *testing.T) {
 		defer testutils.SetupTestOSContext(t)()
 		defer testutils.SetupTestOSContext(t)()
 	}
 	}
 
 
-	_, err := createTestNetwork("unknowndriver", "testnetwork", options.Generic{})
+	_, err := createTestNetwork("unknowndriver", "testnetwork", options.Generic{}, nil, nil)
 	if err == nil {
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
 	}
@@ -360,7 +351,7 @@ func TestNetworkName(t *testing.T) {
 		},
 		},
 	}
 	}
 
 
-	_, err := createTestNetwork(bridgeNetType, "", netOption)
+	_, err := createTestNetwork(bridgeNetType, "", netOption, nil, nil)
 	if err == nil {
 	if err == nil {
 		t.Fatal("Expected to fail. But instead succeeded")
 		t.Fatal("Expected to fail. But instead succeeded")
 	}
 	}
@@ -370,7 +361,7 @@ func TestNetworkName(t *testing.T) {
 	}
 	}
 
 
 	networkName := "testnetwork"
 	networkName := "testnetwork"
-	n, err := createTestNetwork(bridgeNetType, networkName, netOption)
+	n, err := createTestNetwork(bridgeNetType, networkName, netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -396,7 +387,7 @@ func TestNetworkType(t *testing.T) {
 		},
 		},
 	}
 	}
 
 
-	n, err := createTestNetwork(bridgeNetType, "testnetwork", netOption)
+	n, err := createTestNetwork(bridgeNetType, "testnetwork", netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -422,7 +413,7 @@ func TestNetworkID(t *testing.T) {
 		},
 		},
 	}
 	}
 
 
-	n, err := createTestNetwork(bridgeNetType, "testnetwork", netOption)
+	n, err := createTestNetwork(bridgeNetType, "testnetwork", netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -449,7 +440,7 @@ func TestDeleteNetworkWithActiveEndpoints(t *testing.T) {
 		netlabel.GenericData: netOption,
 		netlabel.GenericData: netOption,
 	}
 	}
 
 
-	network, err := createTestNetwork(bridgeNetType, "testnetwork", option)
+	network, err := createTestNetwork(bridgeNetType, "testnetwork", option, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -490,7 +481,7 @@ func TestUnknownNetwork(t *testing.T) {
 		netlabel.GenericData: netOption,
 		netlabel.GenericData: netOption,
 	}
 	}
 
 
-	network, err := createTestNetwork(bridgeNetType, "testnetwork", option)
+	network, err := createTestNetwork(bridgeNetType, "testnetwork", option, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -515,20 +506,15 @@ func TestUnknownEndpoint(t *testing.T) {
 		defer testutils.SetupTestOSContext(t)()
 		defer testutils.SetupTestOSContext(t)()
 	}
 	}
 
 
-	subnet, err := types.ParseCIDR("192.168.100.1/24")
-	if err != nil {
-		t.Fatal(err)
-	}
-
 	netOption := options.Generic{
 	netOption := options.Generic{
-		"BridgeName":  "testnetwork",
-		"AddressIPv4": subnet,
+		"BridgeName": "testnetwork",
 	}
 	}
 	option := options.Generic{
 	option := options.Generic{
 		netlabel.GenericData: netOption,
 		netlabel.GenericData: netOption,
 	}
 	}
+	ipamV4ConfList := []*libnetwork.IpamConf{&libnetwork.IpamConf{PreferredPool: "192.168.100.0/24"}}
 
 
-	network, err := createTestNetwork(bridgeNetType, "testnetwork", option)
+	network, err := createTestNetwork(bridgeNetType, "testnetwork", option, ipamV4ConfList, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -569,7 +555,7 @@ func TestNetworkEndpointsWalkers(t *testing.T) {
 		},
 		},
 	}
 	}
 
 
-	net1, err := createTestNetwork(bridgeNetType, "network1", netOption)
+	net1, err := createTestNetwork(bridgeNetType, "network1", netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -641,7 +627,7 @@ func TestNetworkEndpointsWalkers(t *testing.T) {
 		},
 		},
 	}
 	}
 
 
-	net2, err := createTestNetwork(bridgeNetType, "network2", netOption)
+	net2, err := createTestNetwork(bridgeNetType, "network2", netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -697,7 +683,7 @@ func TestDuplicateEndpoint(t *testing.T) {
 			"BridgeName": "testnetwork",
 			"BridgeName": "testnetwork",
 		},
 		},
 	}
 	}
-	n, err := createTestNetwork(bridgeNetType, "testnetwork", netOption)
+	n, err := createTestNetwork(bridgeNetType, "testnetwork", netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -747,7 +733,7 @@ func TestControllerQuery(t *testing.T) {
 			"BridgeName": "network1",
 			"BridgeName": "network1",
 		},
 		},
 	}
 	}
-	net1, err := createTestNetwork(bridgeNetType, "network1", netOption)
+	net1, err := createTestNetwork(bridgeNetType, "network1", netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -763,7 +749,7 @@ func TestControllerQuery(t *testing.T) {
 			"BridgeName": "network2",
 			"BridgeName": "network2",
 		},
 		},
 	}
 	}
-	net2, err := createTestNetwork(bridgeNetType, "network2", netOption)
+	net2, err := createTestNetwork(bridgeNetType, "network2", netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -849,7 +835,7 @@ func TestNetworkQuery(t *testing.T) {
 			"BridgeName": "network1",
 			"BridgeName": "network1",
 		},
 		},
 	}
 	}
-	net1, err := createTestNetwork(bridgeNetType, "network1", netOption)
+	net1, err := createTestNetwork(bridgeNetType, "network1", netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -969,7 +955,7 @@ func TestEndpointJoin(t *testing.T) {
 		netlabel.GenericData: options.Generic{
 		netlabel.GenericData: options.Generic{
 			"BridgeName": "testnetwork1",
 			"BridgeName": "testnetwork1",
 		},
 		},
-	})
+	}, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1078,7 +1064,7 @@ func TestEndpointJoin(t *testing.T) {
 			netlabel.GenericData: options.Generic{
 			netlabel.GenericData: options.Generic{
 				"BridgeName": "testnetwork2",
 				"BridgeName": "testnetwork2",
 			},
 			},
-		})
+		}, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1169,7 +1155,7 @@ func externalKeyTest(t *testing.T, reexec bool) {
 		netlabel.GenericData: options.Generic{
 		netlabel.GenericData: options.Generic{
 			"BridgeName": "testnetwork",
 			"BridgeName": "testnetwork",
 		},
 		},
-	})
+	}, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1318,7 +1304,7 @@ func TestEndpointDeleteWithActiveContainer(t *testing.T) {
 		netlabel.GenericData: options.Generic{
 		netlabel.GenericData: options.Generic{
 			"BridgeName": "testnetwork",
 			"BridgeName": "testnetwork",
 		},
 		},
-	})
+	}, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1381,7 +1367,7 @@ func TestEndpointMultipleJoins(t *testing.T) {
 		netlabel.GenericData: options.Generic{
 		netlabel.GenericData: options.Generic{
 			"BridgeName": "testmultiple",
 			"BridgeName": "testmultiple",
 		},
 		},
-	})
+	}, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1452,7 +1438,7 @@ func TestLeaveAll(t *testing.T) {
 		netlabel.GenericData: options.Generic{
 		netlabel.GenericData: options.Generic{
 			"BridgeName": "testnetwork",
 			"BridgeName": "testnetwork",
 		},
 		},
-	})
+	}, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1505,7 +1491,7 @@ func TestontainerInvalidLeave(t *testing.T) {
 		netlabel.GenericData: options.Generic{
 		netlabel.GenericData: options.Generic{
 			"BridgeName": "testnetwork",
 			"BridgeName": "testnetwork",
 		},
 		},
-	})
+	}, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1571,7 +1557,7 @@ func TestEndpointUpdateParent(t *testing.T) {
 		netlabel.GenericData: options.Generic{
 		netlabel.GenericData: options.Generic{
 			"BridgeName": "testnetwork",
 			"BridgeName": "testnetwork",
 		},
 		},
-	})
+	}, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1655,8 +1641,9 @@ func TestEnableIPv6(t *testing.T) {
 			"BridgeName": "testnetwork",
 			"BridgeName": "testnetwork",
 		},
 		},
 	}
 	}
+	ipamV6ConfList := []*libnetwork.IpamConf{&libnetwork.IpamConf{PreferredPool: "fe80::/98"}}
 
 
-	n, err := createTestNetwork("bridge", "testnetwork", netOption)
+	n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, ipamV6ConfList)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -1814,7 +1801,7 @@ func TestResolvConf(t *testing.T) {
 			"BridgeName": "testnetwork",
 			"BridgeName": "testnetwork",
 		},
 		},
 	}
 	}
-	n, err := createTestNetwork("bridge", "testnetwork", netOption)
+	n, err := createTestNetwork("bridge", "testnetwork", netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -2084,7 +2071,7 @@ func createGlobalInstance(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	net2, err := createTestNetwork("bridge", "network2", netOption)
+	net2, err := createTestNetwork("bridge", "network2", netOption, nil, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}

+ 1 - 1
libnetwork/network.go

@@ -852,7 +852,7 @@ func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error {
 
 
 	*infoList = make([]*IpamInfo, len(*cfgList))
 	*infoList = make([]*IpamInfo, len(*cfgList))
 
 
-	log.Debugf("allocating IPv%d pools for network %s (%s)", ipVer, n.Name(), n.ID())
+	log.Debugf("Allocating IPv%d pools for network %s (%s)", ipVer, n.Name(), n.ID())
 
 
 	for i, cfg := range *cfgList {
 	for i, cfg := range *cfgList {
 		if err = cfg.Validate(); err != nil {
 		if err = cfg.Validate(); err != nil {