Sfoglia il codice sorgente

Windows libnetwork integration

Signed-off-by: msabansal <sabansal@microsoft.com>
msabansal 9 anni fa
parent
commit
e8026d8a98

+ 5 - 0
Makefile

@@ -101,6 +101,11 @@ bundles:
 
 cross: build
 	$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross
+	
+	
+win: build
+	$(DOCKER_RUN_DOCKER) hack/make.sh win
+
 
 deb: build
 	$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary build-deb

+ 301 - 0
container/container.go

@@ -4,8 +4,11 @@ import (
 	"encoding/json"
 	"fmt"
 	"io"
+	"net"
 	"os"
 	"path/filepath"
+	"strconv"
+	"strings"
 	"sync"
 	"syscall"
 	"time"
@@ -23,14 +26,25 @@ import (
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/runconfig"
+	runconfigopts "github.com/docker/docker/runconfig/opts"
 	"github.com/docker/docker/volume"
 	containertypes "github.com/docker/engine-api/types/container"
+	networktypes "github.com/docker/engine-api/types/network"
 	"github.com/docker/go-connections/nat"
+	"github.com/docker/libnetwork"
+	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
 	"github.com/opencontainers/runc/libcontainer/label"
 )
 
 const configFileName = "config.v2.json"
 
+var (
+	errInvalidEndpoint = fmt.Errorf("invalid endpoint while building port map info")
+	errInvalidNetwork  = fmt.Errorf("invalid network settings while building port map info")
+)
+
 // CommonContainer holds the fields for a container which are
 // applicable across all platforms supported by the daemon.
 type CommonContainer struct {
@@ -581,6 +595,293 @@ func (container *Container) InitDNSHostConfig() {
 	}
 }
 
+// GetEndpointInNetwork returns the container's endpoint to the provided network.
+func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
+	endpointName := strings.TrimPrefix(container.Name, "/")
+	return n.EndpointByName(endpointName)
+}
+
+func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
+	if ep == nil {
+		return errInvalidEndpoint
+	}
+
+	networkSettings := container.NetworkSettings
+	if networkSettings == nil {
+		return errInvalidNetwork
+	}
+
+	if len(networkSettings.Ports) == 0 {
+		pm, err := getEndpointPortMapInfo(ep)
+		if err != nil {
+			return err
+		}
+		networkSettings.Ports = pm
+	}
+	return nil
+}
+
+func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
+	pm := nat.PortMap{}
+	driverInfo, err := ep.DriverInfo()
+	if err != nil {
+		return pm, err
+	}
+
+	if driverInfo == nil {
+		// It is not an error for epInfo to be nil
+		return pm, nil
+	}
+
+	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
+		if exposedPorts, ok := expData.([]types.TransportPort); ok {
+			for _, tp := range exposedPorts {
+				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
+				if err != nil {
+					return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
+				}
+				pm[natPort] = nil
+			}
+		}
+	}
+
+	mapData, ok := driverInfo[netlabel.PortMap]
+	if !ok {
+		return pm, nil
+	}
+
+	if portMapping, ok := mapData.([]types.PortBinding); ok {
+		for _, pp := range portMapping {
+			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
+			if err != nil {
+				return pm, err
+			}
+			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
+			pm[natPort] = append(pm[natPort], natBndg)
+		}
+	}
+
+	return pm, nil
+}
+
+func getSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap {
+	pm := nat.PortMap{}
+	if sb == nil {
+		return pm
+	}
+
+	for _, ep := range sb.Endpoints() {
+		pm, _ = getEndpointPortMapInfo(ep)
+		if len(pm) > 0 {
+			break
+		}
+	}
+	return pm
+}
+
+// BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
+func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
+	if ep == nil {
+		return errInvalidEndpoint
+	}
+
+	networkSettings := container.NetworkSettings
+	if networkSettings == nil {
+		return errInvalidNetwork
+	}
+
+	epInfo := ep.Info()
+	if epInfo == nil {
+		// It is not an error to get an empty endpoint info
+		return nil
+	}
+
+	if _, ok := networkSettings.Networks[n.Name()]; !ok {
+		networkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings)
+	}
+	networkSettings.Networks[n.Name()].NetworkID = n.ID()
+	networkSettings.Networks[n.Name()].EndpointID = ep.ID()
+
+	iface := epInfo.Iface()
+	if iface == nil {
+		return nil
+	}
+
+	if iface.MacAddress() != nil {
+		networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
+	}
+
+	if iface.Address() != nil {
+		ones, _ := iface.Address().Mask.Size()
+		networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
+		networkSettings.Networks[n.Name()].IPPrefixLen = ones
+	}
+
+	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
+		onesv6, _ := iface.AddressIPv6().Mask.Size()
+		networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
+		networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
+	}
+
+	return nil
+}
+
+// UpdateJoinInfo updates network settings when container joins network n with endpoint ep.
+func (container *Container) UpdateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
+	if err := container.buildPortMapInfo(ep); err != nil {
+		return err
+	}
+
+	epInfo := ep.Info()
+	if epInfo == nil {
+		// It is not an error to get an empty endpoint info
+		return nil
+	}
+	if epInfo.Gateway() != nil {
+		container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
+	}
+	if epInfo.GatewayIPv6().To16() != nil {
+		container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
+	}
+
+	return nil
+}
+
+// UpdateSandboxNetworkSettings updates the sandbox ID and Key.
+func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
+	container.NetworkSettings.SandboxID = sb.ID()
+	container.NetworkSettings.SandboxKey = sb.Key()
+	return nil
+}
+
+// BuildJoinOptions builds endpoint Join options from a given network.
+func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) {
+	var joinOptions []libnetwork.EndpointOption
+	if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok {
+		for _, str := range epConfig.Links {
+			name, alias, err := runconfigopts.ParseLink(str)
+			if err != nil {
+				return nil, err
+			}
+			joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
+		}
+	}
+	return joinOptions, nil
+}
+
+// BuildCreateEndpointOptions builds endpoint options from a given network.
+func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *networktypes.EndpointSettings, sb libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) {
+	var (
+		bindings      = make(nat.PortMap)
+		pbList        []types.PortBinding
+		exposeList    []types.TransportPort
+		createOptions []libnetwork.EndpointOption
+	)
+
+	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
+
+	if n.Name() == defaultNetName || container.NetworkSettings.IsAnonymousEndpoint {
+		createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
+	}
+
+	if epConfig != nil {
+		ipam := epConfig.IPAMConfig
+		if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") {
+			createOptions = append(createOptions,
+				libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil))
+		}
+
+		for _, alias := range epConfig.Aliases {
+			createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
+		}
+	}
+
+	if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
+		createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
+	}
+
+	// configs that are applicable only for the endpoint in the network
+	// to which container was connected to on docker run.
+	// Ideally all these network-specific endpoint configurations must be moved under
+	// container.NetworkSettings.Networks[n.Name()]
+	if n.Name() == container.HostConfig.NetworkMode.NetworkName() ||
+		(n.Name() == defaultNetName && container.HostConfig.NetworkMode.IsDefault()) {
+		if container.Config.MacAddress != "" {
+			mac, err := net.ParseMAC(container.Config.MacAddress)
+			if err != nil {
+				return nil, err
+			}
+
+			genericOption := options.Generic{
+				netlabel.MacAddress: mac,
+			}
+
+			createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
+		}
+	}
+
+	// Port-mapping rules belong to the container & applicable only to non-internal networks
+	portmaps := getSandboxPortMapInfo(sb)
+	if n.Info().Internal() || len(portmaps) > 0 {
+		return createOptions, nil
+	}
+
+	if container.HostConfig.PortBindings != nil {
+		for p, b := range container.HostConfig.PortBindings {
+			bindings[p] = []nat.PortBinding{}
+			for _, bb := range b {
+				bindings[p] = append(bindings[p], nat.PortBinding{
+					HostIP:   bb.HostIP,
+					HostPort: bb.HostPort,
+				})
+			}
+		}
+	}
+
+	portSpecs := container.Config.ExposedPorts
+	ports := make([]nat.Port, len(portSpecs))
+	var i int
+	for p := range portSpecs {
+		ports[i] = p
+		i++
+	}
+	nat.SortPortMap(ports, bindings)
+	for _, port := range ports {
+		expose := types.TransportPort{}
+		expose.Proto = types.ParseProtocol(port.Proto())
+		expose.Port = uint16(port.Int())
+		exposeList = append(exposeList, expose)
+
+		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
+		binding := bindings[port]
+		for i := 0; i < len(binding); i++ {
+			pbCopy := pb.GetCopy()
+			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
+			var portStart, portEnd int
+			if err == nil {
+				portStart, portEnd, err = newP.Range()
+			}
+			if err != nil {
+				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
+			}
+			pbCopy.HostPort = uint16(portStart)
+			pbCopy.HostPortEnd = uint16(portEnd)
+			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
+			pbList = append(pbList, pbCopy)
+		}
+
+		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
+			pbList = append(pbList, pb)
+		}
+	}
+
+	createOptions = append(createOptions,
+		libnetwork.CreateOptionPortMapping(pbList),
+		libnetwork.CreateOptionExposedPorts(exposeList))
+
+	return createOptions, nil
+}
+
 // UpdateMonitor updates monitor configure for running container
 func (container *Container) UpdateMonitor(restartPolicy containertypes.RestartPolicy) {
 	monitor := container.monitor

+ 0 - 299
container/container_unix.go

@@ -5,10 +5,8 @@ package container
 import (
 	"fmt"
 	"io/ioutil"
-	"net"
 	"os"
 	"path/filepath"
-	"strconv"
 	"strings"
 	"syscall"
 
@@ -17,27 +15,15 @@ import (
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/pkg/system"
-	runconfigopts "github.com/docker/docker/runconfig/opts"
 	"github.com/docker/docker/utils"
 	"github.com/docker/docker/volume"
 	containertypes "github.com/docker/engine-api/types/container"
-	"github.com/docker/engine-api/types/network"
-	"github.com/docker/go-connections/nat"
-	"github.com/docker/libnetwork"
-	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/options"
-	"github.com/docker/libnetwork/types"
 	"github.com/opencontainers/runc/libcontainer/label"
 )
 
 // DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container
 const DefaultSHMSize int64 = 67108864
 
-var (
-	errInvalidEndpoint = fmt.Errorf("invalid endpoint while building port map info")
-	errInvalidNetwork  = fmt.Errorf("invalid network settings while building port map info")
-)
-
 // Container holds the fields specific to unixen implementations.
 // See CommonContainer for standard fields common to all containers.
 type Container struct {
@@ -113,291 +99,6 @@ func (container *Container) BuildHostnameFile() error {
 	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
 }
 
-// GetEndpointInNetwork returns the container's endpoint to the provided network.
-func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
-	endpointName := strings.TrimPrefix(container.Name, "/")
-	return n.EndpointByName(endpointName)
-}
-
-func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
-	if ep == nil {
-		return errInvalidEndpoint
-	}
-
-	networkSettings := container.NetworkSettings
-	if networkSettings == nil {
-		return errInvalidNetwork
-	}
-
-	if len(networkSettings.Ports) == 0 {
-		pm, err := getEndpointPortMapInfo(ep)
-		if err != nil {
-			return err
-		}
-		networkSettings.Ports = pm
-	}
-	return nil
-}
-
-func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
-	pm := nat.PortMap{}
-	driverInfo, err := ep.DriverInfo()
-	if err != nil {
-		return pm, err
-	}
-
-	if driverInfo == nil {
-		// It is not an error for epInfo to be nil
-		return pm, nil
-	}
-
-	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
-		if exposedPorts, ok := expData.([]types.TransportPort); ok {
-			for _, tp := range exposedPorts {
-				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
-				if err != nil {
-					return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
-				}
-				pm[natPort] = nil
-			}
-		}
-	}
-
-	mapData, ok := driverInfo[netlabel.PortMap]
-	if !ok {
-		return pm, nil
-	}
-
-	if portMapping, ok := mapData.([]types.PortBinding); ok {
-		for _, pp := range portMapping {
-			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
-			if err != nil {
-				return pm, err
-			}
-			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
-			pm[natPort] = append(pm[natPort], natBndg)
-		}
-	}
-
-	return pm, nil
-}
-
-func getSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap {
-	pm := nat.PortMap{}
-	if sb == nil {
-		return pm
-	}
-
-	for _, ep := range sb.Endpoints() {
-		pm, _ = getEndpointPortMapInfo(ep)
-		if len(pm) > 0 {
-			break
-		}
-	}
-	return pm
-}
-
-// BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
-func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
-	if ep == nil {
-		return errInvalidEndpoint
-	}
-
-	networkSettings := container.NetworkSettings
-	if networkSettings == nil {
-		return errInvalidNetwork
-	}
-
-	epInfo := ep.Info()
-	if epInfo == nil {
-		// It is not an error to get an empty endpoint info
-		return nil
-	}
-
-	if _, ok := networkSettings.Networks[n.Name()]; !ok {
-		networkSettings.Networks[n.Name()] = new(network.EndpointSettings)
-	}
-	networkSettings.Networks[n.Name()].NetworkID = n.ID()
-	networkSettings.Networks[n.Name()].EndpointID = ep.ID()
-
-	iface := epInfo.Iface()
-	if iface == nil {
-		return nil
-	}
-
-	if iface.MacAddress() != nil {
-		networkSettings.Networks[n.Name()].MacAddress = iface.MacAddress().String()
-	}
-
-	if iface.Address() != nil {
-		ones, _ := iface.Address().Mask.Size()
-		networkSettings.Networks[n.Name()].IPAddress = iface.Address().IP.String()
-		networkSettings.Networks[n.Name()].IPPrefixLen = ones
-	}
-
-	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
-		onesv6, _ := iface.AddressIPv6().Mask.Size()
-		networkSettings.Networks[n.Name()].GlobalIPv6Address = iface.AddressIPv6().IP.String()
-		networkSettings.Networks[n.Name()].GlobalIPv6PrefixLen = onesv6
-	}
-
-	return nil
-}
-
-// UpdateJoinInfo updates network settings when container joins network n with endpoint ep.
-func (container *Container) UpdateJoinInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
-	if err := container.buildPortMapInfo(ep); err != nil {
-		return err
-	}
-
-	epInfo := ep.Info()
-	if epInfo == nil {
-		// It is not an error to get an empty endpoint info
-		return nil
-	}
-	if epInfo.Gateway() != nil {
-		container.NetworkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
-	}
-	if epInfo.GatewayIPv6().To16() != nil {
-		container.NetworkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
-	}
-
-	return nil
-}
-
-// UpdateSandboxNetworkSettings updates the sandbox ID and Key.
-func (container *Container) UpdateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
-	container.NetworkSettings.SandboxID = sb.ID()
-	container.NetworkSettings.SandboxKey = sb.Key()
-	return nil
-}
-
-// BuildJoinOptions builds endpoint Join options from a given network.
-func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) {
-	var joinOptions []libnetwork.EndpointOption
-	if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok {
-		for _, str := range epConfig.Links {
-			name, alias, err := runconfigopts.ParseLink(str)
-			if err != nil {
-				return nil, err
-			}
-			joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
-		}
-	}
-	return joinOptions, nil
-}
-
-// BuildCreateEndpointOptions builds endpoint options from a given network.
-func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *network.EndpointSettings, sb libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) {
-	var (
-		bindings      = make(nat.PortMap)
-		pbList        []types.PortBinding
-		exposeList    []types.TransportPort
-		createOptions []libnetwork.EndpointOption
-	)
-
-	if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint {
-		createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
-	}
-
-	if epConfig != nil {
-		ipam := epConfig.IPAMConfig
-		if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") {
-			createOptions = append(createOptions,
-				libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil))
-		}
-
-		for _, alias := range epConfig.Aliases {
-			createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
-		}
-	}
-
-	if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
-		createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
-	}
-
-	// configs that are applicable only for the endpoint in the network
-	// to which container was connected to on docker run.
-	// Ideally all these network-specific endpoint configurations must be moved under
-	// container.NetworkSettings.Networks[n.Name()]
-	if n.Name() == container.HostConfig.NetworkMode.NetworkName() ||
-		(n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) {
-		if container.Config.MacAddress != "" {
-			mac, err := net.ParseMAC(container.Config.MacAddress)
-			if err != nil {
-				return nil, err
-			}
-
-			genericOption := options.Generic{
-				netlabel.MacAddress: mac,
-			}
-
-			createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
-		}
-	}
-
-	// Port-mapping rules belong to the container & applicable only to non-internal networks
-	portmaps := getSandboxPortMapInfo(sb)
-	if n.Info().Internal() || len(portmaps) > 0 {
-		return createOptions, nil
-	}
-
-	if container.HostConfig.PortBindings != nil {
-		for p, b := range container.HostConfig.PortBindings {
-			bindings[p] = []nat.PortBinding{}
-			for _, bb := range b {
-				bindings[p] = append(bindings[p], nat.PortBinding{
-					HostIP:   bb.HostIP,
-					HostPort: bb.HostPort,
-				})
-			}
-		}
-	}
-
-	portSpecs := container.Config.ExposedPorts
-	ports := make([]nat.Port, len(portSpecs))
-	var i int
-	for p := range portSpecs {
-		ports[i] = p
-		i++
-	}
-	nat.SortPortMap(ports, bindings)
-	for _, port := range ports {
-		expose := types.TransportPort{}
-		expose.Proto = types.ParseProtocol(port.Proto())
-		expose.Port = uint16(port.Int())
-		exposeList = append(exposeList, expose)
-
-		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
-		binding := bindings[port]
-		for i := 0; i < len(binding); i++ {
-			pbCopy := pb.GetCopy()
-			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
-			var portStart, portEnd int
-			if err == nil {
-				portStart, portEnd, err = newP.Range()
-			}
-			if err != nil {
-				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
-			}
-			pbCopy.HostPort = uint16(portStart)
-			pbCopy.HostPortEnd = uint16(portEnd)
-			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
-			pbList = append(pbList, pbCopy)
-		}
-
-		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
-			pbList = append(pbList, pb)
-		}
-	}
-
-	createOptions = append(createOptions,
-		libnetwork.CreateOptionPortMapping(pbList),
-		libnetwork.CreateOptionExposedPorts(exposeList))
-
-	return createOptions, nil
-}
-
 // appendNetworkMounts appends any network mounts to the array of mount points passed in
 func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
 	for _, mnt := range container.NetworkMounts() {

+ 8 - 0
container/container_windows.go

@@ -17,6 +17,9 @@ import (
 type Container struct {
 	CommonContainer
 
+	HostnamePath   string
+	HostsPath      string
+	ResolvConfPath string
 	// Fields below here are platform specific.
 }
 
@@ -84,6 +87,11 @@ func cleanResourcePath(path string) string {
 	return filepath.Join(string(os.PathSeparator), path)
 }
 
+// BuildHostnameFile writes the container's hostname file.
+func (container *Container) BuildHostnameFile() error {
+	return nil
+}
+
 // canMountFS determines if the file system for the container
 // can be mounted locally. In the case of Windows, this is not possible
 // for Hyper-V containers during WORKDIR execution for example.

+ 5 - 2
daemon/config_windows.go

@@ -15,7 +15,9 @@ var (
 // bridgeConfig stores all the bridge driver specific
 // configuration.
 type bridgeConfig struct {
-	VirtualSwitchName string `json:"bridge,omitempty"`
+	FixedCIDR   string
+	NetworkMode string
+	Iface       string `json:"bridge,omitempty"`
 }
 
 // Config defines the configuration of a docker daemon.
@@ -37,6 +39,7 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin
 	config.InstallCommonFlags(cmd, usageFn)
 
 	// Then platform-specific install flags.
-	cmd.StringVar(&config.bridgeConfig.VirtualSwitchName, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch")
+	cmd.StringVar(&config.bridgeConfig.FixedCIDR, []string{"-fixed-cidr"}, "", usageFn("IPv4 subnet for fixed IPs"))
+	cmd.StringVar(&config.bridgeConfig.Iface, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch")
 	cmd.StringVar(&config.SocketGroup, []string{"G", "-group"}, "", usageFn("Users or groups that can access the named pipe"))
 }

+ 737 - 1
daemon/container_operations.go

@@ -1,9 +1,745 @@
 package daemon
 
-import "errors"
+import (
+	"errors"
+	"fmt"
+	"net"
+	"os"
+	"path"
+	"strings"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/container"
+	"github.com/docker/docker/daemon/network"
+	derr "github.com/docker/docker/errors"
+	"github.com/docker/docker/runconfig"
+	containertypes "github.com/docker/engine-api/types/container"
+	networktypes "github.com/docker/engine-api/types/network"
+	"github.com/docker/go-connections/nat"
+	"github.com/docker/libnetwork"
+	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
+)
 
 var (
 	// ErrRootFSReadOnly is returned when a container
 	// rootfs is marked readonly.
 	ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
 )
+
+func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libnetwork.Network) ([]libnetwork.SandboxOption, error) {
+	var (
+		sboxOptions []libnetwork.SandboxOption
+		err         error
+		dns         []string
+		dnsSearch   []string
+		dnsOptions  []string
+		bindings    = make(nat.PortMap)
+		pbList      []types.PortBinding
+		exposeList  []types.TransportPort
+	)
+
+	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
+	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
+		libnetwork.OptionDomainname(container.Config.Domainname))
+
+	if container.HostConfig.NetworkMode.IsHost() {
+		sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
+		sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
+		sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
+	} else if daemon.execDriver.SupportsHooks() {
+		// OptionUseExternalKey is mandatory for userns support.
+		// But optional for non-userns support
+		sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
+	}
+
+	container.HostsPath, err = container.GetRootResourcePath("hosts")
+	if err != nil {
+		return nil, err
+	}
+	sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath))
+
+	container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
+	if err != nil {
+		return nil, err
+	}
+	sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
+
+	if len(container.HostConfig.DNS) > 0 {
+		dns = container.HostConfig.DNS
+	} else if len(daemon.configStore.DNS) > 0 {
+		dns = daemon.configStore.DNS
+	}
+
+	for _, d := range dns {
+		sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d))
+	}
+
+	if len(container.HostConfig.DNSSearch) > 0 {
+		dnsSearch = container.HostConfig.DNSSearch
+	} else if len(daemon.configStore.DNSSearch) > 0 {
+		dnsSearch = daemon.configStore.DNSSearch
+	}
+
+	for _, ds := range dnsSearch {
+		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds))
+	}
+
+	if len(container.HostConfig.DNSOptions) > 0 {
+		dnsOptions = container.HostConfig.DNSOptions
+	} else if len(daemon.configStore.DNSOptions) > 0 {
+		dnsOptions = daemon.configStore.DNSOptions
+	}
+
+	for _, ds := range dnsOptions {
+		sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds))
+	}
+
+	if container.NetworkSettings.SecondaryIPAddresses != nil {
+		name := container.Config.Hostname
+		if container.Config.Domainname != "" {
+			name = name + "." + container.Config.Domainname
+		}
+
+		for _, a := range container.NetworkSettings.SecondaryIPAddresses {
+			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr))
+		}
+	}
+
+	for _, extraHost := range container.HostConfig.ExtraHosts {
+		// allow IPv6 addresses in extra hosts; only split on first ":"
+		parts := strings.SplitN(extraHost, ":", 2)
+		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
+	}
+
+	if container.HostConfig.PortBindings != nil {
+		for p, b := range container.HostConfig.PortBindings {
+			bindings[p] = []nat.PortBinding{}
+			for _, bb := range b {
+				bindings[p] = append(bindings[p], nat.PortBinding{
+					HostIP:   bb.HostIP,
+					HostPort: bb.HostPort,
+				})
+			}
+		}
+	}
+
+	portSpecs := container.Config.ExposedPorts
+	ports := make([]nat.Port, len(portSpecs))
+	var i int
+	for p := range portSpecs {
+		ports[i] = p
+		i++
+	}
+	nat.SortPortMap(ports, bindings)
+	for _, port := range ports {
+		expose := types.TransportPort{}
+		expose.Proto = types.ParseProtocol(port.Proto())
+		expose.Port = uint16(port.Int())
+		exposeList = append(exposeList, expose)
+
+		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
+		binding := bindings[port]
+		for i := 0; i < len(binding); i++ {
+			pbCopy := pb.GetCopy()
+			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
+			var portStart, portEnd int
+			if err == nil {
+				portStart, portEnd, err = newP.Range()
+			}
+			if err != nil {
+				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
+			}
+			pbCopy.HostPort = uint16(portStart)
+			pbCopy.HostPortEnd = uint16(portEnd)
+			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
+			pbList = append(pbList, pbCopy)
+		}
+
+		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
+			pbList = append(pbList, pb)
+		}
+	}
+
+	sboxOptions = append(sboxOptions,
+		libnetwork.OptionPortMapping(pbList),
+		libnetwork.OptionExposedPorts(exposeList))
+
+	// Link feature is supported only for the default bridge network.
+	// return if this call to build join options is not for default bridge network
+	if n.Name() != defaultNetName {
+		return sboxOptions, nil
+	}
+
+	ep, _ := container.GetEndpointInNetwork(n)
+	if ep == nil {
+		return sboxOptions, nil
+	}
+
+	var childEndpoints, parentEndpoints []string
+
+	children := daemon.children(container)
+	for linkAlias, child := range children {
+		if !isLinkable(child) {
+			return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
+		}
+		_, alias := path.Split(linkAlias)
+		// allow access to the linked container via the alias, real name, and container hostname
+		aliasList := alias + " " + child.Config.Hostname
+		// only add the name if alias isn't equal to the name
+		if alias != child.Name[1:] {
+			aliasList = aliasList + " " + child.Name[1:]
+		}
+		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks[defaultNetName].IPAddress))
+		cEndpoint, _ := child.GetEndpointInNetwork(n)
+		if cEndpoint != nil && cEndpoint.ID() != "" {
+			childEndpoints = append(childEndpoints, cEndpoint.ID())
+		}
+	}
+
+	bridgeSettings := container.NetworkSettings.Networks[defaultNetName]
+	for alias, parent := range daemon.parents(container) {
+		if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() {
+			continue
+		}
+
+		_, alias = path.Split(alias)
+		logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress)
+		sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(
+			parent.ID,
+			alias,
+			bridgeSettings.IPAddress,
+		))
+		if ep.ID() != "" {
+			parentEndpoints = append(parentEndpoints, ep.ID())
+		}
+	}
+
+	linkOptions := options.Generic{
+		netlabel.GenericData: options.Generic{
+			"ParentEndpoints": parentEndpoints,
+			"ChildEndpoints":  childEndpoints,
+		},
+	}
+
+	sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions))
+	return sboxOptions, nil
+}
+
+func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network) error {
+	if container.NetworkSettings == nil {
+		container.NetworkSettings = &network.Settings{Networks: make(map[string]*networktypes.EndpointSettings)}
+	}
+
+	if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
+		return runconfig.ErrConflictHostNetwork
+	}
+
+	for s := range container.NetworkSettings.Networks {
+		sn, err := daemon.FindNetwork(s)
+		if err != nil {
+			continue
+		}
+
+		if sn.Name() == n.Name() {
+			// Avoid duplicate config
+			return nil
+		}
+		if !containertypes.NetworkMode(sn.Type()).IsPrivate() ||
+			!containertypes.NetworkMode(n.Type()).IsPrivate() {
+			return runconfig.ErrConflictSharedNetwork
+		}
+		if containertypes.NetworkMode(sn.Name()).IsNone() ||
+			containertypes.NetworkMode(n.Name()).IsNone() {
+			return runconfig.ErrConflictNoNetwork
+		}
+	}
+
+	if _, ok := container.NetworkSettings.Networks[n.Name()]; !ok {
+		container.NetworkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings)
+	}
+
+	return nil
+}
+
+func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error {
+	if err := container.BuildEndpointInfo(n, ep); err != nil {
+		return err
+	}
+
+	if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() {
+		container.NetworkSettings.Bridge = daemon.configStore.bridgeConfig.Iface
+	}
+
+	return nil
+}
+
+// UpdateNetwork is used to update the container's network (e.g. when linked containers
+// get removed/unlinked).
+func (daemon *Daemon) updateNetwork(container *container.Container) error {
+	ctrl := daemon.netController
+	sid := container.NetworkSettings.SandboxID
+
+	sb, err := ctrl.SandboxByID(sid)
+	if err != nil {
+		return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
+	}
+
+	// Find if container is connected to the default bridge network
+	var n libnetwork.Network
+	for name := range container.NetworkSettings.Networks {
+		sn, err := daemon.FindNetwork(name)
+		if err != nil {
+			continue
+		}
+		if sn.Name() == runconfig.DefaultDaemonNetworkMode().NetworkName() {
+			n = sn
+			break
+		}
+	}
+
+	if n == nil {
+		// Not connected to the default bridge network; Nothing to do
+		return nil
+	}
+
+	options, err := daemon.buildSandboxOptions(container, n)
+	if err != nil {
+		return fmt.Errorf("Update network failed: %v", err)
+	}
+
+	if err := sb.Refresh(options...); err != nil {
+		return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
+	}
+
+	return nil
+}
+
+// updateContainerNetworkSettings update the network settings
+func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error {
+	var (
+		n   libnetwork.Network
+		err error
+	)
+
+	// TODO Windows: Remove this once TP4 builds are not supported
+	// Windows TP4 build don't support libnetwork and in that case
+	// daemon.netController will be nil
+	if daemon.netController == nil {
+		return nil
+	}
+
+	mode := container.HostConfig.NetworkMode
+	if container.Config.NetworkDisabled || mode.IsContainer() {
+		return nil
+	}
+
+	networkName := mode.NetworkName()
+	if mode.IsDefault() {
+		networkName = daemon.netController.Config().Daemon.DefaultNetwork
+	}
+	if mode.IsUserDefined() {
+		n, err = daemon.FindNetwork(networkName)
+		if err != nil {
+			return err
+		}
+		networkName = n.Name()
+	}
+	if container.NetworkSettings == nil {
+		container.NetworkSettings = &network.Settings{}
+	}
+	if len(endpointsConfig) > 0 {
+		container.NetworkSettings.Networks = endpointsConfig
+	}
+	if container.NetworkSettings.Networks == nil {
+		container.NetworkSettings.Networks = make(map[string]*networktypes.EndpointSettings)
+		container.NetworkSettings.Networks[networkName] = new(networktypes.EndpointSettings)
+	}
+	if !mode.IsUserDefined() {
+		return nil
+	}
+	// Make sure to internally store the per network endpoint config by network name
+	if _, ok := container.NetworkSettings.Networks[networkName]; ok {
+		return nil
+	}
+	if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
+		container.NetworkSettings.Networks[networkName] = nwConfig
+		delete(container.NetworkSettings.Networks, n.ID())
+		return nil
+	}
+
+	return nil
+}
+
+func (daemon *Daemon) allocateNetwork(container *container.Container) error {
+	controller := daemon.netController
+
+	if daemon.netController == nil {
+		return nil
+	}
+
+	// Cleanup any stale sandbox left over due to ungraceful daemon shutdown
+	if err := controller.SandboxDestroy(container.ID); err != nil {
+		logrus.Errorf("failed to cleanup up stale network sandbox for container %s", container.ID)
+	}
+
+	updateSettings := false
+	if len(container.NetworkSettings.Networks) == 0 {
+		if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() {
+			return nil
+		}
+
+		err := daemon.updateContainerNetworkSettings(container, nil)
+		if err != nil {
+			return err
+		}
+		updateSettings = true
+	}
+
+	for n, nConf := range container.NetworkSettings.Networks {
+		if err := daemon.connectToNetwork(container, n, nConf, updateSettings); err != nil {
+			return err
+		}
+	}
+
+	return container.WriteHostConfig()
+}
+
+func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox {
+	var sb libnetwork.Sandbox
+	daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool {
+		if s.ContainerID() == container.ID {
+			sb = s
+			return true
+		}
+		return false
+	})
+	return sb
+}
+
+// hasUserDefinedIPAddress returns whether the passed endpoint configuration contains IP address configuration
+func hasUserDefinedIPAddress(epConfig *networktypes.EndpointSettings) bool {
+	return epConfig != nil && epConfig.IPAMConfig != nil && (len(epConfig.IPAMConfig.IPv4Address) > 0 || len(epConfig.IPAMConfig.IPv6Address) > 0)
+}
+
+// User specified ip address is acceptable only for networks with user specified subnets.
+func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error {
+	if n == nil || epConfig == nil {
+		return nil
+	}
+	if !hasUserDefinedIPAddress(epConfig) {
+		return nil
+	}
+	_, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig()
+	for _, s := range []struct {
+		ipConfigured  bool
+		subnetConfigs []*libnetwork.IpamConf
+	}{
+		{
+			ipConfigured:  len(epConfig.IPAMConfig.IPv4Address) > 0,
+			subnetConfigs: nwIPv4Configs,
+		},
+		{
+			ipConfigured:  len(epConfig.IPAMConfig.IPv6Address) > 0,
+			subnetConfigs: nwIPv6Configs,
+		},
+	} {
+		if s.ipConfigured {
+			foundSubnet := false
+			for _, cfg := range s.subnetConfigs {
+				if len(cfg.PreferredPool) > 0 {
+					foundSubnet = true
+					break
+				}
+			}
+			if !foundSubnet {
+				return runconfig.ErrUnsupportedNetworkNoSubnetAndIP
+			}
+		}
+	}
+
+	return nil
+}
+
+// cleanOperationalData resets the operational data from the passed endpoint settings
+func cleanOperationalData(es *networktypes.EndpointSettings) {
+	es.EndpointID = ""
+	es.Gateway = ""
+	es.IPAddress = ""
+	es.IPPrefixLen = 0
+	es.IPv6Gateway = ""
+	es.GlobalIPv6Address = ""
+	es.GlobalIPv6PrefixLen = 0
+	es.MacAddress = ""
+}
+
+func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (libnetwork.Network, error) {
+	if container.HostConfig.NetworkMode.IsContainer() {
+		return nil, runconfig.ErrConflictSharedNetwork
+	}
+
+	if containertypes.NetworkMode(idOrName).IsBridge() &&
+		daemon.configStore.DisableBridge {
+		container.Config.NetworkDisabled = true
+		return nil, nil
+	}
+
+	if !containertypes.NetworkMode(idOrName).IsUserDefined() {
+		if hasUserDefinedIPAddress(endpointConfig) {
+			return nil, runconfig.ErrUnsupportedNetworkAndIP
+		}
+		if endpointConfig != nil && len(endpointConfig.Aliases) > 0 {
+			return nil, runconfig.ErrUnsupportedNetworkAndAlias
+		}
+	}
+
+	n, err := daemon.FindNetwork(idOrName)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := validateNetworkingConfig(n, endpointConfig); err != nil {
+		return nil, err
+	}
+
+	if updateSettings {
+		if err := daemon.updateNetworkSettings(container, n); err != nil {
+			return nil, err
+		}
+	}
+	return n, nil
+}
+
+func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
+	// TODO Windows: Remove this once TP4 builds are not supported
+	// Windows TP4 build don't support libnetwork and in that case
+	// daemon.netController will be nil
+	if daemon.netController == nil {
+		return nil
+	}
+
+	n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings)
+	if err != nil {
+		return err
+	}
+	if n == nil {
+		return nil
+	}
+
+	controller := daemon.netController
+
+	sb := daemon.getNetworkSandbox(container)
+	createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb)
+	if err != nil {
+		return err
+	}
+
+	endpointName := strings.TrimPrefix(container.Name, "/")
+	ep, err := n.CreateEndpoint(endpointName, createOptions...)
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if err != nil {
+			if e := ep.Delete(false); e != nil {
+				logrus.Warnf("Could not rollback container connection to network %s", idOrName)
+			}
+		}
+	}()
+
+	if endpointConfig != nil {
+		container.NetworkSettings.Networks[n.Name()] = endpointConfig
+	}
+
+	if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
+		return err
+	}
+
+	if sb == nil {
+		options, err := daemon.buildSandboxOptions(container, n)
+		if err != nil {
+			return err
+		}
+		sb, err = controller.NewSandbox(container.ID, options...)
+		if err != nil {
+			return err
+		}
+
+		container.UpdateSandboxNetworkSettings(sb)
+	}
+
+	joinOptions, err := container.BuildJoinOptions(n)
+	if err != nil {
+		return err
+	}
+
+	if err := ep.Join(sb, joinOptions...); err != nil {
+		return err
+	}
+
+	if err := container.UpdateJoinInfo(n, ep); err != nil {
+		return fmt.Errorf("Updating join info failed: %v", err)
+	}
+
+	daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
+	return nil
+}
+
+// ForceEndpointDelete deletes an endpoing from a network forcefully
+func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
+	ep, err := n.EndpointByName(name)
+	if err != nil {
+		return err
+	}
+	return ep.Delete(true)
+}
+
+func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
+	var (
+		ep   libnetwork.Endpoint
+		sbox libnetwork.Sandbox
+	)
+
+	s := func(current libnetwork.Endpoint) bool {
+		epInfo := current.Info()
+		if epInfo == nil {
+			return false
+		}
+		if sb := epInfo.Sandbox(); sb != nil {
+			if sb.ContainerID() == container.ID {
+				ep = current
+				sbox = sb
+				return true
+			}
+		}
+		return false
+	}
+	n.WalkEndpoints(s)
+
+	if ep == nil && force {
+		epName := strings.TrimPrefix(container.Name, "/")
+		ep, err := n.EndpointByName(epName)
+		if err != nil {
+			return err
+		}
+		return ep.Delete(force)
+	}
+
+	if ep == nil {
+		return fmt.Errorf("container %s is not connected to the network", container.ID)
+	}
+
+	if err := ep.Leave(sbox); err != nil {
+		return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
+	}
+
+	if err := ep.Delete(false); err != nil {
+		return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
+	}
+
+	delete(container.NetworkSettings.Networks, n.Name())
+	return nil
+}
+
+func (daemon *Daemon) initializeNetworking(container *container.Container) error {
+	var err error
+
+	// TODO Windows: Remove this once TP4 builds are not supported
+	// Windows TP4 build don't support libnetwork and in that case
+	// daemon.netController will be nil
+	if daemon.netController == nil {
+		return nil
+	}
+
+	if container.HostConfig.NetworkMode.IsContainer() {
+		// we need to get the hosts files from the container to join
+		nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer())
+		if err != nil {
+			return err
+		}
+		container.HostnamePath = nc.HostnamePath
+		container.HostsPath = nc.HostsPath
+		container.ResolvConfPath = nc.ResolvConfPath
+		container.Config.Hostname = nc.Config.Hostname
+		container.Config.Domainname = nc.Config.Domainname
+		return nil
+	}
+
+	if container.HostConfig.NetworkMode.IsHost() {
+		container.Config.Hostname, err = os.Hostname()
+		if err != nil {
+			return err
+		}
+
+		parts := strings.SplitN(container.Config.Hostname, ".", 2)
+		if len(parts) > 1 {
+			container.Config.Hostname = parts[0]
+			container.Config.Domainname = parts[1]
+		}
+
+	}
+
+	if err := daemon.allocateNetwork(container); err != nil {
+		return err
+	}
+
+	return container.BuildHostnameFile()
+}
+
+func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) {
+	nc, err := daemon.GetContainer(connectedContainerID)
+	if err != nil {
+		return nil, err
+	}
+	if containerID == nc.ID {
+		return nil, fmt.Errorf("cannot join own network")
+	}
+	if !nc.IsRunning() {
+		err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID)
+		return nil, derr.NewRequestConflictError(err)
+	}
+	if nc.IsRestarting() {
+		return nil, errContainerIsRestarting(connectedContainerID)
+	}
+	return nc, nil
+}
+
+func (daemon *Daemon) releaseNetwork(container *container.Container) {
+	if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled {
+		return
+	}
+
+	sid := container.NetworkSettings.SandboxID
+	settings := container.NetworkSettings.Networks
+	container.NetworkSettings.Ports = nil
+
+	if sid == "" || len(settings) == 0 {
+		return
+	}
+
+	var networks []libnetwork.Network
+	for n, epSettings := range settings {
+		if nw, err := daemon.FindNetwork(n); err == nil {
+			networks = append(networks, nw)
+		}
+		cleanOperationalData(epSettings)
+	}
+
+	sb, err := daemon.netController.SandboxByID(sid)
+	if err != nil {
+		logrus.Errorf("error locating sandbox id %s: %v", sid, err)
+		return
+	}
+
+	if err := sb.Delete(); err != nil {
+		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
+	}
+
+	attributes := map[string]string{
+		"container": container.ID,
+	}
+	for _, nw := range networks {
+		daemon.LogNetworkEventWithAttributes(nw, "disconnect", attributes)
+	}
+}

