Pārlūkot izejas kodu

Merge pull request #16910 from mavenugo/ipam

Vendoring libnetwork for the pluggable IPAM driver support
Alexandre Beslic 9 gadi atpakaļ
vecāks
revīzija
4ea3ff7061
79 mainītis faili ar 6425 papildinājumiem un 2082 dzēšanām
  1. 156 9
      api/client/network.go
  2. 34 5
      api/server/router/network/network_routes.go
  3. 6 5
      api/types/types.go
  4. 10 8
      daemon/container_unix.go
  5. 62 23
      daemon/daemon_unix.go
  6. 32 16
      daemon/network.go
  7. 14 0
      daemon/network/settings.go
  8. 2 2
      daemon/stats.go
  9. 0 16
      docker/flags_experimental.go
  10. 2 2
      hack/vendor.sh
  11. 96 10
      integration-cli/docker_api_network_test.go
  12. 1 1
      integration-cli/docker_cli_daemon_test.go
  13. 0 98
      integration-cli/docker_cli_network_test.go
  14. 257 0
      integration-cli/docker_cli_network_unix_test.go
  15. 8 1
      vendor/src/github.com/docker/libkv/README.md
  16. 188 45
      vendor/src/github.com/docker/libkv/store/boltdb/boltdb.go
  17. 40 8
      vendor/src/github.com/docker/libkv/store/consul/consul.go
  18. 44 18
      vendor/src/github.com/docker/libkv/store/etcd/etcd.go
  19. 5 3
      vendor/src/github.com/docker/libkv/store/store.go
  20. 11 2
      vendor/src/github.com/docker/libkv/store/zookeeper/zookeeper.go
  21. 2 1
      vendor/src/github.com/docker/libnetwork/.gitignore
  22. 102 44
      vendor/src/github.com/docker/libnetwork/bitseq/sequence.go
  23. 36 48
      vendor/src/github.com/docker/libnetwork/bitseq/store.go
  24. 91 30
      vendor/src/github.com/docker/libnetwork/config/config.go
  25. 176 89
      vendor/src/github.com/docker/libnetwork/controller.go
  26. 153 0
      vendor/src/github.com/docker/libnetwork/datastore/cache.go
  27. 323 41
      vendor/src/github.com/docker/libnetwork/datastore/datastore.go
  28. 0 20
      vendor/src/github.com/docker/libnetwork/default_gateway.go
  29. 7 0
      vendor/src/github.com/docker/libnetwork/default_gateway_freebsd.go
  30. 29 0
      vendor/src/github.com/docker/libnetwork/default_gateway_linux.go
  31. 7 0
      vendor/src/github.com/docker/libnetwork/default_gateway_windows.go
  32. 25 24
      vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go
  33. 103 0
      vendor/src/github.com/docker/libnetwork/driverapi/ipamdata.go
  34. 31 8
      vendor/src/github.com/docker/libnetwork/drivers.go
  35. 151 269
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
  36. 211 0
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge_store.go
  37. 18 0
      vendor/src/github.com/docker/libnetwork/drivers/bridge/labels.go
  38. 1 1
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go
  39. 0 19
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv4.go
  40. 0 27
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv6.go
  41. 14 100
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go
  42. 18 5
      vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go
  43. 2 2
      vendor/src/github.com/docker/libnetwork/drivers/host/host.go
  44. 2 2
      vendor/src/github.com/docker/libnetwork/drivers/null/null.go
  45. 32 5
      vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go
  46. 23 28
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go
  47. 263 105
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go
  48. 25 24
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go
  49. 6 37
      vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go
  50. 45 23
      vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go
  51. 3 0
      vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go
  52. 35 44
      vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go
  53. 2 2
      vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go
  54. 229 74
      vendor/src/github.com/docker/libnetwork/endpoint.go
  55. 147 0
      vendor/src/github.com/docker/libnetwork/endpoint_cnt.go
  56. 109 45
      vendor/src/github.com/docker/libnetwork/endpoint_info.go
  57. 1 1
      vendor/src/github.com/docker/libnetwork/error.go
  58. 6 6
      vendor/src/github.com/docker/libnetwork/idm/idm.go
  59. 0 175
      vendor/src/github.com/docker/libnetwork/ipallocator/allocator.go
  60. 510 0
      vendor/src/github.com/docker/libnetwork/ipam/allocator.go
  61. 131 0
      vendor/src/github.com/docker/libnetwork/ipam/store.go
  62. 359 0
      vendor/src/github.com/docker/libnetwork/ipam/structures.go
  63. 81 0
      vendor/src/github.com/docker/libnetwork/ipam/utils.go
  64. 72 0
      vendor/src/github.com/docker/libnetwork/ipamapi/contract.go
  65. 35 0
      vendor/src/github.com/docker/libnetwork/ipams/builtin/builtin.go
  66. 77 0
      vendor/src/github.com/docker/libnetwork/ipams/remote/api/api.go
  67. 103 0
      vendor/src/github.com/docker/libnetwork/ipams/remote/remote.go
  68. 42 0
      vendor/src/github.com/docker/libnetwork/ipamutils/utils.go
  69. 71 0
      vendor/src/github.com/docker/libnetwork/ipamutils/utils_linux.go
  70. 22 0
      vendor/src/github.com/docker/libnetwork/ipamutils/utils_windows.go
  71. 68 17
      vendor/src/github.com/docker/libnetwork/netlabel/labels.go
  72. 717 129
      vendor/src/github.com/docker/libnetwork/network.go
  73. 3 3
      vendor/src/github.com/docker/libnetwork/osl/interface_linux.go
  74. 1 19
      vendor/src/github.com/docker/libnetwork/osl/sandbox.go
  75. 1 1
      vendor/src/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go
  76. 92 35
      vendor/src/github.com/docker/libnetwork/sandbox.go
  77. 211 0
      vendor/src/github.com/docker/libnetwork/sandbox_store.go
  78. 273 299
      vendor/src/github.com/docker/libnetwork/store.go
  79. 160 8
      vendor/src/github.com/docker/libnetwork/types/types.go

+ 156 - 9
api/client/network.go

@@ -5,10 +5,14 @@ import (
 	"encoding/json"
 	"fmt"
 	"io"
+	"net"
+	"strings"
 	"text/tabwriter"
 
 	"github.com/docker/docker/api/types"
 	Cli "github.com/docker/docker/cli"
+	"github.com/docker/docker/daemon/network"
+	"github.com/docker/docker/opts"
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/pkg/stringid"
 )
@@ -29,15 +33,37 @@ func (cli *DockerCli) CmdNetwork(args ...string) error {
 // Usage: docker network create [OPTIONS] <NETWORK-NAME>
 func (cli *DockerCli) CmdNetworkCreate(args ...string) error {
 	cmd := Cli.Subcmd("network create", []string{"NETWORK-NAME"}, "Creates a new network with a name specified by the user", false)
-	flDriver := cmd.String([]string{"d", "-driver"}, "", "Driver to manage the Network")
+	flDriver := cmd.String([]string{"d", "-driver"}, "bridge", "Driver to manage the Network")
+
+	flIpamDriver := cmd.String([]string{"-ipam-driver"}, "default", "IP Address Management Driver")
+	flIpamSubnet := opts.NewListOpts(nil)
+	flIpamIPRange := opts.NewListOpts(nil)
+	flIpamGateway := opts.NewListOpts(nil)
+	flIpamAux := opts.NewMapOpts(nil, nil)
+
+	cmd.Var(&flIpamSubnet, []string{"-subnet"}, "Subnet in CIDR format that represents a network segment")
+	cmd.Var(&flIpamIPRange, []string{"-ip-range"}, "allocate container ip from a sub-range")
+	cmd.Var(&flIpamGateway, []string{"-gateway"}, "ipv4 or ipv6 Gateway for the master subnet")
+	cmd.Var(flIpamAux, []string{"-aux-address"}, "Auxiliary ipv4 or ipv6 addresses used by network driver")
+
 	cmd.Require(flag.Exact, 1)
 	err := cmd.ParseFlags(args, true)
 	if err != nil {
 		return err
 	}
 
+	ipamCfg, err := consolidateIpam(flIpamSubnet.GetAll(), flIpamIPRange.GetAll(), flIpamGateway.GetAll(), flIpamAux.GetAll())
+	if err != nil {
+		return err
+	}
+
 	// Construct network create request body
-	nc := types.NetworkCreate{Name: cmd.Arg(0), Driver: *flDriver, CheckDuplicate: true}
+	nc := types.NetworkCreate{
+		Name:           cmd.Arg(0),
+		Driver:         *flDriver,
+		IPAM:           network.IPAM{Driver: *flIpamDriver, Config: ipamCfg},
+		CheckDuplicate: true,
+	}
 	obj, _, err := readBody(cli.call("POST", "/networks/create", nc, nil))
 	if err != nil {
 		return err
@@ -104,12 +130,13 @@ func (cli *DockerCli) CmdNetworkDisconnect(args ...string) error {
 //
 // Usage: docker network ls [OPTIONS]
 func (cli *DockerCli) CmdNetworkLs(args ...string) error {
-	cmd := Cli.Subcmd("network ls", []string{""}, "Lists all the networks created by the user", false)
+	cmd := Cli.Subcmd("network ls", nil, "Lists networks", true)
 	quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
-	noTrunc := cmd.Bool([]string{"", "-no-trunc"}, false, "Do not truncate the output")
-	nLatest := cmd.Bool([]string{"l", "-latest"}, false, "Show the latest network created")
-	last := cmd.Int([]string{"n"}, -1, "Show n last created networks")
+	noTrunc := cmd.Bool([]string{"-no-trunc"}, false, "Do not truncate the output")
+
+	cmd.Require(flag.Exact, 0)
 	err := cmd.ParseFlags(args, true)
+
 	if err != nil {
 		return err
 	}
@@ -117,9 +144,6 @@ func (cli *DockerCli) CmdNetworkLs(args ...string) error {
 	if err != nil {
 		return err
 	}
-	if *last == -1 && *nLatest {
-		*last = 1
-	}
 
 	var networkResources []types.NetworkResource
 	err = json.Unmarshal(obj, &networkResources)
@@ -186,6 +210,129 @@ func (cli *DockerCli) CmdNetworkInspect(args ...string) error {
 	return nil
 }
 
+// Consolidates the ipam configuration as a group from differnt related configurations
+// user can configure network with multiple non-overlapping subnets and hence it is
+// possible to corelate the various related parameters and consolidate them.
+// consoidateIpam consolidates subnets, ip-ranges, gateways and auxilary addresses into
+// structured ipam data.
+func consolidateIpam(subnets, ranges, gateways []string, auxaddrs map[string]string) ([]network.IPAMConfig, error) {
+	if len(subnets) < len(ranges) || len(subnets) < len(gateways) {
+		return nil, fmt.Errorf("every ip-range or gateway must have a corresponding subnet")
+	}
+	iData := map[string]*network.IPAMConfig{}
+
+	// Populate non-overlapping subnets into consolidation map
+	for _, s := range subnets {
+		for k := range iData {
+			ok1, err := subnetMatches(s, k)
+			if err != nil {
+				return nil, err
+			}
+			ok2, err := subnetMatches(k, s)
+			if err != nil {
+				return nil, err
+			}
+			if ok1 || ok2 {
+				return nil, fmt.Errorf("multiple overlapping subnet configuration is not supported")
+			}
+		}
+		iData[s] = &network.IPAMConfig{Subnet: s, AuxAddress: map[string]string{}}
+	}
+
+	// Validate and add valid ip ranges
+	for _, r := range ranges {
+		match := false
+		for _, s := range subnets {
+			ok, err := subnetMatches(s, r)
+			if err != nil {
+				return nil, err
+			}
+			if !ok {
+				continue
+			}
+			if iData[s].IPRange != "" {
+				return nil, fmt.Errorf("cannot configure multiple ranges (%s, %s) on the same subnet (%s)", r, iData[s].IPRange, s)
+			}
+			d := iData[s]
+			d.IPRange = r
+			match = true
+		}
+		if !match {
+			return nil, fmt.Errorf("no matching subnet for range %s", r)
+		}
+	}
+
+	// Validate and add valid gateways
+	for _, g := range gateways {
+		match := false
+		for _, s := range subnets {
+			ok, err := subnetMatches(s, g)
+			if err != nil {
+				return nil, err
+			}
+			if !ok {
+				continue
+			}
+			if iData[s].Gateway != "" {
+				return nil, fmt.Errorf("cannot configure multiple gateways (%s, %s) for the same subnet (%s)", g, iData[s].Gateway, s)
+			}
+			d := iData[s]
+			d.Gateway = g
+			match = true
+		}
+		if !match {
+			return nil, fmt.Errorf("no matching subnet for gateway %s", g)
+		}
+	}
+
+	// Validate and add aux-addresses
+	for key, aa := range auxaddrs {
+		match := false
+		for _, s := range subnets {
+			ok, err := subnetMatches(s, aa)
+			if err != nil {
+				return nil, err
+			}
+			if !ok {
+				continue
+			}
+			iData[s].AuxAddress[key] = aa
+			match = true
+		}
+		if !match {
+			return nil, fmt.Errorf("no matching subnet for aux-address %s", aa)
+		}
+	}
+
+	idl := []network.IPAMConfig{}
+	for _, v := range iData {
+		idl = append(idl, *v)
+	}
+	return idl, nil
+}
+
+func subnetMatches(subnet, data string) (bool, error) {
+	var (
+		ip net.IP
+	)
+
+	_, s, err := net.ParseCIDR(subnet)
+	if err != nil {
+		return false, fmt.Errorf("Invalid subnet %s : %v", s, err)
+	}
+
+	if strings.Contains(data, "/") {
+		ip, _, err = net.ParseCIDR(data)
+		if err != nil {
+			return false, fmt.Errorf("Invalid cidr %s : %v", data, err)
+		}
+	} else {
+		ip = net.ParseIP(data)
+	}
+
+	return s.Contains(ip), nil
+}
+
 func networkUsage() string {
 	networkCommands := map[string]string{
 		"create":     "Create a network",

+ 34 - 5
api/server/router/network/network_routes.go

@@ -11,6 +11,7 @@ import (
 	"github.com/docker/docker/api/server/httputils"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/daemon"
+	"github.com/docker/docker/daemon/network"
 	"github.com/docker/docker/pkg/parsers/filters"
 	"github.com/docker/libnetwork"
 )
@@ -95,7 +96,7 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr
 		warning = fmt.Sprintf("Network with name %s (id : %s) already exists", nw.Name(), nw.ID())
 	}
 
-	nw, err = n.daemon.CreateNetwork(create.Name, create.Driver, create.Options)
+	nw, err = n.daemon.CreateNetwork(create.Name, create.Driver, create.IPAM)
 	if err != nil {
 		return err
 	}
@@ -179,8 +180,11 @@ func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
 
 	r.Name = nw.Name()
 	r.ID = nw.ID()
+	r.Scope = nw.Info().Scope()
 	r.Driver = nw.Type()
 	r.Containers = make(map[string]types.EndpointResource)
+	buildIpamResources(r, nw)
+
 	epl := nw.Endpoints()
 	for _, e := range epl {
 		sb := e.Info().Sandbox()
@@ -193,6 +197,31 @@ func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
 	return r
 }
 
+func buildIpamResources(r *types.NetworkResource, nw libnetwork.Network) {
+	id, ipv4conf, ipv6conf := nw.Info().IpamConfig()
+
+	r.IPAM.Driver = id
+
+	r.IPAM.Config = []network.IPAMConfig{}
+	for _, ip4 := range ipv4conf {
+		iData := network.IPAMConfig{}
+		iData.Subnet = ip4.PreferredPool
+		iData.IPRange = ip4.SubPool
+		iData.Gateway = ip4.Gateway
+		iData.AuxAddress = ip4.AuxAddresses
+		r.IPAM.Config = append(r.IPAM.Config, iData)
+	}
+
+	for _, ip6 := range ipv6conf {
+		iData := network.IPAMConfig{}
+		iData.Subnet = ip6.PreferredPool
+		iData.IPRange = ip6.SubPool
+		iData.Gateway = ip6.Gateway
+		iData.AuxAddress = ip6.AuxAddresses
+		r.IPAM.Config = append(r.IPAM.Config, iData)
+	}
+}
+
 func buildEndpointResource(e libnetwork.Endpoint) types.EndpointResource {
 	er := types.EndpointResource{}
 	if e == nil {
@@ -204,12 +233,12 @@ func buildEndpointResource(e libnetwork.Endpoint) types.EndpointResource {
 		if mac := iface.MacAddress(); mac != nil {
 			er.MacAddress = mac.String()
 		}
-		if ip := iface.Address(); len(ip.IP) > 0 {
-			er.IPv4Address = (&ip).String()
+		if ip := iface.Address(); ip != nil && len(ip.IP) > 0 {
+			er.IPv4Address = ip.String()
 		}
 
-		if ipv6 := iface.AddressIPv6(); len(ipv6.IP) > 0 {
-			er.IPv6Address = (&ipv6).String()
+		if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 {
+			er.IPv6Address = ipv6.String()
 		}
 	}
 	return er

+ 6 - 5
api/types/types.go

@@ -315,9 +315,10 @@ type VolumeCreateRequest struct {
 type NetworkResource struct {
 	Name       string                      `json:"name"`
 	ID         string                      `json:"id"`
+	Scope      string                      `json:"scope"`
 	Driver     string                      `json:"driver"`
+	IPAM       network.IPAM                `json:"ipam"`
 	Containers map[string]EndpointResource `json:"containers"`
-	Options    map[string]interface{}      `json:"options,omitempty"`
 }
 
 //EndpointResource contains network resources allocated and usd for a container in a network
@@ -330,10 +331,10 @@ type EndpointResource struct {
 
 // NetworkCreate is the expected body of the "create network" http request message
 type NetworkCreate struct {
-	Name           string                 `json:"name"`
-	CheckDuplicate bool                   `json:"check_duplicate"`
-	Driver         string                 `json:"driver"`
-	Options        map[string]interface{} `json:"options"`
+	Name           string       `json:"name"`
+	CheckDuplicate bool         `json:"check_duplicate"`
+	Driver         string       `json:"driver"`
+	IPAM           network.IPAM `json:"ipam"`
 }
 
 // NetworkCreateResponse is the response message sent by the server for network create call

+ 10 - 8
daemon/container_unix.go

@@ -30,6 +30,7 @@ import (
 	"github.com/docker/docker/volume"
 	"github.com/docker/docker/volume/store"
 	"github.com/docker/libnetwork"
+	"github.com/docker/libnetwork/drivers/bridge"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/types"
@@ -651,11 +652,13 @@ func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSet
 		return networkSettings, nil
 	}
 
-	ones, _ := iface.Address().Mask.Size()
-	networkSettings.IPAddress = iface.Address().IP.String()
-	networkSettings.IPPrefixLen = ones
+	if iface.Address() != nil {
+		ones, _ := iface.Address().Mask.Size()
+		networkSettings.IPAddress = iface.Address().IP.String()
+		networkSettings.IPPrefixLen = ones
+	}
 
-	if iface.AddressIPv6().IP.To16() != nil {
+	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
 		onesv6, _ := iface.AddressIPv6().Mask.Size()
 		networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String()
 		networkSettings.GlobalIPv6PrefixLen = onesv6
@@ -861,9 +864,8 @@ func createNetwork(controller libnetwork.NetworkController, dnet string, driver
 
 	// Bridge driver is special due to legacy reasons
 	if runconfig.NetworkMode(driver).IsBridge() {
-		genericOption[netlabel.GenericData] = map[string]interface{}{
-			"BridgeName":            dnet,
-			"AllowNonDefaultBridge": "true",
+		genericOption[netlabel.GenericData] = map[string]string{
+			bridge.BridgeName: dnet,
 		}
 		networkOption := libnetwork.NetworkOptionGeneric(genericOption)
 		createOptions = append(createOptions, networkOption)
@@ -1163,7 +1165,7 @@ func (container *Container) disconnectFromNetwork(n libnetwork.Network, updateSe
 	n.WalkEndpoints(s)
 
 	if ep == nil {
-		return fmt.Errorf("could not locate network endpoint for container %s", container.ID)
+		return fmt.Errorf("container %s is not connected to the network", container.ID)
 	}
 
 	if err := ep.Leave(sbox); err != nil {

+ 62 - 23
daemon/daemon_unix.go

@@ -7,6 +7,7 @@ import (
 	"net"
 	"os"
 	"path/filepath"
+	"strconv"
 	"strings"
 	"syscall"
 
@@ -23,8 +24,11 @@ import (
 	"github.com/docker/docker/utils"
 	"github.com/docker/libnetwork"
 	nwconfig "github.com/docker/libnetwork/config"
+	"github.com/docker/libnetwork/drivers/bridge"
+	"github.com/docker/libnetwork/ipamutils"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
 	"github.com/opencontainers/runc/libcontainer/label"
 	"github.com/vishvananda/netlink"
 )
@@ -312,6 +316,9 @@ func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error)
 	if dconfig == nil {
 		return options, nil
 	}
+
+	options = append(options, nwconfig.OptionDataDir(dconfig.Root))
+
 	if strings.TrimSpace(dconfig.DefaultNetwork) != "" {
 		dn := strings.Split(dconfig.DefaultNetwork, ":")
 		if len(dn) < 2 {
@@ -392,22 +399,48 @@ func driverOptions(config *Config) []nwconfig.Option {
 }
 
 func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
-	netOption := options.Generic{
-		"BridgeName":         config.Bridge.Iface,
-		"DefaultBridge":      true,
-		"Mtu":                config.Mtu,
-		"EnableIPMasquerade": config.Bridge.EnableIPMasq,
-		"EnableICC":          config.Bridge.InterContainerCommunication,
+	if n, err := controller.NetworkByName("bridge"); err == nil {
+		if err = n.Delete(); err != nil {
+			return fmt.Errorf("could not delete the default bridge network: %v", err)
+		}
+	}
+
+	bridgeName := bridge.DefaultBridgeName
+	if config.Bridge.Iface != "" {
+		bridgeName = config.Bridge.Iface
+	}
+	netOption := map[string]string{
+		bridge.BridgeName:         bridgeName,
+		bridge.DefaultBridge:      strconv.FormatBool(true),
+		netlabel.DriverMTU:        strconv.Itoa(config.Mtu),
+		bridge.EnableIPMasquerade: strconv.FormatBool(config.Bridge.EnableIPMasq),
+		bridge.EnableICC:          strconv.FormatBool(config.Bridge.InterContainerCommunication),
+	}
+
+	// --ip processing
+	if config.Bridge.DefaultIP != nil {
+		netOption[bridge.DefaultBindingIP] = config.Bridge.DefaultIP.String()
+	}
+
+	ipamV4Conf := libnetwork.IpamConf{}
+
+	ipamV4Conf.AuxAddresses = make(map[string]string)
+
+	if nw, _, err := ipamutils.ElectInterfaceAddresses(bridgeName); err == nil {
+		ipamV4Conf.PreferredPool = nw.String()
+		hip, _ := types.GetHostPartIP(nw.IP, nw.Mask)
+		if hip.IsGlobalUnicast() {
+			ipamV4Conf.Gateway = nw.IP.String()
+		}
 	}
 
 	if config.Bridge.IP != "" {
-		ip, bipNet, err := net.ParseCIDR(config.Bridge.IP)
+		ipamV4Conf.PreferredPool = config.Bridge.IP
+		ip, _, err := net.ParseCIDR(config.Bridge.IP)
 		if err != nil {
 			return err
 		}
-
-		bipNet.IP = ip
-		netOption["AddressIPv4"] = bipNet
+		ipamV4Conf.Gateway = ip.String()
 	}
 
 	if config.Bridge.FixedCIDR != "" {
@@ -416,38 +449,44 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
 			return err
 		}
 
-		netOption["FixedCIDR"] = fCIDR
+		ipamV4Conf.SubPool = fCIDR.String()
 	}
 
+	if config.Bridge.DefaultGatewayIPv4 != nil {
+		ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4.String()
+	}
+
+	var ipamV6Conf *libnetwork.IpamConf
 	if config.Bridge.FixedCIDRv6 != "" {
 		_, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6)
 		if err != nil {
 			return err
 		}
-
-		netOption["FixedCIDRv6"] = fCIDRv6
-	}
-
-	if config.Bridge.DefaultGatewayIPv4 != nil {
-		netOption["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4
+		if ipamV6Conf == nil {
+			ipamV6Conf = &libnetwork.IpamConf{}
+		}
+		ipamV6Conf.PreferredPool = fCIDRv6.String()
 	}
 
 	if config.Bridge.DefaultGatewayIPv6 != nil {
-		netOption["DefaultGatewayIPv6"] = config.Bridge.DefaultGatewayIPv6
+		if ipamV6Conf == nil {
+			ipamV6Conf = &libnetwork.IpamConf{}
+		}
+		ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.Bridge.DefaultGatewayIPv6.String()
 	}
 
-	// --ip processing
-	if config.Bridge.DefaultIP != nil {
-		netOption["DefaultBindingIP"] = config.Bridge.DefaultIP
+	v4Conf := []*libnetwork.IpamConf{&ipamV4Conf}
+	v6Conf := []*libnetwork.IpamConf{}
+	if ipamV6Conf != nil {
+		v6Conf = append(v6Conf, ipamV6Conf)
 	}
-
 	// Initialize default network on "bridge" with the same name
 	_, err := controller.NewNetwork("bridge", "bridge",
 		libnetwork.NetworkOptionGeneric(options.Generic{
 			netlabel.GenericData: netOption,
 			netlabel.EnableIPv6:  config.Bridge.EnableIPv6,
 		}),
-		libnetwork.NetworkOptionPersist(false))
+		libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf))
 	if err != nil {
 		return fmt.Errorf("Error creating default \"bridge\" network: %v", err)
 	}

+ 32 - 16
daemon/network.go

@@ -2,10 +2,12 @@ package daemon
 
 import (
 	"errors"
+	"fmt"
+	"net"
 	"strings"
 
+	"github.com/docker/docker/daemon/network"
 	"github.com/docker/libnetwork"
-	"github.com/docker/libnetwork/netlabel"
 )
 
 const (
@@ -78,29 +80,43 @@ func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network {
 }
 
 // CreateNetwork creates a network with the given name, driver and other optional parameters
-func (daemon *Daemon) CreateNetwork(name, driver string, options map[string]interface{}) (libnetwork.Network, error) {
+func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM) (libnetwork.Network, error) {
 	c := daemon.netController
 	if driver == "" {
 		driver = c.Config().Daemon.DefaultDriver
 	}
 
-	if options == nil {
-		options = make(map[string]interface{})
-	}
-	_, ok := options[netlabel.GenericData]
-	if !ok {
-		options[netlabel.GenericData] = make(map[string]interface{})
+	nwOptions := []libnetwork.NetworkOption{}
+
+	v4Conf, v6Conf, err := getIpamConfig(ipam.Config)
+	if err != nil {
+		return nil, err
 	}
 
-	return c.NewNetwork(driver, name, parseOptions(options)...)
+	if len(ipam.Config) > 0 {
+		nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf))
+	}
+	return c.NewNetwork(driver, name, nwOptions...)
 }
 
-func parseOptions(options map[string]interface{}) []libnetwork.NetworkOption {
-	var setFctList []libnetwork.NetworkOption
-
-	if options != nil {
-		setFctList = append(setFctList, libnetwork.NetworkOptionGeneric(options))
+func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) {
+	ipamV4Cfg := []*libnetwork.IpamConf{}
+	ipamV6Cfg := []*libnetwork.IpamConf{}
+	for _, d := range data {
+		iCfg := libnetwork.IpamConf{}
+		iCfg.PreferredPool = d.Subnet
+		iCfg.SubPool = d.IPRange
+		iCfg.Gateway = d.Gateway
+		iCfg.AuxAddresses = d.AuxAddress
+		ip, _, err := net.ParseCIDR(d.Subnet)
+		if err != nil {
+			return nil, nil, fmt.Errorf("Invalid subnet %s : %v", d.Subnet, err)
+		}
+		if ip.To4() != nil {
+			ipamV4Cfg = append(ipamV4Cfg, &iCfg)
+		} else {
+			ipamV6Cfg = append(ipamV6Cfg, &iCfg)
+		}
 	}
-
-	return setFctList
+	return ipamV4Cfg, ipamV6Cfg, nil
 }

+ 14 - 0
daemon/network/settings.go

@@ -8,6 +8,20 @@ type Address struct {
 	PrefixLen int
 }
 
+// IPAM represents IP Address Management
+type IPAM struct {
+	Driver string       `json:"driver"`
+	Config []IPAMConfig `json:"config"`
+}
+
+// IPAMConfig represents IPAM configurations
+type IPAMConfig struct {
+	Subnet     string            `json:"subnet,omitempty"`
+	IPRange    string            `json:"ip_range,omitempty"`
+	Gateway    string            `json:"gateway,omitempty"`
+	AuxAddress map[string]string `json:"auxiliary_address,omitempty"`
+}
+
 // Settings stores configuration details about the daemon network config
 // TODO Windows. Many of these fields can be factored out.,
 type Settings struct {

+ 2 - 2
daemon/stats.go

@@ -8,7 +8,7 @@ import (
 	"github.com/docker/docker/api/types/versions/v1p20"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/pkg/version"
-	"github.com/docker/libnetwork/osl"
+	lntypes "github.com/docker/libnetwork/types"
 	"github.com/opencontainers/runc/libcontainer"
 )
 
@@ -166,7 +166,7 @@ func (daemon *Daemon) getNetworkStats(c *Container) ([]*libcontainer.NetworkInte
 	return list, nil
 }
 
-func convertLnNetworkStats(name string, stats *osl.InterfaceStatistics) *libcontainer.NetworkInterface {
+func convertLnNetworkStats(name string, stats *lntypes.InterfaceStatistics) *libcontainer.NetworkInterface {
 	n := &libcontainer.NetworkInterface{Name: name}
 	n.RxBytes = stats.RxBytes
 	n.RxPackets = stats.RxPackets

+ 0 - 16
docker/flags_experimental.go

@@ -1,16 +0,0 @@
-// +build experimental
-
-package main
-
-import (
-	"sort"
-
-	"github.com/docker/docker/cli"
-)
-
-func init() {
-	dockerCommands = append(dockerCommands, cli.Command{Name: "network", Description: "Network management"})
-
-	//Sorting logic required here to pass Command Sort Test.
-	sort.Sort(byName(dockerCommands))
-}

+ 2 - 2
hack/vendor.sh

@@ -20,12 +20,12 @@ clone git github.com/tchap/go-patricia v2.1.0
 clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
 
 #get libnetwork packages
-clone git github.com/docker/libnetwork c3a9e0d8d0c53f3db251620e5f48470e267f292b
+clone git github.com/docker/libnetwork 0521fe53fc3e7d4e7c2e463800f36662c9169f20
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
 clone git github.com/hashicorp/serf 7151adcef72687bf95f451a2e0ba15cb19412bf2
-clone git github.com/docker/libkv ea7ff6ae76485ab93ac36799d3e13b1905787ffe
+clone git github.com/docker/libkv 958cd316db2bc916466bdcc632a3188d62ce6e87
 clone git github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
 clone git github.com/vishvananda/netlink 4b5dce31de6d42af5bb9811c6d265472199e0fec
 clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060

+ 96 - 10
integration-cli/docker_api_network_test.go

@@ -2,12 +2,14 @@ package main
 
 import (
 	"encoding/json"
+	"fmt"
 	"net"
 	"net/http"
 	"net/url"
 	"strings"
 
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/daemon/network"
 	"github.com/docker/docker/pkg/parsers/filters"
 	"github.com/go-check/check"
 )
@@ -23,11 +25,15 @@ func (s *DockerSuite) TestApiNetworkGetDefaults(c *check.C) {
 func (s *DockerSuite) TestApiNetworkCreateDelete(c *check.C) {
 	// Create a network
 	name := "testnetwork"
-	id := createNetwork(c, name, true)
+	config := types.NetworkCreate{
+		Name:           name,
+		CheckDuplicate: true,
+	}
+	id := createNetwork(c, config, true)
 	c.Assert(isNetworkAvailable(c, name), check.Equals, true)
 
 	// POST another network with same name and CheckDuplicate must fail
-	createNetwork(c, name, false)
+	createNetwork(c, config, false)
 
 	// delete the network and make sure it is deleted
 	deleteNetwork(c, id, true)
@@ -51,18 +57,46 @@ func (s *DockerSuite) TestApiNetworkInspect(c *check.C) {
 
 	// inspect default bridge network again and make sure the container is connected
 	nr = getNetworkResource(c, nr.ID)
+	c.Assert(nr.Driver, check.Equals, "bridge")
+	c.Assert(nr.Scope, check.Equals, "local")
+	c.Assert(nr.IPAM.Driver, check.Equals, "default")
 	c.Assert(len(nr.Containers), check.Equals, 1)
 	c.Assert(nr.Containers[containerID], check.NotNil)
 
 	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
 	c.Assert(err, check.IsNil)
 	c.Assert(ip.String(), check.Equals, containerIP)
+
+	// IPAM configuration inspect
+	ipam := network.IPAM{
+		Driver: "default",
+		Config: []network.IPAMConfig{{Subnet: "172.28.0.0/16", IPRange: "172.28.5.0/24", Gateway: "172.28.5.254"}},
+	}
+	config := types.NetworkCreate{
+		Name:   "br0",
+		Driver: "bridge",
+		IPAM:   ipam,
+	}
+	id0 := createNetwork(c, config, true)
+	c.Assert(isNetworkAvailable(c, "br0"), check.Equals, true)
+
+	nr = getNetworkResource(c, id0)
+	c.Assert(len(nr.IPAM.Config), check.Equals, 1)
+	c.Assert(nr.IPAM.Config[0].Subnet, check.Equals, "172.28.0.0/16")
+	c.Assert(nr.IPAM.Config[0].IPRange, check.Equals, "172.28.5.0/24")
+	c.Assert(nr.IPAM.Config[0].Gateway, check.Equals, "172.28.5.254")
+	// delete the network and make sure it is deleted
+	deleteNetwork(c, id0, true)
+	c.Assert(isNetworkAvailable(c, "br0"), check.Equals, false)
 }
 
 func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) {
 	// Create test network
 	name := "testnetwork"
-	id := createNetwork(c, name, true)
+	config := types.NetworkCreate{
+		Name: name,
+	}
+	id := createNetwork(c, config, true)
 	nr := getNetworkResource(c, id)
 	c.Assert(nr.Name, check.Equals, name)
 	c.Assert(nr.ID, check.Equals, id)
@@ -96,6 +130,64 @@ func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) {
 	deleteNetwork(c, nr.ID, true)
 }
 
+func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
+	// test0 bridge network
+	ipam0 := network.IPAM{
+		Driver: "default",
+		Config: []network.IPAMConfig{{Subnet: "192.178.0.0/16", IPRange: "192.178.128.0/17", Gateway: "192.178.138.100"}},
+	}
+	config0 := types.NetworkCreate{
+		Name:   "test0",
+		Driver: "bridge",
+		IPAM:   ipam0,
+	}
+	id0 := createNetwork(c, config0, true)
+	c.Assert(isNetworkAvailable(c, "test0"), check.Equals, true)
+
+	ipam1 := network.IPAM{
+		Driver: "default",
+		Config: []network.IPAMConfig{{Subnet: "192.178.128.0/17", Gateway: "192.178.128.1"}},
+	}
+	// test1 bridge network overlaps with test0
+	config1 := types.NetworkCreate{
+		Name:   "test1",
+		Driver: "bridge",
+		IPAM:   ipam1,
+	}
+	createNetwork(c, config1, false)
+	c.Assert(isNetworkAvailable(c, "test1"), check.Equals, false)
+
+	ipam2 := network.IPAM{
+		Driver: "default",
+		Config: []network.IPAMConfig{{Subnet: "192.169.0.0/16", Gateway: "192.169.100.100"}},
+	}
+	// test2 bridge network does not overlap
+	config2 := types.NetworkCreate{
+		Name:   "test2",
+		Driver: "bridge",
+		IPAM:   ipam2,
+	}
+	createNetwork(c, config2, true)
+	c.Assert(isNetworkAvailable(c, "test2"), check.Equals, true)
+
+	// remove test0 and retry to create test1
+	deleteNetwork(c, id0, true)
+	createNetwork(c, config1, true)
+	c.Assert(isNetworkAvailable(c, "test1"), check.Equals, true)
+
+	// for networks w/o ipam specified, docker will choose proper non-overlapping subnets
+	createNetwork(c, types.NetworkCreate{Name: "test3"}, true)
+	c.Assert(isNetworkAvailable(c, "test3"), check.Equals, true)
+	createNetwork(c, types.NetworkCreate{Name: "test4"}, true)
+	c.Assert(isNetworkAvailable(c, "test4"), check.Equals, true)
+	createNetwork(c, types.NetworkCreate{Name: "test5"}, true)
+	c.Assert(isNetworkAvailable(c, "test5"), check.Equals, true)
+
+	for i := 1; i < 6; i++ {
+		deleteNetwork(c, fmt.Sprintf("test%d", i), true)
+	}
+}
+
 func isNetworkAvailable(c *check.C, name string) bool {
 	status, body, err := sockRequest("GET", "/networks", nil)
 	c.Assert(status, check.Equals, http.StatusOK)
@@ -146,13 +238,7 @@ func getNetworkResource(c *check.C, id string) *types.NetworkResource {
 	return &nr
 }
 
-func createNetwork(c *check.C, name string, shouldSucceed bool) string {
-	config := types.NetworkCreate{
-		Name:           name,
-		Driver:         "bridge",
-		CheckDuplicate: true,
-	}
-
+func createNetwork(c *check.C, config types.NetworkCreate, shouldSucceed bool) string {
 	status, resp, err := sockRequest("POST", "/networks/create", config)
 	if !shouldSucceed {
 		c.Assert(status, check.Not(check.Equals), http.StatusCreated)

+ 1 - 1
integration-cli/docker_cli_daemon_test.go

@@ -787,7 +787,7 @@ func (s *DockerDaemonSuite) TestDaemonBridgeFixedCidr(c *check.C) {
 		cName := "Container" + strconv.Itoa(i)
 		out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top")
 		if err != nil {
-			c.Assert(strings.Contains(out, "no available ip addresses"), check.Equals, true,
+			c.Assert(strings.Contains(out, "no available IPv4 addresses"), check.Equals, true,
 				check.Commentf("Could not run a Container : %s %s", err.Error(), out))
 		}
 	}

+ 0 - 98
integration-cli/docker_cli_network_test.go

@@ -1,98 +0,0 @@
-package main
-
-import (
-	"encoding/json"
-	"net"
-	"strings"
-
-	"github.com/docker/docker/api/types"
-	"github.com/go-check/check"
-)
-
-func assertNwIsAvailable(c *check.C, name string) {
-	if !isNwPresent(c, name) {
-		c.Fatalf("Network %s not found in network ls o/p", name)
-	}
-}
-
-func assertNwNotAvailable(c *check.C, name string) {
-	if isNwPresent(c, name) {
-		c.Fatalf("Found network %s in network ls o/p", name)
-	}
-}
-
-func isNwPresent(c *check.C, name string) bool {
-	out, _ := dockerCmd(c, "network", "ls")
-	lines := strings.Split(out, "\n")
-	for i := 1; i < len(lines)-1; i++ {
-		if strings.Contains(lines[i], name) {
-			return true
-		}
-	}
-	return false
-}
-
-func getNwResource(c *check.C, name string) *types.NetworkResource {
-	out, _ := dockerCmd(c, "network", "inspect", name)
-	nr := types.NetworkResource{}
-	err := json.Unmarshal([]byte(out), &nr)
-	c.Assert(err, check.IsNil)
-	return &nr
-}
-
-func (s *DockerSuite) TestDockerNetworkLsDefault(c *check.C) {
-	defaults := []string{"bridge", "host", "none"}
-	for _, nn := range defaults {
-		assertNwIsAvailable(c, nn)
-	}
-}
-
-func (s *DockerSuite) TestDockerNetworkCreateDelete(c *check.C) {
-	dockerCmd(c, "network", "create", "test")
-	assertNwIsAvailable(c, "test")
-
-	dockerCmd(c, "network", "rm", "test")
-	assertNwNotAvailable(c, "test")
-}
-
-func (s *DockerSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
-	dockerCmd(c, "network", "create", "test")
-	assertNwIsAvailable(c, "test")
-	nr := getNwResource(c, "test")
-
-	c.Assert(nr.Name, check.Equals, "test")
-	c.Assert(len(nr.Containers), check.Equals, 0)
-
-	// run a container
-	out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
-	c.Assert(waitRun("test"), check.IsNil)
-	containerID := strings.TrimSpace(out)
-
-	// connect the container to the test network
-	dockerCmd(c, "network", "connect", "test", containerID)
-
-	// inspect the network to make sure container is connected
-	nr = getNetworkResource(c, nr.ID)
-	c.Assert(len(nr.Containers), check.Equals, 1)
-	c.Assert(nr.Containers[containerID], check.NotNil)
-
-	// check if container IP matches network inspect
-	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
-	c.Assert(err, check.IsNil)
-	containerIP := findContainerIP(c, "test")
-	c.Assert(ip.String(), check.Equals, containerIP)
-
-	// disconnect container from the network
-	dockerCmd(c, "network", "disconnect", "test", containerID)
-	nr = getNwResource(c, "test")
-	c.Assert(nr.Name, check.Equals, "test")
-	c.Assert(len(nr.Containers), check.Equals, 0)
-
-	// check if network connect fails for inactive containers
-	dockerCmd(c, "stop", containerID)
-	_, _, err = dockerCmdWithError("network", "connect", "test", containerID)
-	c.Assert(err, check.NotNil)
-
-	dockerCmd(c, "network", "rm", "test")
-	assertNwNotAvailable(c, "test")
-}

+ 257 - 0
integration-cli/docker_cli_network_unix_test.go

@@ -0,0 +1,257 @@
+// +build !windows
+
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net"
+	"net/http"
+	"net/http/httptest"
+	"os"
+	"strings"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/libnetwork/driverapi"
+	"github.com/go-check/check"
+)
+
+const dummyNetworkDriver = "dummy-network-driver"
+
+func init() {
+	check.Suite(&DockerNetworkSuite{
+		ds: &DockerSuite{},
+	})
+}
+
+type DockerNetworkSuite struct {
+	server *httptest.Server
+	ds     *DockerSuite
+	d      *Daemon
+}
+
+func (s *DockerNetworkSuite) SetUpTest(c *check.C) {
+	s.d = NewDaemon(c)
+}
+
+func (s *DockerNetworkSuite) TearDownTest(c *check.C) {
+	s.d.Stop()
+	s.ds.TearDownTest(c)
+}
+
+func (s *DockerNetworkSuite) SetUpSuite(c *check.C) {
+	mux := http.NewServeMux()
+	s.server = httptest.NewServer(mux)
+	if s.server == nil {
+		c.Fatal("Failed to start a HTTP Server")
+	}
+
+	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
+		fmt.Fprintf(w, `{"Implements": ["%s"]}`, driverapi.NetworkPluginEndpointType)
+	})
+
+	mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
+		fmt.Fprintf(w, `{"Scope":"local"}`)
+	})
+
+	mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
+		fmt.Fprintf(w, "null")
+	})
+
+	mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
+		fmt.Fprintf(w, "null")
+	})
+
+	if err := os.MkdirAll("/etc/docker/plugins", 0755); err != nil {
+		c.Fatal(err)
+	}
+
+	fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", dummyNetworkDriver)
+	if err := ioutil.WriteFile(fileName, []byte(s.server.URL), 0644); err != nil {
+		c.Fatal(err)
+	}
+}
+
+func (s *DockerNetworkSuite) TearDownSuite(c *check.C) {
+	if s.server == nil {
+		return
+	}
+
+	s.server.Close()
+
+	if err := os.RemoveAll("/etc/docker/plugins"); err != nil {
+		c.Fatal(err)
+	}
+}
+
+func assertNwIsAvailable(c *check.C, name string) {
+	if !isNwPresent(c, name) {
+		c.Fatalf("Network %s not found in network ls o/p", name)
+	}
+}
+
+func assertNwNotAvailable(c *check.C, name string) {
+	if isNwPresent(c, name) {
+		c.Fatalf("Found network %s in network ls o/p", name)
+	}
+}
+
+func isNwPresent(c *check.C, name string) bool {
+	out, _ := dockerCmd(c, "network", "ls")
+	lines := strings.Split(out, "\n")
+	for i := 1; i < len(lines)-1; i++ {
+		if strings.Contains(lines[i], name) {
+			return true
+		}
+	}
+	return false
+}
+
+func getNwResource(c *check.C, name string) *types.NetworkResource {
+	out, _ := dockerCmd(c, "network", "inspect", name)
+	nr := types.NetworkResource{}
+	err := json.Unmarshal([]byte(out), &nr)
+	c.Assert(err, check.IsNil)
+	return &nr
+}
+
+func (s *DockerNetworkSuite) TestDockerNetworkLsDefault(c *check.C) {
+	defaults := []string{"bridge", "host", "none"}
+	for _, nn := range defaults {
+		assertNwIsAvailable(c, nn)
+	}
+}
+
+func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) {
+	dockerCmd(c, "network", "create", "test")
+	assertNwIsAvailable(c, "test")
+
+	dockerCmd(c, "network", "rm", "test")
+	assertNwNotAvailable(c, "test")
+}
+
+func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
+	dockerCmd(c, "network", "create", "test")
+	assertNwIsAvailable(c, "test")
+	nr := getNwResource(c, "test")
+
+	c.Assert(nr.Name, check.Equals, "test")
+	c.Assert(len(nr.Containers), check.Equals, 0)
+
+	// run a container
+	out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
+	c.Assert(waitRun("test"), check.IsNil)
+	containerID := strings.TrimSpace(out)
+
+	// connect the container to the test network
+	dockerCmd(c, "network", "connect", "test", containerID)
+
+	// inspect the network to make sure container is connected
+	nr = getNetworkResource(c, nr.ID)
+	c.Assert(len(nr.Containers), check.Equals, 1)
+	c.Assert(nr.Containers[containerID], check.NotNil)
+
+	// check if container IP matches network inspect
+	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
+	c.Assert(err, check.IsNil)
+	containerIP := findContainerIP(c, "test")
+	c.Assert(ip.String(), check.Equals, containerIP)
+
+	// disconnect container from the network
+	dockerCmd(c, "network", "disconnect", "test", containerID)
+	nr = getNwResource(c, "test")
+	c.Assert(nr.Name, check.Equals, "test")
+	c.Assert(len(nr.Containers), check.Equals, 0)
+
+	// check if network connect fails for inactive containers
+	dockerCmd(c, "stop", containerID)
+	_, _, err = dockerCmdWithError("network", "connect", "test", containerID)
+	c.Assert(err, check.NotNil)
+
+	dockerCmd(c, "network", "rm", "test")
+	assertNwNotAvailable(c, "test")
+}
+
+func (s *DockerNetworkSuite) TestDockerNetworkIpamMultipleNetworks(c *check.C) {
+	// test0 bridge network
+	dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test1")
+	assertNwIsAvailable(c, "test1")
+
+	// test2 bridge network does not overlap
+	dockerCmd(c, "network", "create", "--subnet=192.169.0.0/16", "test2")
+	assertNwIsAvailable(c, "test2")
+
+	// for networks w/o ipam specified, docker will choose proper non-overlapping subnets
+	dockerCmd(c, "network", "create", "test3")
+	assertNwIsAvailable(c, "test3")
+	dockerCmd(c, "network", "create", "test4")
+	assertNwIsAvailable(c, "test4")
+	dockerCmd(c, "network", "create", "test5")
+	assertNwIsAvailable(c, "test5")
+
+	// test network with multiple subnets
+	// bridge network doesnt support multiple subnets. hence, use a dummy driver that supports
+
+	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", "test6")
+	assertNwIsAvailable(c, "test6")
+
+	// test network with multiple subnets with valid ipam combinations
+	// also check same subnet across networks when the driver supports it.
+	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver,
+		"--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16",
+		"--gateway=192.168.0.100", "--gateway=192.170.0.100",
+		"--ip-range=192.168.1.0/24",
+		"--aux-address", "a=192.168.1.5", "--aux-address", "b=192.168.1.6",
+		"--aux-address", "a=192.170.1.5", "--aux-address", "b=192.170.1.6",
+		"test7")
+	assertNwIsAvailable(c, "test7")
+
+	// cleanup
+	for i := 1; i < 8; i++ {
+		dockerCmd(c, "network", "rm", fmt.Sprintf("test%d", i))
+	}
+}
+
+func (s *DockerNetworkSuite) TestDockerNetworkInspect(c *check.C) {
+	// if unspecified, network gateway will be selected from inside preferred pool
+	dockerCmd(c, "network", "create", "--driver=bridge", "--subnet=172.28.0.0/16", "--ip-range=172.28.5.0/24", "--gateway=172.28.5.254", "br0")
+	assertNwIsAvailable(c, "br0")
+
+	nr := getNetworkResource(c, "br0")
+	c.Assert(nr.Driver, check.Equals, "bridge")
+	c.Assert(nr.Scope, check.Equals, "local")
+	c.Assert(nr.IPAM.Driver, check.Equals, "default")
+	c.Assert(len(nr.IPAM.Config), check.Equals, 1)
+	c.Assert(nr.IPAM.Config[0].Subnet, check.Equals, "172.28.0.0/16")
+	c.Assert(nr.IPAM.Config[0].IPRange, check.Equals, "172.28.5.0/24")
+	c.Assert(nr.IPAM.Config[0].Gateway, check.Equals, "172.28.5.254")
+	dockerCmd(c, "network", "rm", "br0")
+}
+
+func (s *DockerNetworkSuite) TestDockerNetworkIpamInvalidCombinations(c *check.C) {
+	// network with ip-range out of subnet range
+	_, _, err := dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--ip-range=192.170.0.0/16", "test")
+	c.Assert(err, check.NotNil)
+
+	// network with multiple gateways for a single subnet
+	_, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--gateway=192.168.0.1", "--gateway=192.168.0.2", "test")
+	c.Assert(err, check.NotNil)
+
+	// Multiple overlaping subnets in the same network must fail
+	_, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--subnet=192.168.1.0/16", "test")
+	c.Assert(err, check.NotNil)
+
+	// overlapping subnets across networks must fail
+	// create a valid test0 network
+	dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test0")
+	assertNwIsAvailable(c, "test0")
+	// create an overlapping test1 network
+	_, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.128.0/17", "test1")
+	c.Assert(err, check.NotNil)
+	dockerCmd(c, "network", "rm", "test0")
+}

+ 8 - 1
vendor/src/github.com/docker/libkv/README.md

@@ -68,9 +68,16 @@ func main() {
 
 You can find other usage examples for `libkv` under the `docker/swarm` or `docker/libnetwork` repositories.
 
+## Supported versions
+
+`libkv` supports:
+- Consul version >= `0.5.1` because it uses Sessions with `Delete` behavior for the use of `TTLs` (mimics zookeeper's Ephemeral node support), If you don't plan to use `TTLs`: you can use Consul version `0.4.0+`.
+- Etcd version >= `2.0` because it uses the `2.0.0` branch of the `coreos/go-etcd` client, this might change in the future as the support for `APIv3` comes along.
+- Zookeeper version >= `3.4.5`. Although this might work with previous version but this remains untested as of now.
+
 ## TLS
 
-The etcd backend supports etcd servers that require TLS Client Authentication.  Zookeeper and Consul support are planned.  This feature is somewhat experimental and the store.ClientTLSConfig struct may change to accommodate the additional backends.
+The etcd backend supports etcd servers that require TLS Client Authentication. Zookeeper and Consul support are planned. This feature is somewhat experimental and the store.ClientTLSConfig struct may change to accommodate the additional backends.
 
 ## Warning
 

+ 188 - 45
vendor/src/github.com/docker/libkv/store/boltdb/boltdb.go

@@ -6,7 +6,9 @@ import (
 	"errors"
 	"os"
 	"path/filepath"
+	"sync"
 	"sync/atomic"
+	"time"
 
 	"github.com/boltdb/bolt"
 	"github.com/docker/libkv"
@@ -25,15 +27,29 @@ var (
 	ErrBoltAPIUnsupported = errors.New("API not supported by BoltDB backend")
 )
 
+const (
+	filePerm os.FileMode = 0644
+)
+
 //BoltDB type implements the Store interface
 type BoltDB struct {
 	client     *bolt.DB
 	boltBucket []byte
 	dbIndex    uint64
+	path       string
+	timeout    time.Duration
+	// By default libkv opens and closes the bolt DB connection  for every
+	// get/put operation. This allows multiple apps to use a Bolt DB at the
+	// same time.
+	// PersistConnection flag provides an option to override ths behavior.
+	// ie: open the connection in New and use it till Close is called.
+	PersistConnection bool
+	sync.Mutex
 }
 
 const (
 	libkvmetadatalen = 8
+	transientTimeout = time.Duration(10) * time.Second
 )
 
 // Register registers boltdb to libkv
@@ -43,6 +59,12 @@ func Register() {
 
 // New opens a new BoltDB connection to the specified path and bucket
 func New(endpoints []string, options *store.Config) (store.Store, error) {
+	var (
+		db          *bolt.DB
+		err         error
+		boltOptions *bolt.Options
+	)
+
 	if len(endpoints) > 1 {
 		return nil, ErrMultipleEndpointsUnsupported
 	}
@@ -52,39 +74,81 @@ func New(endpoints []string, options *store.Config) (store.Store, error) {
 	}
 
 	dir, _ := filepath.Split(endpoints[0])
-	if err := os.MkdirAll(dir, 0750); err != nil {
+	if err = os.MkdirAll(dir, 0750); err != nil {
 		return nil, err
 	}
 
-	var boltOptions *bolt.Options
-	if options != nil {
+	if options.PersistConnection {
 		boltOptions = &bolt.Options{Timeout: options.ConnectionTimeout}
-	}
-	db, err := bolt.Open(endpoints[0], 0644, boltOptions)
-	if err != nil {
-		return nil, err
+		db, err = bolt.Open(endpoints[0], filePerm, boltOptions)
+		if err != nil {
+			return nil, err
+		}
 	}
 
-	b := &BoltDB{}
+	b := &BoltDB{
+		client:            db,
+		path:              endpoints[0],
+		boltBucket:        []byte(options.Bucket),
+		timeout:           transientTimeout,
+		PersistConnection: options.PersistConnection,
+	}
 
-	b.client = db
-	b.boltBucket = []byte(options.Bucket)
 	return b, nil
 }
 
+func (b *BoltDB) reset() {
+	b.path = ""
+	b.boltBucket = []byte{}
+}
+
+func (b *BoltDB) getDBhandle() (*bolt.DB, error) {
+	var (
+		db  *bolt.DB
+		err error
+	)
+	if !b.PersistConnection {
+		boltOptions := &bolt.Options{Timeout: b.timeout}
+		if db, err = bolt.Open(b.path, filePerm, boltOptions); err != nil {
+			return nil, err
+		}
+		b.client = db
+	}
+
+	return b.client, nil
+}
+
+func (b *BoltDB) releaseDBhandle() {
+	if !b.PersistConnection {
+		b.client.Close()
+	}
+}
+
 // Get the value at "key". BoltDB doesn't provide an inbuilt last modified index with every kv pair. Its implemented by
 // by a atomic counter maintained by the libkv and appened to the value passed by the client.
 func (b *BoltDB) Get(key string) (*store.KVPair, error) {
-	var val []byte
+	var (
+		val []byte
+		db  *bolt.DB
+		err error
+	)
+	b.Lock()
+	defer b.Unlock()
+
+	if db, err = b.getDBhandle(); err != nil {
+		return nil, err
+	}
+	defer b.releaseDBhandle()
 
-	db := b.client
-	err := db.View(func(tx *bolt.Tx) error {
+	err = db.View(func(tx *bolt.Tx) error {
 		bucket := tx.Bucket(b.boltBucket)
 		if bucket == nil {
-			return (ErrBoltBucketNotFound)
+			return ErrBoltBucketNotFound
 		}
 
-		val = bucket.Get([]byte(key))
+		v := bucket.Get([]byte(key))
+		val = make([]byte, len(v))
+		copy(val, v)
 
 		return nil
 	})
@@ -104,11 +168,22 @@ func (b *BoltDB) Get(key string) (*store.KVPair, error) {
 
 //Put the key, value pair. index number metadata is prepended to the value
 func (b *BoltDB) Put(key string, value []byte, opts *store.WriteOptions) error {
-	var dbIndex uint64
-	db := b.client
+	var (
+		dbIndex uint64
+		db      *bolt.DB
+		err     error
+	)
+	b.Lock()
+	defer b.Unlock()
+
 	dbval := make([]byte, libkvmetadatalen)
 
-	err := db.Update(func(tx *bolt.Tx) error {
+	if db, err = b.getDBhandle(); err != nil {
+		return err
+	}
+	defer b.releaseDBhandle()
+
+	err = db.Update(func(tx *bolt.Tx) error {
 		bucket, err := tx.CreateBucketIfNotExists(b.boltBucket)
 		if err != nil {
 			return err
@@ -129,12 +204,22 @@ func (b *BoltDB) Put(key string, value []byte, opts *store.WriteOptions) error {
 
 //Delete the value for the given key.
 func (b *BoltDB) Delete(key string) error {
-	db := b.client
+	var (
+		db  *bolt.DB
+		err error
+	)
+	b.Lock()
+	defer b.Unlock()
+
+	if db, err = b.getDBhandle(); err != nil {
+		return err
+	}
+	defer b.releaseDBhandle()
 
-	err := db.Update(func(tx *bolt.Tx) error {
+	err = db.Update(func(tx *bolt.Tx) error {
 		bucket := tx.Bucket(b.boltBucket)
 		if bucket == nil {
-			return (ErrBoltBucketNotFound)
+			return ErrBoltBucketNotFound
 		}
 		err := bucket.Delete([]byte(key))
 		return err
@@ -144,13 +229,23 @@ func (b *BoltDB) Delete(key string) error {
 
 // Exists checks if the key exists inside the store
 func (b *BoltDB) Exists(key string) (bool, error) {
-	var val []byte
+	var (
+		val []byte
+		db  *bolt.DB
+		err error
+	)
+	b.Lock()
+	defer b.Unlock()
+
+	if db, err = b.getDBhandle(); err != nil {
+		return false, err
+	}
+	defer b.releaseDBhandle()
 
-	db := b.client
-	err := db.View(func(tx *bolt.Tx) error {
+	err = db.View(func(tx *bolt.Tx) error {
 		bucket := tx.Bucket(b.boltBucket)
 		if bucket == nil {
-			return (ErrBoltBucketNotFound)
+			return ErrBoltBucketNotFound
 		}
 
 		val = bucket.Get([]byte(key))
@@ -166,22 +261,35 @@ func (b *BoltDB) Exists(key string) (bool, error) {
 
 // List returns the range of keys starting with the passed in prefix
 func (b *BoltDB) List(keyPrefix string) ([]*store.KVPair, error) {
+	var (
+		db  *bolt.DB
+		err error
+	)
+	b.Lock()
+	defer b.Unlock()
+
 	kv := []*store.KVPair{}
 
-	db := b.client
-	err := db.View(func(tx *bolt.Tx) error {
+	if db, err = b.getDBhandle(); err != nil {
+		return nil, err
+	}
+	defer b.releaseDBhandle()
+
+	err = db.View(func(tx *bolt.Tx) error {
 		bucket := tx.Bucket(b.boltBucket)
 		if bucket == nil {
-			return (ErrBoltBucketNotFound)
+			return ErrBoltBucketNotFound
 		}
 
 		cursor := bucket.Cursor()
 		prefix := []byte(keyPrefix)
 
-		for key, val := cursor.Seek(prefix); bytes.HasPrefix(key, prefix); key, val = cursor.Next() {
+		for key, v := cursor.Seek(prefix); bytes.HasPrefix(key, prefix); key, v = cursor.Next() {
 
-			dbIndex := binary.LittleEndian.Uint64(val[:libkvmetadatalen])
-			val = val[libkvmetadatalen:]
+			dbIndex := binary.LittleEndian.Uint64(v[:libkvmetadatalen])
+			v = v[libkvmetadatalen:]
+			val := make([]byte, len(v))
+			copy(val, v)
 
 			kv = append(kv, &store.KVPair{
 				Key:       string(key),
@@ -201,22 +309,30 @@ func (b *BoltDB) List(keyPrefix string) ([]*store.KVPair, error) {
 // has not been modified in the meantime, throws an
 // error if this is the case
 func (b *BoltDB) AtomicDelete(key string, previous *store.KVPair) (bool, error) {
-	var val []byte
-	var dbIndex uint64
+	var (
+		val []byte
+		db  *bolt.DB
+		err error
+	)
+	b.Lock()
+	defer b.Unlock()
 
 	if previous == nil {
 		return false, store.ErrPreviousNotSpecified
 	}
-	db := b.client
+	if db, err = b.getDBhandle(); err != nil {
+		return false, err
+	}
+	defer b.releaseDBhandle()
 
-	err := db.Update(func(tx *bolt.Tx) error {
+	err = db.Update(func(tx *bolt.Tx) error {
 		bucket := tx.Bucket(b.boltBucket)
 		if bucket == nil {
 			return ErrBoltBucketNotFound
 		}
 
 		val = bucket.Get([]byte(key))
-		dbIndex = binary.LittleEndian.Uint64(val[:libkvmetadatalen])
+		dbIndex := binary.LittleEndian.Uint64(val[:libkvmetadatalen])
 		if dbIndex != previous.LastIndex {
 			return store.ErrKeyModified
 		}
@@ -232,13 +348,23 @@ func (b *BoltDB) AtomicDelete(key string, previous *store.KVPair) (bool, error)
 // AtomicPut puts a value at "key" if the key has not been
 // modified since the last Put, throws an error if this is the case
 func (b *BoltDB) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
-	var val []byte
-	var dbIndex uint64
+	var (
+		val     []byte
+		dbIndex uint64
+		db      *bolt.DB
+		err     error
+	)
+	b.Lock()
+	defer b.Unlock()
+
 	dbval := make([]byte, libkvmetadatalen)
 
-	db := b.client
+	if db, err = b.getDBhandle(); err != nil {
+		return false, nil, err
+	}
+	defer b.releaseDBhandle()
 
-	err := db.Update(func(tx *bolt.Tx) error {
+	err = db.Update(func(tx *bolt.Tx) error {
 		var err error
 		bucket := tx.Bucket(b.boltBucket)
 		if bucket == nil {
@@ -285,18 +411,35 @@ func (b *BoltDB) AtomicPut(key string, value []byte, previous *store.KVPair, opt
 
 // Close the db connection to the BoltDB
 func (b *BoltDB) Close() {
-	db := b.client
+	b.Lock()
+	defer b.Unlock()
 
-	db.Close()
+	if !b.PersistConnection {
+		b.reset()
+	} else {
+		b.client.Close()
+	}
+	return
 }
 
 // DeleteTree deletes a range of keys with a given prefix
 func (b *BoltDB) DeleteTree(keyPrefix string) error {
-	db := b.client
-	err := db.Update(func(tx *bolt.Tx) error {
+	var (
+		db  *bolt.DB
+		err error
+	)
+	b.Lock()
+	defer b.Unlock()
+
+	if db, err = b.getDBhandle(); err != nil {
+		return err
+	}
+	defer b.releaseDBhandle()
+
+	err = db.Update(func(tx *bolt.Tx) error {
 		bucket := tx.Bucket(b.boltBucket)
 		if bucket == nil {
-			return (ErrBoltBucketNotFound)
+			return ErrBoltBucketNotFound
 		}
 
 		cursor := bucket.Cursor()

+ 40 - 8
vendor/src/github.com/docker/libkv/store/consul/consul.go

@@ -35,7 +35,8 @@ type Consul struct {
 }
 
 type consulLock struct {
-	lock *api.Lock
+	lock    *api.Lock
+	renewCh chan struct{}
 }
 
 // Register registers consul to libkv
@@ -87,7 +88,7 @@ func (s *Consul) setTLS(tls *tls.Config) {
 	s.config.Scheme = "https"
 }
 
-// SetTimeout sets the timout for connecting to Consul
+// SetTimeout sets the timeout for connecting to Consul
 func (s *Consul) setTimeout(time time.Duration) {
 	s.config.WaitTime = time
 }
@@ -360,32 +361,63 @@ func (s *Consul) WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*
 // NewLock returns a handle to a lock struct which can
 // be used to provide mutual exclusion on a key
 func (s *Consul) NewLock(key string, options *store.LockOptions) (store.Locker, error) {
-	consulOpts := &api.LockOptions{
+	lockOpts := &api.LockOptions{
 		Key: s.normalize(key),
 	}
 
+	lock := &consulLock{}
+
 	if options != nil {
-		consulOpts.Value = options.Value
+		// Set optional TTL on Lock
+		if options.TTL != 0 {
+			entry := &api.SessionEntry{
+				Behavior:  api.SessionBehaviorRelease, // Release the lock when the session expires
+				TTL:       (options.TTL / 2).String(), // Consul multiplies the TTL by 2x
+				LockDelay: 1 * time.Millisecond,       // Virtually disable lock delay
+			}
+
+			// Create the key session
+			session, _, err := s.client.Session().Create(entry, nil)
+			if err != nil {
+				return nil, err
+			}
+
+			// Place the session on lock
+			lockOpts.Session = session
+
+			// Renew the session ttl lock periodically
+			go s.client.Session().RenewPeriodic(entry.TTL, session, nil, options.RenewLock)
+			lock.renewCh = options.RenewLock
+		}
+
+		// Set optional value on Lock
+		if options.Value != nil {
+			lockOpts.Value = options.Value
+		}
 	}
 
-	l, err := s.client.LockOpts(consulOpts)
+	l, err := s.client.LockOpts(lockOpts)
 	if err != nil {
 		return nil, err
 	}
 
-	return &consulLock{lock: l}, nil
+	lock.lock = l
+	return lock, nil
 }
 
 // Lock attempts to acquire the lock and blocks while
 // doing so. It returns a channel that is closed if our
 // lock is lost or if an error occurs
-func (l *consulLock) Lock() (<-chan struct{}, error) {
-	return l.lock.Lock(nil)
+func (l *consulLock) Lock(stopChan chan struct{}) (<-chan struct{}, error) {
+	return l.lock.Lock(stopChan)
 }
 
 // Unlock the "key". Calling unlock while
 // not holding the lock will throw an error
 func (l *consulLock) Unlock() error {
+	if l.renewCh != nil {
+		close(l.renewCh)
+	}
 	return l.lock.Unlock()
 }
 

+ 44 - 18
vendor/src/github.com/docker/libkv/store/etcd/etcd.go

@@ -2,6 +2,7 @@ package etcd
 
 import (
 	"crypto/tls"
+	"errors"
 	"net"
 	"net/http"
 	"strings"
@@ -12,6 +13,13 @@ import (
 	"github.com/docker/libkv/store"
 )
 
+var (
+	// ErrAbortTryLock is thrown when a user stops trying to seek the lock
+	// by sending a signal to the stop chan, this is used to verify if the
+	// operation succeeded
+	ErrAbortTryLock = errors.New("lock operation aborted")
+)
+
 // Etcd is the receiver type for the
 // Store interface
 type Etcd struct {
@@ -19,12 +27,13 @@ type Etcd struct {
 }
 
 type etcdLock struct {
-	client   *etcd.Client
-	stopLock chan struct{}
-	key      string
-	value    string
-	last     *etcd.Response
-	ttl      uint64
+	client    *etcd.Client
+	stopLock  chan struct{}
+	stopRenew chan struct{}
+	key       string
+	value     string
+	last      *etcd.Response
+	ttl       uint64
 }
 
 const (
@@ -395,6 +404,7 @@ func (s *Etcd) DeleteTree(directory string) error {
 func (s *Etcd) NewLock(key string, options *store.LockOptions) (lock store.Locker, err error) {
 	var value string
 	ttl := uint64(time.Duration(defaultLockTTL).Seconds())
+	renewCh := make(chan struct{})
 
 	// Apply options on Lock
 	if options != nil {
@@ -404,14 +414,18 @@ func (s *Etcd) NewLock(key string, options *store.LockOptions) (lock store.Locke
 		if options.TTL != 0 {
 			ttl = uint64(options.TTL.Seconds())
 		}
+		if options.RenewLock != nil {
+			renewCh = options.RenewLock
+		}
 	}
 
 	// Create lock object
 	lock = &etcdLock{
-		client: s.client,
-		key:    key,
-		value:  value,
-		ttl:    ttl,
+		client:    s.client,
+		stopRenew: renewCh,
+		key:       key,
+		value:     value,
+		ttl:       ttl,
 	}
 
 	return lock, nil
@@ -420,13 +434,13 @@ func (s *Etcd) NewLock(key string, options *store.LockOptions) (lock store.Locke
 // Lock attempts to acquire the lock and blocks while
 // doing so. It returns a channel that is closed if our
 // lock is lost or if an error occurs
-func (l *etcdLock) Lock() (<-chan struct{}, error) {
+func (l *etcdLock) Lock(stopChan chan struct{}) (<-chan struct{}, error) {
 
 	key := store.Normalize(l.key)
 
-	// Lock holder channels
+	// Lock holder channel
 	lockHeld := make(chan struct{})
-	stopLocking := make(chan struct{})
+	stopLocking := l.stopRenew
 
 	var lastIndex uint64
 
@@ -454,7 +468,18 @@ func (l *etcdLock) Lock() (<-chan struct{}, error) {
 			// Seeker section
 			chW := make(chan *etcd.Response)
 			chWStop := make(chan bool)
-			l.waitLock(key, chW, chWStop)
+			free := make(chan bool)
+
+			go l.waitLock(key, chW, chWStop, free)
+
+			// Wait for the key to be available or for
+			// a signal to stop trying to lock the key
+			select {
+			case _ = <-free:
+				break
+			case _ = <-stopChan:
+				return nil, ErrAbortTryLock
+			}
 
 			// Delete or Expire event occured
 			// Retry
@@ -467,10 +492,10 @@ func (l *etcdLock) Lock() (<-chan struct{}, error) {
 // Hold the lock as long as we can
 // Updates the key ttl periodically until we receive
 // an explicit stop signal from the Unlock method
-func (l *etcdLock) holdLock(key string, lockHeld chan struct{}, stopLocking chan struct{}) {
+func (l *etcdLock) holdLock(key string, lockHeld chan struct{}, stopLocking <-chan struct{}) {
 	defer close(lockHeld)
 
-	update := time.NewTicker(defaultUpdateTime)
+	update := time.NewTicker(time.Duration(l.ttl) * time.Second / 3)
 	defer update.Stop()
 
 	var err error
@@ -490,11 +515,12 @@ func (l *etcdLock) holdLock(key string, lockHeld chan struct{}, stopLocking chan
 }
 
 // WaitLock simply waits for the key to be available for creation
-func (l *etcdLock) waitLock(key string, eventCh chan *etcd.Response, stopWatchCh chan bool) {
+func (l *etcdLock) waitLock(key string, eventCh chan *etcd.Response, stopWatchCh chan bool, free chan<- bool) {
 	go l.client.Watch(key, 0, false, eventCh, stopWatchCh)
+
 	for event := range eventCh {
 		if event.Action == "delete" || event.Action == "expire" {
-			return
+			free <- true
 		}
 	}
 }

+ 5 - 3
vendor/src/github.com/docker/libkv/store/store.go

@@ -43,6 +43,7 @@ type Config struct {
 	TLS               *tls.Config
 	ConnectionTimeout time.Duration
 	Bucket            string
+	PersistConnection bool
 }
 
 // ClientTLSConfig contains data for a Client TLS configuration in the form
@@ -113,13 +114,14 @@ type WriteOptions struct {
 
 // LockOptions contains optional request parameters
 type LockOptions struct {
-	Value []byte        // Optional, value to associate with the lock
-	TTL   time.Duration // Optional, expiration ttl associated with the lock
+	Value     []byte        // Optional, value to associate with the lock
+	TTL       time.Duration // Optional, expiration ttl associated with the lock
+	RenewLock chan struct{} // Optional, chan used to control and stop the session ttl renewal for the lock
 }
 
 // Locker provides locking mechanism on top of the store.
 // Similar to `sync.Lock` except it may return errors.
 type Locker interface {
-	Lock() (<-chan struct{}, error)
+	Lock(stopChan chan struct{}) (<-chan struct{}, error)
 	Unlock() error
 }

+ 11 - 2
vendor/src/github.com/docker/libkv/store/zookeeper/zookeeper.go

@@ -10,6 +10,9 @@ import (
 )
 
 const (
+	// SOH control character
+	SOH = "\x01"
+
 	defaultTimeout = 10 * time.Second
 )
 
@@ -72,6 +75,12 @@ func (s *Zookeeper) Get(key string) (pair *store.KVPair, err error) {
 		return nil, err
 	}
 
+	// FIXME handle very rare cases where Get returns the
+	// SOH control character instead of the actual value
+	if string(resp) == SOH {
+		return s.Get(store.Normalize(key))
+	}
+
 	pair = &store.KVPair{
 		Key:       key,
 		Value:     resp,
@@ -301,7 +310,7 @@ func (s *Zookeeper) AtomicPut(key string, value []byte, previous *store.KVPair,
 			// Zookeeper will complain if the directory doesn't exist.
 			if err == zk.ErrNoNode {
 				// Create the directory
-				parts := store.SplitKey(key)
+				parts := store.SplitKey(strings.TrimSuffix(key, "/"))
 				parts = parts[:len(parts)-1]
 				if err = s.createFullPath(parts, false); err != nil {
 					// Failed to create the directory.
@@ -371,7 +380,7 @@ func (s *Zookeeper) NewLock(key string, options *store.LockOptions) (lock store.
 // Lock attempts to acquire the lock and blocks while
 // doing so. It returns a channel that is closed if our
 // lock is lost or if an error occurs
-func (l *zookeeperLock) Lock() (<-chan struct{}, error) {
+func (l *zookeeperLock) Lock(stopChan chan struct{}) (<-chan struct{}, error) {
 	err := l.lock.Lock()
 
 	if err == nil {

+ 2 - 1
vendor/src/github.com/docker/libnetwork/.gitignore

@@ -29,7 +29,8 @@ cmd/dnet/dnet
 *.tmp
 *.coverprofile
 
-# IDE files
+# IDE files and folders
 .project
+.settings/
 
 libnetwork-build.created

+ 102 - 44
vendor/src/github.com/docker/libnetwork/bitseq/sequence.go

@@ -5,6 +5,7 @@ package bitseq
 
 import (
 	"encoding/binary"
+	"encoding/json"
 	"fmt"
 	"sync"
 
@@ -16,10 +17,10 @@ import (
 // If needed we can think of making these configurable
 const (
 	blockLen      = uint32(32)
-	blockBytes    = blockLen / 8
+	blockBytes    = uint64(blockLen / 8)
 	blockMAX      = uint32(1<<blockLen - 1)
 	blockFirstBit = uint32(1) << (blockLen - 1)
-	invalidPos    = blockMAX
+	invalidPos    = uint64(0xFFFFFFFFFFFFFFFF)
 )
 
 var (
@@ -28,8 +29,8 @@ var (
 
 // Handle contains the sequece representing the bitmask and its identifier
 type Handle struct {
-	bits       uint32
-	unselected uint32
+	bits       uint64
+	unselected uint64
 	head       *sequence
 	app        string
 	id         string
@@ -40,7 +41,7 @@ type Handle struct {
 }
 
 // NewHandle returns a thread-safe instance of the bitmask handler
-func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32) (*Handle, error) {
+func NewHandle(app string, ds datastore.DataStore, id string, numElements uint64) (*Handle, error) {
 	h := &Handle{
 		app:        app,
 		id:         id,
@@ -57,21 +58,25 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32
 		return h, nil
 	}
 
-	// Register for status changes
-	h.watchForChanges()
-
 	// Get the initial status from the ds if present.
 	if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
 		return nil, err
 	}
 
+	// If the handle is not in store, write it.
+	if !h.Exists() {
+		if err := h.writeToStore(); err != nil {
+			return nil, fmt.Errorf("failed to write bitsequence to store: %v", err)
+		}
+	}
+
 	return h, nil
 }
 
 // sequence represents a recurring sequence of 32 bits long bitmasks
 type sequence struct {
 	block uint32    // block is a symbol representing 4 byte long allocation bitmask
-	count uint32    // number of consecutive blocks (symbols)
+	count uint64    // number of consecutive blocks (symbols)
 	next  *sequence // next sequence
 }
 
@@ -87,7 +92,7 @@ func (s *sequence) toString() string {
 }
 
 // GetAvailableBit returns the position of the first unset bit in the bitmask represented by this sequence
-func (s *sequence) getAvailableBit(from uint32) (uint32, uint32, error) {
+func (s *sequence) getAvailableBit(from uint64) (uint64, uint64, error) {
 	if s.block == blockMAX || s.count == 0 {
 		return invalidPos, invalidPos, errNoBitAvailable
 	}
@@ -140,9 +145,9 @@ func (s *sequence) toByteArray() ([]byte, error) {
 
 	p := s
 	for p != nil {
-		b := make([]byte, 8)
+		b := make([]byte, 12)
 		binary.BigEndian.PutUint32(b[0:], p.block)
-		binary.BigEndian.PutUint32(b[4:], p.count)
+		binary.BigEndian.PutUint64(b[4:], p.count)
 		bb = append(bb, b...)
 		p = p.next
 	}
@@ -153,7 +158,7 @@ func (s *sequence) toByteArray() ([]byte, error) {
 // fromByteArray construct the sequence from the byte array
 func (s *sequence) fromByteArray(data []byte) error {
 	l := len(data)
-	if l%8 != 0 {
+	if l%12 != 0 {
 		return fmt.Errorf("cannot deserialize byte sequence of lenght %d (%v)", l, data)
 	}
 
@@ -161,8 +166,8 @@ func (s *sequence) fromByteArray(data []byte) error {
 	i := 0
 	for {
 		p.block = binary.BigEndian.Uint32(data[i : i+4])
-		p.count = binary.BigEndian.Uint32(data[i+4 : i+8])
-		i += 8
+		p.count = binary.BigEndian.Uint64(data[i+4 : i+12])
+		i += 12
 		if i == l {
 			break
 		}
@@ -187,7 +192,7 @@ func (h *Handle) getCopy() *Handle {
 }
 
 // SetAnyInRange atomically sets the first unset bit in the specified range in the sequence and returns the corresponding ordinal
-func (h *Handle) SetAnyInRange(start, end uint32) (uint32, error) {
+func (h *Handle) SetAnyInRange(start, end uint64) (uint64, error) {
 	if end-start <= 0 || end >= h.bits {
 		return invalidPos, fmt.Errorf("invalid bit range [%d, %d]", start, end)
 	}
@@ -198,7 +203,7 @@ func (h *Handle) SetAnyInRange(start, end uint32) (uint32, error) {
 }
 
 // SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
-func (h *Handle) SetAny() (uint32, error) {
+func (h *Handle) SetAny() (uint64, error) {
 	if h.Unselected() == 0 {
 		return invalidPos, errNoBitAvailable
 	}
@@ -206,7 +211,7 @@ func (h *Handle) SetAny() (uint32, error) {
 }
 
 // Set atomically sets the corresponding bit in the sequence
-func (h *Handle) Set(ordinal uint32) error {
+func (h *Handle) Set(ordinal uint64) error {
 	if err := h.validateOrdinal(ordinal); err != nil {
 		return err
 	}
@@ -215,7 +220,7 @@ func (h *Handle) Set(ordinal uint32) error {
 }
 
 // Unset atomically unsets the corresponding bit in the sequence
-func (h *Handle) Unset(ordinal uint32) error {
+func (h *Handle) Unset(ordinal uint64) error {
 	if err := h.validateOrdinal(ordinal); err != nil {
 		return err
 	}
@@ -225,7 +230,7 @@ func (h *Handle) Unset(ordinal uint32) error {
 
 // IsSet atomically checks if the ordinal bit is set. In case ordinal
 // is outside of the bit sequence limits, false is returned.
-func (h *Handle) IsSet(ordinal uint32) bool {
+func (h *Handle) IsSet(ordinal uint64) bool {
 	if err := h.validateOrdinal(ordinal); err != nil {
 		return false
 	}
@@ -236,15 +241,21 @@ func (h *Handle) IsSet(ordinal uint32) bool {
 }
 
 // set/reset the bit
-func (h *Handle) set(ordinal, start, end uint32, any bool, release bool) (uint32, error) {
+func (h *Handle) set(ordinal, start, end uint64, any bool, release bool) (uint64, error) {
 	var (
-		bitPos  uint32
-		bytePos uint32
-		ret     uint32
+		bitPos  uint64
+		bytePos uint64
+		ret     uint64
 		err     error
 	)
 
 	for {
+		if h.store != nil {
+			if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
+				return ret, err
+			}
+		}
+
 		h.Lock()
 		// Get position if available
 		if release {
@@ -298,7 +309,7 @@ func (h *Handle) set(ordinal, start, end uint32, any bool, release bool) (uint32
 }
 
 // checks is needed because to cover the case where the number of bits is not a multiple of blockLen
-func (h *Handle) validateOrdinal(ordinal uint32) error {
+func (h *Handle) validateOrdinal(ordinal uint64) error {
 	if ordinal >= h.bits {
 		return fmt.Errorf("bit does not belong to the sequence")
 	}
@@ -306,8 +317,23 @@ func (h *Handle) validateOrdinal(ordinal uint32) error {
 }
 
 // Destroy removes from the datastore the data belonging to this handle
-func (h *Handle) Destroy() {
-	h.deleteFromStore()
+func (h *Handle) Destroy() error {
+	for {
+		if err := h.deleteFromStore(); err != nil {
+			if _, ok := err.(types.RetryError); !ok {
+				return fmt.Errorf("internal failure while destroying the sequence: %v", err)
+			}
+			// Fetch latest
+			if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil {
+				if err == datastore.ErrKeyNotFound { // already removed
+					return nil
+				}
+				return fmt.Errorf("failed to fetch from store when destroying the sequence: %v", err)
+			}
+			continue
+		}
+		return nil
+	}
 }
 
 // ToByteArray converts this handle's data into a byte array
@@ -315,9 +341,9 @@ func (h *Handle) ToByteArray() ([]byte, error) {
 
 	h.Lock()
 	defer h.Unlock()
-	ba := make([]byte, 8)
-	binary.BigEndian.PutUint32(ba[0:], h.bits)
-	binary.BigEndian.PutUint32(ba[4:], h.unselected)
+	ba := make([]byte, 16)
+	binary.BigEndian.PutUint64(ba[0:], h.bits)
+	binary.BigEndian.PutUint64(ba[8:], h.unselected)
 	bm, err := h.head.toByteArray()
 	if err != nil {
 		return nil, fmt.Errorf("failed to serialize head: %s", err.Error())
@@ -334,27 +360,27 @@ func (h *Handle) FromByteArray(ba []byte) error {
 	}
 
 	nh := &sequence{}
-	err := nh.fromByteArray(ba[8:])
+	err := nh.fromByteArray(ba[16:])
 	if err != nil {
 		return fmt.Errorf("failed to deserialize head: %s", err.Error())
 	}
 
 	h.Lock()
 	h.head = nh
-	h.bits = binary.BigEndian.Uint32(ba[0:4])
-	h.unselected = binary.BigEndian.Uint32(ba[4:8])
+	h.bits = binary.BigEndian.Uint64(ba[0:8])
+	h.unselected = binary.BigEndian.Uint64(ba[8:16])
 	h.Unlock()
 
 	return nil
 }
 
 // Bits returns the length of the bit sequence
-func (h *Handle) Bits() uint32 {
+func (h *Handle) Bits() uint64 {
 	return h.bits
 }
 
 // Unselected returns the number of bits which are not selected
-func (h *Handle) Unselected() uint32 {
+func (h *Handle) Unselected() uint64 {
 	h.Lock()
 	defer h.Unlock()
 	return h.unselected
@@ -367,8 +393,40 @@ func (h *Handle) String() string {
 		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
-func getFirstAvailable(head *sequence, start uint32) (uint32, uint32, error) {
+func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) {
 	// Find sequence which contains the start bit
 	byteStart, bitStart := ordinalToPos(start)
 	current, _, _, inBlockBytePos := findSequence(head, byteStart)
@@ -392,7 +450,7 @@ func getFirstAvailable(head *sequence, start uint32) (uint32, uint32, error) {
 
 // checkIfAvailable checks if the bit correspondent to the specified ordinal is unset
 // If the ordinal is beyond the sequence limits, a negative response is returned
-func checkIfAvailable(head *sequence, ordinal uint32) (uint32, uint32, error) {
+func checkIfAvailable(head *sequence, ordinal uint64) (uint64, uint64, error) {
 	bytePos, bitPos := ordinalToPos(ordinal)
 
 	// Find the sequence containing this byte
@@ -412,7 +470,7 @@ func checkIfAvailable(head *sequence, ordinal uint32) (uint32, uint32, error) {
 // sequence containing the byte (current), the pointer to the previous sequence,
 // the number of blocks preceding the block containing the byte inside the current sequence.
 // If bytePos is outside of the list, function will return (nil, nil, 0, invalidPos)
-func findSequence(head *sequence, bytePos uint32) (*sequence, *sequence, uint32, uint32) {
+func findSequence(head *sequence, bytePos uint64) (*sequence, *sequence, uint64, uint64) {
 	// Find the sequence containing this byte
 	previous := head
 	current := head
@@ -453,7 +511,7 @@ func findSequence(head *sequence, bytePos uint32) (*sequence, *sequence, uint32,
 // A) block is first in current:         [prev seq] [new] [modified current seq] [next seq]
 // B) block is last in current:          [prev seq] [modified current seq] [new] [next seq]
 // C) block is in the middle of current: [prev seq] [curr pre] [new] [curr post] [next seq]
-func pushReservation(bytePos, bitPos uint32, head *sequence, release bool) *sequence {
+func pushReservation(bytePos, bitPos uint64, head *sequence, release bool) *sequence {
 	// Store list's head
 	newHead := head
 
@@ -541,18 +599,18 @@ func mergeSequences(seq *sequence) {
 	}
 }
 
-func getNumBlocks(numBits uint32) uint32 {
-	numBlocks := numBits / blockLen
-	if numBits%blockLen != 0 {
+func getNumBlocks(numBits uint64) uint64 {
+	numBlocks := numBits / uint64(blockLen)
+	if numBits%uint64(blockLen) != 0 {
 		numBlocks++
 	}
 	return numBlocks
 }
 
-func ordinalToPos(ordinal uint32) (uint32, uint32) {
+func ordinalToPos(ordinal uint64) (uint64, uint64) {
 	return ordinal / 8, ordinal % 8
 }
 
-func posToOrdinal(bytePos, bitPos uint32) uint32 {
+func posToOrdinal(bytePos, bitPos uint64) uint64 {
 	return bytePos*8 + bitPos
 }

+ 36 - 48
vendor/src/github.com/docker/libnetwork/bitseq/store.go

@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"fmt"
 
-	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/datastore"
 	"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
 func (h *Handle) Value() []byte {
-	b, err := h.ToByteArray()
+	b, err := json.Marshal(h)
 	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
 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
@@ -70,46 +58,46 @@ func (h *Handle) Exists() bool {
 	return h.dbExists
 }
 
+// New method returns a handle based on the receiver handle
+func (h *Handle) New() datastore.KVObject {
+	h.Lock()
+	defer h.Unlock()
+
+	return &Handle{
+		app:   h.app,
+		store: h.store,
+	}
+}
+
+// CopyTo deep copies the handle into the passed destination object
+func (h *Handle) CopyTo(o datastore.KVObject) error {
+	h.Lock()
+	defer h.Unlock()
+
+	dstH := o.(*Handle)
+	dstH.bits = h.bits
+	dstH.unselected = h.unselected
+	dstH.head = h.head.getCopy()
+	dstH.app = h.app
+	dstH.id = h.id
+	dstH.dbIndex = h.dbIndex
+	dstH.dbExists = h.dbExists
+	dstH.store = h.store
+
+	return nil
+}
+
 // Skip provides a way for a KV Object to avoid persisting it in the KV Store
 func (h *Handle) Skip() bool {
 	return false
 }
 
 // DataScope method returns the storage scope of the datastore
-func (h *Handle) DataScope() datastore.DataScope {
-	return datastore.GlobalScope
-}
-
-func (h *Handle) watchForChanges() error {
+func (h *Handle) DataScope() string {
 	h.Lock()
-	store := h.store
-	h.Unlock()
-
-	if store == nil {
-		return nil
-	}
+	defer h.Unlock()
 
-	kvpChan, err := store.KVStore().Watch(datastore.Key(h.Key()...), nil)
-	if err != nil {
-		return err
-	}
-	go func() {
-		for {
-			select {
-			case kvPair := <-kvpChan:
-				// Only process remote update
-				if kvPair != nil && (kvPair.LastIndex != h.Index()) {
-					err := h.fromDsValue(kvPair.Value)
-					if err != nil {
-						log.Warnf("Failed to reconstruct bitseq handle from ds watch: %s", err.Error())
-					} else {
-						h.SetIndex(kvPair.LastIndex)
-					}
-				}
-			}
-		}
-	}()
-	return nil
+	return h.store.Scope()
 }
 
 func (h *Handle) fromDsValue(value []byte) error {

+ 91 - 30
vendor/src/github.com/docker/libnetwork/config/config.go

@@ -6,20 +6,23 @@ import (
 	"github.com/BurntSushi/toml"
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/discovery"
+	"github.com/docker/docker/pkg/tlsconfig"
 	"github.com/docker/libkv/store"
+	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/netlabel"
 )
 
 // Config encapsulates configurations of various Libnetwork components
 type Config struct {
-	Daemon                  DaemonCfg
-	Cluster                 ClusterCfg
-	GlobalStore, LocalStore DatastoreCfg
+	Daemon  DaemonCfg
+	Cluster ClusterCfg
+	Scopes  map[string]*datastore.ScopeCfg
 }
 
 // DaemonCfg represents libnetwork core configuration
 type DaemonCfg struct {
 	Debug          bool
+	DataDir        string
 	DefaultNetwork string
 	DefaultDriver  string
 	Labels         []string
@@ -34,26 +37,28 @@ type ClusterCfg struct {
 	Heartbeat uint64
 }
 
-// DatastoreCfg represents Datastore configuration.
-type DatastoreCfg struct {
-	Embedded bool
-	Client   DatastoreClientCfg
-}
-
-// DatastoreClientCfg represents Datastore Client-only mode configuration
-type DatastoreClientCfg struct {
-	Provider string
-	Address  string
-	Config   *store.Config
+// LoadDefaultScopes loads default scope configs for scopes which
+// doesn't have explicit user specified configs.
+func (c *Config) LoadDefaultScopes(dataDir string) {
+	for k, v := range datastore.DefaultScopes(dataDir) {
+		if _, ok := c.Scopes[k]; !ok {
+			c.Scopes[k] = v
+		}
+	}
 }
 
 // ParseConfig parses the libnetwork configuration file
 func ParseConfig(tomlCfgFile string) (*Config, error) {
-	var cfg Config
-	if _, err := toml.DecodeFile(tomlCfgFile, &cfg); err != nil {
+	cfg := &Config{
+		Scopes: map[string]*datastore.ScopeCfg{},
+	}
+
+	if _, err := toml.DecodeFile(tomlCfgFile, cfg); err != nil {
 		return nil, err
 	}
-	return &cfg, nil
+
+	cfg.LoadDefaultScopes(cfg.Daemon.DataDir)
+	return cfg, nil
 }
 
 // Option is a option setter function type used to pass varios configurations
@@ -63,7 +68,7 @@ type Option func(c *Config)
 // OptionDefaultNetwork function returns an option setter for a default network
 func OptionDefaultNetwork(dn string) Option {
 	return func(c *Config) {
-		log.Infof("Option DefaultNetwork: %s", dn)
+		log.Debugf("Option DefaultNetwork: %s", dn)
 		c.Daemon.DefaultNetwork = strings.TrimSpace(dn)
 	}
 }
@@ -71,7 +76,7 @@ func OptionDefaultNetwork(dn string) Option {
 // OptionDefaultDriver function returns an option setter for default driver
 func OptionDefaultDriver(dd string) Option {
 	return func(c *Config) {
-		log.Infof("Option DefaultDriver: %s", dd)
+		log.Debugf("Option DefaultDriver: %s", dd)
 		c.Daemon.DefaultDriver = strings.TrimSpace(dd)
 	}
 }
@@ -97,16 +102,56 @@ func OptionLabels(labels []string) Option {
 // OptionKVProvider function returns an option setter for kvstore provider
 func OptionKVProvider(provider string) Option {
 	return func(c *Config) {
-		log.Infof("Option OptionKVProvider: %s", provider)
-		c.GlobalStore.Client.Provider = strings.TrimSpace(provider)
+		log.Debugf("Option OptionKVProvider: %s", provider)
+		if _, ok := c.Scopes[datastore.GlobalScope]; !ok {
+			c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{}
+		}
+		c.Scopes[datastore.GlobalScope].Client.Provider = strings.TrimSpace(provider)
 	}
 }
 
 // OptionKVProviderURL function returns an option setter for kvstore url
 func OptionKVProviderURL(url string) Option {
 	return func(c *Config) {
-		log.Infof("Option OptionKVProviderURL: %s", url)
-		c.GlobalStore.Client.Address = strings.TrimSpace(url)
+		log.Debugf("Option OptionKVProviderURL: %s", url)
+		if _, ok := c.Scopes[datastore.GlobalScope]; !ok {
+			c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{}
+		}
+		c.Scopes[datastore.GlobalScope].Client.Address = strings.TrimSpace(url)
+	}
+}
+
+// OptionKVOpts function returns an option setter for kvstore options
+func OptionKVOpts(opts map[string]string) Option {
+	return func(c *Config) {
+		if opts["kv.cacertfile"] != "" && opts["kv.certfile"] != "" && opts["kv.keyfile"] != "" {
+			log.Info("Option Initializing KV with TLS")
+			tlsConfig, err := tlsconfig.Client(tlsconfig.Options{
+				CAFile:   opts["kv.cacertfile"],
+				CertFile: opts["kv.certfile"],
+				KeyFile:  opts["kv.keyfile"],
+			})
+			if err != nil {
+				log.Errorf("Unable to set up TLS: %s", err)
+				return
+			}
+			if _, ok := c.Scopes[datastore.GlobalScope]; !ok {
+				c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{}
+			}
+			if c.Scopes[datastore.GlobalScope].Client.Config == nil {
+				c.Scopes[datastore.GlobalScope].Client.Config = &store.Config{TLS: tlsConfig}
+			} else {
+				c.Scopes[datastore.GlobalScope].Client.Config.TLS = tlsConfig
+			}
+			// Workaround libkv/etcd bug for https
+			c.Scopes[datastore.GlobalScope].Client.Config.ClientTLS = &store.ClientTLSConfig{
+				CACertFile: opts["kv.cacertfile"],
+				CertFile:   opts["kv.certfile"],
+				KeyFile:    opts["kv.keyfile"],
+			}
+		} else {
+			log.Info("Option Initializing KV without TLS")
+		}
 	}
 }
 
@@ -124,6 +169,13 @@ func OptionDiscoveryAddress(address string) Option {
 	}
 }
 
+// OptionDataDir function returns an option setter for data folder
+func OptionDataDir(dataDir string) Option {
+	return func(c *Config) {
+		c.Daemon.DataDir = dataDir
+	}
+}
+
 // ProcessOptions processes options and stores it in config
 func (c *Config) ProcessOptions(options ...Option) {
 	for _, opt := range options {
@@ -135,7 +187,7 @@ func (c *Config) ProcessOptions(options ...Option) {
 
 // IsValidName validates configuration objects supported by libnetwork
 func IsValidName(name string) bool {
-	if strings.TrimSpace(name) == "" || strings.Contains(name, ".") {
+	if strings.TrimSpace(name) == "" {
 		return false
 	}
 	return true
@@ -144,23 +196,32 @@ func IsValidName(name string) bool {
 // OptionLocalKVProvider function returns an option setter for kvstore provider
 func OptionLocalKVProvider(provider string) Option {
 	return func(c *Config) {
-		log.Infof("Option OptionLocalKVProvider: %s", provider)
-		c.LocalStore.Client.Provider = strings.TrimSpace(provider)
+		log.Debugf("Option OptionLocalKVProvider: %s", provider)
+		if _, ok := c.Scopes[datastore.LocalScope]; !ok {
+			c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{}
+		}
+		c.Scopes[datastore.LocalScope].Client.Provider = strings.TrimSpace(provider)
 	}
 }
 
 // OptionLocalKVProviderURL function returns an option setter for kvstore url
 func OptionLocalKVProviderURL(url string) Option {
 	return func(c *Config) {
-		log.Infof("Option OptionLocalKVProviderURL: %s", url)
-		c.LocalStore.Client.Address = strings.TrimSpace(url)
+		log.Debugf("Option OptionLocalKVProviderURL: %s", url)
+		if _, ok := c.Scopes[datastore.LocalScope]; !ok {
+			c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{}
+		}
+		c.Scopes[datastore.LocalScope].Client.Address = strings.TrimSpace(url)
 	}
 }
 
 // OptionLocalKVProviderConfig function returns an option setter for kvstore config
 func OptionLocalKVProviderConfig(config *store.Config) Option {
 	return func(c *Config) {
-		log.Infof("Option OptionLocalKVProviderConfig: %v", config)
-		c.LocalStore.Client.Config = config
+		log.Debugf("Option OptionLocalKVProviderConfig: %v", config)
+		if _, ok := c.Scopes[datastore.LocalScope]; !ok {
+			c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{}
+		}
+		c.Scopes[datastore.LocalScope].Client.Config = config
 	}
 }

+ 176 - 89
vendor/src/github.com/docker/libnetwork/controller.go

@@ -58,6 +58,8 @@ import (
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/hostdiscovery"
+	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/types"
 )
@@ -116,60 +118,82 @@ type driverData struct {
 	capability driverapi.Capability
 }
 
+type ipamData struct {
+	driver ipamapi.Ipam
+	// default address spaces are provided by ipam driver at registration time
+	defaultLocalAddressSpace, defaultGlobalAddressSpace string
+}
+
 type driverTable map[string]*driverData
-type networkTable map[string]*network
-type endpointTable map[string]*endpoint
+
+//type networkTable map[string]*network
+//type endpointTable map[string]*endpoint
+type ipamTable map[string]*ipamData
 type sandboxTable map[string]*sandbox
 
 type controller struct {
-	id                      string
-	networks                networkTable
-	drivers                 driverTable
-	sandboxes               sandboxTable
-	cfg                     *config.Config
-	globalStore, localStore datastore.DataStore
-	discovery               hostdiscovery.HostDiscovery
-	extKeyListener          net.Listener
+	id string
+	//networks       networkTable
+	drivers        driverTable
+	ipamDrivers    ipamTable
+	sandboxes      sandboxTable
+	cfg            *config.Config
+	stores         []datastore.DataStore
+	discovery      hostdiscovery.HostDiscovery
+	extKeyListener net.Listener
+	watchCh        chan *endpoint
+	unWatchCh      chan *endpoint
+	svcDb          map[string]svcMap
 	sync.Mutex
 }
 
 // New creates a new instance of network controller.
 func New(cfgOptions ...config.Option) (NetworkController, error) {
 	var cfg *config.Config
+	cfg = &config.Config{
+		Daemon: config.DaemonCfg{
+			DriverCfg: make(map[string]interface{}),
+		},
+		Scopes: make(map[string]*datastore.ScopeCfg),
+	}
+
 	if len(cfgOptions) > 0 {
-		cfg = &config.Config{
-			Daemon: config.DaemonCfg{
-				DriverCfg: make(map[string]interface{}),
-			},
-		}
 		cfg.ProcessOptions(cfgOptions...)
 	}
+	cfg.LoadDefaultScopes(cfg.Daemon.DataDir)
+
 	c := &controller{
-		id:        stringid.GenerateRandomID(),
-		cfg:       cfg,
-		networks:  networkTable{},
-		sandboxes: sandboxTable{},
-		drivers:   driverTable{}}
-	if err := initDrivers(c); err != nil {
+		id:          stringid.GenerateRandomID(),
+		cfg:         cfg,
+		sandboxes:   sandboxTable{},
+		drivers:     driverTable{},
+		ipamDrivers: ipamTable{},
+		svcDb:       make(map[string]svcMap),
+	}
+
+	if err := c.initStores(); err != nil {
 		return nil, err
 	}
 
-	if cfg != nil {
-		if err := c.initGlobalStore(); err != nil {
-			// Failing to initalize datastore is a bad situation to be in.
-			// But it cannot fail creating the Controller
-			log.Debugf("Failed to Initialize Datastore due to %v. Operating in non-clustered mode", err)
-		}
+	if cfg != nil && cfg.Cluster.Watcher != nil {
 		if err := c.initDiscovery(cfg.Cluster.Watcher); err != nil {
 			// Failing to initalize discovery is a bad situation to be in.
 			// But it cannot fail creating the Controller
 			log.Debugf("Failed to Initialize Discovery : %v", err)
 		}
-		if err := c.initLocalStore(); err != nil {
-			log.Debugf("Failed to Initialize LocalDatastore due to %v.", err)
-		}
 	}
 
+	if err := initDrivers(c); err != nil {
+		return nil, err
+	}
+
+	if err := initIpams(c, c.getStore(datastore.LocalScope),
+		c.getStore(datastore.GlobalScope)); err != nil {
+		return nil, err
+	}
+
+	c.sandboxCleanup()
+
 	if err := c.startExternalKeyListener(); err != nil {
 		return nil, err
 	}
@@ -272,43 +296,91 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver,
 	return nil
 }
 
+func (c *controller) RegisterIpamDriver(name string, driver ipamapi.Ipam) error {
+	if !config.IsValidName(name) {
+		return ErrInvalidName(name)
+	}
+
+	c.Lock()
+	_, ok := c.ipamDrivers[name]
+	c.Unlock()
+	if ok {
+		return driverapi.ErrActiveRegistration(name)
+	}
+	locAS, glbAS, err := driver.GetDefaultAddressSpaces()
+	if err != nil {
+		return fmt.Errorf("ipam driver %s failed to return default address spaces: %v", name, err)
+	}
+	c.Lock()
+	c.ipamDrivers[name] = &ipamData{driver: driver, defaultLocalAddressSpace: locAS, defaultGlobalAddressSpace: glbAS}
+	c.Unlock()
+
+	log.Debugf("Registering ipam provider: %s", name)
+
+	return nil
+}
+
 // NewNetwork creates a new network of the specified network type. The options
 // are network specific and modeled in a generic way.
 func (c *controller) NewNetwork(networkType, name string, options ...NetworkOption) (Network, error) {
 	if !config.IsValidName(name) {
 		return nil, ErrInvalidName(name)
 	}
-	// Check if a network already exists with the specified network name
-	c.Lock()
-	for _, n := range c.networks {
-		if n.name == name {
-			c.Unlock()
-			return nil, NetworkNameError(name)
-		}
-	}
-	c.Unlock()
 
 	// Construct the network object
 	network := &network{
 		name:        name,
 		networkType: networkType,
+		generic:     map[string]interface{}{netlabel.GenericData: make(map[string]string)},
+		ipamType:    ipamapi.DefaultIPAM,
 		id:          stringid.GenerateRandomID(),
 		ctrlr:       c,
-		endpoints:   endpointTable{},
 		persist:     true,
+		drvOnce:     &sync.Once{},
 	}
 
 	network.processOptions(options...)
 
+	// Make sure we have a driver available for this network type
+	// before we allocate anything.
+	if _, err := network.driver(); err != nil {
+		return nil, err
+	}
+
+	err := network.ipamAllocate()
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		if err != nil {
+			network.ipamRelease()
+		}
+	}()
+
 	if err := c.addNetwork(network); err != nil {
 		return nil, err
 	}
+	defer func() {
+		if err != nil {
+			if e := network.deleteNetwork(); e != nil {
+				log.Warnf("couldn't roll back driver network on network %s creation failure: %v", network.name, err)
+			}
+		}
+	}()
 
-	if err := c.updateToStore(network); err != nil {
-		log.Warnf("couldnt create network %s: %v", network.name, err)
-		if e := network.Delete(); e != nil {
-			log.Warnf("couldnt cleanup network %s: %v", network.name, err)
+	if err = c.updateToStore(network); err != nil {
+		return nil, err
+	}
+	defer func() {
+		if err != nil {
+			if e := c.deleteFromStore(network); e != nil {
+				log.Warnf("couldnt rollback from store, network %s on failure (%v): %v", network.name, err, e)
+			}
 		}
+	}()
+
+	network.epCnt = &endpointCnt{n: network}
+	if err = c.updateToStore(network.epCnt); err != nil {
 		return nil, err
 	}
 
@@ -316,49 +388,28 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
 }
 
 func (c *controller) addNetwork(n *network) error {
-
-	c.Lock()
-	// Check if a driver for the specified network type is available
-	dd, ok := c.drivers[n.networkType]
-	c.Unlock()
-
-	if !ok {
-		var err error
-		dd, err = c.loadDriver(n.networkType)
-		if err != nil {
-			return err
-		}
+	d, err := n.driver()
+	if err != nil {
+		return err
 	}
 
-	n.Lock()
-	n.svcRecords = svcMap{}
-	n.driver = dd.driver
-	n.dataScope = dd.capability.DataScope
-	d := n.driver
-	n.Unlock()
-
 	// Create the network
-	if err := d.CreateNetwork(n.id, n.generic); err != nil {
+	if err := d.CreateNetwork(n.id, n.generic, n.getIPData(4), n.getIPData(6)); err != nil {
 		return err
 	}
-	if n.isGlobalScoped() {
-		if err := n.watchEndpoints(); err != nil {
-			return err
-		}
-	}
-	c.Lock()
-	c.networks[n.id] = n
-	c.Unlock()
 
 	return nil
 }
 
 func (c *controller) Networks() []Network {
-	c.Lock()
-	defer c.Unlock()
+	var list []Network
+
+	networks, err := c.getNetworksFromStore()
+	if err != nil {
+		log.Error(err)
+	}
 
-	list := make([]Network, 0, len(c.networks))
-	for _, n := range c.networks {
+	for _, n := range networks {
 		list = append(list, n)
 	}
 
@@ -400,12 +451,13 @@ func (c *controller) NetworkByID(id string) (Network, error) {
 	if id == "" {
 		return nil, ErrInvalidID(id)
 	}
-	c.Lock()
-	defer c.Unlock()
-	if n, ok := c.networks[id]; ok {
-		return n, nil
+
+	n, err := c.getNetworkFromStore(id)
+	if err != nil {
+		return nil, ErrNoSuchNetwork(id)
 	}
-	return nil, ErrNoSuchNetwork(id)
+
+	return n, nil
 }
 
 // NewSandbox creates a new sandbox for the passed container id
@@ -456,6 +508,18 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
 	c.Lock()
 	c.sandboxes[sb.id] = sb
 	c.Unlock()
+	defer func() {
+		if err != nil {
+			c.Lock()
+			delete(c.sandboxes, sb.id)
+			c.Unlock()
+		}
+	}()
+
+	err = sb.storeUpdate()
+	if err != nil {
+		return nil, fmt.Errorf("updating the store state of sandbox failed: %v", err)
+	}
 
 	return sb, nil
 }
@@ -534,20 +598,43 @@ func (c *controller) loadDriver(networkType string) (*driverData, error) {
 	return dd, nil
 }
 
-func (c *controller) getDriver(networkType string) (*driverData, error) {
+func (c *controller) loadIpamDriver(name string) (*ipamData, error) {
+	if _, err := plugins.Get(name, ipamapi.PluginEndpointType); err != nil {
+		if err == plugins.ErrNotFound {
+			return nil, types.NotFoundErrorf(err.Error())
+		}
+		return nil, err
+	}
 	c.Lock()
-	defer c.Unlock()
-	dd, ok := c.drivers[networkType]
+	id, ok := c.ipamDrivers[name]
+	c.Unlock()
 	if !ok {
-		return nil, types.NotFoundErrorf("driver %s not found", networkType)
+		return nil, ErrInvalidNetworkDriver(name)
 	}
-	return dd, nil
+	return id, nil
 }
 
-func (c *controller) Stop() {
-	if c.localStore != nil {
-		c.localStore.KVStore().Close()
+func (c *controller) getIPAM(name string) (id *ipamData, err error) {
+	var ok bool
+	c.Lock()
+	id, ok = c.ipamDrivers[name]
+	c.Unlock()
+	if !ok {
+		id, err = c.loadIpamDriver(name)
 	}
+	return id, err
+}
+
+func (c *controller) getIpamDriver(name string) (ipamapi.Ipam, error) {
+	id, err := c.getIPAM(name)
+	if err != nil {
+		return nil, err
+	}
+	return id.driver, nil
+}
+
+func (c *controller) Stop() {
+	c.closeStores()
 	c.stopExternalKeyListener()
 	osl.GC()
 }

+ 153 - 0
vendor/src/github.com/docker/libnetwork/datastore/cache.go

@@ -0,0 +1,153 @@
+package datastore
+
+import (
+	"fmt"
+	"sync"
+
+	"github.com/docker/libkv/store"
+	"github.com/docker/libkv/store/boltdb"
+)
+
+type kvMap map[string]KVObject
+
+type cache struct {
+	sync.Mutex
+	kmm map[string]kvMap
+	ds  *datastore
+}
+
+func newCache(ds *datastore) *cache {
+	return &cache{kmm: make(map[string]kvMap), ds: ds}
+}
+
+func (c *cache) kmap(kvObject KVObject) (kvMap, error) {
+	var err error
+
+	c.Lock()
+	keyPrefix := Key(kvObject.KeyPrefix()...)
+	kmap, ok := c.kmm[keyPrefix]
+	c.Unlock()
+
+	if ok {
+		return kmap, nil
+	}
+
+	kmap = kvMap{}
+
+	// Bail out right away if the kvObject does not implement KVConstructor
+	ctor, ok := kvObject.(KVConstructor)
+	if !ok {
+		return nil, fmt.Errorf("error while populating kmap, object does not implement KVConstructor interface")
+	}
+
+	kvList, err := c.ds.store.List(keyPrefix)
+	if err != nil {
+		// In case of BoltDB it may return ErrBoltBucketNotFound when no writes
+		// have ever happened on the db bucket. So check for both err codes
+		if err == store.ErrKeyNotFound || err == boltdb.ErrBoltBucketNotFound {
+			// If the store doesn't have anything then there is nothing to
+			// populate in the cache. Just bail out.
+			goto out
+		}
+
+		return nil, fmt.Errorf("error while populating kmap: %v", err)
+	}
+
+	for _, kvPair := range kvList {
+		// Ignore empty kvPair values
+		if len(kvPair.Value) == 0 {
+			continue
+		}
+
+		dstO := ctor.New()
+		err = dstO.SetValue(kvPair.Value)
+		if err != nil {
+			return nil, err
+		}
+
+		// Make sure the object has a correct view of the DB index in
+		// case we need to modify it and update the DB.
+		dstO.SetIndex(kvPair.LastIndex)
+
+		kmap[Key(dstO.Key()...)] = dstO
+	}
+
+out:
+	// There may multiple go routines racing to fill the
+	// cache. The one which places the kmap in c.kmm first
+	// wins. The others should just use what the first populated.
+	c.Lock()
+	kmapNew, ok := c.kmm[keyPrefix]
+	if ok {
+		c.Unlock()
+		return kmapNew, nil
+	}
+
+	c.kmm[keyPrefix] = kmap
+	c.Unlock()
+
+	return kmap, nil
+}
+
+func (c *cache) add(kvObject KVObject) error {
+	kmap, err := c.kmap(kvObject)
+	if err != nil {
+		return err
+	}
+
+	c.Lock()
+	kmap[Key(kvObject.Key()...)] = kvObject
+	c.Unlock()
+	return nil
+}
+
+func (c *cache) del(kvObject KVObject) error {
+	kmap, err := c.kmap(kvObject)
+	if err != nil {
+		return err
+	}
+
+	c.Lock()
+	delete(kmap, Key(kvObject.Key()...))
+	c.Unlock()
+	return nil
+}
+
+func (c *cache) get(key string, kvObject KVObject) error {
+	kmap, err := c.kmap(kvObject)
+	if err != nil {
+		return err
+	}
+
+	c.Lock()
+	defer c.Unlock()
+
+	o, ok := kmap[Key(kvObject.Key()...)]
+	if !ok {
+		return ErrKeyNotFound
+	}
+
+	ctor, ok := o.(KVConstructor)
+	if !ok {
+		return fmt.Errorf("kvobject does not implement KVConstructor interface. could not get object")
+	}
+
+	return ctor.CopyTo(kvObject)
+}
+
+func (c *cache) list(kvObject KVObject) ([]KVObject, error) {
+	kmap, err := c.kmap(kvObject)
+	if err != nil {
+		return nil, err
+	}
+
+	c.Lock()
+	defer c.Unlock()
+
+	var kvol []KVObject
+	for _, v := range kmap {
+		kvol = append(kvol, v)
+	}
+
+	return kvol, nil
+}

+ 323 - 41
vendor/src/github.com/docker/libnetwork/datastore/datastore.go

@@ -1,8 +1,11 @@
 package datastore
 
 import (
+	"fmt"
+	"log"
 	"reflect"
 	"strings"
+	"sync"
 
 	"github.com/docker/libkv"
 	"github.com/docker/libkv/store"
@@ -10,26 +13,37 @@ import (
 	"github.com/docker/libkv/store/consul"
 	"github.com/docker/libkv/store/etcd"
 	"github.com/docker/libkv/store/zookeeper"
-	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/types"
 )
 
 //DataStore exported
 type DataStore interface {
 	// GetObject gets data from datastore and unmarshals to the specified object
-	GetObject(key string, o KV) error
+	GetObject(key string, o KVObject) error
 	// PutObject adds a new Record based on an object into the datastore
-	PutObject(kvObject KV) error
+	PutObject(kvObject KVObject) error
 	// PutObjectAtomic provides an atomic add and update operation for a Record
-	PutObjectAtomic(kvObject KV) error
+	PutObjectAtomic(kvObject KVObject) error
 	// DeleteObject deletes a record
-	DeleteObject(kvObject KV) error
+	DeleteObject(kvObject KVObject) error
 	// DeleteObjectAtomic performs an atomic delete operation
-	DeleteObjectAtomic(kvObject KV) error
+	DeleteObjectAtomic(kvObject KVObject) error
 	// DeleteTree deletes a record
-	DeleteTree(kvObject KV) error
+	DeleteTree(kvObject KVObject) error
+	// Watchable returns whether the store is watchable are not
+	Watchable() bool
+	// Watch for changes on a KVObject
+	Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error)
+	// List returns of a list of KVObjects belonging to the parent
+	// key. The caller must pass a KVObject of the same type as
+	// the objects that need to be listed
+	List(string, KVObject) ([]KVObject, error)
+	// Scope returns the scope of the store
+	Scope() string
 	// KVStore returns access to the KV Store
 	KVStore() store.Store
+	// Close closes the data store
+	Close()
 }
 
 // ErrKeyModified is raised for an atomic update when the update is working on a stale state
@@ -39,11 +53,14 @@ var (
 )
 
 type datastore struct {
+	scope string
 	store store.Store
+	cache *cache
+	sync.Mutex
 }
 
-//KV Key Value interface used by objects to be part of the DataStore
-type KV interface {
+// KVObject is  Key/Value interface used by objects to be part of the DataStore
+type KVObject interface {
 	// Key method lets an object to provide the Key to be used in KV Store
 	Key() []string
 	// KeyPrefix method lets an object to return immediate parent key that can be used for tree walk
@@ -60,19 +77,39 @@ type KV interface {
 	// When SetIndex() is called, the object has been stored.
 	Exists() bool
 	// DataScope indicates the storage scope of the KV object
-	DataScope() DataScope
+	DataScope() string
 	// Skip provides a way for a KV Object to avoid persisting it in the KV Store
 	Skip() bool
 }
 
-// DataScope indicates the storage scope
-type DataScope int
+// KVConstructor interface defines methods which can construct a KVObject from another.
+type KVConstructor interface {
+	// New returns a new object which is created based on the
+	// source object
+	New() KVObject
+	// CopyTo deep copies the contents of the implementing object
+	// to the passed destination object
+	CopyTo(KVObject) error
+}
+
+// ScopeCfg represents Datastore configuration.
+type ScopeCfg struct {
+	Client ScopeClientCfg
+}
+
+// ScopeClientCfg represents Datastore Client-only mode configuration
+type ScopeClientCfg struct {
+	Provider string
+	Address  string
+	Config   *store.Config
+}
 
 const (
 	// LocalScope indicates to store the KV object in local datastore such as boltdb
-	LocalScope DataScope = iota
+	LocalScope = "local"
 	// GlobalScope indicates to store the KV object in global datastore such as consul/etcd/zookeeper
-	GlobalScope
+	GlobalScope   = "global"
+	defaultPrefix = "/var/lib/docker/network/files"
 )
 
 const (
@@ -82,7 +119,26 @@ const (
 	EndpointKeyPrefix = "endpoint"
 )
 
-var rootChain = []string{"docker", "libnetwork"}
+var (
+	defaultScopes = makeDefaultScopes()
+)
+
+func makeDefaultScopes() map[string]*ScopeCfg {
+	def := make(map[string]*ScopeCfg)
+	def[LocalScope] = &ScopeCfg{
+		Client: ScopeClientCfg{
+			Provider: "boltdb",
+			Address:  defaultPrefix + "/local-kv.db",
+			Config: &store.Config{
+				Bucket: "libnetwork",
+			},
+		},
+	}
+
+	return def
+}
+
+var rootChain = []string{"docker", "network", "v1.0"}
 
 func init() {
 	consul.Register()
@@ -91,6 +147,28 @@ func init() {
 	boltdb.Register()
 }
 
+// DefaultScopes returns a map of default scopes and it's config for clients to use.
+func DefaultScopes(dataDir string) map[string]*ScopeCfg {
+	if dataDir != "" {
+		defaultScopes[LocalScope].Client.Address = dataDir + "/network/files/local-kv.db"
+		return defaultScopes
+	}
+
+	defaultScopes[LocalScope].Client.Address = defaultPrefix + "/local-kv.db"
+	return defaultScopes
+}
+
+// IsValid checks if the scope config has valid configuration.
+func (cfg *ScopeCfg) IsValid() bool {
+	if cfg == nil ||
+		strings.TrimSpace(cfg.Client.Provider) == "" ||
+		strings.TrimSpace(cfg.Client.Address) == "" {
+		return false
+	}
+
+	return true
+}
+
 //Key provides convenient method to create a Key
 func Key(key ...string) string {
 	keychain := append(rootChain, key...)
@@ -110,7 +188,11 @@ func ParseKey(key string) ([]string, error) {
 }
 
 // newClient used to connect to KV Store
-func newClient(kv string, addrs string, config *store.Config) (DataStore, error) {
+func newClient(scope string, kv string, addrs string, config *store.Config, cached bool) (DataStore, error) {
+	if cached && scope != LocalScope {
+		return nil, fmt.Errorf("caching supported only for scope %s", LocalScope)
+	}
+
 	if config == nil {
 		config = &store.Config{}
 	}
@@ -118,22 +200,82 @@ func newClient(kv string, addrs string, config *store.Config) (DataStore, error)
 	if err != nil {
 		return nil, err
 	}
-	ds := &datastore{store: store}
+
+	ds := &datastore{scope: scope, store: store}
+	if cached {
+		ds.cache = newCache(ds)
+	}
+
 	return ds, nil
 }
 
 // NewDataStore creates a new instance of LibKV data store
-func NewDataStore(cfg *config.DatastoreCfg) (DataStore, error) {
-	if cfg == nil {
-		return nil, types.BadRequestErrorf("invalid configuration passed to datastore")
+func NewDataStore(scope string, cfg *ScopeCfg) (DataStore, error) {
+	if cfg == nil || cfg.Client.Provider == "" || cfg.Client.Address == "" {
+		c, ok := defaultScopes[scope]
+		if !ok || c.Client.Provider == "" || c.Client.Address == "" {
+			return nil, fmt.Errorf("unexpected scope %s without configuration passed", scope)
+		}
+
+		cfg = c
 	}
-	// TODO : cfg.Embedded case
-	return newClient(cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config)
+
+	var cached bool
+	if scope == LocalScope {
+		cached = true
+	}
+
+	return newClient(scope, cfg.Client.Provider, cfg.Client.Address, cfg.Client.Config, cached)
 }
 
-// NewCustomDataStore can be used by clients to plugin cusom datatore that adhers to store.Store
-func NewCustomDataStore(customStore store.Store) DataStore {
-	return &datastore{store: customStore}
+func (ds *datastore) Close() {
+	ds.store.Close()
+}
+
+func (ds *datastore) Scope() string {
+	return ds.scope
+}
+
+func (ds *datastore) Watchable() bool {
+	return ds.scope != LocalScope
+}
+
+func (ds *datastore) Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error) {
+	sCh := make(chan struct{})
+
+	ctor, ok := kvObject.(KVConstructor)
+	if !ok {
+		return nil, fmt.Errorf("error watching object type %T, object does not implement KVConstructor interface", kvObject)
+	}
+
+	kvpCh, err := ds.store.Watch(Key(kvObject.Key()...), sCh)
+	if err != nil {
+		return nil, err
+	}
+
+	kvoCh := make(chan KVObject)
+
+	go func() {
+		for {
+			select {
+			case <-stopCh:
+				close(sCh)
+				return
+			case kvPair := <-kvpCh:
+				dstO := ctor.New()
+
+				if err := dstO.SetValue(kvPair.Value); err != nil {
+					log.Printf("Could not unmarshal kvpair value = %s", string(kvPair.Value))
+					break
+				}
+
+				dstO.SetIndex(kvPair.LastIndex)
+				kvoCh <- dstO
+			}
+		}
+	}()
+
+	return kvoCh, nil
 }
 
 func (ds *datastore) KVStore() store.Store {
@@ -141,40 +283,76 @@ func (ds *datastore) KVStore() store.Store {
 }
 
 // PutObjectAtomic adds a new Record based on an object into the datastore
-func (ds *datastore) PutObjectAtomic(kvObject KV) error {
+func (ds *datastore) PutObjectAtomic(kvObject KVObject) error {
+	var (
+		previous *store.KVPair
+		pair     *store.KVPair
+		err      error
+	)
+	ds.Lock()
+	defer ds.Unlock()
+
 	if kvObject == nil {
 		return types.BadRequestErrorf("invalid KV Object : nil")
 	}
+
 	kvObjValue := kvObject.Value()
 
 	if kvObjValue == nil {
 		return types.BadRequestErrorf("invalid KV Object with a nil Value for key %s", Key(kvObject.Key()...))
 	}
 
-	var previous *store.KVPair
+	if kvObject.Skip() {
+		goto add_cache
+	}
+
 	if kvObject.Exists() {
 		previous = &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
 	} else {
 		previous = nil
 	}
-	_, pair, err := ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil)
+
+	_, pair, err = ds.store.AtomicPut(Key(kvObject.Key()...), kvObjValue, previous, nil)
 	if err != nil {
 		return err
 	}
 
 	kvObject.SetIndex(pair.LastIndex)
+
+add_cache:
+	if ds.cache != nil {
+		return ds.cache.add(kvObject)
+	}
+
 	return nil
 }
 
 // PutObject adds a new Record based on an object into the datastore
-func (ds *datastore) PutObject(kvObject KV) error {
+func (ds *datastore) PutObject(kvObject KVObject) error {
+	ds.Lock()
+	defer ds.Unlock()
+
 	if kvObject == nil {
 		return types.BadRequestErrorf("invalid KV Object : nil")
 	}
-	return ds.putObjectWithKey(kvObject, kvObject.Key()...)
+
+	if kvObject.Skip() {
+		goto add_cache
+	}
+
+	if err := ds.putObjectWithKey(kvObject, kvObject.Key()...); err != nil {
+		return err
+	}
+
+add_cache:
+	if ds.cache != nil {
+		return ds.cache.add(kvObject)
+	}
+
+	return nil
 }
 
-func (ds *datastore) putObjectWithKey(kvObject KV, key ...string) error {
+func (ds *datastore) putObjectWithKey(kvObject KVObject, key ...string) error {
 	kvObjValue := kvObject.Value()
 
 	if kvObjValue == nil {
@@ -184,39 +362,143 @@ func (ds *datastore) putObjectWithKey(kvObject KV, key ...string) error {
 }
 
 // GetObject returns a record matching the key
-func (ds *datastore) GetObject(key string, o KV) error {
+func (ds *datastore) GetObject(key string, o KVObject) error {
+	ds.Lock()
+	defer ds.Unlock()
+
+	if ds.cache != nil {
+		return ds.cache.get(key, o)
+	}
+
 	kvPair, err := ds.store.Get(key)
 	if err != nil {
 		return err
 	}
-	err = o.SetValue(kvPair.Value)
-	if err != nil {
+
+	if err := o.SetValue(kvPair.Value); err != nil {
 		return err
 	}
 
-	// Make sure the object has a correct view of the DB index in case we need to modify it
-	// and update the DB.
+	// Make sure the object has a correct view of the DB index in
+	// case we need to modify it and update the DB.
 	o.SetIndex(kvPair.LastIndex)
 	return nil
 }
 
+func (ds *datastore) ensureKey(key string) error {
+	exists, err := ds.store.Exists(key)
+	if err != nil {
+		return err
+	}
+	if exists {
+		return nil
+	}
+	return ds.store.Put(key, []byte{}, nil)
+}
+
+func (ds *datastore) List(key string, kvObject KVObject) ([]KVObject, error) {
+	ds.Lock()
+	defer ds.Unlock()
+
+	if ds.cache != nil {
+		return ds.cache.list(kvObject)
+	}
+
+	// Bail out right away if the kvObject does not implement KVConstructor
+	ctor, ok := kvObject.(KVConstructor)
+	if !ok {
+		return nil, fmt.Errorf("error listing objects, object does not implement KVConstructor interface")
+	}
+
+	// Make sure the parent key exists
+	if err := ds.ensureKey(key); err != nil {
+		return nil, err
+	}
+
+	kvList, err := ds.store.List(key)
+	if err != nil {
+		return nil, err
+	}
+
+	var kvol []KVObject
+	for _, kvPair := range kvList {
+		if len(kvPair.Value) == 0 {
+			continue
+		}
+
+		dstO := ctor.New()
+		if err := dstO.SetValue(kvPair.Value); err != nil {
+			return nil, err
+		}
+
+		// Make sure the object has a correct view of the DB index in
+		// case we need to modify it and update the DB.
+		dstO.SetIndex(kvPair.LastIndex)
+
+		kvol = append(kvol, dstO)
+	}
+
+	return kvol, nil
+}
+
 // DeleteObject unconditionally deletes a record from the store
-func (ds *datastore) DeleteObject(kvObject KV) error {
+func (ds *datastore) DeleteObject(kvObject KVObject) error {
+	ds.Lock()
+	defer ds.Unlock()
+
+	// cleaup the cache first
+	if ds.cache != nil {
+		ds.cache.del(kvObject)
+	}
+
+	if kvObject.Skip() {
+		return nil
+	}
+
 	return ds.store.Delete(Key(kvObject.Key()...))
 }
 
 // DeleteObjectAtomic performs atomic delete on a record
-func (ds *datastore) DeleteObjectAtomic(kvObject KV) error {
+func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error {
+	ds.Lock()
+	defer ds.Unlock()
+
 	if kvObject == nil {
 		return types.BadRequestErrorf("invalid KV Object : nil")
 	}
 
 	previous := &store.KVPair{Key: Key(kvObject.Key()...), LastIndex: kvObject.Index()}
-	_, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous)
-	return err
+
+	if kvObject.Skip() {
+		goto del_cache
+	}
+
+	if _, err := ds.store.AtomicDelete(Key(kvObject.Key()...), previous); err != nil {
+		return err
+	}
+
+del_cache:
+	// cleanup the cache only if AtomicDelete went through successfully
+	if ds.cache != nil {
+		return ds.cache.del(kvObject)
+	}
+
+	return nil
 }
 
 // DeleteTree unconditionally deletes a record from the store
-func (ds *datastore) DeleteTree(kvObject KV) error {
+func (ds *datastore) DeleteTree(kvObject KVObject) error {
+	ds.Lock()
+	defer ds.Unlock()
+
+	// cleaup the cache first
+	if ds.cache != nil {
+		ds.cache.del(kvObject)
+	}
+
+	if kvObject.Skip() {
+		return nil
+	}
+
 	return ds.store.DeleteTree(Key(kvObject.KeyPrefix()...))
 }

+ 0 - 20
vendor/src/github.com/docker/libnetwork/default_gateway.go

@@ -4,7 +4,6 @@ import (
 	"fmt"
 
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -92,25 +91,6 @@ func (sb *sandbox) clearDefaultGW() error {
 	return nil
 }
 
-func (c *controller) createGWNetwork() (Network, error) {
-	netOption := options.Generic{
-		"BridgeName":         libnGWNetwork,
-		"EnableICC":          false,
-		"EnableIPMasquerade": true,
-	}
-
-	n, err := c.NewNetwork("bridge", libnGWNetwork,
-		NetworkOptionGeneric(options.Generic{
-			netlabel.GenericData: netOption,
-			netlabel.EnableIPv6:  false,
-		}))
-
-	if err != nil {
-		return nil, fmt.Errorf("error creating external connectivity network: %v", err)
-	}
-	return n, err
-}
-
 func (sb *sandbox) needDefaultGW() bool {
 	var needGW bool
 

+ 7 - 0
vendor/src/github.com/docker/libnetwork/default_gateway_freebsd.go

@@ -0,0 +1,7 @@
+package libnetwork
+
+import "github.com/docker/libnetwork/types"
+
+func (c *controller) createGWNetwork() (Network, error) {
+	return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in freebsd")
+}

+ 29 - 0
vendor/src/github.com/docker/libnetwork/default_gateway_linux.go

@@ -0,0 +1,29 @@
+package libnetwork
+
+import (
+	"fmt"
+	"strconv"
+
+	"github.com/docker/libnetwork/drivers/bridge"
+	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/options"
+)
+
+func (c *controller) createGWNetwork() (Network, error) {
+	netOption := map[string]string{
+		bridge.BridgeName:         libnGWNetwork,
+		bridge.EnableICC:          strconv.FormatBool(false),
+		bridge.EnableIPMasquerade: strconv.FormatBool(true),
+	}
+
+	n, err := c.NewNetwork("bridge", libnGWNetwork,
+		NetworkOptionGeneric(options.Generic{
+			netlabel.GenericData: netOption,
+			netlabel.EnableIPv6:  false,
+		}))
+
+	if err != nil {
+		return nil, fmt.Errorf("error creating external connectivity network: %v", err)
+	}
+	return n, err
+}

+ 7 - 0
vendor/src/github.com/docker/libnetwork/default_gateway_windows.go

@@ -0,0 +1,7 @@
+package libnetwork
+
+import "github.com/docker/libnetwork/types"
+
+func (c *controller) createGWNetwork() (Network, error) {
+	return nil, types.NotImplementedErrorf("default gateway functionality is not implemented in windows")
+}

+ 25 - 24
vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go

@@ -1,10 +1,6 @@
 package driverapi
 
-import (
-	"net"
-
-	"github.com/docker/libnetwork/datastore"
-)
+import "net"
 
 // NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
 const NetworkPluginEndpointType = "NetworkDriver"
@@ -14,7 +10,7 @@ type Driver interface {
 	// CreateNetwork invokes the driver method to create a network passing
 	// the network id and network specific config. The config mechanism will
 	// eventually be replaced with labels which are yet to be introduced.
-	CreateNetwork(nid string, options map[string]interface{}) error
+	CreateNetwork(nid string, options map[string]interface{}, ipV4Data, ipV6Data []IPAMData) error
 
 	// DeleteNetwork invokes the driver method to delete network passing
 	// the network id.
@@ -25,7 +21,7 @@ type Driver interface {
 	// specific config. The endpoint information can be either consumed by
 	// the driver or populated by the driver. The config mechanism will
 	// eventually be replaced with labels which are yet to be introduced.
-	CreateEndpoint(nid, eid string, epInfo EndpointInfo, options map[string]interface{}) error
+	CreateEndpoint(nid, eid string, ifInfo InterfaceInfo, options map[string]interface{}) error
 
 	// DeleteEndpoint invokes the driver method to delete an endpoint
 	// passing the network id and endpoint id.
@@ -50,31 +46,26 @@ type Driver interface {
 	Type() string
 }
 
-// EndpointInfo provides a go interface to fetch or populate endpoint assigned network resources.
-type EndpointInfo interface {
-	// Interface returns the interface bound to the endpoint.
-	// If the value is not nil the driver is only expected to consume the interface.
-	// It is an error to try to add interface if the passed down value is non-nil
-	// If the value is nil the driver is expected to add an interface
-	Interface() InterfaceInfo
-
-	// AddInterface is used by the driver to add an interface for the endpoint.
-	// This method will return an error if the driver attempts to add interface
-	// if the Interface() method returned a non-nil value.
-	AddInterface(mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error
-}
-
 // InterfaceInfo provides a go interface for drivers to retrive
 // network information to interface resources.
 type InterfaceInfo interface {
+	// SetMacAddress allows the driver to set the mac address to the endpoint interface
+	// during the call to CreateEndpoint, if the mac address is not already set.
+	SetMacAddress(mac net.HardwareAddr) error
+
+	// SetIPAddress allows the driver to set the ip address to the endpoint interface
+	// during the call to CreateEndpoint, if the address is not already set.
+	// The API is to be used to assign both the IPv4 and IPv6 address types.
+	SetIPAddress(ip *net.IPNet) error
+
 	// MacAddress returns the MAC address.
 	MacAddress() net.HardwareAddr
 
 	// Address returns the IPv4 address.
-	Address() net.IPNet
+	Address() *net.IPNet
 
 	// AddressIPv6 returns the IPv6 address.
-	AddressIPv6() net.IPNet
+	AddressIPv6() *net.IPNet
 }
 
 // InterfaceNameInfo provides a go interface for the drivers to assign names
@@ -110,7 +101,7 @@ type DriverCallback interface {
 
 // Capability represents the high level capabilities of the drivers which libnetwork can make use of
 type Capability struct {
-	DataScope datastore.DataScope
+	DataScope string
 }
 
 // DiscoveryType represents the type of discovery element the DiscoverNew function is invoked on
@@ -126,3 +117,13 @@ type NodeDiscoveryData struct {
 	Address string
 	Self    bool
 }
+
+// IPAMData represents the per-network ip related
+// operational information libnetwork will send
+// to the network driver during CreateNetwork()
+type IPAMData struct {
+	AddressSpace string
+	Pool         *net.IPNet
+	Gateway      *net.IPNet
+	AuxAddresses map[string]*net.IPNet
+}

+ 103 - 0
vendor/src/github.com/docker/libnetwork/driverapi/ipamdata.go

@@ -0,0 +1,103 @@
+package driverapi
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+
+	"github.com/docker/libnetwork/types"
+)
+
+// MarshalJSON encodes IPAMData into json message
+func (i *IPAMData) MarshalJSON() ([]byte, error) {
+	m := map[string]interface{}{}
+	m["AddressSpace"] = i.AddressSpace
+	if i.Pool != nil {
+		m["Pool"] = i.Pool.String()
+	}
+	if i.Gateway != nil {
+		m["Gateway"] = i.Gateway.String()
+	}
+	if i.AuxAddresses != nil {
+		am := make(map[string]string, len(i.AuxAddresses))
+		for k, v := range i.AuxAddresses {
+			am[k] = v.String()
+		}
+		m["AuxAddresses"] = am
+	}
+	return json.Marshal(m)
+}
+
+// UnmarshalJSON decodes a json message into IPAMData
+func (i *IPAMData) UnmarshalJSON(data []byte) error {
+	var (
+		m   map[string]interface{}
+		err error
+	)
+	if err := json.Unmarshal(data, &m); err != nil {
+		return err
+	}
+	i.AddressSpace = m["AddressSpace"].(string)
+	if v, ok := m["Pool"]; ok {
+		if i.Pool, err = types.ParseCIDR(v.(string)); err != nil {
+			return err
+		}
+	}
+	if v, ok := m["Gateway"]; ok {
+		if i.Gateway, err = types.ParseCIDR(v.(string)); err != nil {
+			return err
+		}
+	}
+	if v, ok := m["AuxAddresses"]; ok {
+		b, _ := json.Marshal(v)
+		var am map[string]string
+		if err = json.Unmarshal(b, &am); err != nil {
+			return err
+		}
+		i.AuxAddresses = make(map[string]*net.IPNet, len(am))
+		for k, v := range am {
+			if i.AuxAddresses[k], err = types.ParseCIDR(v); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+// Validate checks wheter the IPAMData structure contains congruent data
+func (i *IPAMData) Validate() error {
+	var isV6 bool
+	if i.Pool == nil {
+		return types.BadRequestErrorf("invalid pool")
+	}
+	if i.Gateway == nil {
+		return types.BadRequestErrorf("invalid gateway address")
+	}
+	isV6 = i.IsV6()
+	if isV6 && i.Gateway.IP.To4() != nil || !isV6 && i.Gateway.IP.To4() == nil {
+		return types.BadRequestErrorf("incongruent ip versions for pool and gateway")
+	}
+	for k, sip := range i.AuxAddresses {
+		if isV6 && sip.IP.To4() != nil || !isV6 && sip.IP.To4() == nil {
+			return types.BadRequestErrorf("incongruent ip versions for pool and secondary ip address %s", k)
+		}
+	}
+	if !i.Pool.Contains(i.Gateway.IP) {
+		return types.BadRequestErrorf("invalid gateway address (%s) does not belong to the pool (%s)", i.Gateway, i.Pool)
+	}
+	for k, sip := range i.AuxAddresses {
+		if !i.Pool.Contains(sip.IP) {
+			return types.BadRequestErrorf("invalid secondary address %s (%s) does not belong to the pool (%s)", k, i.Gateway, i.Pool)
+		}
+	}
+	return nil
+}
+
+// IsV6 returns wheter this is an IPv6 IPAMData structure
+func (i *IPAMData) IsV6() bool {
+	return nil == i.Pool.IP.To4()
+}
+
+func (i *IPAMData) String() string {
+	return fmt.Sprintf("AddressSpace: %s\nPool: %v\nGateway: %v\nAddresses: %v", i.AddressSpace, i.Pool, i.Gateway, i.AuxAddresses)
+}

+ 31 - 8
vendor/src/github.com/docker/libnetwork/drivers.go

@@ -4,6 +4,9 @@ import (
 	"strings"
 
 	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/ipamapi"
+	builtinIpam "github.com/docker/libnetwork/ipams/builtin"
+	remoteIpam "github.com/docker/libnetwork/ipams/remote"
 	"github.com/docker/libnetwork/netlabel"
 )
 
@@ -29,11 +32,6 @@ func makeDriverConfig(c *controller, ntype string) map[string]interface{} {
 
 	config := make(map[string]interface{})
 
-	if c.validateGlobalStoreConfig() {
-		config[netlabel.KVProvider] = c.cfg.GlobalStore.Client.Provider
-		config[netlabel.KVProviderURL] = c.cfg.GlobalStore.Client.Address
-	}
-
 	for _, label := range c.cfg.Daemon.Labels {
 		if !strings.HasPrefix(netlabel.Key(label), netlabel.DriverPrefix+"."+ntype) {
 			continue
@@ -43,13 +41,38 @@ func makeDriverConfig(c *controller, ntype string) map[string]interface{} {
 	}
 
 	drvCfg, ok := c.cfg.Daemon.DriverCfg[ntype]
-	if !ok {
+	if ok {
+		for k, v := range drvCfg.(map[string]interface{}) {
+			config[k] = v
+		}
+	}
+
+	// We don't send datastore configs to external plugins
+	if ntype == "remote" {
 		return config
 	}
 
-	for k, v := range drvCfg.(map[string]interface{}) {
-		config[k] = v
+	for k, v := range c.cfg.Scopes {
+		if !v.IsValid() {
+			continue
+		}
+
+		config[netlabel.MakeKVProvider(k)] = v.Client.Provider
+		config[netlabel.MakeKVProviderURL(k)] = v.Client.Address
+		config[netlabel.MakeKVProviderConfig(k)] = v.Client.Config
 	}
 
 	return config
 }
+
+func initIpams(ic ipamapi.Callback, lDs, gDs interface{}) error {
+	for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
+		builtinIpam.Init,
+		remoteIpam.Init,
+	} {
+		if err := fn(ic, lDs, gDs); err != nil {
+			return err
+		}
+	}
+	return nil
+}

+ 151 - 269
vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go

@@ -16,7 +16,6 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/driverapi"
-	"github.com/docker/libnetwork/ipallocator"
 	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
@@ -35,8 +34,11 @@ const (
 	maxAllocatePortAttempts = 10
 )
 
-var (
-	ipAllocator *ipallocator.IPAllocator
+const (
+	// DefaultGatewayV4AuxKey represents the default-gateway configured by the user
+	DefaultGatewayV4AuxKey = "DefaultGatewayIPv4"
+	// DefaultGatewayV6AuxKey represents the ipv6 default-gateway configured by the user
+	DefaultGatewayV6AuxKey = "DefaultGatewayIPv6"
 )
 
 // configuration info for the "bridge" driver.
@@ -48,18 +50,21 @@ type configuration struct {
 
 // networkConfiguration for network specific configuration
 type networkConfiguration struct {
+	ID                 string
 	BridgeName         string
-	AddressIPv4        *net.IPNet
-	FixedCIDR          *net.IPNet
-	FixedCIDRv6        *net.IPNet
 	EnableIPv6         bool
 	EnableIPMasquerade bool
 	EnableICC          bool
 	Mtu                int
-	DefaultGatewayIPv4 net.IP
-	DefaultGatewayIPv6 net.IP
 	DefaultBindingIP   net.IP
 	DefaultBridge      bool
+	// Internal fields set after ipam data parsing
+	AddressIPv4        *net.IPNet
+	AddressIPv6        *net.IPNet
+	DefaultGatewayIPv4 net.IP
+	DefaultGatewayIPv6 net.IP
+	dbIndex            uint64
+	dbExists           bool
 }
 
 // endpointConfiguration represents the user specified configuration for the sandbox endpoint
@@ -102,12 +107,12 @@ type driver struct {
 	natChain    *iptables.ChainInfo
 	filterChain *iptables.ChainInfo
 	networks    map[string]*bridgeNetwork
+	store       datastore.DataStore
 	sync.Mutex
 }
 
 // New constructs a new bridge driver
 func newDriver() *driver {
-	ipAllocator = ipallocator.New()
 	return &driver{networks: map[string]*bridgeNetwork{}, config: &configuration{}}
 }
 
@@ -148,19 +153,6 @@ func (c *networkConfiguration) Validate() error {
 
 	// If bridge v4 subnet is specified
 	if c.AddressIPv4 != nil {
-		// If Container restricted subnet is specified, it must be a subset of bridge subnet
-		if c.FixedCIDR != nil {
-			// Check Network address
-			if !c.AddressIPv4.Contains(c.FixedCIDR.IP) {
-				return &ErrInvalidContainerSubnet{}
-			}
-			// Check it is effectively a subset
-			brNetLen, _ := c.AddressIPv4.Mask.Size()
-			cnNetLen, _ := c.FixedCIDR.Mask.Size()
-			if brNetLen > cnNetLen {
-				return &ErrInvalidContainerSubnet{}
-			}
-		}
 		// If default gw is specified, it must be part of bridge subnet
 		if c.DefaultGatewayIPv4 != nil {
 			if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
@@ -169,167 +161,81 @@ func (c *networkConfiguration) Validate() error {
 		}
 	}
 
-	// If default v6 gw is specified, FixedCIDRv6 must be specified and gw must belong to FixedCIDRv6 subnet
+	// 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.FixedCIDRv6 == nil || !c.FixedCIDRv6.Contains(c.DefaultGatewayIPv6) {
+		if c.AddressIPv6 == nil || !c.AddressIPv6.Contains(c.DefaultGatewayIPv6) {
 			return &ErrInvalidGateway{}
 		}
 	}
-
 	return nil
 }
 
 // Conflicts check if two NetworkConfiguration objects overlap
-func (c *networkConfiguration) Conflicts(o *networkConfiguration) bool {
+func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
 	if o == nil {
-		return false
+		return fmt.Errorf("same configuration")
 	}
 
 	// Also empty, becasue only one network with empty name is allowed
 	if c.BridgeName == o.BridgeName {
-		return true
+		return fmt.Errorf("networks have same bridge name")
 	}
 
 	// They must be in different subnets
 	if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) &&
 		(c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
-		return true
+		return fmt.Errorf("networks have overlapping IPv4")
 	}
 
-	return false
-}
-
-// fromMap retrieve the configuration data from the map form.
-func (c *networkConfiguration) fromMap(data map[string]interface{}) error {
-	var err error
-
-	if i, ok := data["BridgeName"]; ok && i != nil {
-		if c.BridgeName, ok = i.(string); !ok {
-			return types.BadRequestErrorf("invalid type for BridgeName value")
-		}
-	}
-
-	if i, ok := data["Mtu"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if c.Mtu, err = strconv.Atoi(s); err != nil {
-				return types.BadRequestErrorf("failed to parse Mtu value: %s", err.Error())
-			}
-		} else {
-			return types.BadRequestErrorf("invalid type for Mtu value")
-		}
+	// 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")
 	}
 
-	if i, ok := data["EnableIPv6"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if c.EnableIPv6, err = strconv.ParseBool(s); err != nil {
-				return types.BadRequestErrorf("failed to parse EnableIPv6 value: %s", err.Error())
-			}
-		} else {
-			return types.BadRequestErrorf("invalid type for EnableIPv6 value")
-		}
-	}
-
-	if i, ok := data["EnableIPMasquerade"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if c.EnableIPMasquerade, err = strconv.ParseBool(s); err != nil {
-				return types.BadRequestErrorf("failed to parse EnableIPMasquerade value: %s", err.Error())
-			}
-		} else {
-			return types.BadRequestErrorf("invalid type for EnableIPMasquerade value")
-		}
-	}
-
-	if i, ok := data["EnableICC"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if c.EnableICC, err = strconv.ParseBool(s); err != nil {
-				return types.BadRequestErrorf("failed to parse EnableICC value: %s", err.Error())
-			}
-		} else {
-			return types.BadRequestErrorf("invalid type for EnableICC value")
-		}
-	}
+	return nil
+}
 
-	if i, ok := data["DefaultBridge"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if c.DefaultBridge, err = strconv.ParseBool(s); err != nil {
-				return types.BadRequestErrorf("failed to parse DefaultBridge value: %s", err.Error())
+func (c *networkConfiguration) fromLabels(labels map[string]string) error {
+	var err error
+	for label, value := range labels {
+		switch label {
+		case BridgeName:
+			c.BridgeName = value
+		case netlabel.DriverMTU:
+			if c.Mtu, err = strconv.Atoi(value); err != nil {
+				return parseErr(label, value, err.Error())
 			}
-		} else {
-			return types.BadRequestErrorf("invalid type for DefaultBridge value")
-		}
-	}
-
-	if i, ok := data["AddressIPv4"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if ip, nw, e := net.ParseCIDR(s); e == nil {
-				nw.IP = ip
-				c.AddressIPv4 = nw
-			} else {
-				return types.BadRequestErrorf("failed to parse AddressIPv4 value")
+		case netlabel.EnableIPv6:
+			if c.EnableIPv6, err = strconv.ParseBool(value); err != nil {
+				return parseErr(label, value, err.Error())
 			}
-		} else {
-			return types.BadRequestErrorf("invalid type for AddressIPv4 value")
-		}
-	}
-
-	if i, ok := data["FixedCIDR"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if ip, nw, e := net.ParseCIDR(s); e == nil {
-				nw.IP = ip
-				c.FixedCIDR = nw
-			} else {
-				return types.BadRequestErrorf("failed to parse FixedCIDR value")
+		case EnableIPMasquerade:
+			if c.EnableIPMasquerade, err = strconv.ParseBool(value); err != nil {
+				return parseErr(label, value, err.Error())
 			}
-		} else {
-			return types.BadRequestErrorf("invalid type for FixedCIDR value")
-		}
-	}
-
-	if i, ok := data["FixedCIDRv6"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if ip, nw, e := net.ParseCIDR(s); e == nil {
-				nw.IP = ip
-				c.FixedCIDRv6 = nw
-			} else {
-				return types.BadRequestErrorf("failed to parse FixedCIDRv6 value")
+		case EnableICC:
+			if c.EnableICC, err = strconv.ParseBool(value); err != nil {
+				return parseErr(label, value, err.Error())
 			}
-		} else {
-			return types.BadRequestErrorf("invalid type for FixedCIDRv6 value")
-		}
-	}
-
-	if i, ok := data["DefaultGatewayIPv4"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if c.DefaultGatewayIPv4 = net.ParseIP(s); c.DefaultGatewayIPv4 == nil {
-				return types.BadRequestErrorf("failed to parse DefaultGatewayIPv4 value")
+		case DefaultBridge:
+			if c.DefaultBridge, err = strconv.ParseBool(value); err != nil {
+				return parseErr(label, value, err.Error())
 			}
-		} else {
-			return types.BadRequestErrorf("invalid type for DefaultGatewayIPv4 value")
-		}
-	}
-
-	if i, ok := data["DefaultGatewayIPv6"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if c.DefaultGatewayIPv6 = net.ParseIP(s); c.DefaultGatewayIPv6 == nil {
-				return types.BadRequestErrorf("failed to parse DefaultGatewayIPv6 value")
+		case DefaultBindingIP:
+			if c.DefaultBindingIP = net.ParseIP(value); c.DefaultBindingIP == nil {
+				return parseErr(label, value, "nil ip")
 			}
-		} else {
-			return types.BadRequestErrorf("invalid type for DefaultGatewayIPv6 value")
 		}
 	}
 
-	if i, ok := data["DefaultBindingIP"]; ok && i != nil {
-		if s, ok := i.(string); ok {
-			if c.DefaultBindingIP = net.ParseIP(s); c.DefaultBindingIP == nil {
-				return types.BadRequestErrorf("failed to parse DefaultBindingIP value")
-			}
-		} else {
-			return types.BadRequestErrorf("invalid type for DefaultBindingIP value")
-		}
-	}
 	return nil
 }
 
+func parseErr(label, value, errString string) error {
+	return types.BadRequestErrorf("failed to parse %s value: %v (%s)", label, value, errString)
+}
+
 func (n *bridgeNetwork) getDriverChains() (*iptables.ChainInfo, *iptables.ChainInfo, error) {
 	n.Lock()
 	defer n.Unlock()
@@ -435,6 +341,11 @@ func (d *driver) configure(option map[string]interface{}) error {
 	var config *configuration
 	var err error
 
+	err = d.initStore(option)
+	if err != nil {
+		return err
+	}
+
 	d.Lock()
 	defer d.Unlock()
 
@@ -498,12 +409,12 @@ func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error)
 	switch opt := data.(type) {
 	case *networkConfiguration:
 		config = opt
-	case map[string]interface{}:
+	case map[string]string:
 		config = &networkConfiguration{
 			EnableICC:          true,
 			EnableIPMasquerade: true,
 		}
-		err = config.fromMap(opt)
+		err = config.fromLabels(opt)
 	case options.Generic:
 		var opaqueConfig interface{}
 		if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil {
@@ -516,9 +427,41 @@ func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error)
 	return config, err
 }
 
+func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
+	if len(ipamV4Data) > 1 || len(ipamV6Data) > 1 {
+		return types.ForbiddenErrorf("bridge driver doesnt support multiple subnets")
+	}
+
+	if len(ipamV4Data) == 0 {
+		return types.BadRequestErrorf("bridge network %s requires ipv4 configuration", id)
+	}
+
+	if ipamV4Data[0].Gateway != nil {
+		c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway)
+	}
+
+	if gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]; ok {
+		c.DefaultGatewayIPv4 = 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
+}
+
 func parseNetworkOptions(id string, option options.Generic) (*networkConfiguration, error) {
-	var err error
-	config := &networkConfiguration{}
+	var (
+		err    error
+		config = &networkConfiguration{}
+	)
 
 	// Parse generic label first, config will be re-assigned
 	if genData, ok := option[netlabel.GenericData]; ok && genData != nil {
@@ -528,8 +471,8 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati
 	}
 
 	// Process well-known labels next
-	if _, ok := option[netlabel.EnableIPv6]; ok {
-		config.EnableIPv6 = option[netlabel.EnableIPv6].(bool)
+	if val, ok := option[netlabel.EnableIPv6]; ok {
+		config.EnableIPv6 = val.(bool)
 	}
 
 	// Finally validate the configuration
@@ -540,15 +483,16 @@ func parseNetworkOptions(id string, option options.Generic) (*networkConfigurati
 	if config.BridgeName == "" && config.DefaultBridge == false {
 		config.BridgeName = "br-" + id[:12]
 	}
+
+	config.ID = id
 	return config, nil
 }
 
 // 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 {
-	if config.FixedCIDRv6 != nil {
-		return config.FixedCIDRv6
+	if config.AddressIPv6 != nil {
+		return config.AddressIPv6
 	}
-
 	if i.bridgeIPv6 != nil && i.bridgeIPv6.IP != nil && !i.bridgeIPv6.IP.IsLinkLocalUnicast() {
 		return i.bridgeIPv6
 	}
@@ -569,11 +513,7 @@ func (d *driver) getNetworks() []*bridgeNetwork {
 }
 
 // Create a new network using bridge plugin
-func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
-	var err error
-
-	defer osl.InitOSContext()()
-
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	// Sanity checks
 	d.Lock()
 	if _, ok := d.networks[id]; ok {
@@ -587,19 +527,38 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 	if err != nil {
 		return err
 	}
+
+	err = config.processIPAM(id, ipV4Data, ipV6Data)
+	if err != nil {
+		return err
+	}
+
+	if err = d.createNetwork(config); err != nil {
+		return err
+	}
+
+	return d.storeUpdate(config)
+}
+
+func (d *driver) createNetwork(config *networkConfiguration) error {
+	var err error
+
+	defer osl.InitOSContext()()
+
 	networkList := d.getNetworks()
 	for _, nw := range networkList {
 		nw.Lock()
 		nwConfig := nw.config
 		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, config.ID, nw.id, nw.config.BridgeName, err.Error())
 		}
 	}
 
 	// Create and set network handler in driver
 	network := &bridgeNetwork{
-		id:         id,
+		id:         config.ID,
 		endpoints:  make(map[string]*bridgeEndpoint),
 		config:     config,
 		portMapper: portmapper.New(),
@@ -607,14 +566,14 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 	}
 
 	d.Lock()
-	d.networks[id] = network
+	d.networks[config.ID] = network
 	d.Unlock()
 
 	// On failure make sure to reset driver network handler to nil
 	defer func() {
 		if err != nil {
 			d.Lock()
-			delete(d.networks, id)
+			delete(d.networks, config.ID)
 			d.Unlock()
 		}
 	}()
@@ -627,7 +586,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 	// networks. This step is needed now because driver might have now set the bridge
 	// name on this config struct. And because we need to check for possible address
 	// conflicts, so we need to check against operationa lnetworks.
-	if err = config.conflictsWithNetworks(id, networkList); err != nil {
+	if err = config.conflictsWithNetworks(config.ID, networkList); err != nil {
 		return err
 	}
 
@@ -654,10 +613,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 	// Even if a bridge exists try to setup IPv4.
 	bridgeSetup.queueStep(setupBridgeIPv4)
 
-	enableIPv6Forwarding := false
-	if d.config.EnableIPForwarding && config.FixedCIDRv6 != nil {
-		enableIPv6Forwarding = true
-	}
+	enableIPv6Forwarding := d.config.EnableIPForwarding && config.AddressIPv6 != nil
 
 	// Conditionally queue setup steps depending on configuration values.
 	for _, step := range []struct {
@@ -674,14 +630,6 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 		// the case of a previously existing device.
 		{bridgeAlreadyExists, setupVerifyAndReconcile},
 
-		// Setup the bridge to allocate containers IPv4 addresses in the
-		// specified subnet.
-		{config.FixedCIDR != nil, setupFixedCIDRv4},
-
-		// Setup the bridge to allocate containers global IPv6 addresses in the
-		// specified subnet.
-		{config.FixedCIDRv6 != nil, setupFixedCIDRv6},
-
 		// Enable IPv6 Forwarding
 		{enableIPv6Forwarding, setupIPv6Forwarding},
 
@@ -712,8 +660,6 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 		}
 	}
 
-	// Block bridge IP from being allocated.
-	bridgeSetup.queueStep(allocateBridgeIP)
 	// Apply the prepared list of steps, and abort at the first error.
 	bridgeSetup.queueStep(setupDeviceUp)
 	if err = bridgeSetup.apply(); err != nil {
@@ -741,10 +687,6 @@ func (d *driver) DeleteNetwork(nid string) error {
 	config := n.config
 	n.Unlock()
 
-	if config.BridgeName == DefaultBridgeName {
-		return types.ForbiddenErrorf("default network of type \"%s\" cannot be deleted", networkType)
-	}
-
 	d.Lock()
 	delete(d.networks, nid)
 	d.Unlock()
@@ -789,22 +731,12 @@ func (d *driver) DeleteNetwork(nid string) error {
 		return err
 	}
 
-	// Programming
-	err = netlink.LinkDel(n.bridge.Link)
-
-	// Release ip addresses (ignore errors)
-	if config.FixedCIDR == nil || config.FixedCIDR.Contains(config.DefaultGatewayIPv4) {
-		if e := ipAllocator.ReleaseIP(n.bridge.bridgeIPv4, n.bridge.gatewayIPv4); e != nil {
-			logrus.Warnf("Failed to release default gateway address %s: %v", n.bridge.gatewayIPv4.String(), e)
-		}
-	}
-	if config.FixedCIDR == nil || config.FixedCIDR.Contains(n.bridge.bridgeIPv4.IP) {
-		if e := ipAllocator.ReleaseIP(n.bridge.bridgeIPv4, n.bridge.bridgeIPv4.IP); e != nil {
-			logrus.Warnf("Failed to release bridge IP %s: %v", n.bridge.bridgeIPv4.IP.String(), e)
-		}
+	// We only delete the bridge when it's not the default bridge. This is keep the backward compatible behavior.
+	if !config.DefaultBridge {
+		err = netlink.LinkDel(n.bridge.Link)
 	}
 
-	return err
+	return d.storeDelete(config)
 }
 
 func addToBridge(ifaceName, bridgeName string) error {
@@ -861,20 +793,11 @@ func setHairpinMode(link netlink.Link, enable bool) error {
 	return nil
 }
 
-func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
-	var (
-		ipv6Addr *net.IPNet
-		err      error
-	)
-
+func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
 	defer osl.InitOSContext()()
 
-	if epInfo == nil {
-		return errors.New("invalid endpoint info passed")
-	}
-
-	if epInfo.Interface() != nil {
-		return errors.New("non-nil interface passed to bridge(local) driver")
+	if ifInfo == nil {
+		return errors.New("invalid interface info passed")
 	}
 
 	// Get the network handler and make sure it exists
@@ -1000,12 +923,11 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 		}
 	}
 
-	// v4 address for the sandbox side pipe interface
-	ip4, err := ipAllocator.RequestIP(n.bridge.bridgeIPv4, nil)
-	if err != nil {
-		return err
-	}
-	ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
+	// 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.
 	if err = netlink.LinkSetDown(sbox); err != nil {
@@ -1013,56 +935,38 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 	}
 
 	// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
-	mac := electMacAddress(epConfig, ip4)
-	err = netlink.LinkSetHardwareAddr(sbox, mac)
+	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, endpoint.macAddress)
 	if err != nil {
 		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
 	if err = netlink.LinkSetUp(host); err != nil {
 		return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
 	}
 
-	// v6 address for the sandbox side pipe interface
-	ipv6Addr = &net.IPNet{}
-	if config.EnableIPv6 {
+	if endpoint.addrv6 == nil && config.EnableIPv6 {
 		var ip6 net.IP
-
 		network := n.bridge.bridgeIPv6
-		if config.FixedCIDRv6 != nil {
-			network = config.FixedCIDRv6
-		}
-
 		ones, _ := network.Mask.Size()
 		if ones <= 80 {
 			ip6 = make(net.IP, len(network.IP))
 			copy(ip6, network.IP)
-			for i, h := range mac {
+			for i, h := range endpoint.macAddress {
 				ip6[i+10] = h
 			}
 		}
 
-		ip6, err := ipAllocator.RequestIP(network, ip6)
-		if err != nil {
+		endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
+		if err := ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
 			return err
 		}
-
-		ipv6Addr = &net.IPNet{IP: ip6, Mask: network.Mask}
-	}
-
-	// Create the sandbox side pipe interface
-	endpoint.srcName = containerIfName
-	endpoint.addr = ipv4Addr
-
-	if config.EnableIPv6 {
-		endpoint.addrv6 = ipv6Addr
-	}
-
-	err = epInfo.AddInterface(endpoint.macAddress, *ipv4Addr, *ipv6Addr)
-	if err != nil {
-		return err
 	}
 
 	// Program any required port mapping and store them in the endpoint
@@ -1128,28 +1032,6 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
 	// Remove port mappings. Do not stop endpoint delete on unmap failure
 	n.releasePorts(ep)
 
-	// Release the v4 address allocated to this endpoint's sandbox interface
-	err = ipAllocator.ReleaseIP(n.bridge.bridgeIPv4, ep.addr.IP)
-	if err != nil {
-		return err
-	}
-
-	n.Lock()
-	config := n.config
-	n.Unlock()
-
-	// Release the v6 address allocated to this endpoint's sandbox interface
-	if config.EnableIPv6 {
-		network := n.bridge.bridgeIPv6
-		if config.FixedCIDRv6 != nil {
-			network = config.FixedCIDRv6
-		}
-		err := ipAllocator.ReleaseIP(network, ep.addrv6.IP)
-		if err != nil {
-			return err
-		}
-	}
-
 	// Try removal of link. Discard error: link pair might have
 	// already been deleted by sandbox delete. Make sure defer
 	// does not see this error either.

+ 211 - 0
vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge_store.go

@@ -0,0 +1,211 @@
+package bridge
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/libkv/store"
+	"github.com/docker/libkv/store/boltdb"
+	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/types"
+)
+
+const bridgePrefix = "bridge"
+
+func (d *driver) initStore(option map[string]interface{}) error {
+	var err error
+
+	provider, provOk := option[netlabel.LocalKVProvider]
+	provURL, urlOk := option[netlabel.LocalKVProviderURL]
+
+	if provOk && urlOk {
+		cfg := &datastore.ScopeCfg{
+			Client: datastore.ScopeClientCfg{
+				Provider: provider.(string),
+				Address:  provURL.(string),
+			},
+		}
+
+		provConfig, confOk := option[netlabel.LocalKVProviderConfig]
+		if confOk {
+			cfg.Client.Config = provConfig.(*store.Config)
+		}
+
+		d.store, err = datastore.NewDataStore(datastore.LocalScope, cfg)
+		if err != nil {
+			return fmt.Errorf("bridge driver failed to initialize data store: %v", err)
+		}
+
+		return d.populateNetworks()
+	}
+
+	return nil
+}
+
+func (d *driver) populateNetworks() error {
+	kvol, err := d.store.List(datastore.Key(bridgePrefix), &networkConfiguration{})
+	if err != nil && err != datastore.ErrKeyNotFound && err != boltdb.ErrBoltBucketNotFound {
+		return fmt.Errorf("failed to get bridge network configurations from store: %v", err)
+	}
+
+	// It's normal for network configuration state to be empty. Just return.
+	if err == datastore.ErrKeyNotFound {
+		return nil
+	}
+
+	for _, kvo := range kvol {
+		ncfg := kvo.(*networkConfiguration)
+		if err = d.createNetwork(ncfg); err != nil {
+			logrus.Warnf("could not create bridge network for id %s bridge name %s while booting up from persistent state", ncfg.ID, ncfg.BridgeName)
+		}
+	}
+
+	return nil
+}
+
+func (d *driver) storeUpdate(kvObject datastore.KVObject) error {
+	if d.store == nil {
+		logrus.Warnf("bridge store not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...))
+		return nil
+	}
+
+	if err := d.store.PutObjectAtomic(kvObject); err != nil {
+		return fmt.Errorf("failed to update bridge store for object type %T: %v", kvObject, err)
+	}
+
+	return nil
+}
+
+func (d *driver) storeDelete(kvObject datastore.KVObject) error {
+	if d.store == nil {
+		logrus.Debugf("bridge store not initialized. kv object %s is not deleted from store", datastore.Key(kvObject.Key()...))
+		return nil
+	}
+
+retry:
+	if err := d.store.DeleteObjectAtomic(kvObject); err != nil {
+		if err == datastore.ErrKeyModified {
+			if err := d.store.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil {
+				return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err)
+			}
+			goto retry
+		}
+		return err
+	}
+
+	return nil
+}
+
+func (ncfg *networkConfiguration) MarshalJSON() ([]byte, error) {
+	nMap := make(map[string]interface{})
+	nMap["ID"] = ncfg.ID
+	nMap["BridgeName"] = ncfg.BridgeName
+	nMap["EnableIPv6"] = ncfg.EnableIPv6
+	nMap["EnableIPMasquerade"] = ncfg.EnableIPMasquerade
+	nMap["EnableICC"] = ncfg.EnableICC
+	nMap["Mtu"] = ncfg.Mtu
+	nMap["DefaultBridge"] = ncfg.DefaultBridge
+	nMap["DefaultBindingIP"] = ncfg.DefaultBindingIP.String()
+	nMap["DefaultGatewayIPv4"] = ncfg.DefaultGatewayIPv4.String()
+	nMap["DefaultGatewayIPv6"] = ncfg.DefaultGatewayIPv6.String()
+
+	if ncfg.AddressIPv4 != nil {
+		nMap["AddressIPv4"] = ncfg.AddressIPv4.String()
+	}
+
+	if ncfg.AddressIPv6 != nil {
+		nMap["AddressIPv6"] = ncfg.AddressIPv6.String()
+	}
+
+	return json.Marshal(nMap)
+}
+
+func (ncfg *networkConfiguration) UnmarshalJSON(b []byte) error {
+	var (
+		err  error
+		nMap map[string]interface{}
+	)
+
+	if err = json.Unmarshal(b, &nMap); err != nil {
+		return err
+	}
+
+	if v, ok := nMap["AddressIPv4"]; ok {
+		if ncfg.AddressIPv4, err = types.ParseCIDR(v.(string)); err != nil {
+			return types.InternalErrorf("failed to decode bridge network address IPv4 after json unmarshal: %s", v.(string))
+		}
+	}
+
+	if v, ok := nMap["AddressIPv6"]; ok {
+		if ncfg.AddressIPv6, err = types.ParseCIDR(v.(string)); err != nil {
+			return types.InternalErrorf("failed to decode bridge network address IPv6 after json unmarshal: %s", v.(string))
+		}
+	}
+
+	ncfg.DefaultBridge = nMap["DefaultBridge"].(bool)
+	ncfg.DefaultBindingIP = net.ParseIP(nMap["DefaultBindingIP"].(string))
+	ncfg.DefaultGatewayIPv4 = net.ParseIP(nMap["DefaultGatewayIPv4"].(string))
+	ncfg.DefaultGatewayIPv6 = net.ParseIP(nMap["DefaultGatewayIPv6"].(string))
+	ncfg.ID = nMap["ID"].(string)
+	ncfg.BridgeName = nMap["BridgeName"].(string)
+	ncfg.EnableIPv6 = nMap["EnableIPv6"].(bool)
+	ncfg.EnableIPMasquerade = nMap["EnableIPMasquerade"].(bool)
+	ncfg.EnableICC = nMap["EnableICC"].(bool)
+	ncfg.Mtu = int(nMap["Mtu"].(float64))
+
+	return nil
+}
+
+func (ncfg *networkConfiguration) Key() []string {
+	return []string{bridgePrefix, ncfg.ID}
+}
+
+func (ncfg *networkConfiguration) KeyPrefix() []string {
+	return []string{bridgePrefix}
+}
+
+func (ncfg *networkConfiguration) Value() []byte {
+	b, err := json.Marshal(ncfg)
+	if err != nil {
+		return nil
+	}
+	return b
+}
+
+func (ncfg *networkConfiguration) SetValue(value []byte) error {
+	return json.Unmarshal(value, ncfg)
+}
+
+func (ncfg *networkConfiguration) Index() uint64 {
+	return ncfg.dbIndex
+}
+
+func (ncfg *networkConfiguration) SetIndex(index uint64) {
+	ncfg.dbIndex = index
+	ncfg.dbExists = true
+}
+
+func (ncfg *networkConfiguration) Exists() bool {
+	return ncfg.dbExists
+}
+
+func (ncfg *networkConfiguration) Skip() bool {
+	return ncfg.DefaultBridge
+}
+
+func (ncfg *networkConfiguration) New() datastore.KVObject {
+	return &networkConfiguration{}
+}
+
+func (ncfg *networkConfiguration) CopyTo(o datastore.KVObject) error {
+	dstNcfg := o.(*networkConfiguration)
+	*dstNcfg = *ncfg
+	return nil
+}
+
+func (ncfg *networkConfiguration) DataScope() string {
+	return datastore.LocalScope
+}

+ 18 - 0
vendor/src/github.com/docker/libnetwork/drivers/bridge/labels.go

@@ -0,0 +1,18 @@
+package bridge
+
+const (
+	// BridgeName label for bridge driver
+	BridgeName = "com.docker.network.bridge.name"
+
+	// EnableIPMasquerade label for bridge driver
+	EnableIPMasquerade = "com.docker.network.bridge.enable_ip_masquerade"
+
+	// EnableICC label
+	EnableICC = "com.docker.network.bridge.enable_icc"
+
+	// DefaultBindingIP label
+	DefaultBindingIP = "com.docker.network.bridge.host_binding_ipv4"
+
+	// DefaultBridge label
+	DefaultBridge = "com.docker.network.bridge.default_bridge"
+)

+ 1 - 1
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go

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

+ 0 - 19
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv4.go

@@ -1,19 +0,0 @@
-package bridge
-
-import (
-	log "github.com/Sirupsen/logrus"
-)
-
-func setupFixedCIDRv4(config *networkConfiguration, i *bridgeInterface) error {
-	addrv4, _, err := i.addresses()
-	if err != nil {
-		return err
-	}
-
-	log.Debugf("Using IPv4 subnet: %v", config.FixedCIDR)
-	if err := ipAllocator.RegisterSubnet(addrv4.IPNet, config.FixedCIDR); err != nil {
-		return &FixedCIDRv4Error{Subnet: config.FixedCIDR, Net: addrv4.IPNet, Err: err}
-	}
-
-	return nil
-}

+ 0 - 27
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_fixedcidrv6.go

@@ -1,27 +0,0 @@
-package bridge
-
-import (
-	"os"
-
-	log "github.com/Sirupsen/logrus"
-	"github.com/vishvananda/netlink"
-)
-
-func setupFixedCIDRv6(config *networkConfiguration, i *bridgeInterface) error {
-	log.Debugf("Using IPv6 subnet: %v", config.FixedCIDRv6)
-	if err := ipAllocator.RegisterSubnet(config.FixedCIDRv6, config.FixedCIDRv6); err != nil {
-		return &FixedCIDRv6Error{Net: config.FixedCIDRv6, Err: err}
-	}
-
-	// Setting route to global IPv6 subnet
-	log.Debugf("Adding route to IPv6 network %s via device %s", config.FixedCIDRv6.String(), config.BridgeName)
-	err := netlink.RouteAdd(&netlink.Route{
-		Scope:     netlink.SCOPE_UNIVERSE,
-		LinkIndex: i.Link.Attrs().Index,
-		Dst:       config.FixedCIDRv6,
-	})
-	if err != nil && !os.IsExist(err) {
-		log.Errorf("Could not add route to IPv6 network %s via device %s", config.FixedCIDRv6.String(), config.BridgeName)
-	}
-	return nil
-}

+ 14 - 100
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go

@@ -3,129 +3,43 @@ package bridge
 import (
 	"fmt"
 	"io/ioutil"
-	"net"
 	"path/filepath"
 
 	log "github.com/Sirupsen/logrus"
-	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 	"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 {
 	addrv4, _, err := i.addresses()
 	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
-	i.bridgeIPv4 = bridgeIPv4
-	i.gatewayIPv4 = i.bridgeIPv4.IP
+	i.bridgeIPv4 = config.AddressIPv4
+	i.gatewayIPv4 = config.AddressIPv4.IP
 
 	return nil
 }
 
-func allocateBridgeIP(config *networkConfiguration, i *bridgeInterface) error {
-	// Because of the way ipallocator manages the container address space,
-	// reserve bridge address only if it belongs to the container network
-	// (if defined), no need otherwise
-	if config.FixedCIDR == nil || config.FixedCIDR.Contains(i.bridgeIPv4.IP) {
-		if _, err := ipAllocator.RequestIP(i.bridgeIPv4, i.bridgeIPv4.IP); err != nil {
-			return fmt.Errorf("failed to reserve bridge IP %s: %v", i.bridgeIPv4.IP.String(), err)
-		}
-	}
-	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 {
 	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
 		return &ErrInvalidGateway{}
 	}
 
-	// Because of the way ipallocator manages the container address space,
-	// reserve default gw address only if it belongs to the container network
-	// (if defined), no need otherwise
-	if config.FixedCIDR == nil || config.FixedCIDR.Contains(config.DefaultGatewayIPv4) {
-		if _, err := ipAllocator.RequestIP(i.bridgeIPv4, config.DefaultGatewayIPv4); err != nil {
-			return fmt.Errorf("failed to reserve default gateway %s: %v", config.DefaultGatewayIPv4.String(), err)
-		}
-	}
-
 	// Store requested default gateway
 	i.gatewayIPv4 = config.DefaultGatewayIPv4
 

+ 18 - 5
vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ipv6.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"io/ioutil"
 	"net"
+	"os"
 
 	"github.com/Sirupsen/logrus"
 	"github.com/vishvananda/netlink"
@@ -57,19 +58,31 @@ func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
 	i.bridgeIPv6 = bridgeIPv6
 	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
 }
 
 func setupGatewayIPv6(config *networkConfiguration, i *bridgeInterface) error {
-	if config.FixedCIDRv6 == nil {
+	if config.AddressIPv6 == nil {
 		return &ErrInvalidContainerSubnet{}
 	}
-	if !config.FixedCIDRv6.Contains(config.DefaultGatewayIPv6) {
+	if !config.AddressIPv6.Contains(config.DefaultGatewayIPv6) {
 		return &ErrInvalidGateway{}
 	}
-	if _, err := ipAllocator.RequestIP(config.FixedCIDRv6, config.DefaultGatewayIPv6); err != nil {
-		return err
-	}
 
 	// Store requested default gateway
 	i.gatewayIPv6 = config.DefaultGatewayIPv6

+ 2 - 2
vendor/src/github.com/docker/libnetwork/drivers/host/host.go

@@ -23,7 +23,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
 	return dc.RegisterDriver(networkType, &driver{}, c)
 }
 
-func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	d.Lock()
 	defer d.Unlock()
 
@@ -40,7 +40,7 @@ func (d *driver) DeleteNetwork(nid string) error {
 	return types.ForbiddenErrorf("network of type \"%s\" cannot be deleted", networkType)
 }
 
-func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
+func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
 	return nil
 }
 

+ 2 - 2
vendor/src/github.com/docker/libnetwork/drivers/null/null.go

@@ -23,7 +23,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
 	return dc.RegisterDriver(networkType, &driver{}, c)
 }
 
-func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	d.Lock()
 	defer d.Unlock()
 
@@ -40,7 +40,7 @@ func (d *driver) DeleteNetwork(nid string) error {
 	return types.ForbiddenErrorf("network of type \"%s\" cannot be deleted", networkType)
 }
 
-func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
+func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
 	return nil
 }
 

+ 32 - 5
vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go

@@ -4,7 +4,9 @@ import (
 	"fmt"
 	"net"
 
+	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
 )
 
@@ -24,11 +26,27 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		return fmt.Errorf("could not find endpoint with id %s", eid)
 	}
 
+	s := n.getSubnetforIP(ep.addr)
+	if s == nil {
+		return fmt.Errorf("could not find subnet for endpoint %s", eid)
+	}
+
+	if err := n.obtainVxlanID(s); err != nil {
+		return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err)
+	}
+
 	if err := n.joinSandbox(); err != nil {
-		return fmt.Errorf("network sandbox join failed: %v",
-			err)
+		return fmt.Errorf("network sandbox join failed: %v", err)
+	}
+
+	if err := n.joinSubnetSandbox(s); err != nil {
+		return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
 	}
 
+	// joinSubnetSandbox gets called when an endpoint comes up on a new subnet in the
+	// overlay network. Hence the Endpoint count should be updated outside joinSubnetSandbox
+	n.incEndpointCount()
+
 	sbox := n.sandbox()
 
 	name1, name2, err := createVethPair()
@@ -49,7 +67,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 	}
 
 	if err := sbox.AddInterface(name1, "veth",
-		sbox.InterfaceOptions().Master("bridge1")); err != nil {
+		sbox.InterfaceOptions().Master(s.brName)); err != nil {
 		return fmt.Errorf("could not add veth pair inside the network sandbox: %v", err)
 	}
 
@@ -63,7 +81,16 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 	}
 
 	if err := netlink.LinkSetHardwareAddr(veth, ep.mac); err != nil {
-		return fmt.Errorf("could not set mac address to the container interface: %v", err)
+		return fmt.Errorf("could not set mac address (%v) to the container interface: %v", ep.mac, err)
+	}
+
+	for _, sub := range n.subnets {
+		if sub == s {
+			continue
+		}
+		if err := jinfo.AddStaticRoute(sub.subnetIP, types.NEXTHOP, s.gwIP.IP); err != nil {
+			log.Errorf("Adding subnet %s static route in network %q failed\n", s.subnetIP, n.id)
+		}
 	}
 
 	if iNames := jinfo.InterfaceName(); iNames != nil {
@@ -73,7 +100,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		}
 	}
 
-	d.peerDbAdd(nid, eid, ep.addr.IP, ep.mac,
+	d.peerDbAdd(nid, eid, ep.addr.IP, ep.addr.Mask, ep.mac,
 		net.ParseIP(d.bindAddress), true)
 	d.pushLocalEndpointEvent("join", nid, eid)
 

+ 23 - 28
vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go

@@ -1,7 +1,6 @@
 package overlay
 
 import (
-	"encoding/binary"
 	"fmt"
 	"net"
 
@@ -36,9 +35,18 @@ func (n *network) deleteEndpoint(eid string) {
 	n.Unlock()
 }
 
-func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
+func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 	epOptions map[string]interface{}) error {
-	if err := validateID(nid, eid); err != nil {
+	var err error
+
+	if err = validateID(nid, eid); err != nil {
+		return err
+	}
+
+	// Since we perform lazy configuration make sure we try
+	// configuring the driver when we enter CreateEndpoint since
+	// CreateNetwork may not be called in every node.
+	if err := d.configure(); err != nil {
 		return err
 	}
 
@@ -48,35 +56,23 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 	}
 
 	ep := &endpoint{
-		id: eid,
+		id:   eid,
+		addr: ifInfo.Address(),
+		mac:  ifInfo.MacAddress(),
 	}
-
-	if epInfo != nil && epInfo.Interface() != nil {
-		addr := epInfo.Interface().Address()
-		ep.addr = &addr
-		ep.mac = epInfo.Interface().MacAddress()
-		n.addEndpoint(ep)
-		return nil
-	}
-
-	ipID, err := d.ipAllocator.GetID()
-	if err != nil {
-		return fmt.Errorf("could not allocate ip from subnet %s: %v",
-			bridgeSubnet.String(), err)
+	if ep.addr == nil {
+		return fmt.Errorf("create endpoint was not passed interface IP address")
 	}
 
-	ep.addr = &net.IPNet{
-		Mask: bridgeSubnet.Mask,
+	if s := n.getSubnetforIP(ep.addr); s == nil {
+		return fmt.Errorf("no matching subnet for IP %q in network %q\n", ep.addr, nid)
 	}
-	ep.addr.IP = make([]byte, 4)
-
-	binary.BigEndian.PutUint32(ep.addr.IP, bridgeSubnetInt+ipID)
-
-	ep.mac = netutils.GenerateMACFromIP(ep.addr.IP)
 
-	err = epInfo.AddInterface(ep.mac, *ep.addr, net.IPNet{})
-	if err != nil {
-		return fmt.Errorf("could not add interface to endpoint info: %v", err)
+	if ep.mac == nil {
+		ep.mac = netutils.GenerateMACFromIP(ep.addr.IP)
+		if err := ifInfo.SetMacAddress(ep.mac); err != nil {
+			return err
+		}
 	}
 
 	n.addEndpoint(ep)
@@ -99,7 +95,6 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
 		return fmt.Errorf("endpoint id %q not found", eid)
 	}
 
-	d.ipAllocator.Release(binary.BigEndian.Uint32(ep.addr.IP) - bridgeSubnetInt)
 	n.deleteEndpoint(eid)
 	return nil
 }

+ 263 - 105
vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go

@@ -9,37 +9,54 @@ import (
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/datastore"
-	"github.com/docker/libnetwork/ipallocator"
+	"github.com/docker/libnetwork/driverapi"
+	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/osl"
+	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink/nl"
 )
 
 type networkTable map[string]*network
 
+type subnet struct {
+	once      *sync.Once
+	vxlanName string
+	brName    string
+	vni       uint32
+	initErr   error
+	subnetIP  *net.IPNet
+	gwIP      *net.IPNet
+}
+
+type subnetJSON struct {
+	SubnetIP string
+	GwIP     string
+	Vni      uint32
+}
+
 type network struct {
-	id          string
-	vni         uint32
-	dbIndex     uint64
-	dbExists    bool
-	sbox        osl.Sandbox
-	endpoints   endpointTable
-	ipAllocator *ipallocator.IPAllocator
-	gw          net.IP
-	vxlanName   string
-	driver      *driver
-	joinCnt     int
-	once        *sync.Once
-	initEpoch   int
-	initErr     error
+	id        string
+	dbIndex   uint64
+	dbExists  bool
+	sbox      osl.Sandbox
+	endpoints endpointTable
+	driver    *driver
+	joinCnt   int
+	once      *sync.Once
+	initEpoch int
+	initErr   error
+	subnets   []*subnet
 	sync.Mutex
 }
 
-func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	if id == "" {
 		return fmt.Errorf("invalid network id")
 	}
 
+	// Since we perform lazy configuration make sure we try
+	// configuring the driver when we enter CreateNetwork
 	if err := d.configure(); err != nil {
 		return err
 	}
@@ -49,19 +66,43 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 		driver:    d,
 		endpoints: endpointTable{},
 		once:      &sync.Once{},
+		subnets:   []*subnet{},
 	}
 
-	n.gw = bridgeIP.IP
-
-	d.addNetwork(n)
+	for _, ipd := range ipV4Data {
+		s := &subnet{
+			subnetIP: ipd.Pool,
+			gwIP:     ipd.Gateway,
+			once:     &sync.Once{},
+		}
+		n.subnets = append(n.subnets, s)
+	}
 
-	if err := n.obtainVxlanID(); err != nil {
-		return err
+	if err := n.writeToStore(); err != nil {
+		return fmt.Errorf("failed to update data store for network %v: %v", n.id, err)
 	}
 
+	d.addNetwork(n)
+
 	return nil
 }
 
+/* func (d *driver) createNetworkfromStore(nid string) (*network, error) {
+	n := &network{
+		id:        nid,
+		driver:    d,
+		endpoints: endpointTable{},
+		once:      &sync.Once{},
+		subnets:   []*subnet{},
+	}
+
+	err := d.store.GetObject(datastore.Key(n.Key()...), n)
+	if err != nil {
+		return nil, fmt.Errorf("unable to get network %q from data store, %v", nid, err)
+	}
+	return n, nil
+}*/
+
 func (d *driver) DeleteNetwork(nid string) error {
 	if nid == "" {
 		return fmt.Errorf("invalid network id")
@@ -77,15 +118,13 @@ func (d *driver) DeleteNetwork(nid string) error {
 	return n.releaseVxlanID()
 }
 
-func (n *network) joinSandbox() error {
+func (n *network) incEndpointCount() {
 	n.Lock()
-	if n.joinCnt != 0 {
-		n.joinCnt++
-		n.Unlock()
-		return nil
-	}
-	n.Unlock()
+	defer n.Unlock()
+	n.joinCnt++
+}
 
+func (n *network) joinSandbox() error {
 	// If there is a race between two go routines here only one will win
 	// the other will wait.
 	n.once.Do(func() {
@@ -94,16 +133,14 @@ func (n *network) joinSandbox() error {
 		n.initErr = n.initSandbox()
 	})
 
-	// Increment joinCnt in all the goroutines only when the one time initSandbox
-	// was a success.
-	n.Lock()
-	if n.initErr == nil {
-		n.joinCnt++
-	}
-	err := n.initErr
-	n.Unlock()
+	return n.initErr
+}
 
-	return err
+func (n *network) joinSubnetSandbox(s *subnet) error {
+	s.once.Do(func() {
+		s.initErr = n.initSubnetSandbox(s)
+	})
+	return s.initErr
 }
 
 func (n *network) leaveSandbox() {
@@ -118,6 +155,9 @@ func (n *network) leaveSandbox() {
 	// Reinitialize the once variable so that we will be able to trigger one time
 	// sandbox initialization(again) when another container joins subsequently.
 	n.once = &sync.Once{}
+	for _, s := range n.subnets {
+		s.once = &sync.Once{}
+	}
 	n.Unlock()
 
 	n.destroySandbox()
@@ -130,14 +170,50 @@ func (n *network) destroySandbox() {
 			iface.Remove()
 		}
 
-		if err := deleteVxlan(n.vxlanName); err != nil {
-			logrus.Warnf("could not cleanup sandbox properly: %v", err)
+		for _, s := range n.subnets {
+			if s.vxlanName != "" {
+				err := deleteVxlan(s.vxlanName)
+				if err != nil {
+					logrus.Warnf("could not cleanup sandbox properly: %v", err)
+				}
+			}
 		}
-
 		sbox.Destroy()
 	}
 }
 
+func (n *network) initSubnetSandbox(s *subnet) error {
+	// create a bridge and vxlan device for this subnet and move it to the sandbox
+	brName, err := netutils.GenerateIfaceName("bridge", 7)
+	if err != nil {
+		return err
+	}
+	sbox := n.sandbox()
+
+	if err := sbox.AddInterface(brName, "br",
+		sbox.InterfaceOptions().Address(s.gwIP),
+		sbox.InterfaceOptions().Bridge(true)); err != nil {
+		return fmt.Errorf("bridge creation in sandbox failed for subnet %q: %v", s.subnetIP.IP.String(), err)
+	}
+
+	vxlanName, err := createVxlan(n.vxlanID(s))
+	if err != nil {
+		return err
+	}
+
+	if err := sbox.AddInterface(vxlanName, "vxlan",
+		sbox.InterfaceOptions().Master(brName)); err != nil {
+		return fmt.Errorf("vxlan interface creation failed for subnet %q: %v", s.subnetIP.IP.String(), err)
+	}
+
+	n.Lock()
+	s.vxlanName = vxlanName
+	s.brName = brName
+	n.Unlock()
+
+	return nil
+}
+
 func (n *network) initSandbox() error {
 	n.Lock()
 	n.initEpoch++
@@ -149,15 +225,10 @@ func (n *network) initSandbox() error {
 		return fmt.Errorf("could not create network sandbox: %v", err)
 	}
 
-	// Add a bridge inside the namespace
-	if err := sbox.AddInterface("bridge1", "br",
-		sbox.InterfaceOptions().Address(bridgeIP),
-		sbox.InterfaceOptions().Bridge(true)); err != nil {
-		return fmt.Errorf("could not create bridge inside the network sandbox: %v", err)
-	}
-
 	n.setSandbox(sbox)
 
+	n.driver.peerDbUpdateSandbox(n.id)
+
 	var nlSock *nl.NetlinkSocket
 	sbox.InvokeFunc(func() {
 		nlSock, err = nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_NEIGH)
@@ -167,27 +238,6 @@ func (n *network) initSandbox() error {
 	})
 
 	go n.watchMiss(nlSock)
-	return n.initVxlan()
-}
-
-func (n *network) initVxlan() error {
-	var vxlanName string
-	n.Lock()
-	sbox := n.sbox
-	n.Unlock()
-
-	vxlanName, err := createVxlan(n.vxlanID())
-	if err != nil {
-		return err
-	}
-
-	if err = sbox.AddInterface(vxlanName, "vxlan",
-		sbox.InterfaceOptions().Master("bridge1")); err != nil {
-		return fmt.Errorf("could not add vxlan interface inside the network sandbox: %v", err)
-	}
-
-	n.vxlanName = vxlanName
-	n.driver.peerDbUpdateSandbox(n.id)
 	return nil
 }
 
@@ -218,14 +268,14 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
 				continue
 			}
 
-			mac, vtep, err := n.driver.resolvePeer(n.id, neigh.IP)
+			mac, IPmask, vtep, err := n.driver.resolvePeer(n.id, neigh.IP)
 			if err != nil {
 				logrus.Errorf("could not resolve peer %q: %v", neigh.IP, err)
 				continue
 			}
 
-			if err := n.driver.peerAdd(n.id, "dummy", neigh.IP, mac, vtep, true); err != nil {
-				logrus.Errorf("could not add neighbor entry for missed peer: %v", err)
+			if err := n.driver.peerAdd(n.id, "dummy", neigh.IP, IPmask, mac, vtep, true); err != nil {
+				logrus.Errorf("could not add neighbor entry for missed peer %q: %v", neigh.IP, err)
 			}
 		}
 	}
@@ -245,9 +295,34 @@ func (d *driver) deleteNetwork(nid string) {
 
 func (d *driver) network(nid string) *network {
 	d.Lock()
-	defer d.Unlock()
+	networks := d.networks
+	d.Unlock()
+
+	n, ok := networks[nid]
+	if !ok {
+		n = d.getNetworkFromStore(nid)
+		if n != nil {
+			n.driver = d
+			n.endpoints = endpointTable{}
+			n.once = &sync.Once{}
+			networks[nid] = n
+		}
+	}
+
+	return n
+}
+
+func (d *driver) getNetworkFromStore(nid string) *network {
+	if d.store == nil {
+		return nil
+	}
 
-	return d.networks[nid]
+	n := &network{id: nid}
+	if err := d.store.GetObject(datastore.Key(n.Key()...), n); err != nil {
+		return nil
+	}
+
+	return n
 }
 
 func (n *network) sandbox() osl.Sandbox {
@@ -263,16 +338,16 @@ func (n *network) setSandbox(sbox osl.Sandbox) {
 	n.Unlock()
 }
 
-func (n *network) vxlanID() uint32 {
+func (n *network) vxlanID(s *subnet) uint32 {
 	n.Lock()
 	defer n.Unlock()
 
-	return n.vni
+	return s.vni
 }
 
-func (n *network) setVxlanID(vni uint32) {
+func (n *network) setVxlanID(s *subnet, vni uint32) {
 	n.Lock()
-	n.vni = vni
+	s.vni = vni
 	n.Unlock()
 }
 
@@ -285,11 +360,22 @@ func (n *network) KeyPrefix() []string {
 }
 
 func (n *network) Value() []byte {
-	b, err := json.Marshal(n.vxlanID())
+	netJSON := []*subnetJSON{}
+
+	for _, s := range n.subnets {
+		sj := &subnetJSON{
+			SubnetIP: s.subnetIP.String(),
+			GwIP:     s.gwIP.String(),
+			Vni:      s.vni,
+		}
+		netJSON = append(netJSON, sj)
+	}
+
+	b, err := json.Marshal(netJSON)
+
 	if err != nil {
 		return []byte{}
 	}
-
 	return b
 }
 
@@ -311,15 +397,45 @@ func (n *network) Skip() bool {
 }
 
 func (n *network) SetValue(value []byte) error {
-	var vni uint32
-	err := json.Unmarshal(value, &vni)
-	if err == nil {
-		n.setVxlanID(vni)
+	var newNet bool
+	netJSON := []*subnetJSON{}
+
+	err := json.Unmarshal(value, &netJSON)
+	if err != nil {
+		return err
 	}
-	return err
+
+	if len(n.subnets) == 0 {
+		newNet = true
+	}
+
+	for _, sj := range netJSON {
+		subnetIPstr := sj.SubnetIP
+		gwIPstr := sj.GwIP
+		vni := sj.Vni
+
+		subnetIP, _ := types.ParseCIDR(subnetIPstr)
+		gwIP, _ := types.ParseCIDR(gwIPstr)
+
+		if newNet {
+			s := &subnet{
+				subnetIP: subnetIP,
+				gwIP:     gwIP,
+				vni:      vni,
+				once:     &sync.Once{},
+			}
+			n.subnets = append(n.subnets, s)
+		} else {
+			sNet := n.getMatchingSubnet(subnetIP)
+			if sNet != nil {
+				sNet.vni = vni
+			}
+		}
+	}
+	return nil
 }
 
-func (n *network) DataScope() datastore.DataScope {
+func (n *network) DataScope() string {
 	return datastore.GlobalScope
 }
 
@@ -332,7 +448,7 @@ func (n *network) releaseVxlanID() error {
 		return fmt.Errorf("no datastore configured. cannot release vxlan id")
 	}
 
-	if n.vxlanID() == 0 {
+	if len(n.subnets) == 0 {
 		return nil
 	}
 
@@ -346,38 +462,80 @@ func (n *network) releaseVxlanID() error {
 		return fmt.Errorf("failed to delete network to vxlan id map: %v", err)
 	}
 
-	n.driver.vxlanIdm.Release(n.vxlanID())
-	n.setVxlanID(0)
+	for _, s := range n.subnets {
+		n.driver.vxlanIdm.Release(uint64(n.vxlanID(s)))
+		n.setVxlanID(s, 0)
+	}
 	return nil
 }
 
-func (n *network) obtainVxlanID() error {
+func (n *network) obtainVxlanID(s *subnet) error {
+	//return if the subnet already has a vxlan id assigned
+	if s.vni != 0 {
+		return nil
+	}
+
 	if n.driver.store == nil {
 		return fmt.Errorf("no datastore configured. cannot obtain vxlan id")
 	}
 
 	for {
-		var vxlanID uint32
 		if err := n.driver.store.GetObject(datastore.Key(n.Key()...), n); err != nil {
-			if err == datastore.ErrKeyNotFound {
-				vxlanID, err = n.driver.vxlanIdm.GetID()
-				if err != nil {
-					return fmt.Errorf("failed to allocate vxlan id: %v", err)
-				}
+			return fmt.Errorf("getting network %q from datastore failed %v", n.id, err)
+		}
 
-				n.setVxlanID(vxlanID)
-				if err := n.writeToStore(); err != nil {
-					n.driver.vxlanIdm.Release(n.vxlanID())
-					n.setVxlanID(0)
-					if err == datastore.ErrKeyModified {
-						continue
-					}
-					return fmt.Errorf("failed to update data store with vxlan id: %v", err)
+		if s.vni == 0 {
+			vxlanID, err := n.driver.vxlanIdm.GetID()
+			if err != nil {
+				return fmt.Errorf("failed to allocate vxlan id: %v", err)
+			}
+
+			n.setVxlanID(s, uint32(vxlanID))
+			if err := n.writeToStore(); err != nil {
+				n.driver.vxlanIdm.Release(uint64(n.vxlanID(s)))
+				n.setVxlanID(s, 0)
+				if err == datastore.ErrKeyModified {
+					continue
 				}
-				return nil
+				return fmt.Errorf("network %q failed to update data store: %v", n.id, err)
 			}
-			return fmt.Errorf("failed to obtain vxlan id from data store: %v", err)
+			return nil
 		}
 		return nil
 	}
 }
+
+// getSubnetforIP returns the subnet to which the given IP belongs
+func (n *network) getSubnetforIP(ip *net.IPNet) *subnet {
+	for _, s := range n.subnets {
+		// first check if the mask lengths are the same
+		i, _ := s.subnetIP.Mask.Size()
+		j, _ := ip.Mask.Size()
+		if i != j {
+			continue
+		}
+		if s.subnetIP.Contains(ip.IP) {
+			return s
+		}
+	}
+	return nil
+}
+
+// getMatchingSubnet return the network's subnet that matches the input
+func (n *network) getMatchingSubnet(ip *net.IPNet) *subnet {
+	if ip == nil {
+		return nil
+	}
+	for _, s := range n.subnets {
+		// first check if the mask lengths are the same
+		i, _ := s.subnetIP.Mask.Size()
+		j, _ := ip.Mask.Size()
+		if i != j {
+			continue
+		}
+		if s.subnetIP.IP.Equal(ip.IP) {
+			return s
+		}
+	}
+	return nil
+}

+ 25 - 24
vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go

@@ -47,7 +47,7 @@ func (d *driver) serfInit() error {
 	config.UserCoalescePeriod = 1 * time.Second
 	config.UserQuiescentPeriod = 50 * time.Millisecond
 
-	config.LogOutput = logrus.StandardLogger().Out
+	config.LogOutput = &logWriter{}
 
 	s, err := serf.Create(config)
 	if err != nil {
@@ -83,34 +83,35 @@ func (d *driver) notifyEvent(event ovNotify) {
 	n := d.network(event.nid)
 	ep := n.endpoint(event.eid)
 
-	ePayload := fmt.Sprintf("%s %s %s", event.action, ep.addr.IP.String(), ep.mac.String())
+	ePayload := fmt.Sprintf("%s %s %s %s", event.action, ep.addr.IP.String(),
+		net.IP(ep.addr.Mask).String(), ep.mac.String())
 	eName := fmt.Sprintf("jl %s %s %s", d.serfInstance.LocalMember().Addr.String(),
 		event.nid, event.eid)
 
 	if err := d.serfInstance.UserEvent(eName, []byte(ePayload), true); err != nil {
-		fmt.Printf("Sending user event failed: %v\n", err)
+		logrus.Errorf("Sending user event failed: %v\n", err)
 	}
 }
 
 func (d *driver) processEvent(u serf.UserEvent) {
-	fmt.Printf("Received user event name:%s, payload:%s\n", u.Name,
+	logrus.Debugf("Received user event name:%s, payload:%s\n", u.Name,
 		string(u.Payload))
 
-	var dummy, action, vtepStr, nid, eid, ipStr, macStr string
+	var dummy, action, vtepStr, nid, eid, ipStr, maskStr, macStr string
 	if _, err := fmt.Sscan(u.Name, &dummy, &vtepStr, &nid, &eid); err != nil {
 		fmt.Printf("Failed to scan name string: %v\n", err)
 	}
 
 	if _, err := fmt.Sscan(string(u.Payload), &action,
-		&ipStr, &macStr); err != nil {
+		&ipStr, &maskStr, &macStr); err != nil {
 		fmt.Printf("Failed to scan value string: %v\n", err)
 	}
 
-	fmt.Printf("Parsed data = %s/%s/%s/%s/%s\n", nid, eid, vtepStr, ipStr, macStr)
+	logrus.Debugf("Parsed data = %s/%s/%s/%s/%s/%s\n", nid, eid, vtepStr, ipStr, maskStr, macStr)
 
 	mac, err := net.ParseMAC(macStr)
 	if err != nil {
-		fmt.Printf("Failed to parse mac: %v\n", err)
+		logrus.Errorf("Failed to parse mac: %v\n", err)
 	}
 
 	if d.serfInstance.LocalMember().Addr.String() == vtepStr {
@@ -119,20 +120,20 @@ func (d *driver) processEvent(u serf.UserEvent) {
 
 	switch action {
 	case "join":
-		if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), mac,
+		if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac,
 			net.ParseIP(vtepStr), true); err != nil {
-			fmt.Printf("Peer add failed in the driver: %v\n", err)
+			logrus.Errorf("Peer add failed in the driver: %v\n", err)
 		}
 	case "leave":
-		if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), mac,
+		if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), net.IPMask(net.ParseIP(maskStr).To4()), mac,
 			net.ParseIP(vtepStr), true); err != nil {
-			fmt.Printf("Peer delete failed in the driver: %v\n", err)
+			logrus.Errorf("Peer delete failed in the driver: %v\n", err)
 		}
 	}
 }
 
 func (d *driver) processQuery(q *serf.Query) {
-	fmt.Printf("Received query name:%s, payload:%s\n", q.Name,
+	logrus.Debugf("Received query name:%s, payload:%s\n", q.Name,
 		string(q.Payload))
 
 	var nid, ipStr string
@@ -140,38 +141,38 @@ func (d *driver) processQuery(q *serf.Query) {
 		fmt.Printf("Failed to scan query payload string: %v\n", err)
 	}
 
-	peerMac, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr))
+	peerMac, peerIPMask, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr))
 	if err != nil {
 		return
 	}
 
-	q.Respond([]byte(fmt.Sprintf("%s %s", peerMac.String(), vtep.String())))
+	q.Respond([]byte(fmt.Sprintf("%s %s %s", peerMac.String(), net.IP(peerIPMask).String(), vtep.String())))
 }
 
-func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
+func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) {
 	qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String())
 	resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil)
 	if err != nil {
-		return nil, nil, fmt.Errorf("resolving peer by querying the cluster failed: %v", err)
+		return nil, nil, nil, fmt.Errorf("resolving peer by querying the cluster failed: %v", err)
 	}
 
 	respCh := resp.ResponseCh()
 	select {
 	case r := <-respCh:
-		var macStr, vtepStr string
-		if _, err := fmt.Sscan(string(r.Payload), &macStr, &vtepStr); err != nil {
-			return nil, nil, fmt.Errorf("bad response %q for the resolve query: %v", string(r.Payload), err)
+		var macStr, maskStr, vtepStr string
+		if _, err := fmt.Sscan(string(r.Payload), &macStr, &maskStr, &vtepStr); err != nil {
+			return nil, nil, nil, fmt.Errorf("bad response %q for the resolve query: %v", string(r.Payload), err)
 		}
 
 		mac, err := net.ParseMAC(macStr)
 		if err != nil {
-			return nil, nil, fmt.Errorf("failed to parse mac: %v", err)
+			return nil, nil, nil, fmt.Errorf("failed to parse mac: %v", err)
 		}
 
-		return mac, net.ParseIP(vtepStr), nil
+		return mac, net.IPMask(net.ParseIP(maskStr).To4()), net.ParseIP(vtepStr), nil
 
 	case <-time.After(time.Second):
-		return nil, nil, fmt.Errorf("timed out resolving peer by querying the cluster")
+		return nil, nil, nil, fmt.Errorf("timed out resolving peer by querying the cluster")
 	}
 }
 
@@ -192,7 +193,7 @@ func (d *driver) startSerfLoop(eventCh chan serf.Event, notifyCh chan ovNotify,
 			}
 
 			if err := d.serfInstance.Leave(); err != nil {
-				fmt.Printf("failed leaving the cluster: %v\n", err)
+				logrus.Errorf("failed leaving the cluster: %v\n", err)
 			}
 
 			d.serfInstance.Shutdown()

+ 6 - 37
vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go

@@ -1,14 +1,11 @@
 package overlay
 
 import (
-	"encoding/binary"
 	"fmt"
-	"net"
 	"sync"
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/libkv/store"
-	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/idm"
@@ -44,36 +41,8 @@ type driver struct {
 	sync.Mutex
 }
 
-var (
-	bridgeSubnet, bridgeIP *net.IPNet
-	once                   sync.Once
-	bridgeSubnetInt        uint32
-)
-
-func onceInit() {
-	var err error
-	_, bridgeSubnet, err = net.ParseCIDR("172.21.0.0/16")
-	if err != nil {
-		panic("could not parse cid 172.21.0.0/16")
-	}
-
-	bridgeSubnetInt = binary.BigEndian.Uint32(bridgeSubnet.IP.To4())
-
-	ip, subnet, err := net.ParseCIDR("172.21.255.254/16")
-	if err != nil {
-		panic("could not parse cid 172.21.255.254/16")
-	}
-
-	bridgeIP = &net.IPNet{
-		IP:   ip,
-		Mask: subnet.Mask,
-	}
-}
-
 // Init registers a new instance of overlay driver
 func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
-	once.Do(onceInit)
-
 	c := driverapi.Capability{
 		DataScope: datastore.GlobalScope,
 	}
@@ -110,21 +79,21 @@ func (d *driver) configure() error {
 	}
 
 	d.once.Do(func() {
-		provider, provOk := d.config[netlabel.KVProvider]
-		provURL, urlOk := d.config[netlabel.KVProviderURL]
+		provider, provOk := d.config[netlabel.GlobalKVProvider]
+		provURL, urlOk := d.config[netlabel.GlobalKVProviderURL]
 
 		if provOk && urlOk {
-			cfg := &config.DatastoreCfg{
-				Client: config.DatastoreClientCfg{
+			cfg := &datastore.ScopeCfg{
+				Client: datastore.ScopeClientCfg{
 					Provider: provider.(string),
 					Address:  provURL.(string),
 				},
 			}
-			provConfig, confOk := d.config[netlabel.KVProviderConfig]
+			provConfig, confOk := d.config[netlabel.GlobalKVProviderConfig]
 			if confOk {
 				cfg.Client.Config = provConfig.(*store.Config)
 			}
-			d.store, err = datastore.NewDataStore(cfg)
+			d.store, err = datastore.NewDataStore(datastore.GlobalScope, cfg)
 			if err != nil {
 				err = fmt.Errorf("failed to initialize data store: %v", err)
 				return

+ 45 - 23
vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go

@@ -13,10 +13,11 @@ type peerKey struct {
 }
 
 type peerEntry struct {
-	eid       string
-	vtep      net.IP
-	inSandbox bool
-	isLocal   bool
+	eid        string
+	vtep       net.IP
+	peerIPMask net.IPMask
+	inSandbox  bool
+	isLocal    bool
 }
 
 type peerMap struct {
@@ -98,16 +99,18 @@ func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool
 	return nil
 }
 
-func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
+func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.IPMask, net.IP, error) {
 	var (
-		peerMac net.HardwareAddr
-		vtep    net.IP
-		found   bool
+		peerMac    net.HardwareAddr
+		vtep       net.IP
+		peerIPMask net.IPMask
+		found      bool
 	)
 
 	err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
 		if pKey.peerIP.Equal(peerIP) {
 			peerMac = pKey.peerMac
+			peerIPMask = pEntry.peerIPMask
 			vtep = pEntry.vtep
 			found = true
 			return found
@@ -117,17 +120,17 @@ func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.
 	})
 
 	if err != nil {
-		return nil, nil, fmt.Errorf("peerdb search for peer ip %q failed: %v", peerIP, err)
+		return nil, nil, nil, fmt.Errorf("peerdb search for peer ip %q failed: %v", peerIP, err)
 	}
 
 	if !found {
-		return nil, nil, fmt.Errorf("peer ip %q not found in peerdb", peerIP)
+		return nil, nil, nil, fmt.Errorf("peer ip %q not found in peerdb", peerIP)
 	}
 
-	return peerMac, vtep, nil
+	return peerMac, peerIPMask, vtep, nil
 }
 
-func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP,
+func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
 	peerMac net.HardwareAddr, vtep net.IP, isLocal bool) {
 
 	peerDbWg.Wait()
@@ -149,9 +152,10 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP,
 	}
 
 	pEntry := peerEntry{
-		eid:     eid,
-		vtep:    vtep,
-		isLocal: isLocal,
+		eid:        eid,
+		vtep:       vtep,
+		peerIPMask: peerIPMask,
+		isLocal:    isLocal,
 	}
 
 	pMap.Lock()
@@ -159,7 +163,7 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP,
 	pMap.Unlock()
 }
 
-func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP,
+func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
 	peerMac net.HardwareAddr, vtep net.IP) {
 	peerDbWg.Wait()
 
@@ -209,7 +213,7 @@ func (d *driver) peerDbUpdateSandbox(nid string) {
 		// a copy of pEntry before capturing it in the following closure.
 		entry := pEntry
 		op := func() {
-			if err := d.peerAdd(nid, entry.eid, pKey.peerIP,
+			if err := d.peerAdd(nid, entry.eid, pKey.peerIP, entry.peerIPMask,
 				pKey.peerMac, entry.vtep,
 				false); err != nil {
 				fmt.Printf("peerdbupdate in sandbox failed for ip %s and mac %s: %v",
@@ -228,7 +232,7 @@ func (d *driver) peerDbUpdateSandbox(nid string) {
 	peerDbWg.Done()
 }
 
-func (d *driver) peerAdd(nid, eid string, peerIP net.IP,
+func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
 	peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
 
 	if err := validateID(nid, eid); err != nil {
@@ -236,7 +240,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP,
 	}
 
 	if updateDb {
-		d.peerDbAdd(nid, eid, peerIP, peerMac, vtep, false)
+		d.peerDbAdd(nid, eid, peerIP, peerIPMask, peerMac, vtep, false)
 	}
 
 	n := d.network(nid)
@@ -249,13 +253,31 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP,
 		return nil
 	}
 
+	IP := &net.IPNet{
+		IP:   peerIP,
+		Mask: peerIPMask,
+	}
+
+	s := n.getSubnetforIP(IP)
+	if s == nil {
+		return fmt.Errorf("couldn't find the subnet %q in network %q\n", IP.String(), n.id)
+	}
+
+	if err := n.obtainVxlanID(s); err != nil {
+		return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err)
+	}
+
+	if err := n.joinSubnetSandbox(s); err != nil {
+		return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
+	}
+
 	// Add neighbor entry for the peer IP
-	if err := sbox.AddNeighbor(peerIP, peerMac, sbox.NeighborOptions().LinkName(n.vxlanName)); err != nil {
+	if err := sbox.AddNeighbor(peerIP, peerMac, sbox.NeighborOptions().LinkName(s.vxlanName)); err != nil {
 		return fmt.Errorf("could not add neigbor entry into the sandbox: %v", err)
 	}
 
 	// Add fdb entry to the bridge for the peer mac
-	if err := sbox.AddNeighbor(vtep, peerMac, sbox.NeighborOptions().LinkName(n.vxlanName),
+	if err := sbox.AddNeighbor(vtep, peerMac, sbox.NeighborOptions().LinkName(s.vxlanName),
 		sbox.NeighborOptions().Family(syscall.AF_BRIDGE)); err != nil {
 		return fmt.Errorf("could not add fdb entry into the sandbox: %v", err)
 	}
@@ -263,7 +285,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP,
 	return nil
 }
 
-func (d *driver) peerDelete(nid, eid string, peerIP net.IP,
+func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
 	peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
 
 	if err := validateID(nid, eid); err != nil {
@@ -271,7 +293,7 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP,
 	}
 
 	if updateDb {
-		d.peerDbDelete(nid, eid, peerIP, peerMac, vtep)
+		d.peerDbDelete(nid, eid, peerIP, peerIPMask, peerMac, vtep)
 	}
 
 	n := d.network(nid)

+ 3 - 0
vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go

@@ -34,6 +34,9 @@ type CreateNetworkRequest struct {
 
 	// A free form map->object interface for communication of options.
 	Options map[string]interface{}
+
+	// IPAMData contains the address pool information for this network
+	IPv4Data, IPv6Data []driverapi.IPAMData
 }
 
 // CreateNetworkResponse is the response to the CreateNetworkRequest.

+ 35 - 44
vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go

@@ -82,10 +82,12 @@ func (d *driver) call(methodName string, arg interface{}, retVal maybeError) err
 	return nil
 }
 
-func (d *driver) CreateNetwork(id string, options map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	create := &api.CreateNetworkRequest{
 		NetworkID: id,
 		Options:   options,
+		IPv4Data:  ipV4Data,
+		IPv6Data:  ipV6Data,
 	}
 	return d.call("CreateNetwork", create, &api.CreateNetworkResponse{})
 }
@@ -95,23 +97,22 @@ func (d *driver) DeleteNetwork(nid string) error {
 	return d.call("DeleteNetwork", delete, &api.DeleteNetworkResponse{})
 }
 
-func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
-	var reqIface *api.EndpointInterface
-
-	if epInfo == nil {
-		return fmt.Errorf("must not be called with nil EndpointInfo")
+func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
+	if ifInfo == nil {
+		return fmt.Errorf("must not be called with nil InterfaceInfo")
 	}
 
-	iface := epInfo.Interface()
-	if iface != nil {
-		addr4 := iface.Address()
-		addr6 := iface.AddressIPv6()
-		reqIface = &api.EndpointInterface{
-			Address:     addr4.String(),
-			AddressIPv6: addr6.String(),
-			MacAddress:  iface.MacAddress().String(),
-		}
+	reqIface := &api.EndpointInterface{}
+	if ifInfo.Address() != nil {
+		reqIface.Address = ifInfo.Address().String()
+	}
+	if ifInfo.AddressIPv6() != nil {
+		reqIface.AddressIPv6 = ifInfo.AddressIPv6().String()
+	}
+	if ifInfo.MacAddress() != nil {
+		reqIface.MacAddress = ifInfo.MacAddress().String()
 	}
+
 	create := &api.CreateEndpointRequest{
 		NetworkID:  nid,
 		EndpointID: eid,
@@ -127,24 +128,27 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 	if err != nil {
 		return err
 	}
-	if reqIface != nil && inIface != nil {
-		// We're not supposed to add interface if there is already
-		// one. Attempt to roll back
-		return errorWithRollback("driver attempted to add interface ignoring the one provided", d.DeleteEndpoint(nid, eid))
+	if inIface == nil {
+		// Remote driver did not set any field
+		return nil
 	}
 
-	if inIface != nil {
-		var addr4, addr6 net.IPNet
-		if inIface.Address != nil {
-			addr4 = *(inIface.Address)
+	if inIface.MacAddress != nil {
+		if err := ifInfo.SetMacAddress(inIface.MacAddress); err != nil {
+			return errorWithRollback(fmt.Sprintf("driver modified interface MAC address: %v", err), d.DeleteEndpoint(nid, eid))
 		}
-		if inIface.AddressIPv6 != nil {
-			addr6 = *(inIface.AddressIPv6)
+	}
+	if inIface.Address != nil {
+		if err := ifInfo.SetIPAddress(inIface.Address); err != nil {
+			return errorWithRollback(fmt.Sprintf("driver modified interface address: %v", err), d.DeleteEndpoint(nid, eid))
 		}
-		if err := epInfo.AddInterface(inIface.MacAddress, addr4, addr6); err != nil {
-			return errorWithRollback(fmt.Sprintf("failed to AddInterface %v: %s", inIface, err), d.DeleteEndpoint(nid, eid))
+	}
+	if inIface.AddressIPv6 != nil {
+		if err := ifInfo.SetIPAddress(inIface.AddressIPv6); err != nil {
+			return errorWithRollback(fmt.Sprintf("driver modified interface address: %v", err), d.DeleteEndpoint(nid, eid))
 		}
 	}
+
 	return nil
 }
 
@@ -193,11 +197,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 	}
 
 	ifaceName := res.InterfaceName
-	if jinfo.InterfaceName() != nil && ifaceName == nil {
-		return fmt.Errorf("no interface name information received while one is expected")
-	}
-
-	if iface := jinfo.InterfaceName(); iface != nil {
+	if iface := jinfo.InterfaceName(); iface != nil && ifaceName != nil {
 		if err := iface.SetNames(ifaceName.SrcName, ifaceName.DstPrefix); err != nil {
 			return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid))
 		}
@@ -278,7 +278,7 @@ func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
 		outRoute := &types.StaticRoute{RouteType: inRoute.RouteType}
 
 		if inRoute.Destination != "" {
-			if outRoute.Destination, err = toAddr(inRoute.Destination); err != nil {
+			if outRoute.Destination, err = types.ParseCIDR(inRoute.Destination); err != nil {
 				return nil, err
 			}
 		}
@@ -304,12 +304,12 @@ func parseInterface(r api.CreateEndpointResponse) (*api.Interface, error) {
 		var err error
 		outIf = &api.Interface{}
 		if inIf.Address != "" {
-			if outIf.Address, err = toAddr(inIf.Address); err != nil {
+			if outIf.Address, err = types.ParseCIDR(inIf.Address); err != nil {
 				return nil, err
 			}
 		}
 		if inIf.AddressIPv6 != "" {
-			if outIf.AddressIPv6, err = toAddr(inIf.AddressIPv6); err != nil {
+			if outIf.AddressIPv6, err = types.ParseCIDR(inIf.AddressIPv6); err != nil {
 				return nil, err
 			}
 		}
@@ -322,12 +322,3 @@ func parseInterface(r api.CreateEndpointResponse) (*api.Interface, error) {
 
 	return outIf, nil
 }
-
-func toAddr(ipAddr string) (*net.IPNet, error) {
-	ip, ipnet, err := net.ParseCIDR(ipAddr)
-	if err != nil {
-		return nil, err
-	}
-	ipnet.IP = ip
-	return ipnet, nil
-}

+ 2 - 2
vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go

@@ -19,7 +19,7 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
 	return dc.RegisterDriver(networkType, &driver{}, c)
 }
 
-func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
 	return nil
 }
 
@@ -27,7 +27,7 @@ func (d *driver) DeleteNetwork(nid string) error {
 	return nil
 }
 
-func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
+func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
 	return nil
 }
 

+ 229 - 74
vendor/src/github.com/docker/libnetwork/endpoint.go

@@ -10,7 +10,9 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/ipamapi"
 	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -71,7 +73,9 @@ func (ep *endpoint) MarshalJSON() ([]byte, error) {
 	epMap["id"] = ep.id
 	epMap["ep_iface"] = ep.iface
 	epMap["exposed_ports"] = ep.exposedPorts
-	epMap["generic"] = ep.generic
+	if ep.generic != nil {
+		epMap["generic"] = ep.generic
+	}
 	epMap["sandbox"] = ep.sandboxID
 	return json.Marshal(epMap)
 }
@@ -98,12 +102,43 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
 	cb, _ := json.Marshal(epMap["sandbox"])
 	json.Unmarshal(cb, &ep.sandboxID)
 
-	if epMap["generic"] != nil {
-		ep.generic = epMap["generic"].(map[string]interface{})
+	if v, ok := epMap["generic"]; ok {
+		ep.generic = v.(map[string]interface{})
 	}
 	return nil
 }
 
+func (ep *endpoint) New() datastore.KVObject {
+	return &endpoint{network: ep.getNetwork()}
+}
+
+func (ep *endpoint) CopyTo(o datastore.KVObject) error {
+	ep.Lock()
+	defer ep.Unlock()
+
+	dstEp := o.(*endpoint)
+	dstEp.name = ep.name
+	dstEp.id = ep.id
+	dstEp.sandboxID = ep.sandboxID
+	dstEp.dbIndex = ep.dbIndex
+	dstEp.dbExists = ep.dbExists
+
+	if ep.iface != nil {
+		dstEp.iface = &endpointInterface{}
+		ep.iface.CopyTo(dstEp.iface)
+	}
+
+	dstEp.exposedPorts = make([]types.TransportPort, len(ep.exposedPorts))
+	copy(dstEp.exposedPorts, ep.exposedPorts)
+
+	dstEp.generic = options.Generic{}
+	for k, v := range ep.generic {
+		dstEp.generic[k] = v
+	}
+
+	return nil
+}
+
 func (ep *endpoint) ID() string {
 	ep.Lock()
 	defer ep.Unlock()
@@ -119,16 +154,28 @@ func (ep *endpoint) Name() string {
 }
 
 func (ep *endpoint) Network() string {
-	return ep.getNetwork().name
+	if ep.network == nil {
+		return ""
+	}
+
+	return ep.network.name
 }
 
 // endpoint Key structure : endpoint/network-id/endpoint-id
 func (ep *endpoint) Key() []string {
-	return []string{datastore.EndpointKeyPrefix, ep.getNetwork().id, ep.id}
+	if ep.network == nil {
+		return nil
+	}
+
+	return []string{datastore.EndpointKeyPrefix, ep.network.id, ep.id}
 }
 
 func (ep *endpoint) KeyPrefix() []string {
-	return []string{datastore.EndpointKeyPrefix, ep.getNetwork().id}
+	if ep.network == nil {
+		return nil
+	}
+
+	return []string{datastore.EndpointKeyPrefix, ep.network.id}
 }
 
 func (ep *endpoint) networkIDFromKey(key string) (string, error) {
@@ -188,8 +235,22 @@ func (ep *endpoint) processOptions(options ...EndpointOption) {
 	}
 }
 
-func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
+func (ep *endpoint) getNetwork() *network {
+	ep.Lock()
+	defer ep.Unlock()
+
+	return ep.network
+}
+
+func (ep *endpoint) getNetworkFromStore() (*network, error) {
+	if ep.network == nil {
+		return nil, fmt.Errorf("invalid network object in endpoint %s", ep.Name())
+	}
 
+	return ep.network.ctrlr.getNetworkFromStore(ep.network.id)
+}
+
+func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
 	if sbox == nil {
 		return types.BadRequestErrorf("endpoint cannot be joined by nil container")
 	}
@@ -212,15 +273,27 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
 		return types.BadRequestErrorf("not a valid Sandbox interface")
 	}
 
+	network, err := ep.getNetworkFromStore()
+	if err != nil {
+		return fmt.Errorf("failed to get network from store during join: %v", err)
+	}
+
+	ep, err = network.getEndpointFromStore(ep.ID())
+	if err != nil {
+		return fmt.Errorf("failed to get endpoint from store during join: %v", err)
+	}
+
 	ep.Lock()
 	if ep.sandboxID != "" {
 		ep.Unlock()
-		return types.ForbiddenErrorf("a sandbox has already joined the endpoint")
+		return types.ForbiddenErrorf("another container is attached to the same network endpoint")
 	}
+	ep.Unlock()
 
+	ep.Lock()
+	ep.network = network
 	ep.sandboxID = sbox.ID()
 	ep.joinInfo = &endpointJoinInfo{}
-	network := ep.network
 	epid := ep.id
 	ep.Unlock()
 	defer func() {
@@ -232,12 +305,16 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
 	}()
 
 	network.Lock()
-	driver := network.driver
 	nid := network.id
 	network.Unlock()
 
 	ep.processOptions(options...)
 
+	driver, err := network.driver()
+	if err != nil {
+		return fmt.Errorf("failed to join endpoint: %v", err)
+	}
+
 	err = driver.Join(nid, epid, sbox.Key(), ep, sbox.Labels())
 	if err != nil {
 		return err
@@ -259,14 +336,15 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
 		return err
 	}
 
-	if err = sb.updateDNS(ep.getNetwork().enableIPv6); err != nil {
+	// Watch for service records
+	network.getController().watchSvcRecord(ep)
+
+	if err = sb.updateDNS(network.enableIPv6); err != nil {
 		return err
 	}
 
-	if !ep.isLocalScoped() {
-		if err = network.ctrlr.updateToStore(ep); err != nil {
-			return err
-		}
+	if err = network.getController().updateToStore(ep); err != nil {
+		return err
 	}
 
 	sb.Lock()
@@ -324,6 +402,16 @@ func (ep *endpoint) sbLeave(sbox Sandbox, options ...EndpointOption) error {
 		return types.BadRequestErrorf("not a valid Sandbox interface")
 	}
 
+	n, err := ep.getNetworkFromStore()
+	if err != nil {
+		return fmt.Errorf("failed to get network from store during leave: %v", err)
+	}
+
+	ep, err = n.getEndpointFromStore(ep.ID())
+	if err != nil {
+		return fmt.Errorf("failed to get endpoint from store during leave: %v", err)
+	}
+
 	ep.Lock()
 	sid := ep.sandboxID
 	ep.Unlock()
@@ -339,21 +427,19 @@ func (ep *endpoint) sbLeave(sbox Sandbox, options ...EndpointOption) error {
 
 	ep.Lock()
 	ep.sandboxID = ""
-	n := ep.network
+	ep.network = n
 	ep.Unlock()
 
-	n.Lock()
-	c := n.ctrlr
-	d := n.driver
-	n.Unlock()
+	if err := n.getController().updateToStore(ep); err != nil {
+		ep.Lock()
+		ep.sandboxID = sid
+		ep.Unlock()
+		return err
+	}
 
-	if !ep.isLocalScoped() {
-		if err := c.updateToStore(ep); err != nil {
-			ep.Lock()
-			ep.sandboxID = sid
-			ep.Unlock()
-			return err
-		}
+	d, err := n.driver()
+	if err != nil {
+		return fmt.Errorf("failed to leave endpoint: %v", err)
 	}
 
 	if err := d.Leave(n.id, ep.id); err != nil {
@@ -364,6 +450,9 @@ func (ep *endpoint) sbLeave(sbox Sandbox, options ...EndpointOption) error {
 		return err
 	}
 
+	// unwatch for service records
+	n.getController().unWatchSvcRecord(ep)
+
 	if sb.needDefaultGW() {
 		ep := sb.getEPwithoutGateway()
 		if ep == nil {
@@ -376,45 +465,44 @@ func (ep *endpoint) sbLeave(sbox Sandbox, options ...EndpointOption) error {
 
 func (ep *endpoint) Delete() error {
 	var err error
+	n, err := ep.getNetworkFromStore()
+	if err != nil {
+		return fmt.Errorf("failed to get network during Delete: %v", err)
+	}
+
+	ep, err = n.getEndpointFromStore(ep.ID())
+	if err != nil {
+		return fmt.Errorf("failed to get endpoint from store during Delete: %v", err)
+	}
+
 	ep.Lock()
 	epid := ep.id
 	name := ep.name
-	n := ep.network
 	if ep.sandboxID != "" {
 		ep.Unlock()
 		return &ActiveContainerError{name: name, id: epid}
 	}
-	n.Lock()
-	ctrlr := n.ctrlr
-	n.Unlock()
 	ep.Unlock()
 
-	if !ep.isLocalScoped() {
-		if err = ctrlr.deleteFromStore(ep); err != nil {
-			return err
-		}
+	if err = n.getEpCnt().DecEndpointCnt(); err != nil {
+		return err
 	}
 	defer func() {
 		if err != nil {
-			ep.dbExists = false
-			if !ep.isLocalScoped() {
-				if e := ctrlr.updateToStore(ep); e != nil {
-					log.Warnf("failed to recreate endpoint in store %s : %v", name, e)
-				}
+			if e := n.getEpCnt().IncEndpointCnt(); e != nil {
+				log.Warnf("failed to update network %s : %v", n.name, e)
 			}
 		}
 	}()
 
-	// Update the endpoint count in network and update it in the datastore
-	n.DecEndpointCnt()
-	if err = ctrlr.updateToStore(n); err != nil {
+	if err = n.getController().deleteFromStore(ep); err != nil {
 		return err
 	}
 	defer func() {
 		if err != nil {
-			n.IncEndpointCnt()
-			if e := ctrlr.updateToStore(n); e != nil {
-				log.Warnf("failed to update network %s : %v", n.name, e)
+			ep.dbExists = false
+			if e := n.getController().updateToStore(ep); e != nil {
+				log.Warnf("failed to recreate endpoint in store %s : %v", name, e)
 			}
 		}
 	}()
@@ -423,6 +511,8 @@ func (ep *endpoint) Delete() error {
 		return err
 	}
 
+	ep.releaseAddress()
+
 	return nil
 }
 
@@ -433,38 +523,21 @@ func (ep *endpoint) deleteEndpoint() error {
 	epid := ep.id
 	ep.Unlock()
 
-	n.Lock()
-	_, ok := n.endpoints[epid]
-	if !ok {
-		n.Unlock()
-		return nil
+	driver, err := n.driver()
+	if err != nil {
+		return fmt.Errorf("failed to delete endpoint: %v", err)
 	}
 
-	nid := n.id
-	driver := n.driver
-	delete(n.endpoints, epid)
-	n.Unlock()
-
-	if err := driver.DeleteEndpoint(nid, epid); err != nil {
+	if err := driver.DeleteEndpoint(n.id, epid); err != nil {
 		if _, ok := err.(types.ForbiddenError); ok {
-			n.Lock()
-			n.endpoints[epid] = ep
-			n.Unlock()
 			return err
 		}
 		log.Warnf("driver error deleting endpoint %s : %v", name, err)
 	}
 
-	n.updateSvcRecord(ep, false)
 	return nil
 }
 
-func (ep *endpoint) getNetwork() *network {
-	ep.Lock()
-	defer ep.Unlock()
-	return ep.network
-}
-
 func (ep *endpoint) getSandbox() (*sandbox, bool) {
 	ep.Lock()
 	c := ep.network.getController()
@@ -482,7 +555,7 @@ func (ep *endpoint) getFirstInterfaceAddress() net.IP {
 	ep.Lock()
 	defer ep.Unlock()
 
-	if ep.iface != nil {
+	if ep.iface.addr != nil {
 		return ep.iface.addr.IP
 	}
 
@@ -540,12 +613,94 @@ func JoinOptionPriority(ep Endpoint, prio int) EndpointOption {
 	}
 }
 
-func (ep *endpoint) DataScope() datastore.DataScope {
-	ep.Lock()
-	defer ep.Unlock()
-	return ep.network.dataScope
+func (ep *endpoint) DataScope() string {
+	return ep.getNetwork().DataScope()
+}
+
+func (ep *endpoint) assignAddress() error {
+	var (
+		ipam ipamapi.Ipam
+		err  error
+	)
+
+	n := ep.getNetwork()
+	if n.Type() == "host" || n.Type() == "null" {
+		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)
+	if err != nil {
+		return err
+	}
+	err = ep.assignAddressVersion(4, ipam)
+	if err != nil {
+		return err
+	}
+	return ep.assignAddressVersion(6, ipam)
 }
 
-func (ep *endpoint) isLocalScoped() bool {
-	return ep.DataScope() == datastore.LocalScope
+func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error {
+	var (
+		poolID  *string
+		address **net.IPNet
+	)
+
+	n := ep.getNetwork()
+	switch ipVer {
+	case 4:
+		poolID = &ep.iface.v4PoolID
+		address = &ep.iface.addr
+	case 6:
+		poolID = &ep.iface.v6PoolID
+		address = &ep.iface.addrv6
+	default:
+		return types.InternalErrorf("incorrect ip version number passed: %d", ipVer)
+	}
+
+	ipInfo := n.getIPInfo(ipVer)
+
+	// ipv6 address is not mandatory
+	if len(ipInfo) == 0 && ipVer == 6 {
+		return nil
+	}
+
+	for _, d := range ipInfo {
+		addr, _, err := ipam.RequestAddress(d.PoolID, nil, nil)
+		if err == nil {
+			ep.Lock()
+			*address = addr
+			*poolID = d.PoolID
+			ep.Unlock()
+			return nil
+		}
+		if err != ipamapi.ErrNoAvailableIPs {
+			return err
+		}
+	}
+	return fmt.Errorf("no available IPv%d addresses on this network's address pools: %s (%s)", ipVer, n.Name(), n.ID())
+}
+
+func (ep *endpoint) releaseAddress() {
+	n := ep.getNetwork()
+	if n.Type() == "host" || n.Type() == "null" {
+		return
+	}
+
+	log.Debugf("Releasing addresses for endpoint %s's interface on network %s", ep.Name(), n.Name())
+
+	ipam, err := n.getController().getIpamDriver(n.ipamType)
+	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)
+		return
+	}
+	if err := ipam.ReleaseAddress(ep.iface.v4PoolID, ep.iface.addr.IP); err != nil {
+		log.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addr.IP, ep.Name(), ep.ID(), err)
+	}
+	if ep.iface.addrv6 != nil && ep.iface.addrv6.IP.IsGlobalUnicast() {
+		if err := ipam.ReleaseAddress(ep.iface.v6PoolID, ep.iface.addrv6.IP); err != nil {
+			log.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addrv6.IP, ep.Name(), ep.ID(), err)
+		}
+	}
 }

+ 147 - 0
vendor/src/github.com/docker/libnetwork/endpoint_cnt.go

@@ -0,0 +1,147 @@
+package libnetwork
+
+import (
+	"encoding/json"
+	"fmt"
+	"sync"
+
+	"github.com/docker/libnetwork/datastore"
+)
+
+type endpointCnt struct {
+	n        *network
+	Count    uint64
+	dbIndex  uint64
+	dbExists bool
+	sync.Mutex
+}
+
+const epCntKeyPrefix = "endpoint_count"
+
+func (ec *endpointCnt) Key() []string {
+	ec.Lock()
+	defer ec.Unlock()
+
+	return []string{epCntKeyPrefix, ec.n.id}
+}
+
+func (ec *endpointCnt) KeyPrefix() []string {
+	ec.Lock()
+	defer ec.Unlock()
+
+	return []string{epCntKeyPrefix, ec.n.id}
+}
+
+func (ec *endpointCnt) Value() []byte {
+	ec.Lock()
+	defer ec.Unlock()
+
+	b, err := json.Marshal(ec)
+	if err != nil {
+		return nil
+	}
+	return b
+}
+
+func (ec *endpointCnt) SetValue(value []byte) error {
+	ec.Lock()
+	defer ec.Unlock()
+
+	return json.Unmarshal(value, &ec)
+}
+
+func (ec *endpointCnt) Index() uint64 {
+	ec.Lock()
+	defer ec.Unlock()
+	return ec.dbIndex
+}
+
+func (ec *endpointCnt) SetIndex(index uint64) {
+	ec.Lock()
+	ec.dbIndex = index
+	ec.dbExists = true
+	ec.Unlock()
+}
+
+func (ec *endpointCnt) Exists() bool {
+	ec.Lock()
+	defer ec.Unlock()
+	return ec.dbExists
+}
+
+func (ec *endpointCnt) Skip() bool {
+	ec.Lock()
+	defer ec.Unlock()
+	return !ec.n.persist
+}
+
+func (ec *endpointCnt) New() datastore.KVObject {
+	ec.Lock()
+	defer ec.Unlock()
+
+	return &endpointCnt{
+		n: ec.n,
+	}
+}
+
+func (ec *endpointCnt) CopyTo(o datastore.KVObject) error {
+	ec.Lock()
+	defer ec.Unlock()
+
+	dstEc := o.(*endpointCnt)
+	dstEc.n = ec.n
+	dstEc.Count = ec.Count
+	dstEc.dbExists = ec.dbExists
+	dstEc.dbIndex = ec.dbIndex
+
+	return nil
+}
+
+func (ec *endpointCnt) DataScope() string {
+	return ec.n.DataScope()
+}
+
+func (ec *endpointCnt) EndpointCnt() uint64 {
+	ec.Lock()
+	defer ec.Unlock()
+
+	return ec.Count
+}
+
+func (ec *endpointCnt) atomicIncDecEpCnt(inc bool) error {
+retry:
+	ec.Lock()
+	if inc {
+		ec.Count++
+	} else {
+		ec.Count--
+	}
+	ec.Unlock()
+
+	store := ec.n.getController().getStore(ec.DataScope())
+	if store == nil {
+		return fmt.Errorf("store not found for scope %s", ec.DataScope())
+	}
+
+	if err := ec.n.getController().updateToStore(ec); err != nil {
+		if err == datastore.ErrKeyModified {
+			if err := store.GetObject(datastore.Key(ec.Key()...), ec); err != nil {
+				return fmt.Errorf("could not update the kvobject to latest when trying to atomic add endpoint count: %v", err)
+			}
+
+			goto retry
+		}
+
+		return err
+	}
+
+	return nil
+}
+
+func (ec *endpointCnt) IncEndpointCnt() error {
+	return ec.atomicIncDecEpCnt(true)
+}
+
+func (ec *endpointCnt) DecEndpointCnt() error {
+	return ec.atomicIncDecEpCnt(false)
+}

+ 109 - 45
vendor/src/github.com/docker/libnetwork/endpoint_info.go

@@ -2,6 +2,7 @@ package libnetwork
 
 import (
 	"encoding/json"
+	"fmt"
 	"net"
 
 	"github.com/docker/libnetwork/driverapi"
@@ -34,26 +35,34 @@ type InterfaceInfo interface {
 	MacAddress() net.HardwareAddr
 
 	// Address returns the IPv4 address assigned to the endpoint.
-	Address() net.IPNet
+	Address() *net.IPNet
 
 	// AddressIPv6 returns the IPv6 address assigned to the endpoint.
-	AddressIPv6() net.IPNet
+	AddressIPv6() *net.IPNet
 }
 
 type endpointInterface struct {
 	mac       net.HardwareAddr
-	addr      net.IPNet
-	addrv6    net.IPNet
+	addr      *net.IPNet
+	addrv6    *net.IPNet
 	srcName   string
 	dstPrefix string
 	routes    []*net.IPNet
+	v4PoolID  string
+	v6PoolID  string
 }
 
 func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
 	epMap := make(map[string]interface{})
-	epMap["mac"] = epi.mac.String()
-	epMap["addr"] = epi.addr.String()
-	epMap["addrv6"] = epi.addrv6.String()
+	if epi.mac != nil {
+		epMap["mac"] = epi.mac.String()
+	}
+	if epi.addr != nil {
+		epMap["addr"] = epi.addr.String()
+	}
+	if epi.addrv6 != nil {
+		epMap["addrv6"] = epi.addrv6.String()
+	}
 	epMap["srcName"] = epi.srcName
 	epMap["dstPrefix"] = epi.dstPrefix
 	var routes []string
@@ -61,28 +70,33 @@ func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
 		routes = append(routes, route.String())
 	}
 	epMap["routes"] = routes
+	epMap["v4PoolID"] = epi.v4PoolID
+	epMap["v6PoolID"] = epi.v6PoolID
 	return json.Marshal(epMap)
 }
 
-func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) {
-	var epMap map[string]interface{}
-	if err := json.Unmarshal(b, &epMap); err != nil {
+func (epi *endpointInterface) UnmarshalJSON(b []byte) error {
+	var (
+		err   error
+		epMap map[string]interface{}
+	)
+	if err = json.Unmarshal(b, &epMap); err != nil {
 		return err
 	}
-
-	mac, _ := net.ParseMAC(epMap["mac"].(string))
-	epi.mac = mac
-
-	ip, ipnet, _ := net.ParseCIDR(epMap["addr"].(string))
-	if ipnet != nil {
-		ipnet.IP = ip
-		epi.addr = *ipnet
+	if v, ok := epMap["mac"]; ok {
+		if epi.mac, err = net.ParseMAC(v.(string)); err != nil {
+			return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string))
+		}
 	}
-
-	ip, ipnet, _ = net.ParseCIDR(epMap["addrv6"].(string))
-	if ipnet != nil {
-		ipnet.IP = ip
-		epi.addrv6 = *ipnet
+	if v, ok := epMap["addr"]; ok {
+		if epi.addr, err = types.ParseCIDR(v.(string)); err != nil {
+			return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err)
+		}
+	}
+	if v, ok := epMap["addrv6"]; ok {
+		if epi.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
+			return types.InternalErrorf("failed to decode endpoint interface ipv6 address after json unmarshal: %v", err)
+		}
 	}
 
 	epi.srcName = epMap["srcName"].(string)
@@ -99,6 +113,24 @@ func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) {
 			epi.routes = append(epi.routes, ipr)
 		}
 	}
+	epi.v4PoolID = epMap["v4PoolID"].(string)
+	epi.v6PoolID = epMap["v6PoolID"].(string)
+
+	return nil
+}
+
+func (epi *endpointInterface) CopyTo(dstEpi *endpointInterface) error {
+	dstEpi.mac = types.GetMacCopy(epi.mac)
+	dstEpi.addr = types.GetIPNetCopy(epi.addr)
+	dstEpi.addrv6 = types.GetIPNetCopy(epi.addrv6)
+	dstEpi.srcName = epi.srcName
+	dstEpi.dstPrefix = epi.dstPrefix
+	dstEpi.v4PoolID = epi.v4PoolID
+	dstEpi.v6PoolID = epi.v6PoolID
+
+	for _, route := range epi.routes {
+		dstEpi.routes = append(dstEpi.routes, types.GetIPNetCopy(route))
+	}
 
 	return nil
 }
@@ -110,21 +142,38 @@ type endpointJoinInfo struct {
 }
 
 func (ep *endpoint) Info() EndpointInfo {
-	return ep
+	n, err := ep.getNetworkFromStore()
+	if err != nil {
+		return nil
+	}
+
+	ep, err = n.getEndpointFromStore(ep.ID())
+	if err != nil {
+		return nil
+	}
+
+	sb, ok := ep.getSandbox()
+	if !ok {
+		// endpoint hasn't joined any sandbox.
+		// Just return the endpoint
+		return ep
+	}
+
+	return sb.getEndpoint(ep.ID())
 }
 
 func (ep *endpoint) DriverInfo() (map[string]interface{}, error) {
-	ep.Lock()
-	network := ep.network
-	epid := ep.id
-	ep.Unlock()
+	n, err := ep.getNetworkFromStore()
+	if err != nil {
+		return nil, fmt.Errorf("could not find network in store for driver info: %v", err)
+	}
 
-	network.Lock()
-	driver := network.driver
-	nid := network.id
-	network.Unlock()
+	driver, err := n.driver()
+	if err != nil {
+		return nil, fmt.Errorf("failed to get driver info: %v", err)
+	}
 
-	return driver.EndpointOperInfo(nid, epid)
+	return driver.EndpointOperInfo(n.ID(), ep.ID())
 }
 
 func (ep *endpoint) Iface() InterfaceInfo {
@@ -149,17 +198,32 @@ func (ep *endpoint) Interface() driverapi.InterfaceInfo {
 	return nil
 }
 
-func (ep *endpoint) AddInterface(mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error {
-	ep.Lock()
-	defer ep.Unlock()
+func (epi *endpointInterface) SetMacAddress(mac net.HardwareAddr) error {
+	if epi.mac != nil {
+		return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", epi.mac, mac)
+	}
+	if mac == nil {
+		return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
+	}
+	epi.mac = types.GetMacCopy(mac)
+	return nil
+}
 
-	iface := &endpointInterface{
-		addr:   *types.GetIPNetCopy(&ipv4),
-		addrv6: *types.GetIPNetCopy(&ipv6),
+func (epi *endpointInterface) SetIPAddress(address *net.IPNet) error {
+	if address.IP == nil {
+		return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
+	}
+	if address.IP.To4() == nil {
+		return setAddress(&epi.addrv6, address)
 	}
-	iface.mac = types.GetMacCopy(mac)
+	return setAddress(&epi.addr, address)
+}
 
-	ep.iface = iface
+func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
+	if *ifaceAddr != nil {
+		return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
+	}
+	*ifaceAddr = types.GetIPNetCopy(address)
 	return nil
 }
 
@@ -167,12 +231,12 @@ func (epi *endpointInterface) MacAddress() net.HardwareAddr {
 	return types.GetMacCopy(epi.mac)
 }
 
-func (epi *endpointInterface) Address() net.IPNet {
-	return (*types.GetIPNetCopy(&epi.addr))
+func (epi *endpointInterface) Address() *net.IPNet {
+	return types.GetIPNetCopy(epi.addr)
 }
 
-func (epi *endpointInterface) AddressIPv6() net.IPNet {
-	return (*types.GetIPNetCopy(&epi.addrv6))
+func (epi *endpointInterface) AddressIPv6() *net.IPNet {
+	return types.GetIPNetCopy(epi.addrv6)
 }
 
 func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {

+ 1 - 1
vendor/src/github.com/docker/libnetwork/error.go

@@ -129,7 +129,7 @@ type ActiveEndpointsError struct {
 }
 
 func (aee *ActiveEndpointsError) Error() string {
-	return fmt.Sprintf("network with name %s id %s has active endpoints", aee.name, aee.id)
+	return fmt.Sprintf("network %s has active endpoints", aee.name)
 }
 
 // Forbidden denotes the type of this error

+ 6 - 6
vendor/src/github.com/docker/libnetwork/idm/idm.go

@@ -10,13 +10,13 @@ import (
 
 // Idm manages the reservation/release of numerical ids from a contiguos set
 type Idm struct {
-	start  uint32
-	end    uint32
+	start  uint64
+	end    uint64
 	handle *bitseq.Handle
 }
 
 // New returns an instance of id manager for a set of [start-end] numerical ids
-func New(ds datastore.DataStore, id string, start, end uint32) (*Idm, error) {
+func New(ds datastore.DataStore, id string, start, end uint64) (*Idm, error) {
 	if id == "" {
 		return nil, fmt.Errorf("Invalid id")
 	}
@@ -33,7 +33,7 @@ func New(ds datastore.DataStore, id string, start, end uint32) (*Idm, error) {
 }
 
 // GetID returns the first available id in the set
-func (i *Idm) GetID() (uint32, error) {
+func (i *Idm) GetID() (uint64, error) {
 	if i.handle == nil {
 		return 0, fmt.Errorf("ID set is not initialized")
 	}
@@ -42,7 +42,7 @@ func (i *Idm) GetID() (uint32, error) {
 }
 
 // GetSpecificID tries to reserve the specified id
-func (i *Idm) GetSpecificID(id uint32) error {
+func (i *Idm) GetSpecificID(id uint64) error {
 	if i.handle == nil {
 		return fmt.Errorf("ID set is not initialized")
 	}
@@ -55,6 +55,6 @@ func (i *Idm) GetSpecificID(id uint32) error {
 }
 
 // Release releases the specified id
-func (i *Idm) Release(id uint32) {
+func (i *Idm) Release(id uint64) {
 	i.handle.Unset(id - i.start)
 }

+ 0 - 175
vendor/src/github.com/docker/libnetwork/ipallocator/allocator.go

@@ -1,175 +0,0 @@
-// Package ipallocator defines the default IP allocator. It will move out of libnetwork as an external IPAM plugin.
-// This has been imported unchanged from Docker, besides additon of registration logic
-package ipallocator
-
-import (
-	"errors"
-	"math/big"
-	"net"
-	"sync"
-
-	"github.com/Sirupsen/logrus"
-	"github.com/docker/libnetwork/netutils"
-)
-
-// allocatedMap is thread-unsafe set of allocated IP
-type allocatedMap struct {
-	p     map[string]struct{}
-	last  *big.Int
-	begin *big.Int
-	end   *big.Int
-}
-
-func newAllocatedMap(network *net.IPNet) *allocatedMap {
-	firstIP, lastIP := netutils.NetworkRange(network)
-	begin := big.NewInt(0).Add(ipToBigInt(firstIP), big.NewInt(1))
-	end := big.NewInt(0).Sub(ipToBigInt(lastIP), big.NewInt(1))
-
-	return &allocatedMap{
-		p:     make(map[string]struct{}),
-		begin: begin,
-		end:   end,
-		last:  big.NewInt(0).Sub(begin, big.NewInt(1)), // so first allocated will be begin
-	}
-}
-
-type networkSet map[string]*allocatedMap
-
-var (
-	// ErrNoAvailableIPs preformatted error
-	ErrNoAvailableIPs = errors.New("no available ip addresses on network")
-	// ErrIPAlreadyAllocated preformatted error
-	ErrIPAlreadyAllocated = errors.New("ip already allocated")
-	// ErrIPOutOfRange preformatted error
-	ErrIPOutOfRange = errors.New("requested ip is out of range")
-	// ErrNetworkAlreadyRegistered preformatted error
-	ErrNetworkAlreadyRegistered = errors.New("network already registered")
-	// ErrBadSubnet preformatted error
-	ErrBadSubnet = errors.New("network does not contain specified subnet")
-)
-
-// IPAllocator manages the ipam
-type IPAllocator struct {
-	allocatedIPs networkSet
-	mutex        sync.Mutex
-}
-
-// New returns a new instance of IPAllocator
-func New() *IPAllocator {
-	return &IPAllocator{networkSet{}, sync.Mutex{}}
-}
-
-// RegisterSubnet registers network in global allocator with bounds
-// defined by subnet. If you want to use network range you must call
-// this method before first RequestIP, otherwise full network range will be used
-func (a *IPAllocator) RegisterSubnet(network *net.IPNet, subnet *net.IPNet) error {
-	a.mutex.Lock()
-	defer a.mutex.Unlock()
-
-	nw := &net.IPNet{IP: network.IP.Mask(network.Mask), Mask: network.Mask}
-	key := nw.String()
-	if _, ok := a.allocatedIPs[key]; ok {
-		return ErrNetworkAlreadyRegistered
-	}
-
-	// Check that subnet is within network
-	beginIP, endIP := netutils.NetworkRange(subnet)
-	if !(network.Contains(beginIP) && network.Contains(endIP)) {
-		return ErrBadSubnet
-	}
-
-	n := newAllocatedMap(subnet)
-	a.allocatedIPs[key] = n
-	return nil
-}
-
-// RequestIP requests an available ip from the given network.  It
-// will return the next available ip if the ip provided is nil.  If the
-// ip provided is not nil it will validate that the provided ip is available
-// for use or return an error
-func (a *IPAllocator) RequestIP(network *net.IPNet, ip net.IP) (net.IP, error) {
-	a.mutex.Lock()
-	defer a.mutex.Unlock()
-
-	nw := &net.IPNet{IP: network.IP.Mask(network.Mask), Mask: network.Mask}
-	key := nw.String()
-	allocated, ok := a.allocatedIPs[key]
-	if !ok {
-		allocated = newAllocatedMap(nw)
-		a.allocatedIPs[key] = allocated
-	}
-
-	if ip == nil {
-		return allocated.getNextIP()
-	}
-	return allocated.checkIP(ip)
-}
-
-// ReleaseIP adds the provided ip back into the pool of
-// available ips to be returned for use.
-func (a *IPAllocator) ReleaseIP(network *net.IPNet, ip net.IP) error {
-	a.mutex.Lock()
-	defer a.mutex.Unlock()
-
-	nw := &net.IPNet{IP: network.IP.Mask(network.Mask), Mask: network.Mask}
-	if allocated, exists := a.allocatedIPs[nw.String()]; exists {
-		delete(allocated.p, ip.String())
-	}
-	return nil
-}
-
-func (allocated *allocatedMap) checkIP(ip net.IP) (net.IP, error) {
-	if _, ok := allocated.p[ip.String()]; ok {
-		return nil, ErrIPAlreadyAllocated
-	}
-
-	pos := ipToBigInt(ip)
-	// Verify that the IP address is within our network range.
-	if pos.Cmp(allocated.begin) == -1 || pos.Cmp(allocated.end) == 1 {
-		return nil, ErrIPOutOfRange
-	}
-
-	// Register the IP.
-	allocated.p[ip.String()] = struct{}{}
-
-	return ip, nil
-}
-
-// return an available ip if one is currently available.  If not,
-// return the next available ip for the network
-func (allocated *allocatedMap) getNextIP() (net.IP, error) {
-	pos := big.NewInt(0).Set(allocated.last)
-	allRange := big.NewInt(0).Sub(allocated.end, allocated.begin)
-	for i := big.NewInt(0); i.Cmp(allRange) <= 0; i.Add(i, big.NewInt(1)) {
-		pos.Add(pos, big.NewInt(1))
-		if pos.Cmp(allocated.end) == 1 {
-			pos.Set(allocated.begin)
-		}
-		if _, ok := allocated.p[bigIntToIP(pos).String()]; ok {
-			continue
-		}
-		allocated.p[bigIntToIP(pos).String()] = struct{}{}
-		allocated.last.Set(pos)
-		return bigIntToIP(pos), nil
-	}
-	return nil, ErrNoAvailableIPs
-}
-
-// Converts a 4 bytes IP into a 128 bit integer
-func ipToBigInt(ip net.IP) *big.Int {
-	x := big.NewInt(0)
-	if ip4 := ip.To4(); ip4 != nil {
-		return x.SetBytes(ip4)
-	}
-	if ip6 := ip.To16(); ip6 != nil {
-		return x.SetBytes(ip6)
-	}
-
-	logrus.Errorf("ipToBigInt: Wrong IP length! %s", ip)
-	return nil
-}
-
-// Converts 128 bit integer into a 4 bytes IP address
-func bigIntToIP(v *big.Int) net.IP {
-	return net.IP(v.Bytes())
-}

+ 510 - 0
vendor/src/github.com/docker/libnetwork/ipam/allocator.go

@@ -0,0 +1,510 @@
+package ipam
+
+import (
+	"fmt"
+	"net"
+	"sync"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/bitseq"
+	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/ipamutils"
+	"github.com/docker/libnetwork/types"
+)
+
+const (
+	localAddressSpace  = "LocalDefault"
+	globalAddressSpace = "GlobalDefault"
+	// The biggest configurable host subnets
+	minNetSize   = 8
+	minNetSizeV6 = 64
+	// datastore keyes for ipam objects
+	dsConfigKey = "ipam/" + ipamapi.DefaultIPAM + "/config"
+	dsDataKey   = "ipam/" + ipamapi.DefaultIPAM + "/data"
+)
+
+// Allocator provides per address space ipv4/ipv6 book keeping
+type Allocator struct {
+	// Predefined pools for default address spaces
+	predefined map[string][]*net.IPNet
+	addrSpaces map[string]*addrSpace
+	// stores        []datastore.Datastore
+	// Allocated addresses in each address space's subnet
+	addresses map[SubnetKey]*bitseq.Handle
+	sync.Mutex
+}
+
+// NewAllocator returns an instance of libnetwork ipam
+func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
+	a := &Allocator{}
+
+	// Load predefined subnet pools
+	a.predefined = map[string][]*net.IPNet{
+		localAddressSpace:  ipamutils.PredefinedBroadNetworks,
+		globalAddressSpace: ipamutils.PredefinedGranularNetworks,
+	}
+
+	// Initialize bitseq map
+	a.addresses = make(map[SubnetKey]*bitseq.Handle)
+
+	// Initialize address spaces
+	a.addrSpaces = make(map[string]*addrSpace)
+	for _, aspc := range []struct {
+		as string
+		ds datastore.DataStore
+	}{
+		{localAddressSpace, lcDs},
+		{globalAddressSpace, glDs},
+	} {
+		if aspc.ds == nil {
+			continue
+		}
+
+		a.addrSpaces[aspc.as] = &addrSpace{
+			subnets: map[SubnetKey]*PoolData{},
+			id:      dsConfigKey + "/" + aspc.as,
+			scope:   aspc.ds.Scope(),
+			ds:      aspc.ds,
+			alloc:   a,
+		}
+	}
+
+	return a, nil
+}
+
+func (a *Allocator) refresh(as string) error {
+	aSpace, err := a.getAddressSpaceFromStore(as)
+	if err != nil {
+		return fmt.Errorf("error getting pools config from store during init: %v",
+			err)
+	}
+
+	if aSpace == nil {
+		return nil
+	}
+
+	if err := a.updateBitMasks(aSpace); err != nil {
+		return fmt.Errorf("error updating bit masks during init: %v", err)
+	}
+
+	a.Lock()
+	a.addrSpaces[as] = aSpace
+	a.Unlock()
+
+	return nil
+}
+
+func (a *Allocator) updateBitMasks(aSpace *addrSpace) error {
+	var inserterList []func() error
+
+	aSpace.Lock()
+	for k, v := range aSpace.subnets {
+		if v.Range == nil {
+			kk := k
+			vv := v
+			inserterList = append(inserterList, func() error { return a.insertBitMask(kk, vv.Pool) })
+		}
+	}
+	aSpace.Unlock()
+
+	// Add the bitmasks (data could come from datastore)
+	if inserterList != nil {
+		for _, f := range inserterList {
+			if err := f(); err != nil {
+				return err
+			}
+		}
+	}
+
+	return nil
+}
+
+// GetDefaultAddressSpaces returns the local and global default address spaces
+func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) {
+	return localAddressSpace, globalAddressSpace, nil
+}
+
+// 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) {
+	log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6)
+	k, nw, ipr, err := a.parsePoolRequest(addressSpace, pool, subPool, v6)
+	if err != nil {
+		return "", nil, nil, types.InternalErrorf("failed to parse pool request for address space %q pool %q subpool %q: %v", addressSpace, pool, subPool, err)
+	}
+
+retry:
+	if err := a.refresh(addressSpace); err != nil {
+		return "", nil, nil, err
+	}
+
+	aSpace, err := a.getAddrSpace(addressSpace)
+	if err != nil {
+		return "", nil, nil, err
+	}
+
+	insert, err := aSpace.updatePoolDBOnAdd(*k, nw, ipr)
+	if err != nil {
+		return "", nil, nil, err
+	}
+
+	if err := a.writeToStore(aSpace); err != nil {
+		if _, ok := err.(types.RetryError); !ok {
+			return "", nil, nil, types.InternalErrorf("pool configuration failed because of %s", err.Error())
+		}
+
+		goto retry
+	}
+
+	return k.String(), nw, nil, insert()
+}
+
+// ReleasePool releases the address pool identified by the passed id
+func (a *Allocator) ReleasePool(poolID string) error {
+	log.Debugf("ReleasePool(%s)", poolID)
+	k := SubnetKey{}
+	if err := k.FromString(poolID); err != nil {
+		return types.BadRequestErrorf("invalid pool id: %s", poolID)
+	}
+
+retry:
+	if err := a.refresh(k.AddressSpace); err != nil {
+		return err
+	}
+
+	aSpace, err := a.getAddrSpace(k.AddressSpace)
+	if err != nil {
+		return err
+	}
+
+	remove, err := aSpace.updatePoolDBOnRemoval(k)
+	if err != nil {
+		return err
+	}
+
+	if err = a.writeToStore(aSpace); err != nil {
+		if _, ok := err.(types.RetryError); !ok {
+			return types.InternalErrorf("pool (%s) removal failed because of %v", poolID, err)
+		}
+		goto retry
+	}
+
+	return remove()
+}
+
+// Given the address space, returns the local or global PoolConfig based on the
+// address space is local or global. AddressSpace locality is being registered with IPAM out of band.
+func (a *Allocator) getAddrSpace(as string) (*addrSpace, error) {
+	a.Lock()
+	defer a.Unlock()
+	aSpace, ok := a.addrSpaces[as]
+	if !ok {
+		return nil, types.BadRequestErrorf("cannot find address space %s (most likey the backing datastore is not configured)", as)
+	}
+	return aSpace, nil
+}
+
+func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool) (*SubnetKey, *net.IPNet, *AddressRange, error) {
+	var (
+		nw  *net.IPNet
+		ipr *AddressRange
+		err error
+	)
+
+	if addressSpace == "" {
+		return nil, nil, nil, ipamapi.ErrInvalidAddressSpace
+	}
+
+	if pool == "" && subPool != "" {
+		return nil, nil, nil, ipamapi.ErrInvalidSubPool
+	}
+
+	if pool != "" {
+		if _, nw, err = net.ParseCIDR(pool); err != nil {
+			return nil, nil, nil, ipamapi.ErrInvalidPool
+		}
+		if subPool != "" {
+			if ipr, err = getAddressRange(subPool); err != nil {
+				return nil, nil, nil, err
+			}
+		}
+	} else {
+		if nw, err = a.getPredefinedPool(addressSpace, v6); err != nil {
+			return nil, nil, nil, err
+		}
+
+	}
+
+	return &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String(), ChildSubnet: subPool}, nw, ipr, nil
+}
+
+func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
+	//log.Debugf("Inserting bitmask (%s, %s)", key.String(), pool.String())
+
+	store := a.getStore(key.AddressSpace)
+	if store == nil {
+		return fmt.Errorf("could not find store for address space %s while inserting bit mask", key.AddressSpace)
+	}
+
+	ipVer := getAddressVersion(pool.IP)
+	ones, bits := pool.Mask.Size()
+	numAddresses := uint64(1 << uint(bits-ones))
+
+	if ipVer == v4 {
+		// Do not let broadcast address be reserved
+		numAddresses--
+	}
+
+	// Allow /64 subnet
+	if ipVer == v6 && numAddresses == 0 {
+		numAddresses--
+	}
+
+	// Generate the new address masks. AddressMask content may come from datastore
+	h, err := bitseq.NewHandle(dsDataKey, store, key.String(), numAddresses)
+	if err != nil {
+		return err
+	}
+
+	// Do not let network identifier address be reserved
+	// Do the same for IPv6 so that bridge ip starts with XXXX...::1
+	h.Set(0)
+
+	a.Lock()
+	a.addresses[key] = h
+	a.Unlock()
+	return nil
+}
+
+func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle, error) {
+	a.Lock()
+	bm, ok := a.addresses[k]
+	a.Unlock()
+	if !ok {
+		log.Debugf("Retrieving bitmask (%s, %s)", k.String(), n.String())
+		if err := a.insertBitMask(k, n); err != nil {
+			return nil, fmt.Errorf("could not find bitmask in datastore for %s", k.String())
+		}
+		a.Lock()
+		bm = a.addresses[k]
+		a.Unlock()
+	}
+	return bm, nil
+}
+
+func (a *Allocator) getPredefineds(as string) []*net.IPNet {
+	a.Lock()
+	defer a.Unlock()
+	l := make([]*net.IPNet, 0, len(a.predefined[as]))
+	for _, pool := range a.predefined[as] {
+		l = append(l, pool)
+	}
+	return l
+}
+
+func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) {
+	var v ipVersion
+	v = v4
+	if ipV6 {
+		v = v6
+	}
+
+	if as != localAddressSpace && as != globalAddressSpace {
+		return nil, fmt.Errorf("no default pool availbale for non-default addresss spaces")
+	}
+
+	aSpace, err := a.getAddrSpace(as)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, nw := range a.getPredefineds(as) {
+		if v != getAddressVersion(nw.IP) {
+			continue
+		}
+		aSpace.Lock()
+		_, ok := aSpace.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]
+		aSpace.Unlock()
+		if ok {
+			continue
+		}
+
+		if !aSpace.contains(as, nw) {
+			if as == localAddressSpace {
+				// Check if nw overlap with system routes, name servers
+				if _, err := ipamutils.FindAvailableNetwork([]*net.IPNet{nw}); err == nil {
+					return nw, nil
+				}
+				continue
+			}
+			return nw, nil
+		}
+	}
+
+	return nil, types.NotFoundErrorf("could not find an available predefined network")
+}
+
+// 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) {
+	log.Debugf("RequestAddress(%s, %v, %v)", poolID, prefAddress, opts)
+	k := SubnetKey{}
+	if err := k.FromString(poolID); err != nil {
+		return nil, nil, types.BadRequestErrorf("invalid pool id: %s", poolID)
+	}
+
+	if err := a.refresh(k.AddressSpace); err != nil {
+		return nil, nil, err
+	}
+
+	aSpace, err := a.getAddrSpace(k.AddressSpace)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	aSpace.Lock()
+	p, ok := aSpace.subnets[k]
+	if !ok {
+		aSpace.Unlock()
+		return nil, nil, types.NotFoundErrorf("cannot find address pool for poolID:%s", poolID)
+	}
+
+	if prefAddress != nil && !p.Pool.Contains(prefAddress) {
+		aSpace.Unlock()
+		return nil, nil, ipamapi.ErrIPOutOfRange
+	}
+
+	c := p
+	for c.Range != nil {
+		k = c.ParentKey
+		c, ok = aSpace.subnets[k]
+	}
+	aSpace.Unlock()
+
+	bm, err := a.retrieveBitmask(k, c.Pool)
+	if err != nil {
+		return nil, nil, fmt.Errorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
+			k.String(), prefAddress, poolID, err)
+	}
+	ip, err := a.getAddress(p.Pool, bm, prefAddress, p.Range)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	return &net.IPNet{IP: ip, Mask: p.Pool.Mask}, nil, nil
+}
+
+// ReleaseAddress releases the address from the specified pool ID
+func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
+	log.Debugf("ReleaseAddress(%s, %v)", poolID, address)
+	k := SubnetKey{}
+	if err := k.FromString(poolID); err != nil {
+		return types.BadRequestErrorf("invalid pool id: %s", poolID)
+	}
+
+	if err := a.refresh(k.AddressSpace); err != nil {
+		return err
+	}
+
+	aSpace, err := a.getAddrSpace(k.AddressSpace)
+	if err != nil {
+		return err
+	}
+
+	aSpace.Lock()
+	p, ok := aSpace.subnets[k]
+	if !ok {
+		aSpace.Unlock()
+		return ipamapi.ErrBadPool
+	}
+
+	if address == nil {
+		aSpace.Unlock()
+		return ipamapi.ErrInvalidRequest
+	}
+
+	if !p.Pool.Contains(address) {
+		aSpace.Unlock()
+		return ipamapi.ErrIPOutOfRange
+	}
+
+	c := p
+	for c.Range != nil {
+		k = c.ParentKey
+		c = aSpace.subnets[k]
+	}
+	aSpace.Unlock()
+
+	mask := p.Pool.Mask
+	if p.Range != nil {
+		mask = p.Range.Sub.Mask
+	}
+
+	h, err := types.GetHostPartIP(address, mask)
+	if err != nil {
+		return fmt.Errorf("failed to release address %s: %v", address.String(), err)
+	}
+
+	bm, err := a.retrieveBitmask(k, c.Pool)
+	if err != nil {
+		return fmt.Errorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v",
+			k.String(), address, poolID, err)
+	}
+
+	return bm.Unset(ipToUint64(h))
+}
+
+func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddress net.IP, ipr *AddressRange) (net.IP, error) {
+	var (
+		ordinal uint64
+		err     error
+		base    *net.IPNet
+	)
+
+	base = types.GetIPNetCopy(nw)
+
+	if bitmask.Unselected() <= 0 {
+		return nil, ipamapi.ErrNoAvailableIPs
+	}
+	if ipr == nil && prefAddress == nil {
+		ordinal, err = bitmask.SetAny()
+	} else if prefAddress != nil {
+		hostPart, e := types.GetHostPartIP(prefAddress, base.Mask)
+		if e != nil {
+			return nil, fmt.Errorf("failed to allocate preferred address %s: %v", prefAddress.String(), e)
+		}
+		ordinal = ipToUint64(types.GetMinimalIP(hostPart))
+		err = bitmask.Set(ordinal)
+	} else {
+		base.IP = ipr.Sub.IP
+		ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End)
+	}
+	if err != nil {
+		return nil, ipamapi.ErrNoAvailableIPs
+	}
+
+	// Convert IP ordinal for this subnet into IP address
+	return generateAddress(ordinal, base), nil
+}
+
+// DumpDatabase dumps the internal info
+func (a *Allocator) DumpDatabase() string {
+	a.Lock()
+	defer a.Unlock()
+
+	var s string
+	for as, aSpace := range a.addrSpaces {
+		s = fmt.Sprintf("\n\n%s Config", as)
+		aSpace.Lock()
+		for k, config := range aSpace.subnets {
+			s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
+		}
+		aSpace.Unlock()
+	}
+
+	s = fmt.Sprintf("%s\n\nBitmasks", s)
+	for k, bm := range a.addresses {
+		s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n\t%s: %s\n\t%d", k, bm, bm.Unselected()))
+	}
+
+	return s
+}

+ 131 - 0
vendor/src/github.com/docker/libnetwork/ipam/store.go

@@ -0,0 +1,131 @@
+package ipam
+
+import (
+	"encoding/json"
+	"fmt"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/types"
+)
+
+// Key provides the Key to be used in KV Store
+func (aSpace *addrSpace) Key() []string {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+	return []string{aSpace.id}
+}
+
+// KeyPrefix returns the immediate parent key that can be used for tree walk
+func (aSpace *addrSpace) KeyPrefix() []string {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+	return []string{dsConfigKey}
+}
+
+// Value marshals the data to be stored in the KV store
+func (aSpace *addrSpace) Value() []byte {
+	b, err := json.Marshal(aSpace)
+	if err != nil {
+		log.Warnf("Failed to marshal ipam configured pools: %v", err)
+		return nil
+	}
+	return b
+}
+
+// SetValue unmarshalls the data from the KV store.
+func (aSpace *addrSpace) SetValue(value []byte) error {
+	rc := &addrSpace{subnets: make(map[SubnetKey]*PoolData)}
+	if err := json.Unmarshal(value, rc); err != nil {
+		return err
+	}
+	aSpace.subnets = rc.subnets
+	return nil
+}
+
+// Index returns the latest DB Index as seen by this object
+func (aSpace *addrSpace) Index() uint64 {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+	return aSpace.dbIndex
+}
+
+// SetIndex method allows the datastore to store the latest DB Index into this object
+func (aSpace *addrSpace) SetIndex(index uint64) {
+	aSpace.Lock()
+	aSpace.dbIndex = index
+	aSpace.dbExists = true
+	aSpace.Unlock()
+}
+
+// Exists method is true if this object has been stored in the DB.
+func (aSpace *addrSpace) Exists() bool {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+	return aSpace.dbExists
+}
+
+// Skip provides a way for a KV Object to avoid persisting it in the KV Store
+func (aSpace *addrSpace) Skip() bool {
+	return false
+}
+
+func (a *Allocator) getStore(as string) datastore.DataStore {
+	a.Lock()
+	defer a.Unlock()
+
+	if aSpace, ok := a.addrSpaces[as]; ok {
+		return aSpace.ds
+	}
+
+	return nil
+}
+
+func (a *Allocator) getAddressSpaceFromStore(as string) (*addrSpace, error) {
+	store := a.getStore(as)
+	if store == nil {
+		return nil, fmt.Errorf("store for address space %s not found", as)
+	}
+
+	pc := &addrSpace{id: dsConfigKey + "/" + as, ds: store, alloc: a}
+	if err := store.GetObject(datastore.Key(pc.Key()...), pc); err != nil {
+		if err == datastore.ErrKeyNotFound {
+			return nil, nil
+		}
+
+		return nil, fmt.Errorf("could not get pools config from store: %v", err)
+	}
+
+	return pc, nil
+}
+
+func (a *Allocator) writeToStore(aSpace *addrSpace) error {
+	store := aSpace.store()
+	if store == nil {
+		return fmt.Errorf("invalid store while trying to write %s address space", aSpace.DataScope())
+	}
+
+	err := store.PutObjectAtomic(aSpace)
+	if err == datastore.ErrKeyModified {
+		return types.RetryErrorf("failed to perform atomic write (%v). retry might fix the error", err)
+	}
+
+	return err
+}
+
+func (a *Allocator) deleteFromStore(aSpace *addrSpace) error {
+	store := aSpace.store()
+	if store == nil {
+		return fmt.Errorf("invalid store while trying to delete %s address space", aSpace.DataScope())
+	}
+
+	return store.DeleteObjectAtomic(aSpace)
+}
+
+// DataScope method returns the storage scope of the datastore
+func (aSpace *addrSpace) DataScope() string {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+
+	return aSpace.scope
+}

+ 359 - 0
vendor/src/github.com/docker/libnetwork/ipam/structures.go

@@ -0,0 +1,359 @@
+package ipam
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"strings"
+	"sync"
+
+	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/types"
+)
+
+// SubnetKey is the pointer to the configured pools in each address space
+type SubnetKey struct {
+	AddressSpace string
+	Subnet       string
+	ChildSubnet  string
+}
+
+// PoolData contains the configured pool data
+type PoolData struct {
+	ParentKey SubnetKey
+	Pool      *net.IPNet
+	Range     *AddressRange `json:",omitempty"`
+	RefCount  int
+}
+
+// addrSpace contains the pool configurations for the address space
+type addrSpace struct {
+	subnets  map[SubnetKey]*PoolData
+	dbIndex  uint64
+	dbExists bool
+	id       string
+	scope    string
+	ds       datastore.DataStore
+	alloc    *Allocator
+	sync.Mutex
+}
+
+// AddressRange specifies first and last ip ordinal which
+// identify a range in a a pool of addresses
+type AddressRange struct {
+	Sub        *net.IPNet
+	Start, End uint64
+}
+
+// String returns the string form of the AddressRange object
+func (r *AddressRange) String() string {
+	return fmt.Sprintf("Sub: %s, range [%d, %d]", r.Sub, r.Start, r.End)
+}
+
+// MarshalJSON returns the JSON encoding of the Range object
+func (r *AddressRange) MarshalJSON() ([]byte, error) {
+	m := map[string]interface{}{
+		"Sub":   r.Sub.String(),
+		"Start": r.Start,
+		"End":   r.End,
+	}
+	return json.Marshal(m)
+}
+
+// UnmarshalJSON decodes data into the Range object
+func (r *AddressRange) UnmarshalJSON(data []byte) error {
+	m := map[string]interface{}{}
+	err := json.Unmarshal(data, &m)
+	if err != nil {
+		return err
+	}
+	if r.Sub, err = types.ParseCIDR(m["Sub"].(string)); err != nil {
+		return err
+	}
+	r.Start = uint64(m["Start"].(float64))
+	r.End = uint64(m["End"].(float64))
+	return nil
+}
+
+// String returns the string form of the SubnetKey object
+func (s *SubnetKey) String() string {
+	k := fmt.Sprintf("%s/%s", s.AddressSpace, s.Subnet)
+	if s.ChildSubnet != "" {
+		k = fmt.Sprintf("%s/%s", k, s.ChildSubnet)
+	}
+	return k
+}
+
+// FromString populate the SubnetKey object reading it from string
+func (s *SubnetKey) FromString(str string) error {
+	if str == "" || !strings.Contains(str, "/") {
+		return fmt.Errorf("invalid string form for subnetkey: %s", str)
+	}
+
+	p := strings.Split(str, "/")
+	if len(p) != 3 && len(p) != 5 {
+		return fmt.Errorf("invalid string form for subnetkey: %s", str)
+	}
+	s.AddressSpace = p[0]
+	s.Subnet = fmt.Sprintf("%s/%s", p[1], p[2])
+	if len(p) == 5 {
+		s.ChildSubnet = fmt.Sprintf("%s/%s", p[3], p[4])
+	}
+
+	return nil
+}
+
+// String returns the string form of the PoolData object
+func (p *PoolData) String() string {
+	return fmt.Sprintf("ParentKey: %s, Pool: %s, Range: %s, RefCount: %d",
+		p.ParentKey.String(), p.Pool.String(), p.Range, p.RefCount)
+}
+
+// MarshalJSON returns the JSON encoding of the PoolData object
+func (p *PoolData) MarshalJSON() ([]byte, error) {
+	m := map[string]interface{}{
+		"ParentKey": p.ParentKey,
+		"RefCount":  p.RefCount,
+	}
+	if p.Pool != nil {
+		m["Pool"] = p.Pool.String()
+	}
+	if p.Range != nil {
+		m["Range"] = p.Range
+	}
+	return json.Marshal(m)
+}
+
+// UnmarshalJSON decodes data into the PoolData object
+func (p *PoolData) UnmarshalJSON(data []byte) error {
+	var (
+		err error
+		t   struct {
+			ParentKey SubnetKey
+			Pool      string
+			Range     *AddressRange `json:",omitempty"`
+			RefCount  int
+		}
+	)
+
+	if err = json.Unmarshal(data, &t); err != nil {
+		return err
+	}
+
+	p.ParentKey = t.ParentKey
+	p.Range = t.Range
+	p.RefCount = t.RefCount
+	if t.Pool != "" {
+		if p.Pool, err = types.ParseCIDR(t.Pool); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// MarshalJSON returns the JSON encoding of the addrSpace object
+func (aSpace *addrSpace) MarshalJSON() ([]byte, error) {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+
+	m := map[string]interface{}{
+		"Scope": string(aSpace.scope),
+	}
+
+	if aSpace.subnets != nil {
+		s := map[string]*PoolData{}
+		for k, v := range aSpace.subnets {
+			s[k.String()] = v
+		}
+		m["Subnets"] = s
+	}
+
+	return json.Marshal(m)
+}
+
+// UnmarshalJSON decodes data into the addrSpace object
+func (aSpace *addrSpace) UnmarshalJSON(data []byte) error {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+
+	m := map[string]interface{}{}
+	err := json.Unmarshal(data, &m)
+	if err != nil {
+		return err
+	}
+
+	aSpace.scope = datastore.LocalScope
+	s := m["Scope"].(string)
+	if s == string(datastore.GlobalScope) {
+		aSpace.scope = datastore.GlobalScope
+	}
+
+	if v, ok := m["Subnets"]; ok {
+		sb, _ := json.Marshal(v)
+		var s map[string]*PoolData
+		err := json.Unmarshal(sb, &s)
+		if err != nil {
+			return err
+		}
+		for ks, v := range s {
+			k := SubnetKey{}
+			k.FromString(ks)
+			aSpace.subnets[k] = v
+		}
+	}
+
+	return nil
+}
+
+// CopyTo deep copies the pool data to the destination pooldata
+func (p *PoolData) CopyTo(dstP *PoolData) error {
+	dstP.ParentKey = p.ParentKey
+	dstP.Pool = types.GetIPNetCopy(p.Pool)
+
+	if p.Range != nil {
+		dstP.Range = &AddressRange{}
+		dstP.Range.Sub = types.GetIPNetCopy(p.Range.Sub)
+		dstP.Range.Start = p.Range.Start
+		dstP.Range.End = p.Range.End
+	}
+
+	dstP.RefCount = p.RefCount
+	return nil
+}
+
+func (aSpace *addrSpace) CopyTo(o datastore.KVObject) error {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+
+	dstAspace := o.(*addrSpace)
+
+	dstAspace.id = aSpace.id
+	dstAspace.ds = aSpace.ds
+	dstAspace.alloc = aSpace.alloc
+	dstAspace.scope = aSpace.scope
+	dstAspace.dbIndex = aSpace.dbIndex
+	dstAspace.dbExists = aSpace.dbExists
+
+	dstAspace.subnets = make(map[SubnetKey]*PoolData)
+	for k, v := range aSpace.subnets {
+		dstAspace.subnets[k] = &PoolData{}
+		v.CopyTo(dstAspace.subnets[k])
+	}
+
+	return nil
+}
+
+func (aSpace *addrSpace) New() datastore.KVObject {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+
+	return &addrSpace{
+		id:    aSpace.id,
+		ds:    aSpace.ds,
+		alloc: aSpace.alloc,
+		scope: aSpace.scope,
+	}
+}
+
+func (aSpace *addrSpace) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *AddressRange) (func() error, error) {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+
+	// Check if already allocated
+	if p, ok := aSpace.subnets[k]; ok {
+		aSpace.incRefCount(p, 1)
+		return func() error { return nil }, nil
+	}
+
+	// If master pool, check for overlap
+	if ipr == nil {
+		if aSpace.contains(k.AddressSpace, nw) {
+			return nil, ipamapi.ErrPoolOverlap
+		}
+		// This is a new master pool, add it along with corresponding bitmask
+		aSpace.subnets[k] = &PoolData{Pool: nw, RefCount: 1}
+		return func() error { return aSpace.alloc.insertBitMask(k, nw) }, nil
+	}
+
+	// This is a new non-master pool
+	p := &PoolData{
+		ParentKey: SubnetKey{AddressSpace: k.AddressSpace, Subnet: k.Subnet},
+		Pool:      nw,
+		Range:     ipr,
+		RefCount:  1,
+	}
+	aSpace.subnets[k] = p
+
+	// Look for parent pool
+	pp, ok := aSpace.subnets[p.ParentKey]
+	if ok {
+		aSpace.incRefCount(pp, 1)
+		return func() error { return nil }, nil
+	}
+
+	// Parent pool does not exist, add it along with corresponding bitmask
+	aSpace.subnets[p.ParentKey] = &PoolData{Pool: nw, RefCount: 1}
+	return func() error { return aSpace.alloc.insertBitMask(p.ParentKey, nw) }, nil
+}
+
+func (aSpace *addrSpace) updatePoolDBOnRemoval(k SubnetKey) (func() error, error) {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+
+	p, ok := aSpace.subnets[k]
+	if !ok {
+		return nil, ipamapi.ErrBadPool
+	}
+
+	aSpace.incRefCount(p, -1)
+
+	c := p
+	for ok {
+		if c.RefCount == 0 {
+			delete(aSpace.subnets, k)
+			if c.Range == nil {
+				return func() error {
+					bm, err := aSpace.alloc.retrieveBitmask(k, c.Pool)
+					if err != nil {
+						return fmt.Errorf("could not find bitmask in datastore for pool %s removal: %v", k.String(), err)
+					}
+					return bm.Destroy()
+				}, nil
+			}
+		}
+		k = c.ParentKey
+		c, ok = aSpace.subnets[k]
+	}
+
+	return func() error { return nil }, nil
+}
+
+func (aSpace *addrSpace) incRefCount(p *PoolData, delta int) {
+	c := p
+	ok := true
+	for ok {
+		c.RefCount += delta
+		c, ok = aSpace.subnets[c.ParentKey]
+	}
+}
+
+// Checks whether the passed subnet is a superset or subset of any of the subset in this config db
+func (aSpace *addrSpace) contains(space string, nw *net.IPNet) bool {
+	for k, v := range aSpace.subnets {
+		if space == k.AddressSpace && k.ChildSubnet == "" {
+			if nw.Contains(v.Pool.IP) || v.Pool.Contains(nw.IP) {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func (aSpace *addrSpace) store() datastore.DataStore {
+	aSpace.Lock()
+	defer aSpace.Unlock()
+
+	return aSpace.ds
+}

+ 81 - 0
vendor/src/github.com/docker/libnetwork/ipam/utils.go

@@ -0,0 +1,81 @@
+package ipam
+
+import (
+	"fmt"
+	"net"
+
+	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/types"
+)
+
+type ipVersion int
+
+const (
+	v4 = 4
+	v6 = 6
+)
+
+func getAddressRange(pool string) (*AddressRange, error) {
+	ip, nw, err := net.ParseCIDR(pool)
+	if err != nil {
+		return nil, ipamapi.ErrInvalidSubPool
+	}
+	lIP, e := types.GetHostPartIP(nw.IP, nw.Mask)
+	if e != nil {
+		return nil, fmt.Errorf("failed to compute range's lowest ip address: %v", e)
+	}
+	bIP, e := types.GetBroadcastIP(nw.IP, nw.Mask)
+	if e != nil {
+		return nil, fmt.Errorf("failed to compute range's broadcast ip address: %v", e)
+	}
+	hIP, e := types.GetHostPartIP(bIP, nw.Mask)
+	if e != nil {
+		return nil, fmt.Errorf("failed to compute range's highest ip address: %v", e)
+	}
+	nw.IP = ip
+	return &AddressRange{nw, ipToUint64(types.GetMinimalIP(lIP)), ipToUint64(types.GetMinimalIP(hIP))}, nil
+}
+
+// It generates the ip address in the passed subnet specified by
+// the passed host address ordinal
+func generateAddress(ordinal uint64, network *net.IPNet) net.IP {
+	var address [16]byte
+
+	// Get network portion of IP
+	if getAddressVersion(network.IP) == v4 {
+		copy(address[:], network.IP.To4())
+	} else {
+		copy(address[:], network.IP)
+	}
+
+	end := len(network.Mask)
+	addIntToIP(address[:end], ordinal)
+
+	return net.IP(address[:end])
+}
+
+func getAddressVersion(ip net.IP) ipVersion {
+	if ip.To4() == nil {
+		return v6
+	}
+	return v4
+}
+
+// Adds the ordinal IP to the current array
+// 192.168.0.0 + 53 => 192.168.53
+func addIntToIP(array []byte, ordinal uint64) {
+	for i := len(array) - 1; i >= 0; i-- {
+		array[i] |= (byte)(ordinal & 0xff)
+		ordinal >>= 8
+	}
+}
+
+// Convert an ordinal to the respective IP address
+func ipToUint64(ip []byte) (value uint64) {
+	cip := types.GetMinimalIP(ip)
+	for i := 0; i < len(cip); i++ {
+		j := len(cip) - 1 - i
+		value += uint64(cip[i]) << uint(j*8)
+	}
+	return value
+}

+ 72 - 0
vendor/src/github.com/docker/libnetwork/ipamapi/contract.go

@@ -0,0 +1,72 @@
+// Package ipamapi specifies the contract the IPAM service (built-in or remote) needs to satisfy.
+package ipamapi
+
+import (
+	"errors"
+	"net"
+)
+
+/********************
+ * IPAM plugin types
+ ********************/
+
+const (
+	// DefaultIPAM is the name of the built-in default ipam driver
+	DefaultIPAM = "default"
+	// PluginEndpointType represents the Endpoint Type used by Plugin system
+	PluginEndpointType = "IpamDriver"
+)
+
+// Callback provides a Callback interface for registering an IPAM instance into LibNetwork
+type Callback interface {
+	// RegisterDriver provides a way for Remote drivers to dynamically register new NetworkType and associate with a ipam instance
+	RegisterIpamDriver(name string, driver Ipam) error
+}
+
+/**************
+ * IPAM Errors
+ **************/
+
+// Weel-known errors returned by IPAM
+var (
+	ErrInvalidIpamService       = errors.New("Invalid IPAM Service")
+	ErrInvalidIpamConfigService = errors.New("Invalid IPAM Config Service")
+	ErrIpamNotAvailable         = errors.New("IPAM Service not available")
+	ErrIpamInternalError        = errors.New("IPAM Internal Error")
+	ErrInvalidAddressSpace      = errors.New("Invalid Address Space")
+	ErrInvalidPool              = errors.New("Invalid Address Pool")
+	ErrInvalidSubPool           = errors.New("Invalid Address SubPool")
+	ErrInvalidRequest           = errors.New("Invalid Request")
+	ErrPoolNotFound             = errors.New("Address Pool not found")
+	ErrOverlapPool              = errors.New("Address pool overlaps with existing pool on this address space")
+	ErrNoAvailablePool          = errors.New("No available pool")
+	ErrNoAvailableIPs           = errors.New("No available addresses on this pool")
+	ErrIPAlreadyAllocated       = errors.New("Address already in use")
+	ErrIPOutOfRange             = errors.New("Requested address is out of range")
+	ErrPoolOverlap              = errors.New("Pool overlaps with other one on this address space")
+	ErrBadPool                  = errors.New("Address space does not contain specified address pool")
+)
+
+/*******************************
+ * IPAM Service Interface
+ *******************************/
+
+// Ipam represents the interface the IPAM service plugins must implement
+// in order to allow injection/modification of IPAM database.
+type Ipam interface {
+	// GetDefaultAddressSpaces returns the default local and global address spaces for this ipam
+	GetDefaultAddressSpaces() (string, string, error)
+	// RequestPool returns an address pool along with its unique id. Address space is a mandatory field
+	// which denotes a set of non-overlapping pools. pool describes the pool of addresses in CIDR notation.
+	// subpool indicates a smaller range of addresses from the pool, for now it is specified in CIDR notation.
+	// Both pool and subpool are non mandatory fields. When they are not specified, Ipam driver may choose to
+	// return a self chosen pool for this request. In such case the v6 flag needs to be set appropriately so
+	// that the driver would return the expected ip version pool.
+	RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error)
+	// ReleasePool releases the address pool identified by the passed id
+	ReleasePool(poolID string) error
+	// Request address from the specified pool ID. Input options or preferred IP can be passed.
+	RequestAddress(string, net.IP, map[string]string) (*net.IPNet, map[string]string, error)
+	// Release the address from the specified pool ID
+	ReleaseAddress(string, net.IP) error
+}

+ 35 - 0
vendor/src/github.com/docker/libnetwork/ipams/builtin/builtin.go

@@ -0,0 +1,35 @@
+package builtin
+
+import (
+	"fmt"
+
+	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/ipam"
+	"github.com/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 fmt.Errorf("incorrect local datastore passed to built-in ipam init")
+		}
+	}
+
+	if g != nil {
+		if globalDs, ok = g.(datastore.DataStore); !ok {
+			return fmt.Errorf("incorrect global datastore passed to built-in ipam init")
+		}
+	}
+	a, err := ipam.NewAllocator(localDs, globalDs)
+	if err != nil {
+		return err
+	}
+
+	return ic.RegisterIpamDriver(ipamapi.DefaultIPAM, a)
+}

+ 77 - 0
vendor/src/github.com/docker/libnetwork/ipams/remote/api/api.go

@@ -0,0 +1,77 @@
+// Package api defines the data structure to be used in the request/response
+// messages between libnetwork and the remote ipam plugin
+package api
+
+// Response is the basic response structure used in all responses
+type Response struct {
+	Error string
+}
+
+// IsSuccess returns wheter the plugin response is successful
+func (r *Response) IsSuccess() bool {
+	return r.Error == ""
+}
+
+// GetError returns the error from the response, if any.
+func (r *Response) GetError() string {
+	return r.Error
+}
+
+// GetAddressSpacesResponse is the response to the ``get default address spaces`` request message
+type GetAddressSpacesResponse struct {
+	Response
+	LocalDefaultAddressSpace  string
+	GlobalDefaultAddressSpace string
+}
+
+// RequestPoolRequest represents the expected data in a ``request address pool`` request message
+type RequestPoolRequest struct {
+	AddressSpace string
+	Pool         string
+	SubPool      string
+	Options      map[string]string
+	V6           bool
+}
+
+// RequestPoolResponse represents the response message to a ``request address pool`` request
+type RequestPoolResponse struct {
+	Response
+	PoolID string
+	Pool   string // CIDR format
+	Data   map[string]string
+}
+
+// ReleasePoolRequest represents the expected data in a ``release address pool`` request message
+type ReleasePoolRequest struct {
+	PoolID string
+}
+
+// ReleasePoolResponse represents the response message to a ``release address pool`` request
+type ReleasePoolResponse struct {
+	Response
+}
+
+// RequestAddressRequest represents the expected data in a ``request address`` request message
+type RequestAddressRequest struct {
+	PoolID  string
+	Address string
+	Options map[string]string
+}
+
+// RequestAddressResponse represents the expected data in the response message to a ``request address`` request
+type RequestAddressResponse struct {
+	Response
+	Address string // in CIDR format
+	Data    map[string]string
+}
+
+// ReleaseAddressRequest represents the expected data in a ``release address`` request message
+type ReleaseAddressRequest struct {
+	PoolID  string
+	Address string
+}
+
+// ReleaseAddressResponse represents the response message to a ``release address`` request
+type ReleaseAddressResponse struct {
+	Response
+}

+ 103 - 0
vendor/src/github.com/docker/libnetwork/ipams/remote/remote.go

@@ -0,0 +1,103 @@
+package remote
+
+import (
+	"fmt"
+	"net"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/docker/pkg/plugins"
+	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/ipams/remote/api"
+	"github.com/docker/libnetwork/types"
+)
+
+type allocator struct {
+	endpoint *plugins.Client
+	name     string
+}
+
+// PluginResponse is the interface for the plugin request responses
+type PluginResponse interface {
+	IsSuccess() bool
+	GetError() string
+}
+
+func newAllocator(name string, client *plugins.Client) ipamapi.Ipam {
+	a := &allocator{name: name, endpoint: client}
+	return a
+}
+
+// Init registers a remote ipam when its plugin is activated
+func Init(cb ipamapi.Callback, l, g interface{}) error {
+	plugins.Handle(ipamapi.PluginEndpointType, func(name string, client *plugins.Client) {
+		if err := cb.RegisterIpamDriver(name, newAllocator(name, client)); err != nil {
+			log.Errorf("error registering remote ipam %s due to %v", name, err)
+		}
+	})
+	return nil
+}
+
+func (a *allocator) call(methodName string, arg interface{}, retVal PluginResponse) error {
+	method := ipamapi.PluginEndpointType + "." + methodName
+	err := a.endpoint.Call(method, arg, retVal)
+	if err != nil {
+		return err
+	}
+	if !retVal.IsSuccess() {
+		return fmt.Errorf("remote: %s", retVal.GetError())
+	}
+	return nil
+}
+
+// GetDefaultAddressSpaces returns the local and global default address spaces
+func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
+	res := &api.GetAddressSpacesResponse{}
+	if err := a.call("GetDefaultAddressSpaces", nil, res); err != nil {
+		return "", "", err
+	}
+	return res.LocalDefaultAddressSpace, res.GlobalDefaultAddressSpace, nil
+}
+
+// RequestPool requests an address pool in the specified address space
+func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
+	req := &api.RequestPoolRequest{AddressSpace: addressSpace, Pool: pool, SubPool: subPool, Options: options, V6: v6}
+	res := &api.RequestPoolResponse{}
+	if err := a.call("RequestPool", req, res); err != nil {
+		return "", nil, nil, err
+	}
+	retPool, err := types.ParseCIDR(res.Pool)
+	return res.PoolID, retPool, res.Data, err
+}
+
+// ReleasePool removes an address pool from the specified address space
+func (a *allocator) ReleasePool(poolID string) error {
+	req := &api.ReleasePoolRequest{PoolID: poolID}
+	res := &api.ReleasePoolResponse{}
+	return a.call("ReleasePool", req, res)
+}
+
+// RequestAddress requests an address from the address pool
+func (a *allocator) RequestAddress(poolID string, address net.IP, options map[string]string) (*net.IPNet, map[string]string, error) {
+	var prefAddress string
+	if address != nil {
+		prefAddress = address.String()
+	}
+	req := &api.RequestAddressRequest{PoolID: poolID, Address: prefAddress, Options: options}
+	res := &api.RequestAddressResponse{}
+	if err := a.call("RequestAddress", req, res); err != nil {
+		return nil, nil, err
+	}
+	retAddress, err := types.ParseCIDR(res.Address)
+	return retAddress, res.Data, err
+}
+
+// ReleaseAddress releases the address from the specified address pool
+func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
+	var relAddress string
+	if address != nil {
+		relAddress = address.String()
+	}
+	req := &api.ReleaseAddressRequest{PoolID: poolID, Address: relAddress}
+	res := &api.ReleaseAddressResponse{}
+	return a.call("ReleaseAddress", req, res)
+}

+ 42 - 0
vendor/src/github.com/docker/libnetwork/ipamutils/utils.go

@@ -0,0 +1,42 @@
+// Package ipamutils provides utililty functions for ipam management
+package ipamutils
+
+import "net"
+
+var (
+	// PredefinedBroadNetworks 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 `PredefinedGranularNetworks`
+	PredefinedBroadNetworks []*net.IPNet
+	// PredefinedGranularNetworks 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 `PredefinedBroadNetworks`
+	PredefinedGranularNetworks []*net.IPNet
+)
+
+func init() {
+	PredefinedBroadNetworks = initBroadPredefinedNetworks()
+	PredefinedGranularNetworks = initGranularPredefinedNetworks()
+}
+
+func initBroadPredefinedNetworks() []*net.IPNet {
+	pl := make([]*net.IPNet, 0, 31)
+	mask := []byte{255, 255, 0, 0}
+	for i := 17; i < 32; i++ {
+		pl = append(pl, &net.IPNet{IP: []byte{172, byte(i), 0, 0}, Mask: mask})
+	}
+	mask20 := []byte{255, 255, 240, 0}
+	for i := 0; i < 16; i++ {
+		pl = append(pl, &net.IPNet{IP: []byte{192, 168, byte(i << 4), 0}, Mask: mask20})
+	}
+	return pl
+}
+
+func initGranularPredefinedNetworks() []*net.IPNet {
+	pl := make([]*net.IPNet, 0, 256*256)
+	mask := []byte{255, 255, 255, 0}
+	for i := 0; i < 256; i++ {
+		for j := 0; j < 256; j++ {
+			pl = append(pl, &net.IPNet{IP: []byte{10, byte(i), byte(j), 0}, Mask: mask})
+		}
+	}
+	return pl
+}

+ 71 - 0
vendor/src/github.com/docker/libnetwork/ipamutils/utils_linux.go

@@ -0,0 +1,71 @@
+// Package ipamutils provides utililty functions for ipam management
+package ipamutils
+
+import (
+	"fmt"
+	"net"
+
+	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/resolvconf"
+	"github.com/vishvananda/netlink"
+)
+
+// ElectInterfaceAddresses looks for an interface on the OS with the specified name
+// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist,
+// it chooses from a predifined list the first IPv4 address which does not conflict
+// with other interfaces on the system.
+func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
+	var (
+		v4Net  *net.IPNet
+		v6Nets []*net.IPNet
+		err    error
+	)
+
+	link, _ := netlink.LinkByName(name)
+	if link != nil {
+		v4addr, err := netlink.AddrList(link, netlink.FAMILY_V4)
+		if err != nil {
+			return nil, nil, err
+		}
+		v6addr, err := netlink.AddrList(link, netlink.FAMILY_V6)
+		if err != nil {
+			return nil, nil, err
+		}
+		if len(v4addr) > 0 {
+			v4Net = v4addr[0].IPNet
+		}
+		for _, nlAddr := range v6addr {
+			v6Nets = append(v6Nets, nlAddr.IPNet)
+		}
+	}
+
+	if link == nil || v4Net == nil {
+		// Choose from predifined broad networks
+		v4Net, err = FindAvailableNetwork(PredefinedBroadNetworks)
+		if err != nil {
+			return nil, nil, err
+		}
+	}
+
+	return v4Net, v6Nets, nil
+}
+
+// FindAvailableNetwork returns a network from the passed list which does not
+// overlap with existing interfaces in the system
+func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
+	// We don't check for an error here, because we don't really care if we
+	// can't read /etc/resolv.conf. So instead we skip the append if resolvConf
+	// is nil. It either doesn't exist, or we can't read it for some reason.
+	var nameservers []string
+	if rc, err := resolvconf.Get(); err == nil {
+		nameservers = resolvconf.GetNameserversAsCIDR(rc.Content)
+	}
+	for _, nw := range list {
+		if err := netutils.CheckNameserverOverlaps(nameservers, nw); err == nil {
+			if err := netutils.CheckRouteOverlaps(nw); err == nil {
+				return nw, nil
+			}
+		}
+	}
+	return nil, fmt.Errorf("no available network")
+}

+ 22 - 0
vendor/src/github.com/docker/libnetwork/ipamutils/utils_windows.go

@@ -0,0 +1,22 @@
+// Package ipamutils provides utililty functions for ipam management
+package ipamutils
+
+import (
+	"net"
+
+	"github.com/docker/libnetwork/types"
+)
+
+// ElectInterfaceAddresses looks for an interface on the OS with the specified name
+// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist,
+// it chooses from a predifined list the first IPv4 address which does not conflict
+// with other interfaces on the system.
+func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
+	return nil, nil, types.NotImplementedErrorf("not supported on windows")
+}
+
+// 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) {
+	return nil, types.NotImplementedErrorf("not supported on windows")
+}

+ 68 - 17
vendor/src/github.com/docker/libnetwork/netlabel/labels.go

@@ -1,6 +1,8 @@
 package netlabel
 
-import "strings"
+import (
+	"strings"
+)
 
 const (
 	// Prefix constant marks the reserved label space for libnetwork
@@ -9,6 +11,10 @@ const (
 	// DriverPrefix constant marks the reserved label space for libnetwork drivers
 	DriverPrefix = Prefix + ".driver"
 
+	// DriverPrivatePrefix constant marks the reserved label space
+	// for internal libnetwork drivers
+	DriverPrivatePrefix = DriverPrefix + ".private"
+
 	// GenericData constant that helps to identify an option as a Generic constant
 	GenericData = Prefix + ".generic"
 
@@ -18,38 +24,83 @@ const (
 	// MacAddress constant represents Mac Address config of a Container
 	MacAddress = Prefix + ".endpoint.macaddress"
 
-	// ExposedPorts constant represents exposedports of a Container
+	// ExposedPorts constant represents the container's Exposed Ports
 	ExposedPorts = Prefix + ".endpoint.exposedports"
 
 	//EnableIPv6 constant represents enabling IPV6 at network level
 	EnableIPv6 = Prefix + ".enable_ipv6"
 
-	// KVProvider constant represents the KV provider backend
-	KVProvider = DriverPrefix + ".kv_provider"
-
-	// KVProviderURL constant represents the KV provider URL
-	KVProviderURL = DriverPrefix + ".kv_provider_url"
-
-	// KVProviderConfig constant represents the KV provider Config
-	KVProviderConfig = DriverPrefix + ".kv_provider_config"
+	// DriverMTU constant represents the MTU size for the network driver
+	DriverMTU = DriverPrefix + ".mtu"
 
 	// OverlayBindInterface constant represents overlay driver bind interface
 	OverlayBindInterface = DriverPrefix + ".overlay.bind_interface"
 
 	// OverlayNeighborIP constant represents overlay driver neighbor IP
 	OverlayNeighborIP = DriverPrefix + ".overlay.neighbor_ip"
+
+	// Gateway represents the gateway for the network
+	Gateway = Prefix + ".gateway"
 )
 
-// Key extracts the key portion of the label
-func Key(label string) string {
-	kv := strings.SplitN(label, "=", 2)
+var (
+	// GlobalKVProvider constant represents the KV provider backend
+	GlobalKVProvider = MakeKVProvider("global")
+
+	// GlobalKVProviderURL constant represents the KV provider URL
+	GlobalKVProviderURL = MakeKVProviderURL("global")
+
+	// GlobalKVProviderConfig constant represents the KV provider Config
+	GlobalKVProviderConfig = MakeKVProviderConfig("global")
+
+	// LocalKVProvider constant represents the KV provider backend
+	LocalKVProvider = MakeKVProvider("local")
+
+	// LocalKVProviderURL constant represents the KV provider URL
+	LocalKVProviderURL = MakeKVProviderURL("local")
 
-	return kv[0]
+	// LocalKVProviderConfig constant represents the KV provider Config
+	LocalKVProviderConfig = MakeKVProviderConfig("local")
+)
+
+// MakeKVProvider returns the kvprovider label for the scope
+func MakeKVProvider(scope string) string {
+	return DriverPrivatePrefix + scope + "kv_provider"
+}
+
+// MakeKVProviderURL returns the kvprovider url label for the scope
+func MakeKVProviderURL(scope string) string {
+	return DriverPrivatePrefix + scope + "kv_provider_url"
+}
+
+// MakeKVProviderConfig returns the kvprovider config label for the scope
+func MakeKVProviderConfig(scope string) string {
+	return DriverPrivatePrefix + scope + "kv_provider_config"
+}
+
+// Key extracts the key portion of the label
+func Key(label string) (key string) {
+	if kv := strings.SplitN(label, "=", 2); len(kv) > 0 {
+		key = kv[0]
+	}
+	return
 }
 
 // Value extracts the value portion of the label
-func Value(label string) string {
-	kv := strings.SplitN(label, "=", 2)
+func Value(label string) (value string) {
+	if kv := strings.SplitN(label, "=", 2); len(kv) > 1 {
+		value = kv[1]
+	}
+	return
+}
 
-	return kv[1]
+// KeyValue decomposes the label in the (key,value) pair
+func KeyValue(label string) (key string, value string) {
+	if kv := strings.SplitN(label, "=", 2); len(kv) > 0 {
+		key = kv[0]
+		if len(kv) > 1 {
+			value = kv[1]
+		}
+	}
+	return
 }

+ 717 - 129
vendor/src/github.com/docker/libnetwork/network.go

@@ -2,7 +2,9 @@ package libnetwork
 
 import (
 	"encoding/json"
+	"fmt"
 	"net"
+	"strconv"
 	"sync"
 
 	log "github.com/Sirupsen/logrus"
@@ -11,6 +13,7 @@ import (
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/etchosts"
+	"github.com/docker/libnetwork/ipamapi"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
 	"github.com/docker/libnetwork/types"
@@ -47,6 +50,16 @@ type Network interface {
 
 	// EndpointByID returns the Endpoint which has the passed id. If not found, the error ErrNoSuchEndpoint is returned.
 	EndpointByID(id string) (Endpoint, error)
+
+	// Return certain operational data belonging to this network
+	Info() NetworkInfo
+}
+
+// NetworkInfo returns some configuration and operational information about the network
+type NetworkInfo interface {
+	IpamConfig() (string, []*IpamConf, []*IpamConf)
+	Labels() map[string]string
+	Scope() string
 }
 
 // EndpointWalker is a client provided function which will be used to walk the Endpoints.
@@ -55,22 +68,98 @@ type EndpointWalker func(ep Endpoint) bool
 
 type svcMap map[string]net.IP
 
+// IpamConf contains all the ipam related configurations for a network
+type IpamConf struct {
+	// The master address pool for containers and network interfaces
+	PreferredPool string
+	// A subset of the master pool. If specified,
+	// this becomes the container pool
+	SubPool string
+	// Input options for IPAM Driver (optional)
+	Options map[string]string
+	// Preferred Network Gateway address (optional)
+	Gateway string
+	// Auxiliary addresses for network driver. Must be within the master pool.
+	// libnetwork will reserve them if they fall into the container pool
+	AuxAddresses map[string]string
+}
+
+// Validate checks whether the configuration is valid
+func (c *IpamConf) Validate() error {
+	if c.Gateway != "" && nil == net.ParseIP(c.Gateway) {
+		return types.BadRequestErrorf("invalid gateway address %s in Ipam configuration", c.Gateway)
+	}
+	return nil
+}
+
+// IpamInfo contains all the ipam related operational info for a network
+type IpamInfo struct {
+	PoolID string
+	Meta   map[string]string
+	driverapi.IPAMData
+}
+
+// MarshalJSON encodes IpamInfo into json message
+func (i *IpamInfo) MarshalJSON() ([]byte, error) {
+	m := map[string]interface{}{
+		"PoolID": i.PoolID,
+	}
+	v, err := json.Marshal(&i.IPAMData)
+	if err != nil {
+		return nil, err
+	}
+	m["IPAMData"] = string(v)
+
+	if i.Meta != nil {
+		m["Meta"] = i.Meta
+	}
+	return json.Marshal(m)
+}
+
+// UnmarshalJSON decodes json message into PoolData
+func (i *IpamInfo) UnmarshalJSON(data []byte) error {
+	var (
+		m   map[string]interface{}
+		err error
+	)
+	if err = json.Unmarshal(data, &m); err != nil {
+		return err
+	}
+	i.PoolID = m["PoolID"].(string)
+	if v, ok := m["Meta"]; ok {
+		b, _ := json.Marshal(v)
+		if err = json.Unmarshal(b, &i.Meta); err != nil {
+			return err
+		}
+	}
+	if v, ok := m["IPAMData"]; ok {
+		if err = json.Unmarshal([]byte(v.(string)), &i.IPAMData); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 type network struct {
-	ctrlr       *controller
-	name        string
-	networkType string
-	id          string
-	driver      driverapi.Driver
-	enableIPv6  bool
-	endpointCnt uint64
-	endpoints   endpointTable
-	generic     options.Generic
-	dbIndex     uint64
-	svcRecords  svcMap
-	dbExists    bool
-	persist     bool
-	stopWatchCh chan struct{}
-	dataScope   datastore.DataScope
+	ctrlr        *controller
+	name         string
+	networkType  string
+	id           string
+	ipamType     string
+	addrSpace    string
+	ipamV4Config []*IpamConf
+	ipamV6Config []*IpamConf
+	ipamV4Info   []*IpamInfo
+	ipamV6Info   []*IpamInfo
+	enableIPv6   bool
+	epCnt        *endpointCnt
+	generic      options.Generic
+	dbIndex      uint64
+	svcRecords   svcMap
+	dbExists     bool
+	persist      bool
+	stopWatchCh  chan struct{}
+	drvOnce      *sync.Once
 	sync.Mutex
 }
 
@@ -92,11 +181,7 @@ func (n *network) Type() string {
 	n.Lock()
 	defer n.Unlock()
 
-	if n.driver == nil {
-		return ""
-	}
-
-	return n.driver.Type()
+	return n.networkType
 }
 
 func (n *network) Key() []string {
@@ -148,28 +233,116 @@ func (n *network) Skip() bool {
 	return !n.persist
 }
 
-func (n *network) DataScope() datastore.DataScope {
+func (n *network) New() datastore.KVObject {
 	n.Lock()
 	defer n.Unlock()
-	return n.dataScope
+
+	return &network{
+		ctrlr:   n.ctrlr,
+		drvOnce: &sync.Once{},
+	}
 }
 
-func (n *network) EndpointCnt() uint64 {
+// CopyTo deep copies to the destination IpamConfig
+func (c *IpamConf) CopyTo(dstC *IpamConf) error {
+	dstC.PreferredPool = c.PreferredPool
+	dstC.SubPool = c.SubPool
+	dstC.Gateway = c.Gateway
+	if c.Options != nil {
+		dstC.Options = make(map[string]string, len(c.Options))
+		for k, v := range c.Options {
+			dstC.Options[k] = v
+		}
+	}
+	if c.AuxAddresses != nil {
+		dstC.AuxAddresses = make(map[string]string, len(c.AuxAddresses))
+		for k, v := range c.AuxAddresses {
+			dstC.AuxAddresses[k] = v
+		}
+	}
+	return nil
+}
+
+// CopyTo deep copies to the destination IpamInfo
+func (i *IpamInfo) CopyTo(dstI *IpamInfo) error {
+	dstI.PoolID = i.PoolID
+	if i.Meta != nil {
+		dstI.Meta = make(map[string]string)
+		for k, v := range i.Meta {
+			dstI.Meta[k] = v
+		}
+	}
+
+	dstI.AddressSpace = i.AddressSpace
+	dstI.Pool = types.GetIPNetCopy(i.Pool)
+	dstI.Gateway = types.GetIPNetCopy(i.Gateway)
+
+	if i.AuxAddresses != nil {
+		dstI.AuxAddresses = make(map[string]*net.IPNet)
+		for k, v := range i.AuxAddresses {
+			dstI.AuxAddresses[k] = types.GetIPNetCopy(v)
+		}
+	}
+
+	return nil
+}
+
+func (n *network) CopyTo(o datastore.KVObject) error {
 	n.Lock()
 	defer n.Unlock()
-	return n.endpointCnt
+
+	dstN := o.(*network)
+	dstN.name = n.name
+	dstN.id = n.id
+	dstN.networkType = n.networkType
+	dstN.ipamType = n.ipamType
+	dstN.enableIPv6 = n.enableIPv6
+	dstN.persist = n.persist
+	dstN.dbIndex = n.dbIndex
+	dstN.dbExists = n.dbExists
+	dstN.drvOnce = n.drvOnce
+
+	for _, v4conf := range n.ipamV4Config {
+		dstV4Conf := &IpamConf{}
+		v4conf.CopyTo(dstV4Conf)
+		dstN.ipamV4Config = append(dstN.ipamV4Config, dstV4Conf)
+	}
+
+	for _, v4info := range n.ipamV4Info {
+		dstV4Info := &IpamInfo{}
+		v4info.CopyTo(dstV4Info)
+		dstN.ipamV4Info = append(dstN.ipamV4Info, dstV4Info)
+	}
+
+	for _, v6conf := range n.ipamV6Config {
+		dstV6Conf := &IpamConf{}
+		v6conf.CopyTo(dstV6Conf)
+		dstN.ipamV6Config = append(dstN.ipamV6Config, dstV6Conf)
+	}
+
+	for _, v6info := range n.ipamV6Info {
+		dstV6Info := &IpamInfo{}
+		v6info.CopyTo(dstV6Info)
+		dstN.ipamV6Info = append(dstN.ipamV6Info, dstV6Info)
+	}
+
+	dstN.generic = options.Generic{}
+	for k, v := range n.generic {
+		dstN.generic[k] = v
+	}
+
+	return nil
 }
 
-func (n *network) IncEndpointCnt() {
-	n.Lock()
-	n.endpointCnt++
-	n.Unlock()
+func (n *network) DataScope() string {
+	return n.driverScope()
 }
 
-func (n *network) DecEndpointCnt() {
+func (n *network) getEpCnt() *endpointCnt {
 	n.Lock()
-	n.endpointCnt--
-	n.Unlock()
+	defer n.Unlock()
+
+	return n.epCnt
 }
 
 // TODO : Can be made much more generic with the help of reflection (but has some golang limitations)
@@ -178,10 +351,41 @@ func (n *network) MarshalJSON() ([]byte, error) {
 	netMap["name"] = n.name
 	netMap["id"] = n.id
 	netMap["networkType"] = n.networkType
-	netMap["endpointCnt"] = n.endpointCnt
+	netMap["ipamType"] = n.ipamType
+	netMap["addrSpace"] = n.addrSpace
 	netMap["enableIPv6"] = n.enableIPv6
-	netMap["generic"] = n.generic
+	if n.generic != nil {
+		netMap["generic"] = n.generic
+	}
 	netMap["persist"] = n.persist
+	if len(n.ipamV4Config) > 0 {
+		ics, err := json.Marshal(n.ipamV4Config)
+		if err != nil {
+			return nil, err
+		}
+		netMap["ipamV4Config"] = string(ics)
+	}
+	if len(n.ipamV4Info) > 0 {
+		iis, err := json.Marshal(n.ipamV4Info)
+		if err != nil {
+			return nil, err
+		}
+		netMap["ipamV4Info"] = string(iis)
+	}
+	if len(n.ipamV6Config) > 0 {
+		ics, err := json.Marshal(n.ipamV6Config)
+		if err != nil {
+			return nil, err
+		}
+		netMap["ipamV6Config"] = string(ics)
+	}
+	if len(n.ipamV6Info) > 0 {
+		iis, err := json.Marshal(n.ipamV6Info)
+		if err != nil {
+			return nil, err
+		}
+		netMap["ipamV6Info"] = string(iis)
+	}
 	return json.Marshal(netMap)
 }
 
@@ -194,13 +398,53 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
 	n.name = netMap["name"].(string)
 	n.id = netMap["id"].(string)
 	n.networkType = netMap["networkType"].(string)
-	n.endpointCnt = uint64(netMap["endpointCnt"].(float64))
 	n.enableIPv6 = netMap["enableIPv6"].(bool)
-	if netMap["generic"] != nil {
-		n.generic = netMap["generic"].(map[string]interface{})
+
+	if v, ok := netMap["generic"]; ok {
+		n.generic = v.(map[string]interface{})
+		// Restore labels in their map[string]string form
+		if v, ok := n.generic[netlabel.GenericData]; ok {
+			var lmap map[string]string
+			ba, err := json.Marshal(v)
+			if err != nil {
+				return err
+			}
+			if err := json.Unmarshal(ba, &lmap); err != nil {
+				return err
+			}
+			n.generic[netlabel.GenericData] = lmap
+		}
+	}
+	if v, ok := netMap["persist"]; ok {
+		n.persist = v.(bool)
+	}
+	if v, ok := netMap["ipamType"]; ok {
+		n.ipamType = v.(string)
+	} else {
+		n.ipamType = ipamapi.DefaultIPAM
+	}
+	if v, ok := netMap["addrSpace"]; ok {
+		n.addrSpace = v.(string)
+	}
+	if v, ok := netMap["ipamV4Config"]; ok {
+		if err := json.Unmarshal([]byte(v.(string)), &n.ipamV4Config); err != nil {
+			return err
+		}
+	}
+	if v, ok := netMap["ipamV4Info"]; ok {
+		if err := json.Unmarshal([]byte(v.(string)), &n.ipamV4Info); err != nil {
+			return err
+		}
+	}
+	if v, ok := netMap["ipamV6Config"]; ok {
+		if err := json.Unmarshal([]byte(v.(string)), &n.ipamV6Config); err != nil {
+			return err
+		}
 	}
-	if netMap["persist"] != nil {
-		n.persist = netMap["persist"].(bool)
+	if v, ok := netMap["ipamV6Info"]; ok {
+		if err := json.Unmarshal([]byte(v.(string)), &n.ipamV6Info); err != nil {
+			return err
+		}
 	}
 	return nil
 }
@@ -228,6 +472,39 @@ func NetworkOptionPersist(persist bool) NetworkOption {
 	}
 }
 
+// NetworkOptionIpam function returns an option setter for the ipam configuration for this network
+func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ipV6 []*IpamConf) NetworkOption {
+	return func(n *network) {
+		if ipamDriver != "" {
+			n.ipamType = ipamDriver
+		}
+		n.addrSpace = addrSpace
+		n.ipamV4Config = ipV4
+		n.ipamV6Config = ipV6
+	}
+}
+
+// NetworkOptionLabels function returns an option setter for any parameter described by a map
+func NetworkOptionLabels(labels map[string]string) NetworkOption {
+	return func(n *network) {
+		if n.generic == nil {
+			n.generic = make(map[string]interface{})
+		}
+		if labels == nil {
+			labels = make(map[string]string)
+		}
+		// Store the options
+		n.generic[netlabel.GenericData] = labels
+		// Decode and store the endpoint options of libnetwork interest
+		if val, ok := labels[netlabel.EnableIPv6]; ok {
+			var err error
+			if n.enableIPv6, err = strconv.ParseBool(val); err != nil {
+				log.Warnf("Failed to parse %s' value: %s (%s)", netlabel.EnableIPv6, val, err.Error())
+			}
+		}
+	}
+}
+
 func (n *network) processOptions(options ...NetworkOption) {
 	for _, opt := range options {
 		if opt != nil {
@@ -236,95 +513,121 @@ func (n *network) processOptions(options ...NetworkOption) {
 	}
 }
 
-func (n *network) Delete() error {
-	var err error
+func (n *network) driverScope() string {
+	c := n.getController()
 
-	n.Lock()
-	ctrlr := n.ctrlr
-	n.Unlock()
+	c.Lock()
+	// Check if a driver for the specified network type is available
+	dd, ok := c.drivers[n.networkType]
+	c.Unlock()
+
+	if !ok {
+		var err error
+		dd, err = c.loadDriver(n.networkType)
+		if err != nil {
+			// If driver could not be resolved simply return an empty string
+			return ""
+		}
+	}
+
+	return dd.capability.DataScope
+}
 
-	ctrlr.Lock()
-	_, ok := ctrlr.networks[n.id]
-	ctrlr.Unlock()
+func (n *network) driver() (driverapi.Driver, error) {
+	c := n.getController()
+
+	c.Lock()
+	// Check if a driver for the specified network type is available
+	dd, ok := c.drivers[n.networkType]
+	c.Unlock()
 
 	if !ok {
-		return &UnknownNetworkError{name: n.name, id: n.id}
+		var err error
+		dd, err = c.loadDriver(n.networkType)
+		if err != nil {
+			return nil, err
+		}
 	}
 
-	numEps := n.EndpointCnt()
+	return dd.driver, nil
+}
+
+func (n *network) Delete() error {
+	n.Lock()
+	c := n.ctrlr
+	name := n.name
+	id := n.id
+	n.Unlock()
+
+	n, err := c.getNetworkFromStore(id)
+	if err != nil {
+		return &UnknownNetworkError{name: name, id: id}
+	}
+
+	numEps := n.getEpCnt().EndpointCnt()
 	if numEps != 0 {
 		return &ActiveEndpointsError{name: n.name, id: n.id}
 	}
 
-	// deleteNetworkFromStore performs an atomic delete operation and the network.endpointCnt field will help
-	// prevent any possible race between endpoint join and network delete
-	if err = ctrlr.deleteFromStore(n); err != nil {
-		if err == datastore.ErrKeyModified {
-			return types.InternalErrorf("operation in progress. delete failed for network %s. Please try again.")
-		}
+	if err = n.deleteNetwork(); err != nil {
 		return err
 	}
-
 	defer func() {
 		if err != nil {
-			n.dbExists = false
-			if e := ctrlr.updateToStore(n); e != nil {
-				log.Warnf("failed to recreate network in store %s : %v", n.name, e)
+			if e := c.addNetwork(n); e != nil {
+				log.Warnf("failed to rollback deleteNetwork for network %s: %v",
+					n.Name(), err)
 			}
 		}
 	}()
 
-	if err = n.deleteNetwork(); err != nil {
-		return err
+	// deleteFromStore performs an atomic delete operation and the
+	// network.epCnt will help prevent any possible
+	// race between endpoint join and network delete
+	if err = n.getController().deleteFromStore(n.getEpCnt()); err != nil {
+		return fmt.Errorf("error deleting network endpoint count from store: %v", err)
+	}
+	if err = n.getController().deleteFromStore(n); err != nil {
+		return fmt.Errorf("error deleting network from store: %v", err)
 	}
 
+	n.ipamRelease()
+
 	return nil
 }
 
 func (n *network) deleteNetwork() error {
-	n.Lock()
-	id := n.id
-	d := n.driver
-	n.ctrlr.Lock()
-	delete(n.ctrlr.networks, id)
-	n.ctrlr.Unlock()
-	n.Unlock()
+	d, err := n.driver()
+	if err != nil {
+		return fmt.Errorf("failed deleting network: %v", err)
+	}
 
-	if err := d.DeleteNetwork(n.id); err != nil {
+	if err := d.DeleteNetwork(n.ID()); err != nil {
 		// Forbidden Errors should be honored
 		if _, ok := err.(types.ForbiddenError); ok {
-			n.ctrlr.Lock()
-			n.ctrlr.networks[n.id] = n
-			n.ctrlr.Unlock()
 			return err
 		}
-		log.Warnf("driver error deleting network %s : %v", n.name, err)
+
+		if _, ok := err.(types.MaskableError); !ok {
+			log.Warnf("driver error deleting network %s : %v", n.name, err)
+		}
 	}
-	n.stopWatch()
+
 	return nil
 }
 
 func (n *network) addEndpoint(ep *endpoint) error {
-	var err error
-	n.Lock()
-	n.endpoints[ep.id] = ep
-	d := n.driver
-	n.Unlock()
-
-	defer func() {
-		if err != nil {
-			n.Lock()
-			delete(n.endpoints, ep.id)
-			n.Unlock()
-		}
-	}()
+	d, err := n.driver()
+	if err != nil {
+		return fmt.Errorf("failed to add endpoint: %v", err)
+	}
 
-	err = d.CreateEndpoint(n.id, ep.id, ep, ep.generic)
+	err = d.CreateEndpoint(n.id, ep.id, ep.Interface(), ep.generic)
 	if err != nil {
-		return types.InternalErrorf("failed to create endpoint %s on network %s: %v", ep.Name(), n.Name(), err)
+		return types.InternalErrorf("failed to create endpoint %s on network %s: %v",
+			ep.Name(), n.Name(), err)
 	}
 
-	n.updateSvcRecord(ep, true)
 	return nil
 }
 
@@ -338,54 +641,69 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
 		return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
 	}
 
-	ep := &endpoint{name: name,
-		generic: make(map[string]interface{})}
+	ep := &endpoint{name: name, generic: make(map[string]interface{}), iface: &endpointInterface{}}
 	ep.id = stringid.GenerateRandomID()
+
+	// Initialize ep.network with a possibly stale copy of n. We need this to get network from
+	// store. But once we get it from store we will have the most uptodate copy possible.
 	ep.network = n
-	ep.processOptions(options...)
+	ep.network, err = ep.getNetworkFromStore()
+	if err != nil {
+		return nil, fmt.Errorf("failed to get network during CreateEndpoint: %v", err)
+	}
+	n = ep.network
 
-	n.Lock()
-	ctrlr := n.ctrlr
-	n.Unlock()
+	ep.processOptions(options...)
 
-	n.IncEndpointCnt()
-	if err = ctrlr.updateToStore(n); err != nil {
+	if err = ep.assignAddress(); err != nil {
 		return nil, err
 	}
 	defer func() {
 		if err != nil {
-			n.DecEndpointCnt()
-			if err = ctrlr.updateToStore(n); err != nil {
-				log.Warnf("endpoint count cleanup failed when updating network for %s : %v", name, err)
-			}
+			ep.releaseAddress()
 		}
 	}()
+
 	if err = n.addEndpoint(ep); err != nil {
 		return nil, err
 	}
 	defer func() {
 		if err != nil {
-			if e := ep.Delete(); ep != nil {
+			if e := ep.deleteEndpoint(); e != nil {
 				log.Warnf("cleaning up endpoint failed %s : %v", name, e)
 			}
 		}
 	}()
 
-	if !ep.isLocalScoped() {
-		if err = ctrlr.updateToStore(ep); err != nil {
-			return nil, err
+	if err = n.getController().updateToStore(ep); err != nil {
+		return nil, err
+	}
+	defer func() {
+		if err != nil {
+			if e := n.getController().deleteFromStore(ep); e != nil {
+				log.Warnf("error rolling back endpoint %s from store: %v", name, e)
+			}
 		}
+	}()
+
+	// Increment endpoint count to indicate completion of endpoint addition
+	if err = n.getEpCnt().IncEndpointCnt(); err != nil {
+		return nil, err
 	}
 
 	return ep, nil
 }
 
 func (n *network) Endpoints() []Endpoint {
-	n.Lock()
-	defer n.Unlock()
-	list := make([]Endpoint, 0, len(n.endpoints))
-	for _, e := range n.endpoints {
-		list = append(list, e)
+	var list []Endpoint
+
+	endpoints, err := n.getEndpointsFromStore()
+	if err != nil {
+		log.Error(err)
+	}
+
+	for _, ep := range endpoints {
+		list = append(list, ep)
 	}
 
 	return list
@@ -426,28 +744,32 @@ func (n *network) EndpointByID(id string) (Endpoint, error) {
 	if id == "" {
 		return nil, ErrInvalidID(id)
 	}
-	n.Lock()
-	defer n.Unlock()
-	if e, ok := n.endpoints[id]; ok {
-		return e, nil
+
+	ep, err := n.getEndpointFromStore(id)
+	if err != nil {
+		return nil, ErrNoSuchEndpoint(id)
 	}
-	return nil, ErrNoSuchEndpoint(id)
-}
 
-func (n *network) isGlobalScoped() bool {
-	return n.DataScope() == datastore.GlobalScope
+	return ep, nil
 }
 
-func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
+func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool) {
+	c := n.getController()
+	sr, ok := c.svcDb[n.ID()]
+	if !ok {
+		c.svcDb[n.ID()] = svcMap{}
+		sr = c.svcDb[n.ID()]
+	}
+
 	n.Lock()
 	var recs []etchosts.Record
-	if iface := ep.Iface(); iface != nil {
+	if iface := ep.Iface(); iface.Address() != nil {
 		if isAdd {
-			n.svcRecords[ep.Name()] = iface.Address().IP
-			n.svcRecords[ep.Name()+"."+n.name] = iface.Address().IP
+			sr[ep.Name()] = iface.Address().IP
+			sr[ep.Name()+"."+n.name] = iface.Address().IP
 		} else {
-			delete(n.svcRecords, ep.Name())
-			delete(n.svcRecords, ep.Name()+"."+n.name)
+			delete(sr, ep.Name())
+			delete(sr, ep.Name()+"."+n.name)
 		}
 
 		recs = append(recs, etchosts.Record{
@@ -468,12 +790,11 @@ func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
 	}
 
 	var sbList []*sandbox
-	n.WalkEndpoints(func(e Endpoint) bool {
-		if sb, hasSandbox := e.(*endpoint).getSandbox(); hasSandbox {
+	for _, ep := range localEps {
+		if sb, hasSandbox := ep.getSandbox(); hasSandbox {
 			sbList = append(sbList, sb)
 		}
-		return false
-	})
+	}
 
 	for _, sb := range sbList {
 		if isAdd {
@@ -489,7 +810,9 @@ func (n *network) getSvcRecords() []etchosts.Record {
 	defer n.Unlock()
 
 	var recs []etchosts.Record
-	for h, ip := range n.svcRecords {
+	sr, _ := n.ctrlr.svcDb[n.id]
+
+	for h, ip := range sr {
 		recs = append(recs, etchosts.Record{
 			Hosts: h,
 			IP:    ip.String(),
@@ -504,3 +827,268 @@ func (n *network) getController() *controller {
 	defer n.Unlock()
 	return n.ctrlr
 }
+
+func (n *network) ipamAllocate() error {
+	// For now also exclude bridge from using new ipam
+	if n.Type() == "host" || n.Type() == "null" {
+		return nil
+	}
+
+	ipam, err := n.getController().getIpamDriver(n.ipamType)
+	if err != nil {
+		return err
+	}
+
+	if n.addrSpace == "" {
+		if n.addrSpace, err = n.deriveAddressSpace(); err != nil {
+			return err
+		}
+	}
+
+	err = n.ipamAllocateVersion(4, ipam)
+	if err != nil {
+		return err
+	}
+
+	defer func() {
+		if err != nil {
+			n.ipamReleaseVersion(4, ipam)
+		}
+	}()
+
+	return n.ipamAllocateVersion(6, ipam)
+}
+
+func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error {
+	var (
+		cfgList  *[]*IpamConf
+		infoList *[]*IpamInfo
+		err      error
+	)
+
+	switch ipVer {
+	case 4:
+		cfgList = &n.ipamV4Config
+		infoList = &n.ipamV4Info
+	case 6:
+		cfgList = &n.ipamV6Config
+		infoList = &n.ipamV6Info
+	default:
+		return types.InternalErrorf("incorrect ip version passed to ipam allocate: %d", ipVer)
+	}
+
+	if len(*cfgList) == 0 {
+		if ipVer == 6 {
+			return nil
+		}
+		*cfgList = []*IpamConf{&IpamConf{}}
+	}
+
+	*infoList = make([]*IpamInfo, len(*cfgList))
+
+	log.Debugf("Allocating IPv%d pools for network %s (%s)", ipVer, n.Name(), n.ID())
+
+	for i, cfg := range *cfgList {
+		if err = cfg.Validate(); err != nil {
+			return err
+		}
+		d := &IpamInfo{}
+		(*infoList)[i] = d
+
+		d.PoolID, d.Pool, d.Meta, err = ipam.RequestPool(n.addrSpace, cfg.PreferredPool, cfg.SubPool, cfg.Options, ipVer == 6)
+		if err != nil {
+			return err
+		}
+
+		defer func() {
+			if err != nil {
+				if err := ipam.ReleasePool(d.PoolID); err != nil {
+					log.Warnf("Failed to release address pool %s after failure to create network %s (%s)", d.PoolID, n.Name(), n.ID())
+				}
+			}
+		}()
+
+		if gws, ok := d.Meta[netlabel.Gateway]; ok {
+			if d.Gateway, err = types.ParseCIDR(gws); err != nil {
+				return types.BadRequestErrorf("failed to parse gateway address (%v) returned by ipam driver: %v", gws, err)
+			}
+		}
+
+		// If user requested a specific gateway, libnetwork will allocate it
+		// irrespective of whether ipam driver returned a gateway already.
+		// If none of the above is true, libnetwork will allocate one.
+		if cfg.Gateway != "" || d.Gateway == nil {
+			if d.Gateway, _, err = ipam.RequestAddress(d.PoolID, net.ParseIP(cfg.Gateway), nil); err != nil {
+				return types.InternalErrorf("failed to allocate gateway (%v): %v", cfg.Gateway, err)
+			}
+		}
+
+		// Auxiliary addresses must be part of the master address pool
+		// If they fall into the container addressable pool, libnetwork will reserve them
+		if cfg.AuxAddresses != nil {
+			var ip net.IP
+			d.IPAMData.AuxAddresses = make(map[string]*net.IPNet, len(cfg.AuxAddresses))
+			for k, v := range cfg.AuxAddresses {
+				if ip = net.ParseIP(v); ip == nil {
+					return types.BadRequestErrorf("non parsable secondary ip address (%s:%s) passed for network %s", k, v, n.Name())
+				}
+				if !d.Pool.Contains(ip) {
+					return types.ForbiddenErrorf("auxilairy address: (%s:%s) must belong to the master pool: %s", k, v, d.Pool)
+				}
+				// Attempt reservation in the container addressable pool, silent the error if address does not belong to that pool
+				if d.IPAMData.AuxAddresses[k], _, err = ipam.RequestAddress(d.PoolID, ip, nil); err != nil && err != ipamapi.ErrIPOutOfRange {
+					return types.InternalErrorf("failed to allocate secondary ip address (%s:%s): %v", k, v, err)
+				}
+			}
+		}
+	}
+
+	return nil
+}
+
+func (n *network) ipamRelease() {
+	// For now exclude host and null
+	if n.Type() == "host" || n.Type() == "null" {
+		return
+	}
+	ipam, err := n.getController().getIpamDriver(n.ipamType)
+	if err != nil {
+		log.Warnf("Failed to retrieve ipam driver to release address pool(s) on delete of network %s (%s): %v", n.Name(), n.ID(), err)
+		return
+	}
+	n.ipamReleaseVersion(4, ipam)
+	n.ipamReleaseVersion(6, ipam)
+}
+
+func (n *network) ipamReleaseVersion(ipVer int, ipam ipamapi.Ipam) {
+	var infoList []*IpamInfo
+
+	switch ipVer {
+	case 4:
+		infoList = n.ipamV4Info
+	case 6:
+		infoList = n.ipamV6Info
+	default:
+		log.Warnf("incorrect ip version passed to ipam release: %d", ipVer)
+		return
+	}
+
+	if infoList == nil {
+		return
+	}
+
+	log.Debugf("releasing IPv%d pools from network %s (%s)", ipVer, n.Name(), n.ID())
+
+	for _, d := range infoList {
+		if d.Gateway != nil {
+			if err := ipam.ReleaseAddress(d.PoolID, d.Gateway.IP); err != nil {
+				log.Warnf("Failed to release gateway ip address %s on delete of network %s (%s): %v", d.Gateway.IP, n.Name(), n.ID(), err)
+			}
+		}
+		if d.IPAMData.AuxAddresses != nil {
+			for k, nw := range d.IPAMData.AuxAddresses {
+				if d.Pool.Contains(nw.IP) {
+					if err := ipam.ReleaseAddress(d.PoolID, nw.IP); err != nil && err != ipamapi.ErrIPOutOfRange {
+						log.Warnf("Failed to release secondary ip address %s (%v) on delete of network %s (%s): %v", k, nw.IP, n.Name(), n.ID(), err)
+					}
+				}
+			}
+		}
+		if err := ipam.ReleasePool(d.PoolID); err != nil {
+			log.Warnf("Failed to release address pool %s on delete of network %s (%s): %v", d.PoolID, n.Name(), n.ID(), err)
+		}
+	}
+}
+
+func (n *network) getIPInfo(ipVer int) []*IpamInfo {
+	var info []*IpamInfo
+	switch ipVer {
+	case 4:
+		info = n.ipamV4Info
+	case 6:
+		info = n.ipamV6Info
+	default:
+		return nil
+	}
+	l := make([]*IpamInfo, 0, len(info))
+	n.Lock()
+	for _, d := range info {
+		l = append(l, d)
+	}
+	n.Unlock()
+	return l
+}
+
+func (n *network) getIPData(ipVer int) []driverapi.IPAMData {
+	var info []*IpamInfo
+	switch ipVer {
+	case 4:
+		info = n.ipamV4Info
+	case 6:
+		info = n.ipamV6Info
+	default:
+		return nil
+	}
+	l := make([]driverapi.IPAMData, 0, len(info))
+	n.Lock()
+	for _, d := range info {
+		l = append(l, d.IPAMData)
+	}
+	n.Unlock()
+	return l
+}
+
+func (n *network) deriveAddressSpace() (string, error) {
+	c := n.getController()
+	c.Lock()
+	ipd, ok := c.ipamDrivers[n.ipamType]
+	c.Unlock()
+	if !ok {
+		return "", types.NotFoundErrorf("could not find ipam driver %s to get default address space", n.ipamType)
+	}
+	if n.DataScope() == datastore.GlobalScope {
+		return ipd.defaultGlobalAddressSpace, nil
+	}
+	return ipd.defaultLocalAddressSpace, nil
+}
+
+func (n *network) Info() NetworkInfo {
+	return n
+}
+
+func (n *network) Labels() map[string]string {
+	n.Lock()
+	defer n.Unlock()
+	if n.generic != nil {
+		if m, ok := n.generic[netlabel.GenericData]; ok {
+			return m.(map[string]string)
+		}
+	}
+	return map[string]string{}
+}
+
+func (n *network) Scope() string {
+	return n.driverScope()
+}
+
+func (n *network) IpamConfig() (string, []*IpamConf, []*IpamConf) {
+	n.Lock()
+	defer n.Unlock()
+
+	v4L := make([]*IpamConf, len(n.ipamV4Config))
+	v6L := make([]*IpamConf, len(n.ipamV6Config))
+
+	for i, c := range n.ipamV4Config {
+		cc := &IpamConf{}
+		c.CopyTo(cc)
+		v4L[i] = cc
+	}
+
+	for i, c := range n.ipamV6Config {
+		cc := &IpamConf{}
+		c.CopyTo(cc)
+		v6L[i] = cc
+	}
+
+	return n.ipamType, v4L, v6L
+}

+ 3 - 3
vendor/src/github.com/docker/libnetwork/osl/interface_linux.go

@@ -156,7 +156,7 @@ func (i *nwIface) Remove() error {
 }
 
 // Returns the sandbox's side veth interface statistics
-func (i *nwIface) Statistics() (*InterfaceStatistics, error) {
+func (i *nwIface) Statistics() (*types.InterfaceStatistics, error) {
 	i.Lock()
 	n := i.ns
 	i.Unlock()
@@ -165,7 +165,7 @@ func (i *nwIface) Statistics() (*InterfaceStatistics, error) {
 	path := n.path
 	n.Unlock()
 
-	s := &InterfaceStatistics{}
+	s := &types.InterfaceStatistics{}
 
 	err := nsInvoke(path, func(nsFD int) error { return nil }, func(callerFD int) error {
 		// For some reason ioutil.ReadFile(netStatsFile) reads the file in
@@ -356,7 +356,7 @@ const (
 	base         = "[ ]*%s:([ ]+[0-9]+){16}"
 )
 
-func scanInterfaceStats(data, ifName string, i *InterfaceStatistics) error {
+func scanInterfaceStats(data, ifName string, i *types.InterfaceStatistics) error {
 	var (
 		bktStr string
 		bkt    uint64

+ 1 - 19
vendor/src/github.com/docker/libnetwork/osl/sandbox.go

@@ -2,7 +2,6 @@
 package osl
 
 import (
-	"fmt"
 	"net"
 
 	"github.com/docker/libnetwork/types"
@@ -150,22 +149,5 @@ type Interface interface {
 	Remove() error
 
 	// Statistics returns the statistics for this interface
-	Statistics() (*InterfaceStatistics, error)
-}
-
-// InterfaceStatistics represents the interface's statistics
-type InterfaceStatistics struct {
-	RxBytes   uint64
-	RxPackets uint64
-	RxErrors  uint64
-	RxDropped uint64
-	TxBytes   uint64
-	TxPackets uint64
-	TxErrors  uint64
-	TxDropped uint64
-}
-
-func (is *InterfaceStatistics) String() string {
-	return fmt.Sprintf("\nRxBytes: %d, RxPackets: %d, RxErrors: %d, RxDropped: %d, TxBytes: %d, TxPackets: %d, TxErrors: %d, TxDropped: %d",
-		is.RxBytes, is.RxPackets, is.RxErrors, is.RxDropped, is.TxBytes, is.TxPackets, is.TxErrors, is.TxDropped)
+	Statistics() (*types.InterfaceStatistics, error)
 }

+ 1 - 1
vendor/src/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go

@@ -5,7 +5,7 @@ import (
 )
 
 // IPLocalhost is a regex patter for localhost IP address range.
-const IPLocalhost = `((127\.([0-9]{1,3}.){2}[0-9]{1,3})|(::1))`
+const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1))`
 
 var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
 

+ 92 - 35
vendor/src/github.com/docker/libnetwork/sandbox.go

@@ -28,7 +28,7 @@ type Sandbox interface {
 	// Labels returns the sandbox's labels
 	Labels() map[string]interface{}
 	// Statistics retrieves the interfaces' statistics for the sandbox
-	Statistics() (map[string]*osl.InterfaceStatistics, error)
+	Statistics() (map[string]*types.InterfaceStatistics, error)
 	// Refresh leaves all the endpoints, resets and re-apply the options,
 	// re-joins all the endpoints without destroying the osl sandbox
 	Refresh(options ...SandboxOption) error
@@ -64,6 +64,8 @@ type sandbox struct {
 	endpoints     epHeap
 	epPriority    map[string]int
 	joinLeaveDone chan struct{}
+	dbIndex       uint64
+	dbExists      bool
 	sync.Mutex
 }
 
@@ -126,8 +128,8 @@ func (sb *sandbox) Labels() map[string]interface{} {
 	return sb.config.generic
 }
 
-func (sb *sandbox) Statistics() (map[string]*osl.InterfaceStatistics, error) {
-	m := make(map[string]*osl.InterfaceStatistics)
+func (sb *sandbox) Statistics() (map[string]*types.InterfaceStatistics, error) {
+	m := make(map[string]*types.InterfaceStatistics)
 
 	if sb.osSbox == nil {
 		return m, nil
@@ -153,15 +155,24 @@ func (sb *sandbox) Delete() error {
 		if ep.endpointInGWNetwork() {
 			continue
 		}
+
 		if err := ep.Leave(sb); err != nil {
 			log.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err)
 		}
+
+		if err := ep.Delete(); err != nil {
+			log.Warnf("Failed deleting endpoint %s: %v\n", ep.ID(), err)
+		}
 	}
 
 	if sb.osSbox != nil {
 		sb.osSbox.Destroy()
 	}
 
+	if err := sb.storeDelete(); err != nil {
+		log.Warnf("Failed to delete sandbox %s from store: %v", sb.ID(), err)
+	}
+
 	c.Lock()
 	delete(c.sandboxes, sb.ID())
 	c.Unlock()
@@ -247,6 +258,19 @@ func (sb *sandbox) getConnectedEndpoints() []*endpoint {
 	return eps
 }
 
+func (sb *sandbox) getEndpoint(id string) *endpoint {
+	sb.Lock()
+	defer sb.Unlock()
+
+	for _, ep := range sb.endpoints {
+		if ep.id == id {
+			return ep
+		}
+	}
+
+	return nil
+}
+
 func (sb *sandbox) updateGateway(ep *endpoint) error {
 	sb.Lock()
 	osSbox := sb.osSbox
@@ -283,15 +307,21 @@ func (sb *sandbox) SetKey(basePath string) error {
 	}
 
 	sb.Lock()
-	if sb.osSbox != nil {
-		sb.Unlock()
-		return types.ForbiddenErrorf("failed to set sandbox key : already assigned")
-	}
+	osSbox := sb.osSbox
 	sb.Unlock()
-	osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key())
+
+	if osSbox != nil {
+		// If we already have an OS sandbox, release the network resources from that
+		// and destroy the OS snab. We are moving into a new home further down. Note that none
+		// of the network resources gets destroyed during the move.
+		sb.releaseOSSbox()
+	}
+
+	osSbox, err = osl.GetSandboxForExternalKey(basePath, sb.Key())
 	if err != nil {
 		return err
 	}
+
 	sb.Lock()
 	sb.osSbox = osSbox
 	sb.Unlock()
@@ -311,6 +341,45 @@ func (sb *sandbox) SetKey(basePath string) error {
 	return nil
 }
 
+func releaseOSSboxResources(osSbox osl.Sandbox, ep *endpoint) {
+	for _, i := range osSbox.Info().Interfaces() {
+		// Only remove the interfaces owned by this endpoint from the sandbox.
+		if ep.hasInterface(i.SrcName()) {
+			if err := i.Remove(); err != nil {
+				log.Debugf("Remove interface failed: %v", err)
+			}
+		}
+	}
+
+	ep.Lock()
+	joinInfo := ep.joinInfo
+	ep.Unlock()
+
+	// Remove non-interface routes.
+	for _, r := range joinInfo.StaticRoutes {
+		if err := osSbox.RemoveStaticRoute(r); err != nil {
+			log.Debugf("Remove route failed: %v", err)
+		}
+	}
+}
+
+func (sb *sandbox) releaseOSSbox() {
+	sb.Lock()
+	osSbox := sb.osSbox
+	sb.osSbox = nil
+	sb.Unlock()
+
+	if osSbox == nil {
+		return
+	}
+
+	for _, ep := range sb.getConnectedEndpoints() {
+		releaseOSSboxResources(osSbox, ep)
+	}
+
+	osSbox.Destroy()
+}
+
 func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
 	sb.Lock()
 	if sb.osSbox == nil {
@@ -324,12 +393,12 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
 	i := ep.iface
 	ep.Unlock()
 
-	if i != nil {
+	if i.srcName != "" {
 		var ifaceOptions []osl.IfaceOption
 
-		ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(&i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes))
-		if i.addrv6.IP.To16() != nil {
-			ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(&i.addrv6))
+		ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes))
+		if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
+			ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6))
 		}
 
 		if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
@@ -356,33 +425,21 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
 			}
 		}
 	}
-	return nil
+	return sb.storeUpdate()
 }
 
-func (sb *sandbox) clearNetworkResources(ep *endpoint) error {
+func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
+	ep := sb.getEndpoint(origEp.id)
+	if ep == nil {
+		return fmt.Errorf("could not find the sandbox endpoint data for endpoint %s",
+			ep.name)
+	}
+
 	sb.Lock()
 	osSbox := sb.osSbox
 	sb.Unlock()
 	if osSbox != nil {
-		for _, i := range osSbox.Info().Interfaces() {
-			// Only remove the interfaces owned by this endpoint from the sandbox.
-			if ep.hasInterface(i.SrcName()) {
-				if err := i.Remove(); err != nil {
-					log.Debugf("Remove interface failed: %v", err)
-				}
-			}
-		}
-
-		ep.Lock()
-		joinInfo := ep.joinInfo
-		ep.Unlock()
-
-		// Remove non-interface routes.
-		for _, r := range joinInfo.StaticRoutes {
-			if err := osSbox.RemoveStaticRoute(r); err != nil {
-				log.Debugf("Remove route failed: %v", err)
-			}
-		}
+		releaseOSSboxResources(osSbox, ep)
 	}
 
 	sb.Lock()
@@ -423,7 +480,7 @@ func (sb *sandbox) clearNetworkResources(ep *endpoint) error {
 		sb.updateGateway(gwepAfter)
 	}
 
-	return nil
+	return sb.storeUpdate()
 }
 
 const (
@@ -837,7 +894,7 @@ func (eh epHeap) Less(i, j int) bool {
 		cjp = 0
 	}
 	if cip == cjp {
-		return eh[i].getNetwork().Name() < eh[j].getNetwork().Name()
+		return eh[i].network.Name() < eh[j].network.Name()
 	}
 
 	return cip > cjp

+ 211 - 0
vendor/src/github.com/docker/libnetwork/sandbox_store.go

@@ -0,0 +1,211 @@
+package libnetwork
+
+import (
+	"container/heap"
+	"encoding/json"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/datastore"
+	"github.com/docker/libnetwork/osl"
+)
+
+const (
+	sandboxPrefix = "sandbox"
+)
+
+type epState struct {
+	Eid string
+	Nid string
+}
+
+type sbState struct {
+	ID       string
+	Cid      string
+	c        *controller
+	dbIndex  uint64
+	dbExists bool
+	Eps      []epState
+}
+
+func (sbs *sbState) Key() []string {
+	return []string{sandboxPrefix, sbs.ID}
+}
+
+func (sbs *sbState) KeyPrefix() []string {
+	return []string{sandboxPrefix}
+}
+
+func (sbs *sbState) Value() []byte {
+	b, err := json.Marshal(sbs)
+	if err != nil {
+		return nil
+	}
+	return b
+}
+
+func (sbs *sbState) SetValue(value []byte) error {
+	return json.Unmarshal(value, sbs)
+}
+
+func (sbs *sbState) Index() uint64 {
+	sbi, err := sbs.c.SandboxByID(sbs.ID)
+	if err != nil {
+		return sbs.dbIndex
+	}
+
+	sb := sbi.(*sandbox)
+	maxIndex := sb.dbIndex
+	if sbs.dbIndex > maxIndex {
+		maxIndex = sbs.dbIndex
+	}
+
+	return maxIndex
+}
+
+func (sbs *sbState) SetIndex(index uint64) {
+	sbs.dbIndex = index
+	sbs.dbExists = true
+
+	sbi, err := sbs.c.SandboxByID(sbs.ID)
+	if err != nil {
+		return
+	}
+
+	sb := sbi.(*sandbox)
+	sb.dbIndex = index
+	sb.dbExists = true
+}
+
+func (sbs *sbState) Exists() bool {
+	if sbs.dbExists {
+		return sbs.dbExists
+	}
+
+	sbi, err := sbs.c.SandboxByID(sbs.ID)
+	if err != nil {
+		return false
+	}
+
+	sb := sbi.(*sandbox)
+	return sb.dbExists
+}
+
+func (sbs *sbState) Skip() bool {
+	return false
+}
+
+func (sbs *sbState) New() datastore.KVObject {
+	return &sbState{c: sbs.c}
+}
+
+func (sbs *sbState) CopyTo(o datastore.KVObject) error {
+	dstSbs := o.(*sbState)
+	dstSbs.c = sbs.c
+	dstSbs.ID = sbs.ID
+	dstSbs.Cid = sbs.Cid
+	dstSbs.dbIndex = sbs.dbIndex
+	dstSbs.dbExists = sbs.dbExists
+
+	for _, eps := range sbs.Eps {
+		dstSbs.Eps = append(dstSbs.Eps, eps)
+	}
+
+	return nil
+}
+
+func (sbs *sbState) DataScope() string {
+	return datastore.LocalScope
+}
+
+func (sb *sandbox) storeUpdate() error {
+	sbs := &sbState{
+		c:  sb.controller,
+		ID: sb.id,
+	}
+
+	for _, ep := range sb.getConnectedEndpoints() {
+		eps := epState{
+			Nid: ep.getNetwork().ID(),
+			Eid: ep.ID(),
+		}
+
+		sbs.Eps = append(sbs.Eps, eps)
+	}
+
+	return sb.controller.updateToStore(sbs)
+}
+
+func (sb *sandbox) storeDelete() error {
+	sbs := &sbState{
+		c:        sb.controller,
+		ID:       sb.id,
+		Cid:      sb.containerID,
+		dbIndex:  sb.dbIndex,
+		dbExists: sb.dbExists,
+	}
+
+	return sb.controller.deleteFromStore(sbs)
+}
+
+func (c *controller) sandboxCleanup() {
+	store := c.getStore(datastore.LocalScope)
+	if store == nil {
+		logrus.Errorf("Could not find local scope store while trying to cleanup sandboxes")
+		return
+	}
+
+	kvol, err := store.List(datastore.Key(sandboxPrefix), &sbState{c: c})
+	if err != nil && err != datastore.ErrKeyNotFound {
+		logrus.Errorf("failed to get sandboxes for scope %s: %v", store.Scope(), err)
+		return
+	}
+
+	// It's normal for no sandboxes to be found. Just bail out.
+	if err == datastore.ErrKeyNotFound {
+		return
+	}
+
+	for _, kvo := range kvol {
+		sbs := kvo.(*sbState)
+
+		sb := &sandbox{
+			id:          sbs.ID,
+			controller:  sbs.c,
+			containerID: sbs.Cid,
+			endpoints:   epHeap{},
+			epPriority:  map[string]int{},
+			dbIndex:     sbs.dbIndex,
+			dbExists:    true,
+		}
+
+		sb.osSbox, err = osl.NewSandbox(sb.Key(), true)
+		if err != nil {
+			logrus.Errorf("failed to create new osl sandbox while trying to build sandbox for cleanup: %v", err)
+			continue
+		}
+
+		for _, eps := range sbs.Eps {
+			n, err := c.getNetworkFromStore(eps.Nid)
+			if err != nil {
+				logrus.Errorf("getNetworkFromStore for nid %s failed while trying to build sandbox for cleanup: %v", eps.Nid, err)
+				continue
+			}
+
+			ep, err := n.getEndpointFromStore(eps.Eid)
+			if err != nil {
+				logrus.Errorf("getEndpointFromStore for eid %s failed while trying to build sandbox for cleanup: %v", eps.Eid, err)
+				continue
+			}
+
+			heap.Push(&sb.endpoints, ep)
+		}
+
+		c.Lock()
+		c.sandboxes[sb.id] = sb
+		c.Unlock()
+
+		if err := sb.Delete(); err != nil {
+			logrus.Errorf("failed to delete sandbox %s while trying to cleanup: %v", sb.id, err)
+		}
+	}
+}

+ 273 - 299
vendor/src/github.com/docker/libnetwork/store.go

@@ -1,392 +1,366 @@
 package libnetwork
 
 import (
-	"encoding/json"
 	"fmt"
-	"time"
 
 	log "github.com/Sirupsen/logrus"
-	"github.com/docker/libkv/store"
-	"github.com/docker/libnetwork/config"
 	"github.com/docker/libnetwork/datastore"
 )
 
-var (
-	defaultBoltTimeout      = 3 * time.Second
-	defaultLocalStoreConfig = config.DatastoreCfg{
-		Embedded: true,
-		Client: config.DatastoreClientCfg{
-			Provider: "boltdb",
-			Address:  defaultPrefix + "/boltdb.db",
-			Config: &store.Config{
-				Bucket:            "libnetwork",
-				ConnectionTimeout: defaultBoltTimeout,
-			},
-		},
-	}
-)
-
-func (c *controller) validateGlobalStoreConfig() bool {
-	return c.cfg != nil && c.cfg.GlobalStore.Client.Provider != "" && c.cfg.GlobalStore.Client.Address != ""
-}
-
-func (c *controller) initGlobalStore() error {
+func (c *controller) initStores() error {
 	c.Lock()
-	cfg := c.cfg
-	c.Unlock()
-	if !c.validateGlobalStoreConfig() {
-		return fmt.Errorf("globalstore initialization requires a valid configuration")
-	}
-
-	store, err := datastore.NewDataStore(&cfg.GlobalStore)
-	if err != nil {
-		return err
+	if c.cfg == nil {
+		c.Unlock()
+		return nil
 	}
-	c.Lock()
-	c.globalStore = store
+	scopeConfigs := c.cfg.Scopes
 	c.Unlock()
 
-	nws, err := c.getNetworksFromStore(true)
-	if err == nil {
-		c.processNetworkUpdate(nws, nil)
-	} else if err != datastore.ErrKeyNotFound {
-		log.Warnf("failed to read networks from globalstore during init : %v", err)
+	for scope, scfg := range scopeConfigs {
+		store, err := datastore.NewDataStore(scope, scfg)
+		if err != nil {
+			return err
+		}
+		c.Lock()
+		c.stores = append(c.stores, store)
+		c.Unlock()
 	}
-	return c.watchNetworks()
+
+	c.startWatch()
+	return nil
 }
 
-func (c *controller) initLocalStore() error {
-	c.Lock()
-	cfg := c.cfg
-	c.Unlock()
-	localStore, err := datastore.NewDataStore(c.getLocalStoreConfig(cfg))
-	if err != nil {
-		return err
+func (c *controller) closeStores() {
+	for _, store := range c.getStores() {
+		store.Close()
 	}
+}
+
+func (c *controller) getStore(scope string) datastore.DataStore {
 	c.Lock()
-	c.localStore = localStore
-	c.Unlock()
+	defer c.Unlock()
 
-	nws, err := c.getNetworksFromStore(false)
-	if err == nil {
-		c.processNetworkUpdate(nws, nil)
-	} else if err != datastore.ErrKeyNotFound {
-		log.Warnf("failed to read networks from localstore during init : %v", err)
+	for _, store := range c.stores {
+		if store.Scope() == scope {
+			return store
+		}
 	}
+
 	return nil
 }
 
-func (c *controller) getNetworksFromStore(global bool) ([]*store.KVPair, error) {
-	var cs datastore.DataStore
+func (c *controller) getStores() []datastore.DataStore {
 	c.Lock()
-	if global {
-		cs = c.globalStore
-	} else {
-		cs = c.localStore
+	defer c.Unlock()
+
+	return c.stores
+}
+
+func (c *controller) getNetworkFromStore(nid string) (*network, error) {
+	for _, store := range c.getStores() {
+		n := &network{id: nid, ctrlr: c}
+		err := store.GetObject(datastore.Key(n.Key()...), n)
+		if err != nil && err != datastore.ErrKeyNotFound {
+			return nil, fmt.Errorf("could not find network %s: %v", nid, err)
+		}
+
+		// Continue searching in the next store if the key is not found in this store
+		if err == datastore.ErrKeyNotFound {
+			continue
+		}
+
+		ec := &endpointCnt{n: n}
+		err = store.GetObject(datastore.Key(ec.Key()...), ec)
+		if err != nil {
+			return nil, fmt.Errorf("could not find endpoint count for network %s: %v", n.Name(), err)
+		}
+
+		n.epCnt = ec
+		return n, nil
 	}
-	c.Unlock()
-	return cs.KVStore().List(datastore.Key(datastore.NetworkKeyPrefix))
+
+	return nil, fmt.Errorf("network %s not found", nid)
 }
 
-func (c *controller) newNetworkFromStore(n *network) error {
-	n.Lock()
-	n.ctrlr = c
-	n.endpoints = endpointTable{}
-	n.Unlock()
+func (c *controller) getNetworksFromStore() ([]*network, error) {
+	var nl []*network
+
+	for _, store := range c.getStores() {
+		kvol, err := store.List(datastore.Key(datastore.NetworkKeyPrefix),
+			&network{ctrlr: c})
+		if err != nil && err != datastore.ErrKeyNotFound {
+			return nil, fmt.Errorf("failed to get networks for scope %s: %v",
+				store.Scope(), err)
+		}
+
+		// Continue searching in the next store if no keys found in this store
+		if err == datastore.ErrKeyNotFound {
+			continue
+		}
+
+		for _, kvo := range kvol {
+			n := kvo.(*network)
+			n.ctrlr = c
+
+			ec := &endpointCnt{n: n}
+			err = store.GetObject(datastore.Key(ec.Key()...), ec)
+			if err != nil {
+				return nil, fmt.Errorf("could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err)
+			}
+
+			n.epCnt = ec
+			nl = append(nl, n)
+		}
+	}
 
-	return c.addNetwork(n)
+	return nl, nil
 }
 
-func (c *controller) newEndpointFromStore(key string, ep *endpoint) error {
-	ep.Lock()
-	n := ep.network
-	id := ep.id
-	ep.Unlock()
+func (n *network) getEndpointFromStore(eid string) (*endpoint, error) {
+	for _, store := range n.ctrlr.getStores() {
+		ep := &endpoint{id: eid, network: n}
+		err := store.GetObject(datastore.Key(ep.Key()...), ep)
+		if err != nil && err != datastore.ErrKeyNotFound {
+			return nil, fmt.Errorf("could not find endpoint %s: %v", eid, err)
+		}
 
-	_, err := n.EndpointByID(id)
-	if err != nil {
-		if _, ok := err.(ErrNoSuchEndpoint); ok {
-			return n.addEndpoint(ep)
+		// Continue searching in the next store if the key is not found in this store
+		if err == datastore.ErrKeyNotFound {
+			continue
 		}
+
+		return ep, nil
 	}
-	return err
+
+	return nil, fmt.Errorf("endpoint %s not found", eid)
 }
 
-func (c *controller) updateToStore(kvObject datastore.KV) error {
-	if kvObject.Skip() {
-		return nil
+func (n *network) getEndpointsFromStore() ([]*endpoint, error) {
+	var epl []*endpoint
+
+	tmp := endpoint{network: n}
+	for _, store := range n.getController().getStores() {
+		kvol, err := store.List(datastore.Key(tmp.KeyPrefix()...), &endpoint{network: n})
+		if err != nil && err != datastore.ErrKeyNotFound {
+			return nil,
+				fmt.Errorf("failed to get endpoints for network %s scope %s: %v",
+					n.Name(), store.Scope(), err)
+		}
+
+		// Continue searching in the next store if no keys found in this store
+		if err == datastore.ErrKeyNotFound {
+			continue
+		}
+
+		for _, kvo := range kvol {
+			ep := kvo.(*endpoint)
+			ep.network = n
+			epl = append(epl, ep)
+		}
 	}
-	cs := c.getDataStore(kvObject.DataScope())
+
+	return epl, nil
+}
+
+func (c *controller) updateToStore(kvObject datastore.KVObject) error {
+	cs := c.getStore(kvObject.DataScope())
 	if cs == nil {
-		log.Debugf("datastore not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...))
+		log.Warnf("datastore for scope %s not initialized. kv object %s is not added to the store", kvObject.DataScope(), datastore.Key(kvObject.Key()...))
 		return nil
 	}
 
-	return cs.PutObjectAtomic(kvObject)
+	if err := cs.PutObjectAtomic(kvObject); err != nil {
+		if err == datastore.ErrKeyModified {
+			return err
+		}
+		return fmt.Errorf("failed to update store for object type %T: %v", kvObject, err)
+	}
+
+	return nil
 }
 
-func (c *controller) deleteFromStore(kvObject datastore.KV) error {
-	if kvObject.Skip() {
-		return nil
-	}
-	cs := c.getDataStore(kvObject.DataScope())
+func (c *controller) deleteFromStore(kvObject datastore.KVObject) error {
+	cs := c.getStore(kvObject.DataScope())
 	if cs == nil {
-		log.Debugf("datastore not initialized. kv object %s is not deleted from datastore", datastore.Key(kvObject.Key()...))
+		log.Debugf("datastore for scope %s not initialized. kv object %s is not deleted from datastore", kvObject.DataScope(), datastore.Key(kvObject.Key()...))
 		return nil
 	}
 
+retry:
 	if err := cs.DeleteObjectAtomic(kvObject); err != nil {
+		if err == datastore.ErrKeyModified {
+			if err := cs.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil {
+				return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err)
+			}
+			goto retry
+		}
 		return err
 	}
 
 	return nil
 }
 
-func (c *controller) watchNetworks() error {
-	if !c.validateGlobalStoreConfig() {
-		return nil
-	}
+type netWatch struct {
+	localEps  map[string]*endpoint
+	remoteEps map[string]*endpoint
+	stopCh    chan struct{}
+}
 
+func (c *controller) getLocalEps(nw *netWatch) []*endpoint {
 	c.Lock()
-	cs := c.globalStore
-	c.Unlock()
+	defer c.Unlock()
 
-	networkKey := datastore.Key(datastore.NetworkKeyPrefix)
-	if err := ensureKeys(networkKey, cs); err != nil {
-		return fmt.Errorf("failed to ensure if the network keys are valid and present in store: %v", err)
-	}
-	nwPairs, err := cs.KVStore().WatchTree(networkKey, nil)
-	if err != nil {
-		return err
+	var epl []*endpoint
+	for _, ep := range nw.localEps {
+		epl = append(epl, ep)
 	}
-	go func() {
-		for {
-			select {
-			case nws := <-nwPairs:
-				c.Lock()
-				tmpview := networkTable{}
-				lview := c.networks
-				c.Unlock()
-				for k, v := range lview {
-					if v.isGlobalScoped() {
-						tmpview[k] = v
-					}
-				}
-				c.processNetworkUpdate(nws, &tmpview)
-
-				// Delete processing
-				for k := range tmpview {
-					c.Lock()
-					existing, ok := c.networks[k]
-					c.Unlock()
-					if !ok {
-						continue
-					}
-					tmp := network{}
-					if err := c.globalStore.GetObject(datastore.Key(existing.Key()...), &tmp); err != datastore.ErrKeyNotFound {
-						continue
-					}
-					if err := existing.deleteNetwork(); err != nil {
-						log.Debugf("Delete failed %s: %s", existing.name, err)
-					}
-				}
-			}
-		}
-	}()
-	return nil
+
+	return epl
 }
 
-func (n *network) watchEndpoints() error {
-	if n.Skip() || !n.ctrlr.validateGlobalStoreConfig() {
-		return nil
-	}
+func (c *controller) watchSvcRecord(ep *endpoint) {
+	c.watchCh <- ep
+}
 
-	n.Lock()
-	cs := n.ctrlr.globalStore
-	tmp := endpoint{network: n}
-	n.stopWatchCh = make(chan struct{})
-	stopCh := n.stopWatchCh
-	n.Unlock()
+func (c *controller) unWatchSvcRecord(ep *endpoint) {
+	c.unWatchCh <- ep
+}
 
-	endpointKey := datastore.Key(tmp.KeyPrefix()...)
-	if err := ensureKeys(endpointKey, cs); err != nil {
-		return fmt.Errorf("failed to ensure if the endpoint keys are valid and present in store: %v", err)
-	}
-	epPairs, err := cs.KVStore().WatchTree(endpointKey, stopCh)
-	if err != nil {
-		return err
-	}
-	go func() {
-		for {
-			select {
-			case <-stopCh:
-				return
-			case eps := <-epPairs:
-				n.Lock()
-				tmpview := endpointTable{}
-				lview := n.endpoints
-				n.Unlock()
-				for k, v := range lview {
-					if v.network.isGlobalScoped() {
-						tmpview[k] = v
-					}
+func (c *controller) networkWatchLoop(nw *netWatch, ep *endpoint, ecCh <-chan datastore.KVObject) {
+	for {
+		select {
+		case <-nw.stopCh:
+			return
+		case o := <-ecCh:
+			ec := o.(*endpointCnt)
+
+			epl, err := ec.n.getEndpointsFromStore()
+			if err != nil {
+				break
+			}
+
+			c.Lock()
+			var addEp []*endpoint
+
+			delEpMap := make(map[string]*endpoint)
+			for k, v := range nw.remoteEps {
+				delEpMap[k] = v
+			}
+
+			for _, lEp := range epl {
+				if _, ok := nw.localEps[lEp.ID()]; ok {
+					continue
 				}
-				n.ctrlr.processEndpointsUpdate(eps, &tmpview)
-				// Delete processing
-				for k := range tmpview {
-					n.Lock()
-					existing, ok := n.endpoints[k]
-					n.Unlock()
-					if !ok {
-						continue
-					}
-					tmp := endpoint{}
-					if err := cs.GetObject(datastore.Key(existing.Key()...), &tmp); err != datastore.ErrKeyNotFound {
-						continue
-					}
-					if err := existing.deleteEndpoint(); err != nil {
-						log.Debugf("Delete failed %s: %s", existing.name, err)
-					}
+
+				if _, ok := nw.remoteEps[lEp.ID()]; ok {
+					delete(delEpMap, lEp.ID())
+					continue
 				}
+
+				nw.remoteEps[lEp.ID()] = lEp
+				addEp = append(addEp, lEp)
+
+			}
+			c.Unlock()
+
+			for _, lEp := range addEp {
+				ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), true)
 			}
-		}
-	}()
-	return nil
-}
 
-func (n *network) stopWatch() {
-	n.Lock()
-	if n.stopWatchCh != nil {
-		close(n.stopWatchCh)
-		n.stopWatchCh = nil
+			for _, lEp := range delEpMap {
+				ep.getNetwork().updateSvcRecord(lEp, c.getLocalEps(nw), false)
+
+			}
+		}
 	}
-	n.Unlock()
 }
 
-func (c *controller) processNetworkUpdate(nws []*store.KVPair, prune *networkTable) {
-	for _, kve := range nws {
-		var n network
-		err := json.Unmarshal(kve.Value, &n)
-		if err != nil {
-			log.Error(err)
-			continue
-		}
-		if prune != nil {
-			delete(*prune, n.id)
-		}
-		n.SetIndex(kve.LastIndex)
+func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoint) {
+	c.Lock()
+	nw, ok := nmap[ep.getNetwork().ID()]
+	c.Unlock()
+
+	if ok {
+		// Update the svc db for the local endpoint join right away
+		ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), true)
+
 		c.Lock()
-		existing, ok := c.networks[n.id]
+		nw.localEps[ep.ID()] = ep
 		c.Unlock()
-		if ok {
-			existing.Lock()
-			// Skip existing network update
-			if existing.dbIndex != n.Index() {
-				// Can't use SetIndex() since existing is locked.
-				existing.dbIndex = n.Index()
-				existing.dbExists = true
-				existing.endpointCnt = n.endpointCnt
-			}
-			existing.Unlock()
-			continue
-		}
-
-		if err = c.newNetworkFromStore(&n); err != nil {
-			log.Error(err)
-		}
+		return
 	}
-}
 
-func (c *controller) processEndpointUpdate(ep *endpoint) bool {
-	nw := ep.network
-	if nw == nil {
-		return true
+	nw = &netWatch{
+		localEps:  make(map[string]*endpoint),
+		remoteEps: make(map[string]*endpoint),
 	}
-	nw.Lock()
-	id := nw.id
-	nw.Unlock()
+
+	// Update the svc db for the local endpoint join right away
+	// Do this before adding this ep to localEps so that we don't
+	// try to update this ep's container's svc records
+	ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), true)
 
 	c.Lock()
-	n, ok := c.networks[id]
+	nw.localEps[ep.ID()] = ep
+	nmap[ep.getNetwork().ID()] = nw
+	nw.stopCh = make(chan struct{})
 	c.Unlock()
-	if !ok {
-		return true
-	}
-	existing, _ := n.EndpointByID(ep.id)
-	if existing == nil {
-		return true
-	}
 
-	ee := existing.(*endpoint)
-	ee.Lock()
-	if ee.dbIndex != ep.Index() {
-		// Can't use SetIndex() because ee is locked.
-		ee.dbIndex = ep.Index()
-		ee.dbExists = true
-		ee.sandboxID = ep.sandboxID
+	store := c.getStore(ep.getNetwork().DataScope())
+	if store == nil {
+		return
 	}
-	ee.Unlock()
 
-	return false
-}
+	if !store.Watchable() {
+		return
+	}
 
-func ensureKeys(key string, cs datastore.DataStore) error {
-	exists, err := cs.KVStore().Exists(key)
+	ch, err := store.Watch(ep.getNetwork().getEpCnt(), nw.stopCh)
 	if err != nil {
-		return err
-	}
-	if exists {
-		return nil
+		log.Warnf("Error creating watch for network: %v", err)
+		return
 	}
-	return cs.KVStore().Put(key, []byte{}, nil)
-}
 
-func (c *controller) getLocalStoreConfig(cfg *config.Config) *config.DatastoreCfg {
-	if cfg != nil && cfg.LocalStore.Client.Provider != "" && cfg.LocalStore.Client.Address != "" {
-		return &cfg.LocalStore
-	}
-	return &defaultLocalStoreConfig
+	go c.networkWatchLoop(nw, ep, ch)
 }
 
-func (c *controller) getDataStore(dataScope datastore.DataScope) (dataStore datastore.DataStore) {
+func (c *controller) processEndpointDelete(nmap map[string]*netWatch, ep *endpoint) {
 	c.Lock()
-	if dataScope == datastore.GlobalScope {
-		dataStore = c.globalStore
-	} else if dataScope == datastore.LocalScope {
-		dataStore = c.localStore
+	nw, ok := nmap[ep.getNetwork().ID()]
+
+	if ok {
+		delete(nw.localEps, ep.ID())
+		c.Unlock()
+
+		// Update the svc db about local endpoint leave right away
+		// Do this after we remove this ep from localEps so that we
+		// don't try to remove this svc record from this ep's container.
+		ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), false)
+
+		c.Lock()
+		if len(nw.localEps) == 0 {
+			close(nw.stopCh)
+			delete(nmap, ep.getNetwork().ID())
+		}
 	}
 	c.Unlock()
-	return
 }
 
-func (c *controller) processEndpointsUpdate(eps []*store.KVPair, prune *endpointTable) {
-	for _, epe := range eps {
-		var ep endpoint
-		err := json.Unmarshal(epe.Value, &ep)
-		if err != nil {
-			log.Error(err)
-			continue
-		}
-		if prune != nil {
-			delete(*prune, ep.id)
-		}
-		ep.SetIndex(epe.LastIndex)
-		if nid, err := ep.networkIDFromKey(epe.Key); err != nil {
-			log.Error(err)
-			continue
-		} else {
-			if n, err := c.NetworkByID(nid); err != nil {
-				log.Error(err)
-				continue
-			} else {
-				ep.network = n.(*network)
-			}
-		}
-		if c.processEndpointUpdate(&ep) {
-			err = c.newEndpointFromStore(epe.Key, &ep)
-			if err != nil {
-				log.Error(err)
-			}
+func (c *controller) watchLoop(nmap map[string]*netWatch) {
+	for {
+		select {
+		case ep := <-c.watchCh:
+			c.processEndpointCreate(nmap, ep)
+		case ep := <-c.unWatchCh:
+			c.processEndpointDelete(nmap, ep)
 		}
 	}
 }
+
+func (c *controller) startWatch() {
+	c.watchCh = make(chan *endpoint)
+	c.unWatchCh = make(chan *endpoint)
+	nmap := make(map[string]*netWatch)
+
+	go c.watchLoop(nmap)
+}

+ 160 - 8
vendor/src/github.com/docker/libnetwork/types/types.go

@@ -5,6 +5,7 @@ import (
 	"bytes"
 	"fmt"
 	"net"
+	"strconv"
 	"strings"
 )
 
@@ -17,11 +18,46 @@ type TransportPort struct {
 	Port  uint16
 }
 
+// Equal checks if this instance of Transportport is equal to the passed one
+func (t *TransportPort) Equal(o *TransportPort) bool {
+	if t == o {
+		return true
+	}
+
+	if o == nil {
+		return false
+	}
+
+	if t.Proto != o.Proto || t.Port != o.Port {
+		return false
+	}
+
+	return true
+}
+
 // GetCopy returns a copy of this TransportPort structure instance
 func (t *TransportPort) GetCopy() TransportPort {
 	return TransportPort{Proto: t.Proto, Port: t.Port}
 }
 
+// String returns the TransportPort structure in string form
+func (t *TransportPort) String() string {
+	return fmt.Sprintf("%s/%d", t.Proto.String(), t.Port)
+}
+
+// FromString reads the TransportPort structure from string
+func (t *TransportPort) FromString(s string) error {
+	ps := strings.Split(s, "/")
+	if len(ps) == 2 {
+		t.Proto = ParseProtocol(ps[0])
+		if p, err := strconv.ParseUint(ps[1], 10, 16); err == nil {
+			t.Port = uint16(p)
+			return nil
+		}
+	}
+	return BadRequestErrorf("invalid format for transport port: %s", s)
+}
+
 // PortBinding represent a port binding between the container and the host
 type PortBinding struct {
 	Proto       Protocol
@@ -68,6 +104,62 @@ func (p *PortBinding) GetCopy() PortBinding {
 	}
 }
 
+// String return the PortBinding structure in string form
+func (p *PortBinding) String() string {
+	ret := fmt.Sprintf("%s/", p.Proto)
+	if p.IP != nil {
+		ret = fmt.Sprintf("%s%s", ret, p.IP.String())
+	}
+	ret = fmt.Sprintf("%s:%d/", ret, p.Port)
+	if p.HostIP != nil {
+		ret = fmt.Sprintf("%s%s", ret, p.HostIP.String())
+	}
+	ret = fmt.Sprintf("%s:%d", ret, p.HostPort)
+	return ret
+}
+
+// FromString reads the TransportPort structure from string
+func (p *PortBinding) FromString(s string) error {
+	ps := strings.Split(s, "/")
+	if len(ps) != 3 {
+		return BadRequestErrorf("invalid format for port binding: %s", s)
+	}
+
+	p.Proto = ParseProtocol(ps[0])
+
+	var err error
+	if p.IP, p.Port, err = parseIPPort(ps[1]); err != nil {
+		return BadRequestErrorf("failed to parse Container IP/Port in port binding: %s", err.Error())
+	}
+
+	if p.HostIP, p.HostPort, err = parseIPPort(ps[2]); err != nil {
+		return BadRequestErrorf("failed to parse Host IP/Port in port binding: %s", err.Error())
+	}
+
+	return nil
+}
+
+func parseIPPort(s string) (net.IP, uint16, error) {
+	pp := strings.Split(s, ":")
+	if len(pp) != 2 {
+		return nil, 0, BadRequestErrorf("invalid format: %s", s)
+	}
+
+	var ip net.IP
+	if pp[0] != "" {
+		if ip = net.ParseIP(pp[0]); ip == nil {
+			return nil, 0, BadRequestErrorf("invalid ip: %s", pp[0])
+		}
+	}
+
+	port, err := strconv.ParseUint(pp[1], 10, 16)
+	if err != nil {
+		return nil, 0, BadRequestErrorf("invalid port: %s", pp[1])
+	}
+
+	return ip, uint16(port), nil
+}
+
 // Equal checks if this instance of PortBinding is equal to the passed one
 func (p *PortBinding) Equal(o *PortBinding) bool {
 	if p == o {
@@ -154,6 +246,9 @@ func ParseProtocol(s string) Protocol {
 
 // GetMacCopy returns a copy of the passed MAC address
 func GetMacCopy(from net.HardwareAddr) net.HardwareAddr {
+	if from == nil {
+		return nil
+	}
 	to := make(net.HardwareAddr, len(from))
 	copy(to, from)
 	return to
@@ -161,6 +256,9 @@ func GetMacCopy(from net.HardwareAddr) net.HardwareAddr {
 
 // GetIPCopy returns a copy of the passed IP address
 func GetIPCopy(from net.IP) net.IP {
+	if from == nil {
+		return nil
+	}
 	to := make(net.IP, len(from))
 	copy(to, from)
 	return to
@@ -222,23 +320,32 @@ func GetMinimalIPNet(nw *net.IPNet) *net.IPNet {
 
 var v4inV6MaskPrefix = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
 
-// GetHostPartIP returns the host portion of the ip address identified by the mask.
-// IP address representation is not modified. If address and mask are not compatible
-// an error is returned.
-func GetHostPartIP(ip net.IP, mask net.IPMask) (net.IP, error) {
+// compareIPMask checks if the passed ip and mask are semantically compatible.
+// It returns the byte indexes for the address and mask so that caller can
+// do bitwise operations without modifying address representation.
+func compareIPMask(ip net.IP, mask net.IPMask) (is int, ms int, err error) {
 	// Find the effective starting of address and mask
-	is := 0
-	ms := 0
 	if len(ip) == net.IPv6len && ip.To4() != nil {
 		is = 12
 	}
 	if len(ip[is:]) == net.IPv4len && len(mask) == net.IPv6len && bytes.Equal(mask[:12], v4inV6MaskPrefix) {
 		ms = 12
 	}
-
 	// Check if address and mask are semantically compatible
 	if len(ip[is:]) != len(mask[ms:]) {
-		return nil, fmt.Errorf("cannot compute host portion ip address as ip and mask are not compatible: (%#v, %#v)", ip, mask)
+		err = fmt.Errorf("ip and mask are not compatible: (%#v, %#v)", ip, mask)
+	}
+	return
+}
+
+// GetHostPartIP returns the host portion of the ip address identified by the mask.
+// IP address representation is not modified. If address and mask are not compatible
+// an error is returned.
+func GetHostPartIP(ip net.IP, mask net.IPMask) (net.IP, error) {
+	// Find the effective starting of address and mask
+	is, ms, err := compareIPMask(ip, mask)
+	if err != nil {
+		return nil, fmt.Errorf("cannot compute host portion ip address because %s", err)
 	}
 
 	// Compute host portion
@@ -250,6 +357,34 @@ func GetHostPartIP(ip net.IP, mask net.IPMask) (net.IP, error) {
 	return out, nil
 }
 
+// GetBroadcastIP returns the broadcast ip address for the passed network (ip and mask).
+// IP address representation is not modified. If address and mask are not compatible
+// an error is returned.
+func GetBroadcastIP(ip net.IP, mask net.IPMask) (net.IP, error) {
+	// Find the effective starting of address and mask
+	is, ms, err := compareIPMask(ip, mask)
+	if err != nil {
+		return nil, fmt.Errorf("cannot compute broadcast ip address because %s", err)
+	}
+
+	// Compute broadcast address
+	out := GetIPCopy(ip)
+	for i := 0; i < len(mask[ms:]); i++ {
+		out[is+i] |= ^mask[ms+i]
+	}
+
+	return out, nil
+}
+
+// ParseCIDR returns the *net.IPNet represented by the passed CIDR notation
+func ParseCIDR(cidr string) (n *net.IPNet, e error) {
+	var i net.IP
+	if i, n, e = net.ParseCIDR(cidr); e == nil {
+		n.IP = i
+	}
+	return
+}
+
 const (
 	// NEXTHOP indicates a StaticRoute with an IP next hop.
 	NEXTHOP = iota
@@ -278,6 +413,23 @@ func (r *StaticRoute) GetCopy() *StaticRoute {
 	}
 }
 
+// InterfaceStatistics represents the interface's statistics
+type InterfaceStatistics struct {
+	RxBytes   uint64
+	RxPackets uint64
+	RxErrors  uint64
+	RxDropped uint64
+	TxBytes   uint64
+	TxPackets uint64
+	TxErrors  uint64
+	TxDropped uint64
+}
+
+func (is *InterfaceStatistics) String() string {
+	return fmt.Sprintf("\nRxBytes: %d, RxPackets: %d, RxErrors: %d, RxDropped: %d, TxBytes: %d, TxPackets: %d, TxErrors: %d, TxDropped: %d",
+		is.RxBytes, is.RxPackets, is.RxErrors, is.RxDropped, is.TxBytes, is.TxPackets, is.TxErrors, is.TxDropped)
+}
+
 /******************************
  * Well-known Error Interfaces
  ******************************/