+ 3 - 701
daemon/container_operations_unix.go

@@ -4,9 +4,7 @@ package daemon
 
 import (
 	"fmt"
-	"net"
 	"os"
-	"path"
 	"path/filepath"
 	"strconv"
 	"strings"
@@ -17,8 +15,6 @@ import (
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/links"
-	"github.com/docker/docker/daemon/network"
-	"github.com/docker/docker/errors"
 	"github.com/docker/docker/pkg/fileutils"
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/pkg/mount"
@@ -26,12 +22,8 @@ import (
 	"github.com/docker/docker/runconfig"
 	containertypes "github.com/docker/engine-api/types/container"
 	networktypes "github.com/docker/engine-api/types/network"
-	"github.com/docker/go-connections/nat"
 	"github.com/docker/go-units"
 	"github.com/docker/libnetwork"
-	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/options"
-	"github.com/docker/libnetwork/types"
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/devices"
 	"github.com/opencontainers/runc/libcontainer/label"
@@ -41,7 +33,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
 	var env []string
 	children := daemon.children(container)
 
-	bridgeSettings := container.NetworkSettings.Networks["bridge"]
+	bridgeSettings := container.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
 	if bridgeSettings == nil {
 		return nil, nil
 	}
@@ -51,7 +43,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
 			return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
 		}
 
-		childBridgeSettings := child.NetworkSettings.Networks["bridge"]
+		childBridgeSettings := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
 		if childBridgeSettings == nil {
 			return nil, fmt.Errorf("container %s not attached to default bridge network", child.ID)
 		}
@@ -316,477 +308,6 @@ func (daemon *Daemon) getSize(container *container.Container) (int64, int64) {
 	return sizeRw, sizeRootfs
 }
 
-func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libnetwork.Network) ([]libnetwork.SandboxOption, error) {
-	var (
-		sboxOptions []libnetwork.SandboxOption
-		err         error
-		dns         []string
-		dnsSearch   []string
-		dnsOptions  []string
-		bindings    = make(nat.PortMap)
-		pbList      []types.PortBinding
-		exposeList  []types.TransportPort
-	)
-
-	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
-		libnetwork.OptionDomainname(container.Config.Domainname))
-
-	if container.HostConfig.NetworkMode.IsHost() {
-		sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
-		sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
-		sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
-	} else if daemon.execDriver.SupportsHooks() {
-		// OptionUseExternalKey is mandatory for userns support.
-		// But optional for non-userns support
-		sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
-	}
-
-	container.HostsPath, err = container.GetRootResourcePath("hosts")
-	if err != nil {
-		return nil, err
-	}
-	sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath))
-
-	container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
-	if err != nil {
-		return nil, err
-	}
-	sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
-
-	if len(container.HostConfig.DNS) > 0 {
-		dns = container.HostConfig.DNS
-	} else if len(daemon.configStore.DNS) > 0 {
-		dns = daemon.configStore.DNS
-	}
-
-	for _, d := range dns {
-		sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d))
-	}
-
-	if len(container.HostConfig.DNSSearch) > 0 {
-		dnsSearch = container.HostConfig.DNSSearch
-	} else if len(daemon.configStore.DNSSearch) > 0 {
-		dnsSearch = daemon.configStore.DNSSearch
-	}
-
-	for _, ds := range dnsSearch {
-		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds))
-	}
-
-	if len(container.HostConfig.DNSOptions) > 0 {
-		dnsOptions = container.HostConfig.DNSOptions
-	} else if len(daemon.configStore.DNSOptions) > 0 {
-		dnsOptions = daemon.configStore.DNSOptions
-	}
-
-	for _, ds := range dnsOptions {
-		sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds))
-	}
-
-	if container.NetworkSettings.SecondaryIPAddresses != nil {
-		name := container.Config.Hostname
-		if container.Config.Domainname != "" {
-			name = name + "." + container.Config.Domainname
-		}
-
-		for _, a := range container.NetworkSettings.SecondaryIPAddresses {
-			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr))
-		}
-	}
-
-	for _, extraHost := range container.HostConfig.ExtraHosts {
-		// allow IPv6 addresses in extra hosts; only split on first ":"
-		parts := strings.SplitN(extraHost, ":", 2)
-		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
-	}
-
-	if container.HostConfig.PortBindings != nil {
-		for p, b := range container.HostConfig.PortBindings {
-			bindings[p] = []nat.PortBinding{}
-			for _, bb := range b {
-				bindings[p] = append(bindings[p], nat.PortBinding{
-					HostIP:   bb.HostIP,
-					HostPort: bb.HostPort,
-				})
-			}
-		}
-	}
-
-	portSpecs := container.Config.ExposedPorts
-	ports := make([]nat.Port, len(portSpecs))
-	var i int
-	for p := range portSpecs {
-		ports[i] = p
-		i++
-	}
-	nat.SortPortMap(ports, bindings)
-	for _, port := range ports {
-		expose := types.TransportPort{}
-		expose.Proto = types.ParseProtocol(port.Proto())
-		expose.Port = uint16(port.Int())
-		exposeList = append(exposeList, expose)
-
-		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
-		binding := bindings[port]
-		for i := 0; i < len(binding); i++ {
-			pbCopy := pb.GetCopy()
-			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
-			var portStart, portEnd int
-			if err == nil {
-				portStart, portEnd, err = newP.Range()
-			}
-			if err != nil {
-				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
-			}
-			pbCopy.HostPort = uint16(portStart)
-			pbCopy.HostPortEnd = uint16(portEnd)
-			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
-			pbList = append(pbList, pbCopy)
-		}
-
-		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
-			pbList = append(pbList, pb)
-		}
-	}
-
-	sboxOptions = append(sboxOptions,
-		libnetwork.OptionPortMapping(pbList),
-		libnetwork.OptionExposedPorts(exposeList))
-
-	// Link feature is supported only for the default bridge network.
-	// return if this call to build join options is not for default bridge network
-	if n.Name() != "bridge" {
-		return sboxOptions, nil
-	}
-
-	ep, _ := container.GetEndpointInNetwork(n)
-	if ep == nil {
-		return sboxOptions, nil
-	}
-
-	var childEndpoints, parentEndpoints []string
-
-	children := daemon.children(container)
-	for linkAlias, child := range children {
-		if !isLinkable(child) {
-			return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
-		}
-		_, alias := path.Split(linkAlias)
-		// allow access to the linked container via the alias, real name, and container hostname
-		aliasList := alias + " " + child.Config.Hostname
-		// only add the name if alias isn't equal to the name
-		if alias != child.Name[1:] {
-			aliasList = aliasList + " " + child.Name[1:]
-		}
-		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks["bridge"].IPAddress))
-		cEndpoint, _ := child.GetEndpointInNetwork(n)
-		if cEndpoint != nil && cEndpoint.ID() != "" {
-			childEndpoints = append(childEndpoints, cEndpoint.ID())
-		}
-	}
-
-	bridgeSettings := container.NetworkSettings.Networks["bridge"]
-	for alias, parent := range daemon.parents(container) {
-		if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() {
-			continue
-		}
-
-		_, alias = path.Split(alias)
-		logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress)
-		sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(
-			parent.ID,
-			alias,
-			bridgeSettings.IPAddress,
-		))
-		if ep.ID() != "" {
-			parentEndpoints = append(parentEndpoints, ep.ID())
-		}
-	}
-
-	linkOptions := options.Generic{
-		netlabel.GenericData: options.Generic{
-			"ParentEndpoints": parentEndpoints,
-			"ChildEndpoints":  childEndpoints,
-		},
-	}
-
-	sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions))
-	return sboxOptions, nil
-}
-
-func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network) error {
-	if container.NetworkSettings == nil {
-		container.NetworkSettings = &network.Settings{Networks: make(map[string]*networktypes.EndpointSettings)}
-	}
-
-	if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
-		return runconfig.ErrConflictHostNetwork
-	}
-
-	for s := range container.NetworkSettings.Networks {
-		sn, err := daemon.FindNetwork(s)
-		if err != nil {
-			continue
-		}
-
-		if sn.Name() == n.Name() {
-			// Avoid duplicate config
-			return nil
-		}
-		if !containertypes.NetworkMode(sn.Type()).IsPrivate() ||
-			!containertypes.NetworkMode(n.Type()).IsPrivate() {
-			return runconfig.ErrConflictSharedNetwork
-		}
-		if containertypes.NetworkMode(sn.Name()).IsNone() ||
-			containertypes.NetworkMode(n.Name()).IsNone() {
-			return runconfig.ErrConflictNoNetwork
-		}
-	}
-
-	if _, ok := container.NetworkSettings.Networks[n.Name()]; !ok {
-		container.NetworkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings)
-	}
-
-	return nil
-}
-
-func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error {
-	if err := container.BuildEndpointInfo(n, ep); err != nil {
-		return err
-	}
-
-	if container.HostConfig.NetworkMode == containertypes.NetworkMode("bridge") {
-		container.NetworkSettings.Bridge = daemon.configStore.bridgeConfig.Iface
-	}
-
-	return nil
-}
-
-// UpdateNetwork is used to update the container's network (e.g. when linked containers
-// get removed/unlinked).
-func (daemon *Daemon) updateNetwork(container *container.Container) error {
-	ctrl := daemon.netController
-	sid := container.NetworkSettings.SandboxID
-
-	sb, err := ctrl.SandboxByID(sid)
-	if err != nil {
-		return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
-	}
-
-	// Find if container is connected to the default bridge network
-	var n libnetwork.Network
-	for name := range container.NetworkSettings.Networks {
-		sn, err := daemon.FindNetwork(name)
-		if err != nil {
-			continue
-		}
-		if sn.Name() == "bridge" {
-			n = sn
-			break
-		}
-	}
-
-	if n == nil {
-		// Not connected to the default bridge network; Nothing to do
-		return nil
-	}
-
-	options, err := daemon.buildSandboxOptions(container, n)
-	if err != nil {
-		return fmt.Errorf("Update network failed: %v", err)
-	}
-
-	if err := sb.Refresh(options...); err != nil {
-		return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
-	}
-
-	return nil
-}
-
-// updateContainerNetworkSettings update the network settings
-func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error {
-	var (
-		n   libnetwork.Network
-		err error
-	)
-
-	mode := container.HostConfig.NetworkMode
-	if container.Config.NetworkDisabled || mode.IsContainer() {
-		return nil
-	}
-
-	networkName := mode.NetworkName()
-	if mode.IsDefault() {
-		networkName = daemon.netController.Config().Daemon.DefaultNetwork
-	}
-	if mode.IsUserDefined() {
-		n, err = daemon.FindNetwork(networkName)
-		if err != nil {
-			return err
-		}
-		networkName = n.Name()
-	}
-	if container.NetworkSettings == nil {
-		container.NetworkSettings = &network.Settings{}
-	}
-	if len(endpointsConfig) > 0 {
-		container.NetworkSettings.Networks = endpointsConfig
-	}
-	if container.NetworkSettings.Networks == nil {
-		container.NetworkSettings.Networks = make(map[string]*networktypes.EndpointSettings)
-		container.NetworkSettings.Networks[networkName] = new(networktypes.EndpointSettings)
-	}
-	if !mode.IsUserDefined() {
-		return nil
-	}
-	// Make sure to internally store the per network endpoint config by network name
-	if _, ok := container.NetworkSettings.Networks[networkName]; ok {
-		return nil
-	}
-	if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
-		container.NetworkSettings.Networks[networkName] = nwConfig
-		delete(container.NetworkSettings.Networks, n.ID())
-		return nil
-	}
-
-	return nil
-}
-
-func (daemon *Daemon) allocateNetwork(container *container.Container) error {
-	controller := daemon.netController
-
-	// Cleanup any stale sandbox left over due to ungraceful daemon shutdown
-	if err := controller.SandboxDestroy(container.ID); err != nil {
-		logrus.Errorf("failed to cleanup up stale network sandbox for container %s", container.ID)
-	}
-
-	updateSettings := false
-	if len(container.NetworkSettings.Networks) == 0 {
-		if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() {
-			return nil
-		}
-
-		err := daemon.updateContainerNetworkSettings(container, nil)
-		if err != nil {
-			return err
-		}
-		updateSettings = true
-	}
-
-	for n, nConf := range container.NetworkSettings.Networks {
-		if err := daemon.connectToNetwork(container, n, nConf, updateSettings); err != nil {
-			return err
-		}
-	}
-
-	return container.WriteHostConfig()
-}
-
-func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox {
-	var sb libnetwork.Sandbox
-	daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool {
-		if s.ContainerID() == container.ID {
-			sb = s
-			return true
-		}
-		return false
-	})
-	return sb
-}
-
-// hasUserDefinedIPAddress returns whether the passed endpoint configuration contains IP address configuration
-func hasUserDefinedIPAddress(epConfig *networktypes.EndpointSettings) bool {
-	return epConfig != nil && epConfig.IPAMConfig != nil && (len(epConfig.IPAMConfig.IPv4Address) > 0 || len(epConfig.IPAMConfig.IPv6Address) > 0)
-}
-
-// User specified ip address is acceptable only for networks with user specified subnets.
-func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error {
-	if n == nil || epConfig == nil {
-		return nil
-	}
-	if !hasUserDefinedIPAddress(epConfig) {
-		return nil
-	}
-	_, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig()
-	for _, s := range []struct {
-		ipConfigured  bool
-		subnetConfigs []*libnetwork.IpamConf
-	}{
-		{
-			ipConfigured:  len(epConfig.IPAMConfig.IPv4Address) > 0,
-			subnetConfigs: nwIPv4Configs,
-		},
-		{
-			ipConfigured:  len(epConfig.IPAMConfig.IPv6Address) > 0,
-			subnetConfigs: nwIPv6Configs,
-		},
-	} {
-		if s.ipConfigured {
-			foundSubnet := false
-			for _, cfg := range s.subnetConfigs {
-				if len(cfg.PreferredPool) > 0 {
-					foundSubnet = true
-					break
-				}
-			}
-			if !foundSubnet {
-				return runconfig.ErrUnsupportedNetworkNoSubnetAndIP
-			}
-		}
-	}
-
-	return nil
-}
-
-// cleanOperationalData resets the operational data from the passed endpoint settings
-func cleanOperationalData(es *networktypes.EndpointSettings) {
-	es.EndpointID = ""
-	es.Gateway = ""
-	es.IPAddress = ""
-	es.IPPrefixLen = 0
-	es.IPv6Gateway = ""
-	es.GlobalIPv6Address = ""
-	es.GlobalIPv6PrefixLen = 0
-	es.MacAddress = ""
-}
-
-func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (libnetwork.Network, error) {
-	if container.HostConfig.NetworkMode.IsContainer() {
-		return nil, runconfig.ErrConflictSharedNetwork
-	}
-
-	if containertypes.NetworkMode(idOrName).IsBridge() &&
-		daemon.configStore.DisableBridge {
-		container.Config.NetworkDisabled = true
-		return nil, nil
-	}
-
-	if !containertypes.NetworkMode(idOrName).IsUserDefined() {
-		if hasUserDefinedIPAddress(endpointConfig) {
-			return nil, runconfig.ErrUnsupportedNetworkAndIP
-		}
-		if endpointConfig != nil && len(endpointConfig.Aliases) > 0 {
-			return nil, runconfig.ErrUnsupportedNetworkAndAlias
-		}
-	}
-
-	n, err := daemon.FindNetwork(idOrName)
-	if err != nil {
-		return nil, err
-	}
-
-	if err := validateNetworkingConfig(n, endpointConfig); err != nil {
-		return nil, err
-	}
-
-	if updateSettings {
-		if err := daemon.updateNetworkSettings(container, n); err != nil {
-			return nil, err
-		}
-	}
-	return n, nil
-}
-
 // ConnectToNetwork connects a container to a network
 func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error {
 	if !container.Running {
@@ -810,83 +331,6 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName
 	return nil
 }
 
-func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
-	n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings)
-	if err != nil {
-		return err
-	}
-	if n == nil {
-		return nil
-	}
-
-	controller := daemon.netController
-
-	sb := daemon.getNetworkSandbox(container)
-	createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb)
-	if err != nil {
-		return err
-	}
-
-	endpointName := strings.TrimPrefix(container.Name, "/")
-	ep, err := n.CreateEndpoint(endpointName, createOptions...)
-	if err != nil {
-		return err
-	}
-	defer func() {
-		if err != nil {
-			if e := ep.Delete(false); e != nil {
-				logrus.Warnf("Could not rollback container connection to network %s", idOrName)
-			}
-		}
-	}()
-
-	if endpointConfig != nil {
-		container.NetworkSettings.Networks[n.Name()] = endpointConfig
-	}
-
-	if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
-		return err
-	}
-
-	if sb == nil {
-		options, err := daemon.buildSandboxOptions(container, n)
-		if err != nil {
-			return err
-		}
-		sb, err = controller.NewSandbox(container.ID, options...)
-		if err != nil {
-			return err
-		}
-
-		container.UpdateSandboxNetworkSettings(sb)
-	}
-
-	joinOptions, err := container.BuildJoinOptions(n)
-	if err != nil {
-		return err
-	}
-
-	if err := ep.Join(sb, joinOptions...); err != nil {
-		return err
-	}
-
-	if err := container.UpdateJoinInfo(n, ep); err != nil {
-		return fmt.Errorf("Updating join info failed: %v", err)
-	}
-
-	daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
-	return nil
-}
-
-// ForceEndpointDelete deletes an endpoing from a network forcefully
-func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
-	ep, err := n.EndpointByName(name)
-	if err != nil {
-		return err
-	}
-	return ep.Delete(true)
-}
-
 // DisconnectFromNetwork disconnects container from network n.
 func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
 	if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
@@ -918,91 +362,6 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li
 	return nil
 }
 
-func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
-	var (
-		ep   libnetwork.Endpoint
-		sbox libnetwork.Sandbox
-	)
-
-	s := func(current libnetwork.Endpoint) bool {
-		epInfo := current.Info()
-		if epInfo == nil {
-			return false
-		}
-		if sb := epInfo.Sandbox(); sb != nil {
-			if sb.ContainerID() == container.ID {
-				ep = current
-				sbox = sb
-				return true
-			}
-		}
-		return false
-	}
-	n.WalkEndpoints(s)
-
-	if ep == nil && force {
-		epName := strings.TrimPrefix(container.Name, "/")
-		ep, err := n.EndpointByName(epName)
-		if err != nil {
-			return err
-		}
-		return ep.Delete(force)
-	}
-
-	if ep == nil {
-		return fmt.Errorf("container %s is not connected to the network", container.ID)
-	}
-
-	if err := ep.Leave(sbox); err != nil {
-		return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
-	}
-
-	if err := ep.Delete(false); err != nil {
-		return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
-	}
-
-	delete(container.NetworkSettings.Networks, n.Name())
-	return nil
-}
-
-func (daemon *Daemon) initializeNetworking(container *container.Container) error {
-	var err error
-
-	if container.HostConfig.NetworkMode.IsContainer() {
-		// we need to get the hosts files from the container to join
-		nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer())
-		if err != nil {
-			return err
-		}
-		container.HostnamePath = nc.HostnamePath
-		container.HostsPath = nc.HostsPath
-		container.ResolvConfPath = nc.ResolvConfPath
-		container.Config.Hostname = nc.Config.Hostname
-		container.Config.Domainname = nc.Config.Domainname
-		return nil
-	}
-
-	if container.HostConfig.NetworkMode.IsHost() {
-		container.Config.Hostname, err = os.Hostname()
-		if err != nil {
-			return err
-		}
-
-		parts := strings.SplitN(container.Config.Hostname, ".", 2)
-		if len(parts) > 1 {
-			container.Config.Hostname = parts[0]
-			container.Config.Domainname = parts[1]
-		}
-
-	}
-
-	if err := daemon.allocateNetwork(container); err != nil {
-		return err
-	}
-
-	return container.BuildHostnameFile()
-}
-
 // called from the libcontainer pre-start hook to set the network
 // namespace configuration linkage to the libnetwork "sandbox" entity
 func (daemon *Daemon) setNetworkNamespaceKey(containerID string, pid int) error {
@@ -1032,63 +391,6 @@ func (daemon *Daemon) getIpcContainer(container *container.Container) (*containe
 	return c, nil
 }
 
-func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) {
-	nc, err := daemon.GetContainer(connectedContainerID)
-	if err != nil {
-		return nil, err
-	}
-	if containerID == nc.ID {
-		return nil, fmt.Errorf("cannot join own network")
-	}
-	if !nc.IsRunning() {
-		err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID)
-		return nil, errors.NewRequestConflictError(err)
-	}
-	if nc.IsRestarting() {
-		return nil, errContainerIsRestarting(connectedContainerID)
-	}
-	return nc, nil
-}
-
-func (daemon *Daemon) releaseNetwork(container *container.Container) {
-	if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled {
-		return
-	}
-
-	sid := container.NetworkSettings.SandboxID
-	settings := container.NetworkSettings.Networks
-	container.NetworkSettings.Ports = nil
-
-	if sid == "" || len(settings) == 0 {
-		return
-	}
-
-	var networks []libnetwork.Network
-	for n, epSettings := range settings {
-		if nw, err := daemon.FindNetwork(n); err == nil {
-			networks = append(networks, nw)
-		}
-		cleanOperationalData(epSettings)
-	}
-
-	sb, err := daemon.netController.SandboxByID(sid)
-	if err != nil {
-		logrus.Errorf("error locating sandbox id %s: %v", sid, err)
-		return
-	}
-
-	if err := sb.Delete(); err != nil {
-		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
-	}
-
-	attributes := map[string]string{
-		"container": container.ID,
-	}
-	for _, nw := range networks {
-		daemon.LogNetworkEventWithAttributes(nw, "disconnect", attributes)
-	}
-}
-
 func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
 	rootUID, rootGID := daemon.GetRemappedUIDGID()
 	if !c.HasMountFor("/dev/shm") {
@@ -1242,7 +544,7 @@ func detachMounted(path string) error {
 
 func isLinkable(child *container.Container) bool {
 	// A container is linkable only if it belongs to the default network
-	_, ok := child.NetworkSettings.Networks["bridge"]
+	_, ok := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
 	return ok
 }
 

+ 54 - 47
daemon/container_operations_windows.go

@@ -6,11 +6,12 @@ import (
 	"fmt"
 	"strings"
 
+	networktypes "github.com/docker/engine-api/types/network"
+
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver/windows"
 	"github.com/docker/docker/layer"
-	networktypes "github.com/docker/engine-api/types/network"
 	"github.com/docker/libnetwork"
 )
 
@@ -18,28 +19,14 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
 	return nil, nil
 }
 
-// updateContainerNetworkSettings update the network settings
-func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error {
-	return nil
-}
-
-func (daemon *Daemon) initializeNetworking(container *container.Container) error {
-	return nil
-}
-
-// ConnectToNetwork connects a container to the network
+// ConnectToNetwork connects a container to a network
 func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error {
-	return nil
+	return fmt.Errorf("Windows does not support connecting a running container to a network")
 }
 
-// ForceEndpointDelete deletes an endpoing from a network forcefully
-func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
-	return nil
-}
-
-// DisconnectFromNetwork disconnects a container from the network.
+// DisconnectFromNetwork disconnects container from a network.
 func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
-	return nil
+	return fmt.Errorf("Windows does not support disconnecting a running container from a network")
 }
 
 func (daemon *Daemon) populateCommand(c *container.Container, env []string) error {
@@ -47,24 +34,51 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
 		Interface: nil,
 	}
 
-	parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2)
-	switch parts[0] {
-	case "none":
-	case "default", "": // empty string to support existing containers
-		if !c.Config.NetworkDisabled {
-			en.Interface = &execdriver.NetworkInterface{
-				MacAddress:   c.Config.MacAddress,
-				Bridge:       daemon.configStore.bridgeConfig.VirtualSwitchName,
-				PortBindings: c.HostConfig.PortBindings,
-
-				// TODO Windows. Include IPAddress. There already is a
-				// property IPAddress on execDrive.CommonNetworkInterface,
-				// but there is no CLI option in docker to pass through
-				// an IPAddress on docker run.
+	var epList []string
+
+	// Connect all the libnetwork allocated networks to the container
+	if c.NetworkSettings != nil {
+		for n := range c.NetworkSettings.Networks {
+			sn, err := daemon.FindNetwork(n)
+			if err != nil {
+				continue
+			}
+
+			ep, err := c.GetEndpointInNetwork(sn)
+			if err != nil {
+				continue
+			}
+
+			data, err := ep.DriverInfo()
+			if err != nil {
+				continue
+			}
+			if data["hnsid"] != nil {
+				epList = append(epList, data["hnsid"].(string))
 			}
 		}
-	default:
-		return fmt.Errorf("invalid network mode: %s", c.HostConfig.NetworkMode)
+	}
+
+	if daemon.netController == nil {
+		parts := strings.SplitN(string(c.HostConfig.NetworkMode), ":", 2)
+		switch parts[0] {
+		case "none":
+		case "default", "": // empty string to support existing containers
+			if !c.Config.NetworkDisabled {
+				en.Interface = &execdriver.NetworkInterface{
+					MacAddress:   c.Config.MacAddress,
+					Bridge:       daemon.configStore.bridgeConfig.Iface,
+					PortBindings: c.HostConfig.PortBindings,
+
+					// TODO Windows. Include IPAddress. There already is a
+					// property IPAddress on execDrive.CommonNetworkInterface,
+					// but there is no CLI option in docker to pass through
+					// an IPAddress on docker run.
+				}
+			}
+		default:
+			return fmt.Errorf("invalid network mode: %s", c.HostConfig.NetworkMode)
+		}
 	}
 
 	// TODO Windows. More resource controls to be implemented later.
@@ -138,6 +152,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
 		Isolation:   string(c.HostConfig.Isolation),
 		ArgsEscaped: c.Config.ArgsEscaped,
 		HvPartition: hvPartition,
+		EpList:      epList,
 	}
 
 	return nil
@@ -154,18 +169,6 @@ func (daemon *Daemon) setNetworkNamespaceKey(containerID string, pid int) error
 	return nil
 }
 
-// allocateNetwork is a no-op on Windows.
-func (daemon *Daemon) allocateNetwork(container *container.Container) error {
-	return nil
-}
-
-func (daemon *Daemon) updateNetwork(container *container.Container) error {
-	return nil
-}
-
-func (daemon *Daemon) releaseNetwork(container *container.Container) {
-}
-
 func (daemon *Daemon) setupIpcDirs(container *container.Container) error {
 	return nil
 }
@@ -187,3 +190,7 @@ func detachMounted(path string) error {
 func killProcessDirectly(container *container.Container) error {
 	return nil
 }
+
+func isLinkable(child *container.Container) bool {
+	return false
+}

+ 43 - 0
daemon/daemon.go

@@ -71,6 +71,7 @@ import (
 	"github.com/docker/docker/volume/store"
 	"github.com/docker/go-connections/nat"
 	"github.com/docker/libnetwork"
+	nwconfig "github.com/docker/libnetwork/config"
 	lntypes "github.com/docker/libnetwork/types"
 	"github.com/docker/libtrust"
 	"github.com/opencontainers/runc/libcontainer"
@@ -1693,3 +1694,45 @@ func validateID(id string) error {
 	}
 	return nil
 }
+
+func isBridgeNetworkDisabled(config *Config) bool {
+	return config.bridgeConfig.Iface == disableNetworkBridge
+}
+
+func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
+	options := []nwconfig.Option{}
+	if dconfig == nil {
+		return options, nil
+	}
+
+	options = append(options, nwconfig.OptionDataDir(dconfig.Root))
+
+	dd := runconfig.DefaultDaemonNetworkMode()
+	dn := runconfig.DefaultDaemonNetworkMode().NetworkName()
+	options = append(options, nwconfig.OptionDefaultDriver(string(dd)))
+	options = append(options, nwconfig.OptionDefaultNetwork(dn))
+
+	if strings.TrimSpace(dconfig.ClusterStore) != "" {
+		kv := strings.Split(dconfig.ClusterStore, "://")
+		if len(kv) != 2 {
+			return nil, fmt.Errorf("kv store daemon config must be of the form KV-PROVIDER://KV-URL")
+		}
+		options = append(options, nwconfig.OptionKVProvider(kv[0]))
+		options = append(options, nwconfig.OptionKVProviderURL(kv[1]))
+	}
+	if len(dconfig.ClusterOpts) > 0 {
+		options = append(options, nwconfig.OptionKVOpts(dconfig.ClusterOpts))
+	}
+
+	if daemon.discoveryWatcher != nil {
+		options = append(options, nwconfig.OptionDiscoveryWatcher(daemon.discoveryWatcher))
+	}
+
+	if dconfig.ClusterAdvertise != "" {
+		options = append(options, nwconfig.OptionDiscoveryAddress(dconfig.ClusterAdvertise))
+	}
+
+	options = append(options, nwconfig.OptionLabels(dconfig.Labels))
+	options = append(options, driverOptions(dconfig)...)
+	return options, nil
+}

+ 0 - 42
daemon/daemon_unix.go

@@ -518,48 +518,6 @@ func configureKernelSecuritySupport(config *Config, driverName string) error {
 	return nil
 }
 
-func isBridgeNetworkDisabled(config *Config) bool {
-	return config.bridgeConfig.Iface == disableNetworkBridge
-}
-
-func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
-	options := []nwconfig.Option{}
-	if dconfig == nil {
-		return options, nil
-	}
-
-	options = append(options, nwconfig.OptionDataDir(dconfig.Root))
-
-	dd := runconfig.DefaultDaemonNetworkMode()
-	dn := runconfig.DefaultDaemonNetworkMode().NetworkName()
-	options = append(options, nwconfig.OptionDefaultDriver(string(dd)))
-	options = append(options, nwconfig.OptionDefaultNetwork(dn))
-
-	if strings.TrimSpace(dconfig.ClusterStore) != "" {
-		kv := strings.Split(dconfig.ClusterStore, "://")
-		if len(kv) != 2 {
-			return nil, fmt.Errorf("kv store daemon config must be of the form KV-PROVIDER://KV-URL")
-		}
-		options = append(options, nwconfig.OptionKVProvider(kv[0]))
-		options = append(options, nwconfig.OptionKVProviderURL(kv[1]))
-	}
-	if len(dconfig.ClusterOpts) > 0 {
-		options = append(options, nwconfig.OptionKVOpts(dconfig.ClusterOpts))
-	}
-
-	if daemon.discoveryWatcher != nil {
-		options = append(options, nwconfig.OptionDiscoveryWatcher(daemon.discoveryWatcher))
-	}
-
-	if dconfig.ClusterAdvertise != "" {
-		options = append(options, nwconfig.OptionDiscoveryAddress(dconfig.ClusterAdvertise))
-	}
-
-	options = append(options, nwconfig.OptionLabels(dconfig.Labels))
-	options = append(options, driverOptions(dconfig)...)
-	return options, nil
-}
-
 func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) {
 	netOptions, err := daemon.networkOptions(config)
 	if err != nil {

+ 153 - 9
daemon/daemon_windows.go

@@ -9,6 +9,7 @@ import (
 	"runtime"
 	"strings"
 
+	"github.com/Microsoft/hcsshim"
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/daemon/graphdriver"
@@ -16,6 +17,7 @@ import (
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/layer"
 	"github.com/docker/docker/reference"
+	"github.com/docker/docker/runconfig"
 	containertypes "github.com/docker/engine-api/types/container"
 	// register the windows graph driver
 	"github.com/docker/docker/daemon/graphdriver/windows"
@@ -23,11 +25,15 @@ import (
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/libnetwork"
 	nwconfig "github.com/docker/libnetwork/config"
+	winlibnetwork "github.com/docker/libnetwork/drivers/windows"
+	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/options"
 	blkiodev "github.com/opencontainers/runc/libcontainer/configs"
 )
 
 const (
 	defaultVirtualSwitch = "Virtual Switch"
+	defaultNetworkSpace  = "172.16.0.0/12"
 	platformSupported    = true
 	windowsMinCPUShares  = 1
 	windowsMaxCPUShares  = 10000
@@ -125,16 +131,154 @@ func configureMaxThreads(config *Config) error {
 	return nil
 }
 
-func isBridgeNetworkDisabled(config *Config) bool {
-	return false
+func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) {
+	// TODO Windows: Remove this check once TP4 is no longer supported
+	osv, err := system.GetOSVersion()
+	if err != nil {
+		return nil, err
+	}
+
+	if osv.Build < 14260 {
+		// Set the name of the virtual switch if not specified by -b on daemon start
+		if config.bridgeConfig.Iface == "" {
+			config.bridgeConfig.Iface = defaultVirtualSwitch
+		}
+		logrus.Warnf("Network controller is not supported by the current platform build version")
+		return nil, nil
+	}
+
+	netOptions, err := daemon.networkOptions(config)
+	if err != nil {
+		return nil, err
+	}
+	controller, err := libnetwork.New(netOptions...)
+	if err != nil {
+		return nil, fmt.Errorf("error obtaining controller instance: %v", err)
+	}
+
+	hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "")
+	if err != nil {
+		return nil, err
+	}
+
+	// Remove networks not present in HNS
+	for _, v := range controller.Networks() {
+		options := v.Info().DriverOptions()
+		hnsid := options[winlibnetwork.HNSID]
+		found := false
+
+		for _, v := range hnsresponse {
+			if v.Id == hnsid {
+				found = true
+				break
+			}
+		}
+
+		if !found {
+			err = v.Delete()
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	_, err = controller.NewNetwork("null", "none", libnetwork.NetworkOptionPersist(false))
+	if err != nil {
+		return nil, err
+	}
+
+	// discover and add HNS networks to windows
+	// network that exist are removed and added again
+	for _, v := range hnsresponse {
+		var n libnetwork.Network
+		s := func(current libnetwork.Network) bool {
+			options := current.Info().DriverOptions()
+			if options[winlibnetwork.HNSID] == v.Id {
+				n = current
+				return true
+			}
+			return false
+		}
+
+		controller.WalkNetworks(s)
+		if n != nil {
+			v.Name = n.Name()
+			n.Delete()
+		}
+
+		netOption := map[string]string{
+			winlibnetwork.NetworkName: v.Name,
+			winlibnetwork.HNSID:       v.Id,
+		}
+
+		v4Conf := []*libnetwork.IpamConf{}
+		for _, subnet := range v.Subnets {
+			ipamV4Conf := libnetwork.IpamConf{}
+			ipamV4Conf.PreferredPool = subnet.AddressPrefix
+			ipamV4Conf.Gateway = subnet.GatewayAddress
+			v4Conf = append(v4Conf, &ipamV4Conf)
+		}
+
+		name := v.Name
+		// There is only one nat network supported in windows.
+		// If it exists with a different name add it as the default name
+		if runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) {
+			name = runconfig.DefaultDaemonNetworkMode().NetworkName()
+		}
+
+		v6Conf := []*libnetwork.IpamConf{}
+		_, err := controller.NewNetwork(strings.ToLower(v.Type), name,
+			libnetwork.NetworkOptionGeneric(options.Generic{
+				netlabel.GenericData: netOption,
+			}),
+			libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
+		)
+
+		if err != nil {
+			logrus.Errorf("Error occurred when creating network %v", err)
+		}
+	}
+
+	if !config.DisableBridge {
+		// Initialize default driver "bridge"
+		if err := initBridgeDriver(controller, config); err != nil {
+			return nil, err
+		}
+	}
+
+	return controller, nil
 }
 
-func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) {
-	// Set the name of the virtual switch if not specified by -b on daemon start
-	if config.bridgeConfig.VirtualSwitchName == "" {
-		config.bridgeConfig.VirtualSwitchName = defaultVirtualSwitch
+func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
+	if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
+		return nil
 	}
-	return nil, nil
+
+	netOption := map[string]string{
+		winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(),
+	}
+
+	ipamV4Conf := libnetwork.IpamConf{}
+	if config.bridgeConfig.FixedCIDR == "" {
+		ipamV4Conf.PreferredPool = defaultNetworkSpace
+	} else {
+		ipamV4Conf.PreferredPool = config.bridgeConfig.FixedCIDR
+	}
+
+	v4Conf := []*libnetwork.IpamConf{&ipamV4Conf}
+	v6Conf := []*libnetwork.IpamConf{}
+
+	_, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(),
+		libnetwork.NetworkOptionGeneric(options.Generic{
+			netlabel.GenericData: netOption,
+		}),
+		libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
+	)
+
+	if err != nil {
+		return fmt.Errorf("Error creating default network: %v", err)
+	}
+	return nil
 }
 
 // registerLinks sets up links between containers and writes the
@@ -257,6 +401,6 @@ func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) erro
 	return nil
 }
 
-func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
-	return nil, fmt.Errorf("Network controller config reload not aavailable on Windows yet")
+func driverOptions(config *Config) []nwconfig.Option {
+	return []nwconfig.Option{}
 }

+ 1 - 0
daemon/execdriver/driver_windows.go

@@ -56,6 +56,7 @@ type Command struct {
 	Isolation   string   `json:"isolation"`    // Isolation technology for the container
 	ArgsEscaped bool     `json:"args_escaped"` // True if args are already escaped
 	HvPartition bool     `json:"hv_partition"` // True if it's an hypervisor partition
+	EpList      []string `json:"endpoints"`    // List of network endpoints for HNS
 }
 
 // ExitStatus provides exit reasons for a container.

+ 3 - 0
daemon/execdriver/windows/run.go

@@ -89,6 +89,7 @@ type containerInit struct {
 	MappedDirectories       []mappedDir // List of mapped directories (volumes/mounts)
 	SandboxPath             string      // Location of unmounted sandbox (used for Hyper-V containers, not Windows Server containers)
 	HvPartition             bool        // True if it a Hyper-V Container
+	EndpointList            []string    // List of endpoints to be attached to container
 }
 
 // defaultOwner is a tag passed to HCS to allow it to differentiate between
@@ -104,6 +105,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
 		err  error
 	)
 
+	// Allocate Network only if there is no network interface
 	cu := &containerInit{
 		SystemType:              "Container",
 		Name:                    c.ID,
@@ -114,6 +116,7 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
 		LayerFolderPath:         c.LayerFolder,
 		ProcessorWeight:         c.Resources.CPUShares,
 		HostName:                c.Hostname,
+		EndpointList:            c.EpList,
 	}
 
 	cu.HvPartition = c.HvPartition

+ 20 - 0
hack/make/win

@@ -0,0 +1,20 @@
+#!/bin/bash
+set -e
+
+# explicit list of os/arch combos that support being a daemon
+declare -A daemonSupporting
+daemonSupporting=(
+	[linux/amd64]=1
+	[windows/amd64]=1
+)
+platform="windows/amd64"
+export DEST="$DEST/$platform" # bundles/VERSION/cross/GOOS/GOARCH/docker-VERSION
+mkdir -p "$DEST"
+ABS_DEST="$(cd "$DEST" && pwd -P)"
+export GOOS=${platform%/*}
+export GOARCH=${platform##*/}
+if [ -z "${daemonSupporting[$platform]}" ]; then
+	export LDFLAGS_STATIC_DOCKER="" # we just need a simple client for these platforms
+	export BUILDFLAGS=( "${ORIG_BUILDFLAGS[@]/ daemon/}" ) # remove the "daemon" build tag from platforms that aren't supported
+fi
+source "${MAKEDIR}/binary"

+ 3 - 6
runconfig/hostconfig_windows.go

@@ -10,25 +10,22 @@ import (
 // DefaultDaemonNetworkMode returns the default network stack the daemon should
 // use.
 func DefaultDaemonNetworkMode() container.NetworkMode {
-	return container.NetworkMode("default")
+	return container.NetworkMode("nat")
 }
 
 // IsPreDefinedNetwork indicates if a network is predefined by the daemon
 func IsPreDefinedNetwork(network string) bool {
-	return false
+	return !container.NetworkMode(network).IsUserDefined()
 }
 
 // ValidateNetMode ensures that the various combinations of requested
 // network settings are valid.
 func ValidateNetMode(c *container.Config, hc *container.HostConfig) error {
-	// We may not be passed a host config, such as in the case of docker commit
 	if hc == nil {
 		return nil
 	}
 	parts := strings.Split(string(hc.NetworkMode), ":")
-	switch mode := parts[0]; mode {
-	case "default", "none":
-	default:
+	if len(parts) > 1 {
 		return fmt.Errorf("invalid --net: %s", hc.NetworkMode)
 	}
 	return nil