github.com/sams1990/dockerrepo@v17.12.1-ce-rc2+incompatible/daemon/container_operations.go (about)

     1  package daemon
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"os"
     8  	"path"
     9  	"runtime"
    10  	"strings"
    11  	"time"
    12  
    13  	containertypes "github.com/docker/docker/api/types/container"
    14  	networktypes "github.com/docker/docker/api/types/network"
    15  	"github.com/docker/docker/container"
    16  	"github.com/docker/docker/daemon/network"
    17  	"github.com/docker/docker/opts"
    18  	"github.com/docker/docker/pkg/stringid"
    19  	"github.com/docker/docker/runconfig"
    20  	"github.com/docker/go-connections/nat"
    21  	"github.com/docker/libnetwork"
    22  	"github.com/docker/libnetwork/netlabel"
    23  	"github.com/docker/libnetwork/options"
    24  	"github.com/docker/libnetwork/types"
    25  	"github.com/sirupsen/logrus"
    26  )
    27  
    28  var (
    29  	// ErrRootFSReadOnly is returned when a container
    30  	// rootfs is marked readonly.
    31  	ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
    32  	getPortMapInfo    = container.GetSandboxPortMapInfo
    33  )
    34  
    35  func (daemon *Daemon) getDNSSearchSettings(container *container.Container) []string {
    36  	if len(container.HostConfig.DNSSearch) > 0 {
    37  		return container.HostConfig.DNSSearch
    38  	}
    39  
    40  	if len(daemon.configStore.DNSSearch) > 0 {
    41  		return daemon.configStore.DNSSearch
    42  	}
    43  
    44  	return nil
    45  }
    46  
    47  func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]libnetwork.SandboxOption, error) {
    48  	var (
    49  		sboxOptions []libnetwork.SandboxOption
    50  		err         error
    51  		dns         []string
    52  		dnsOptions  []string
    53  		bindings    = make(nat.PortMap)
    54  		pbList      []types.PortBinding
    55  		exposeList  []types.TransportPort
    56  	)
    57  
    58  	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
    59  	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
    60  		libnetwork.OptionDomainname(container.Config.Domainname))
    61  
    62  	if container.HostConfig.NetworkMode.IsHost() {
    63  		sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
    64  		if len(container.HostConfig.ExtraHosts) == 0 {
    65  			sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
    66  		}
    67  		if len(container.HostConfig.DNS) == 0 && len(daemon.configStore.DNS) == 0 &&
    68  			len(container.HostConfig.DNSSearch) == 0 && len(daemon.configStore.DNSSearch) == 0 &&
    69  			len(container.HostConfig.DNSOptions) == 0 && len(daemon.configStore.DNSOptions) == 0 {
    70  			sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
    71  		}
    72  	} else {
    73  		// OptionUseExternalKey is mandatory for userns support.
    74  		// But optional for non-userns support
    75  		sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
    76  	}
    77  
    78  	if err = setupPathsAndSandboxOptions(container, &sboxOptions); err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	if len(container.HostConfig.DNS) > 0 {
    83  		dns = container.HostConfig.DNS
    84  	} else if len(daemon.configStore.DNS) > 0 {
    85  		dns = daemon.configStore.DNS
    86  	}
    87  
    88  	for _, d := range dns {
    89  		sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d))
    90  	}
    91  
    92  	dnsSearch := daemon.getDNSSearchSettings(container)
    93  
    94  	for _, ds := range dnsSearch {
    95  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds))
    96  	}
    97  
    98  	if len(container.HostConfig.DNSOptions) > 0 {
    99  		dnsOptions = container.HostConfig.DNSOptions
   100  	} else if len(daemon.configStore.DNSOptions) > 0 {
   101  		dnsOptions = daemon.configStore.DNSOptions
   102  	}
   103  
   104  	for _, ds := range dnsOptions {
   105  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds))
   106  	}
   107  
   108  	if container.NetworkSettings.SecondaryIPAddresses != nil {
   109  		name := container.Config.Hostname
   110  		if container.Config.Domainname != "" {
   111  			name = name + "." + container.Config.Domainname
   112  		}
   113  
   114  		for _, a := range container.NetworkSettings.SecondaryIPAddresses {
   115  			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr))
   116  		}
   117  	}
   118  
   119  	for _, extraHost := range container.HostConfig.ExtraHosts {
   120  		// allow IPv6 addresses in extra hosts; only split on first ":"
   121  		if _, err := opts.ValidateExtraHost(extraHost); err != nil {
   122  			return nil, err
   123  		}
   124  		parts := strings.SplitN(extraHost, ":", 2)
   125  		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
   126  	}
   127  
   128  	if container.HostConfig.PortBindings != nil {
   129  		for p, b := range container.HostConfig.PortBindings {
   130  			bindings[p] = []nat.PortBinding{}
   131  			for _, bb := range b {
   132  				bindings[p] = append(bindings[p], nat.PortBinding{
   133  					HostIP:   bb.HostIP,
   134  					HostPort: bb.HostPort,
   135  				})
   136  			}
   137  		}
   138  	}
   139  
   140  	portSpecs := container.Config.ExposedPorts
   141  	ports := make([]nat.Port, len(portSpecs))
   142  	var i int
   143  	for p := range portSpecs {
   144  		ports[i] = p
   145  		i++
   146  	}
   147  	nat.SortPortMap(ports, bindings)
   148  	for _, port := range ports {
   149  		expose := types.TransportPort{}
   150  		expose.Proto = types.ParseProtocol(port.Proto())
   151  		expose.Port = uint16(port.Int())
   152  		exposeList = append(exposeList, expose)
   153  
   154  		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
   155  		binding := bindings[port]
   156  		for i := 0; i < len(binding); i++ {
   157  			pbCopy := pb.GetCopy()
   158  			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
   159  			var portStart, portEnd int
   160  			if err == nil {
   161  				portStart, portEnd, err = newP.Range()
   162  			}
   163  			if err != nil {
   164  				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
   165  			}
   166  			pbCopy.HostPort = uint16(portStart)
   167  			pbCopy.HostPortEnd = uint16(portEnd)
   168  			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
   169  			pbList = append(pbList, pbCopy)
   170  		}
   171  
   172  		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
   173  			pbList = append(pbList, pb)
   174  		}
   175  	}
   176  
   177  	sboxOptions = append(sboxOptions,
   178  		libnetwork.OptionPortMapping(pbList),
   179  		libnetwork.OptionExposedPorts(exposeList))
   180  
   181  	// Legacy Link feature is supported only for the default bridge network.
   182  	// return if this call to build join options is not for default bridge network
   183  	// Legacy Link is only supported by docker run --link
   184  	bridgeSettings, ok := container.NetworkSettings.Networks[defaultNetName]
   185  	if !ok || bridgeSettings.EndpointSettings == nil {
   186  		return sboxOptions, nil
   187  	}
   188  
   189  	if bridgeSettings.EndpointID == "" {
   190  		return sboxOptions, nil
   191  	}
   192  
   193  	var (
   194  		childEndpoints, parentEndpoints []string
   195  		cEndpointID                     string
   196  	)
   197  
   198  	children := daemon.children(container)
   199  	for linkAlias, child := range children {
   200  		if !isLinkable(child) {
   201  			return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
   202  		}
   203  		_, alias := path.Split(linkAlias)
   204  		// allow access to the linked container via the alias, real name, and container hostname
   205  		aliasList := alias + " " + child.Config.Hostname
   206  		// only add the name if alias isn't equal to the name
   207  		if alias != child.Name[1:] {
   208  			aliasList = aliasList + " " + child.Name[1:]
   209  		}
   210  		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks[defaultNetName].IPAddress))
   211  		cEndpointID = child.NetworkSettings.Networks[defaultNetName].EndpointID
   212  		if cEndpointID != "" {
   213  			childEndpoints = append(childEndpoints, cEndpointID)
   214  		}
   215  	}
   216  
   217  	for alias, parent := range daemon.parents(container) {
   218  		if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() {
   219  			continue
   220  		}
   221  
   222  		_, alias = path.Split(alias)
   223  		logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress)
   224  		sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(
   225  			parent.ID,
   226  			alias,
   227  			bridgeSettings.IPAddress,
   228  		))
   229  		if cEndpointID != "" {
   230  			parentEndpoints = append(parentEndpoints, cEndpointID)
   231  		}
   232  	}
   233  
   234  	linkOptions := options.Generic{
   235  		netlabel.GenericData: options.Generic{
   236  			"ParentEndpoints": parentEndpoints,
   237  			"ChildEndpoints":  childEndpoints,
   238  		},
   239  	}
   240  
   241  	sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions))
   242  	return sboxOptions, nil
   243  }
   244  
   245  func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network, endpointConfig *networktypes.EndpointSettings) error {
   246  	if container.NetworkSettings == nil {
   247  		container.NetworkSettings = &network.Settings{Networks: make(map[string]*network.EndpointSettings)}
   248  	}
   249  
   250  	if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
   251  		return runconfig.ErrConflictHostNetwork
   252  	}
   253  
   254  	for s := range container.NetworkSettings.Networks {
   255  		sn, err := daemon.FindNetwork(s)
   256  		if err != nil {
   257  			continue
   258  		}
   259  
   260  		if sn.Name() == n.Name() {
   261  			// Avoid duplicate config
   262  			return nil
   263  		}
   264  		if !containertypes.NetworkMode(sn.Type()).IsPrivate() ||
   265  			!containertypes.NetworkMode(n.Type()).IsPrivate() {
   266  			return runconfig.ErrConflictSharedNetwork
   267  		}
   268  		if containertypes.NetworkMode(sn.Name()).IsNone() ||
   269  			containertypes.NetworkMode(n.Name()).IsNone() {
   270  			return runconfig.ErrConflictNoNetwork
   271  		}
   272  	}
   273  
   274  	if _, ok := container.NetworkSettings.Networks[n.Name()]; !ok {
   275  		container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{
   276  			EndpointSettings: endpointConfig,
   277  		}
   278  	}
   279  
   280  	return nil
   281  }
   282  
   283  func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error {
   284  	if err := container.BuildEndpointInfo(n, ep); err != nil {
   285  		return err
   286  	}
   287  
   288  	if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() {
   289  		container.NetworkSettings.Bridge = daemon.configStore.BridgeConfig.Iface
   290  	}
   291  
   292  	return nil
   293  }
   294  
   295  // UpdateNetwork is used to update the container's network (e.g. when linked containers
   296  // get removed/unlinked).
   297  func (daemon *Daemon) updateNetwork(container *container.Container) error {
   298  	var (
   299  		start = time.Now()
   300  		ctrl  = daemon.netController
   301  		sid   = container.NetworkSettings.SandboxID
   302  	)
   303  
   304  	sb, err := ctrl.SandboxByID(sid)
   305  	if err != nil {
   306  		return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
   307  	}
   308  
   309  	// Find if container is connected to the default bridge network
   310  	var n libnetwork.Network
   311  	for name := range container.NetworkSettings.Networks {
   312  		sn, err := daemon.FindNetwork(name)
   313  		if err != nil {
   314  			continue
   315  		}
   316  		if sn.Name() == runconfig.DefaultDaemonNetworkMode().NetworkName() {
   317  			n = sn
   318  			break
   319  		}
   320  	}
   321  
   322  	if n == nil {
   323  		// Not connected to the default bridge network; Nothing to do
   324  		return nil
   325  	}
   326  
   327  	options, err := daemon.buildSandboxOptions(container)
   328  	if err != nil {
   329  		return fmt.Errorf("Update network failed: %v", err)
   330  	}
   331  
   332  	if err := sb.Refresh(options...); err != nil {
   333  		return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
   334  	}
   335  
   336  	networkActions.WithValues("update").UpdateSince(start)
   337  
   338  	return nil
   339  }
   340  
   341  func (daemon *Daemon) findAndAttachNetwork(container *container.Container, idOrName string, epConfig *networktypes.EndpointSettings) (libnetwork.Network, *networktypes.NetworkingConfig, error) {
   342  	n, err := daemon.FindNetwork(idOrName)
   343  	if err != nil {
   344  		// We should always be able to find the network for a
   345  		// managed container.
   346  		if container.Managed {
   347  			return nil, nil, err
   348  		}
   349  	}
   350  
   351  	// If we found a network and if it is not dynamically created
   352  	// we should never attempt to attach to that network here.
   353  	if n != nil {
   354  		if container.Managed || !n.Info().Dynamic() {
   355  			return n, nil, nil
   356  		}
   357  	}
   358  
   359  	var addresses []string
   360  	if epConfig != nil && epConfig.IPAMConfig != nil {
   361  		if epConfig.IPAMConfig.IPv4Address != "" {
   362  			addresses = append(addresses, epConfig.IPAMConfig.IPv4Address)
   363  		}
   364  
   365  		if epConfig.IPAMConfig.IPv6Address != "" {
   366  			addresses = append(addresses, epConfig.IPAMConfig.IPv6Address)
   367  		}
   368  	}
   369  
   370  	var (
   371  		config     *networktypes.NetworkingConfig
   372  		retryCount int
   373  	)
   374  
   375  	for {
   376  		// In all other cases, attempt to attach to the network to
   377  		// trigger attachment in the swarm cluster manager.
   378  		if daemon.clusterProvider != nil {
   379  			var err error
   380  			config, err = daemon.clusterProvider.AttachNetwork(idOrName, container.ID, addresses)
   381  			if err != nil {
   382  				return nil, nil, err
   383  			}
   384  		}
   385  
   386  		n, err = daemon.FindNetwork(idOrName)
   387  		if err != nil {
   388  			if daemon.clusterProvider != nil {
   389  				if err := daemon.clusterProvider.DetachNetwork(idOrName, container.ID); err != nil {
   390  					logrus.Warnf("Could not rollback attachment for container %s to network %s: %v", container.ID, idOrName, err)
   391  				}
   392  			}
   393  
   394  			// Retry network attach again if we failed to
   395  			// find the network after successful
   396  			// attachment because the only reason that
   397  			// would happen is if some other container
   398  			// attached to the swarm scope network went down
   399  			// and removed the network while we were in
   400  			// the process of attaching.
   401  			if config != nil {
   402  				if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
   403  					if retryCount >= 5 {
   404  						return nil, nil, fmt.Errorf("could not find network %s after successful attachment", idOrName)
   405  					}
   406  					retryCount++
   407  					continue
   408  				}
   409  			}
   410  
   411  			return nil, nil, err
   412  		}
   413  
   414  		break
   415  	}
   416  
   417  	// This container has attachment to a swarm scope
   418  	// network. Update the container network settings accordingly.
   419  	container.NetworkSettings.HasSwarmEndpoint = true
   420  	return n, config, nil
   421  }
   422  
   423  // updateContainerNetworkSettings updates the network settings
   424  func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) {
   425  	var n libnetwork.Network
   426  
   427  	mode := container.HostConfig.NetworkMode
   428  	if container.Config.NetworkDisabled || mode.IsContainer() {
   429  		return
   430  	}
   431  
   432  	networkName := mode.NetworkName()
   433  	if mode.IsDefault() {
   434  		networkName = daemon.netController.Config().Daemon.DefaultNetwork
   435  	}
   436  
   437  	if mode.IsUserDefined() {
   438  		var err error
   439  
   440  		n, err = daemon.FindNetwork(networkName)
   441  		if err == nil {
   442  			networkName = n.Name()
   443  		}
   444  	}
   445  
   446  	if container.NetworkSettings == nil {
   447  		container.NetworkSettings = &network.Settings{}
   448  	}
   449  
   450  	if len(endpointsConfig) > 0 {
   451  		if container.NetworkSettings.Networks == nil {
   452  			container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
   453  		}
   454  
   455  		for name, epConfig := range endpointsConfig {
   456  			container.NetworkSettings.Networks[name] = &network.EndpointSettings{
   457  				EndpointSettings: epConfig,
   458  			}
   459  		}
   460  	}
   461  
   462  	if container.NetworkSettings.Networks == nil {
   463  		container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
   464  		container.NetworkSettings.Networks[networkName] = &network.EndpointSettings{
   465  			EndpointSettings: &networktypes.EndpointSettings{},
   466  		}
   467  	}
   468  
   469  	// Convert any settings added by client in default name to
   470  	// engine's default network name key
   471  	if mode.IsDefault() {
   472  		if nConf, ok := container.NetworkSettings.Networks[mode.NetworkName()]; ok {
   473  			container.NetworkSettings.Networks[networkName] = nConf
   474  			delete(container.NetworkSettings.Networks, mode.NetworkName())
   475  		}
   476  	}
   477  
   478  	if !mode.IsUserDefined() {
   479  		return
   480  	}
   481  	// Make sure to internally store the per network endpoint config by network name
   482  	if _, ok := container.NetworkSettings.Networks[networkName]; ok {
   483  		return
   484  	}
   485  
   486  	if n != nil {
   487  		if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
   488  			container.NetworkSettings.Networks[networkName] = nwConfig
   489  			delete(container.NetworkSettings.Networks, n.ID())
   490  			return
   491  		}
   492  	}
   493  }
   494  
   495  func (daemon *Daemon) allocateNetwork(container *container.Container) error {
   496  	start := time.Now()
   497  	controller := daemon.netController
   498  
   499  	if daemon.netController == nil {
   500  		return nil
   501  	}
   502  
   503  	// Cleanup any stale sandbox left over due to ungraceful daemon shutdown
   504  	if err := controller.SandboxDestroy(container.ID); err != nil {
   505  		logrus.Errorf("failed to cleanup up stale network sandbox for container %s", container.ID)
   506  	}
   507  
   508  	if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() {
   509  		return nil
   510  	}
   511  
   512  	updateSettings := false
   513  
   514  	if len(container.NetworkSettings.Networks) == 0 {
   515  		daemon.updateContainerNetworkSettings(container, nil)
   516  		updateSettings = true
   517  	}
   518  
   519  	// always connect default network first since only default
   520  	// network mode support link and we need do some setting
   521  	// on sandbox initialize for link, but the sandbox only be initialized
   522  	// on first network connecting.
   523  	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
   524  	if nConf, ok := container.NetworkSettings.Networks[defaultNetName]; ok {
   525  		cleanOperationalData(nConf)
   526  		if err := daemon.connectToNetwork(container, defaultNetName, nConf.EndpointSettings, updateSettings); err != nil {
   527  			return err
   528  		}
   529  
   530  	}
   531  
   532  	// the intermediate map is necessary because "connectToNetwork" modifies "container.NetworkSettings.Networks"
   533  	networks := make(map[string]*network.EndpointSettings)
   534  	for n, epConf := range container.NetworkSettings.Networks {
   535  		if n == defaultNetName {
   536  			continue
   537  		}
   538  
   539  		networks[n] = epConf
   540  	}
   541  
   542  	for netName, epConf := range networks {
   543  		cleanOperationalData(epConf)
   544  		if err := daemon.connectToNetwork(container, netName, epConf.EndpointSettings, updateSettings); err != nil {
   545  			return err
   546  		}
   547  	}
   548  
   549  	// If the container is not to be connected to any network,
   550  	// create its network sandbox now if not present
   551  	if len(networks) == 0 {
   552  		if nil == daemon.getNetworkSandbox(container) {
   553  			options, err := daemon.buildSandboxOptions(container)
   554  			if err != nil {
   555  				return err
   556  			}
   557  			sb, err := daemon.netController.NewSandbox(container.ID, options...)
   558  			if err != nil {
   559  				return err
   560  			}
   561  			container.UpdateSandboxNetworkSettings(sb)
   562  			defer func() {
   563  				if err != nil {
   564  					sb.Delete()
   565  				}
   566  			}()
   567  		}
   568  
   569  	}
   570  
   571  	if _, err := container.WriteHostConfig(); err != nil {
   572  		return err
   573  	}
   574  	networkActions.WithValues("allocate").UpdateSince(start)
   575  	return nil
   576  }
   577  
   578  func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox {
   579  	var sb libnetwork.Sandbox
   580  	daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool {
   581  		if s.ContainerID() == container.ID {
   582  			sb = s
   583  			return true
   584  		}
   585  		return false
   586  	})
   587  	return sb
   588  }
   589  
   590  // hasUserDefinedIPAddress returns whether the passed endpoint configuration contains IP address configuration
   591  func hasUserDefinedIPAddress(epConfig *networktypes.EndpointSettings) bool {
   592  	return epConfig != nil && epConfig.IPAMConfig != nil && (len(epConfig.IPAMConfig.IPv4Address) > 0 || len(epConfig.IPAMConfig.IPv6Address) > 0)
   593  }
   594  
   595  // User specified ip address is acceptable only for networks with user specified subnets.
   596  func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error {
   597  	if n == nil || epConfig == nil {
   598  		return nil
   599  	}
   600  	if !hasUserDefinedIPAddress(epConfig) {
   601  		return nil
   602  	}
   603  	_, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig()
   604  	for _, s := range []struct {
   605  		ipConfigured  bool
   606  		subnetConfigs []*libnetwork.IpamConf
   607  	}{
   608  		{
   609  			ipConfigured:  len(epConfig.IPAMConfig.IPv4Address) > 0,
   610  			subnetConfigs: nwIPv4Configs,
   611  		},
   612  		{
   613  			ipConfigured:  len(epConfig.IPAMConfig.IPv6Address) > 0,
   614  			subnetConfigs: nwIPv6Configs,
   615  		},
   616  	} {
   617  		if s.ipConfigured {
   618  			foundSubnet := false
   619  			for _, cfg := range s.subnetConfigs {
   620  				if len(cfg.PreferredPool) > 0 {
   621  					foundSubnet = true
   622  					break
   623  				}
   624  			}
   625  			if !foundSubnet {
   626  				return runconfig.ErrUnsupportedNetworkNoSubnetAndIP
   627  			}
   628  		}
   629  	}
   630  
   631  	return nil
   632  }
   633  
   634  // cleanOperationalData resets the operational data from the passed endpoint settings
   635  func cleanOperationalData(es *network.EndpointSettings) {
   636  	es.EndpointID = ""
   637  	es.Gateway = ""
   638  	es.IPAddress = ""
   639  	es.IPPrefixLen = 0
   640  	es.IPv6Gateway = ""
   641  	es.GlobalIPv6Address = ""
   642  	es.GlobalIPv6PrefixLen = 0
   643  	es.MacAddress = ""
   644  	if es.IPAMOperational {
   645  		es.IPAMConfig = nil
   646  	}
   647  }
   648  
   649  func (daemon *Daemon) updateNetworkConfig(container *container.Container, n libnetwork.Network, endpointConfig *networktypes.EndpointSettings, updateSettings bool) error {
   650  
   651  	if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
   652  		if hasUserDefinedIPAddress(endpointConfig) && !enableIPOnPredefinedNetwork() {
   653  			return runconfig.ErrUnsupportedNetworkAndIP
   654  		}
   655  		if endpointConfig != nil && len(endpointConfig.Aliases) > 0 && !container.EnableServiceDiscoveryOnDefaultNetwork() {
   656  			return runconfig.ErrUnsupportedNetworkAndAlias
   657  		}
   658  	} else {
   659  		addShortID := true
   660  		shortID := stringid.TruncateID(container.ID)
   661  		for _, alias := range endpointConfig.Aliases {
   662  			if alias == shortID {
   663  				addShortID = false
   664  				break
   665  			}
   666  		}
   667  		if addShortID {
   668  			endpointConfig.Aliases = append(endpointConfig.Aliases, shortID)
   669  		}
   670  	}
   671  
   672  	if err := validateNetworkingConfig(n, endpointConfig); err != nil {
   673  		return err
   674  	}
   675  
   676  	if updateSettings {
   677  		if err := daemon.updateNetworkSettings(container, n, endpointConfig); err != nil {
   678  			return err
   679  		}
   680  	}
   681  	return nil
   682  }
   683  
   684  func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
   685  	start := time.Now()
   686  	if container.HostConfig.NetworkMode.IsContainer() {
   687  		return runconfig.ErrConflictSharedNetwork
   688  	}
   689  	if containertypes.NetworkMode(idOrName).IsBridge() &&
   690  		daemon.configStore.DisableBridge {
   691  		container.Config.NetworkDisabled = true
   692  		return nil
   693  	}
   694  	if endpointConfig == nil {
   695  		endpointConfig = &networktypes.EndpointSettings{}
   696  	}
   697  
   698  	n, config, err := daemon.findAndAttachNetwork(container, idOrName, endpointConfig)
   699  	if err != nil {
   700  		return err
   701  	}
   702  	if n == nil {
   703  		return nil
   704  	}
   705  
   706  	var operIPAM bool
   707  	if config != nil {
   708  		if epConfig, ok := config.EndpointsConfig[n.Name()]; ok {
   709  			if endpointConfig.IPAMConfig == nil ||
   710  				(endpointConfig.IPAMConfig.IPv4Address == "" &&
   711  					endpointConfig.IPAMConfig.IPv6Address == "" &&
   712  					len(endpointConfig.IPAMConfig.LinkLocalIPs) == 0) {
   713  				operIPAM = true
   714  			}
   715  
   716  			// copy IPAMConfig and NetworkID from epConfig via AttachNetwork
   717  			endpointConfig.IPAMConfig = epConfig.IPAMConfig
   718  			endpointConfig.NetworkID = epConfig.NetworkID
   719  		}
   720  	}
   721  
   722  	err = daemon.updateNetworkConfig(container, n, endpointConfig, updateSettings)
   723  	if err != nil {
   724  		return err
   725  	}
   726  
   727  	controller := daemon.netController
   728  	sb := daemon.getNetworkSandbox(container)
   729  	createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb, daemon.configStore.DNS)
   730  	if err != nil {
   731  		return err
   732  	}
   733  
   734  	endpointName := strings.TrimPrefix(container.Name, "/")
   735  	ep, err := n.CreateEndpoint(endpointName, createOptions...)
   736  	if err != nil {
   737  		return err
   738  	}
   739  	defer func() {
   740  		if err != nil {
   741  			if e := ep.Delete(false); e != nil {
   742  				logrus.Warnf("Could not rollback container connection to network %s", idOrName)
   743  			}
   744  		}
   745  	}()
   746  	container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{
   747  		EndpointSettings: endpointConfig,
   748  		IPAMOperational:  operIPAM,
   749  	}
   750  	if _, ok := container.NetworkSettings.Networks[n.ID()]; ok {
   751  		delete(container.NetworkSettings.Networks, n.ID())
   752  	}
   753  
   754  	if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
   755  		return err
   756  	}
   757  
   758  	if sb == nil {
   759  		options, err := daemon.buildSandboxOptions(container)
   760  		if err != nil {
   761  			return err
   762  		}
   763  		sb, err = controller.NewSandbox(container.ID, options...)
   764  		if err != nil {
   765  			return err
   766  		}
   767  
   768  		container.UpdateSandboxNetworkSettings(sb)
   769  	}
   770  
   771  	joinOptions, err := container.BuildJoinOptions(n)
   772  	if err != nil {
   773  		return err
   774  	}
   775  
   776  	if err := ep.Join(sb, joinOptions...); err != nil {
   777  		return err
   778  	}
   779  
   780  	if !container.Managed {
   781  		// add container name/alias to DNS
   782  		if err := daemon.ActivateContainerServiceBinding(container.Name); err != nil {
   783  			return fmt.Errorf("Activate container service binding for %s failed: %v", container.Name, err)
   784  		}
   785  	}
   786  
   787  	if err := container.UpdateJoinInfo(n, ep); err != nil {
   788  		return fmt.Errorf("Updating join info failed: %v", err)
   789  	}
   790  
   791  	container.NetworkSettings.Ports = getPortMapInfo(sb)
   792  
   793  	daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
   794  	networkActions.WithValues("connect").UpdateSince(start)
   795  	return nil
   796  }
   797  
   798  // ForceEndpointDelete deletes an endpoint from a network forcefully
   799  func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error {
   800  	n, err := daemon.FindNetwork(networkName)
   801  	if err != nil {
   802  		return err
   803  	}
   804  
   805  	ep, err := n.EndpointByName(name)
   806  	if err != nil {
   807  		return err
   808  	}
   809  	return ep.Delete(true)
   810  }
   811  
   812  func (daemon *Daemon) disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
   813  	var (
   814  		ep   libnetwork.Endpoint
   815  		sbox libnetwork.Sandbox
   816  	)
   817  
   818  	s := func(current libnetwork.Endpoint) bool {
   819  		epInfo := current.Info()
   820  		if epInfo == nil {
   821  			return false
   822  		}
   823  		if sb := epInfo.Sandbox(); sb != nil {
   824  			if sb.ContainerID() == container.ID {
   825  				ep = current
   826  				sbox = sb
   827  				return true
   828  			}
   829  		}
   830  		return false
   831  	}
   832  	n.WalkEndpoints(s)
   833  
   834  	if ep == nil && force {
   835  		epName := strings.TrimPrefix(container.Name, "/")
   836  		ep, err := n.EndpointByName(epName)
   837  		if err != nil {
   838  			return err
   839  		}
   840  		return ep.Delete(force)
   841  	}
   842  
   843  	if ep == nil {
   844  		return fmt.Errorf("container %s is not connected to network %s", container.ID, n.Name())
   845  	}
   846  
   847  	if err := ep.Leave(sbox); err != nil {
   848  		return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
   849  	}
   850  
   851  	container.NetworkSettings.Ports = getPortMapInfo(sbox)
   852  
   853  	if err := ep.Delete(false); err != nil {
   854  		return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
   855  	}
   856  
   857  	delete(container.NetworkSettings.Networks, n.Name())
   858  
   859  	daemon.tryDetachContainerFromClusterNetwork(n, container)
   860  
   861  	return nil
   862  }
   863  
   864  func (daemon *Daemon) tryDetachContainerFromClusterNetwork(network libnetwork.Network, container *container.Container) {
   865  	if daemon.clusterProvider != nil && network.Info().Dynamic() && !container.Managed {
   866  		if err := daemon.clusterProvider.DetachNetwork(network.Name(), container.ID); err != nil {
   867  			logrus.Warnf("error detaching from network %s: %v", network.Name(), err)
   868  			if err := daemon.clusterProvider.DetachNetwork(network.ID(), container.ID); err != nil {
   869  				logrus.Warnf("error detaching from network %s: %v", network.ID(), err)
   870  			}
   871  		}
   872  	}
   873  	attributes := map[string]string{
   874  		"container": container.ID,
   875  	}
   876  	daemon.LogNetworkEventWithAttributes(network, "disconnect", attributes)
   877  }
   878  
   879  func (daemon *Daemon) initializeNetworking(container *container.Container) error {
   880  	var err error
   881  
   882  	if container.HostConfig.NetworkMode.IsContainer() {
   883  		// we need to get the hosts files from the container to join
   884  		nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer())
   885  		if err != nil {
   886  			return err
   887  		}
   888  
   889  		err = daemon.initializeNetworkingPaths(container, nc)
   890  		if err != nil {
   891  			return err
   892  		}
   893  
   894  		container.Config.Hostname = nc.Config.Hostname
   895  		container.Config.Domainname = nc.Config.Domainname
   896  		return nil
   897  	}
   898  
   899  	if container.HostConfig.NetworkMode.IsHost() {
   900  		if container.Config.Hostname == "" {
   901  			container.Config.Hostname, err = os.Hostname()
   902  			if err != nil {
   903  				return err
   904  			}
   905  		}
   906  	}
   907  
   908  	if err := daemon.allocateNetwork(container); err != nil {
   909  		return err
   910  	}
   911  
   912  	return container.BuildHostnameFile()
   913  }
   914  
   915  func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) {
   916  	nc, err := daemon.GetContainer(connectedContainerID)
   917  	if err != nil {
   918  		return nil, err
   919  	}
   920  	if containerID == nc.ID {
   921  		return nil, fmt.Errorf("cannot join own network")
   922  	}
   923  	if !nc.IsRunning() {
   924  		err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID)
   925  		return nil, stateConflictError{err}
   926  	}
   927  	if nc.IsRestarting() {
   928  		return nil, errContainerIsRestarting(connectedContainerID)
   929  	}
   930  	return nc, nil
   931  }
   932  
   933  func (daemon *Daemon) releaseNetwork(container *container.Container) {
   934  	start := time.Now()
   935  	if daemon.netController == nil {
   936  		return
   937  	}
   938  	if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled {
   939  		return
   940  	}
   941  
   942  	sid := container.NetworkSettings.SandboxID
   943  	settings := container.NetworkSettings.Networks
   944  	container.NetworkSettings.Ports = nil
   945  
   946  	if sid == "" {
   947  		return
   948  	}
   949  
   950  	var networks []libnetwork.Network
   951  	for n, epSettings := range settings {
   952  		if nw, err := daemon.FindNetwork(n); err == nil {
   953  			networks = append(networks, nw)
   954  		}
   955  
   956  		if epSettings.EndpointSettings == nil {
   957  			continue
   958  		}
   959  
   960  		cleanOperationalData(epSettings)
   961  	}
   962  
   963  	sb, err := daemon.netController.SandboxByID(sid)
   964  	if err != nil {
   965  		logrus.Warnf("error locating sandbox id %s: %v", sid, err)
   966  		return
   967  	}
   968  
   969  	if err := sb.Delete(); err != nil {
   970  		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
   971  	}
   972  
   973  	for _, nw := range networks {
   974  		daemon.tryDetachContainerFromClusterNetwork(nw, container)
   975  	}
   976  	networkActions.WithValues("release").UpdateSince(start)
   977  }
   978  
   979  func errRemovalContainer(containerID string) error {
   980  	return fmt.Errorf("Container %s is marked for removal and cannot be connected or disconnected to the network", containerID)
   981  }
   982  
   983  // ConnectToNetwork connects a container to a network
   984  func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error {
   985  	if endpointConfig == nil {
   986  		endpointConfig = &networktypes.EndpointSettings{}
   987  	}
   988  	container.Lock()
   989  	defer container.Unlock()
   990  
   991  	if !container.Running {
   992  		if container.RemovalInProgress || container.Dead {
   993  			return errRemovalContainer(container.ID)
   994  		}
   995  
   996  		n, err := daemon.FindNetwork(idOrName)
   997  		if err == nil && n != nil {
   998  			if err := daemon.updateNetworkConfig(container, n, endpointConfig, true); err != nil {
   999  				return err
  1000  			}
  1001  		} else {
  1002  			container.NetworkSettings.Networks[idOrName] = &network.EndpointSettings{
  1003  				EndpointSettings: endpointConfig,
  1004  			}
  1005  		}
  1006  	} else if !daemon.isNetworkHotPluggable() {
  1007  		return fmt.Errorf(runtime.GOOS + " does not support connecting a running container to a network")
  1008  	} else {
  1009  		if err := daemon.connectToNetwork(container, idOrName, endpointConfig, true); err != nil {
  1010  			return err
  1011  		}
  1012  	}
  1013  
  1014  	return container.CheckpointTo(daemon.containersReplica)
  1015  }
  1016  
  1017  // DisconnectFromNetwork disconnects container from network n.
  1018  func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error {
  1019  	n, err := daemon.FindNetwork(networkName)
  1020  	container.Lock()
  1021  	defer container.Unlock()
  1022  
  1023  	if !container.Running || (err != nil && force) {
  1024  		if container.RemovalInProgress || container.Dead {
  1025  			return errRemovalContainer(container.ID)
  1026  		}
  1027  		// In case networkName is resolved we will use n.Name()
  1028  		// this will cover the case where network id is passed.
  1029  		if n != nil {
  1030  			networkName = n.Name()
  1031  		}
  1032  		if _, ok := container.NetworkSettings.Networks[networkName]; !ok {
  1033  			return fmt.Errorf("container %s is not connected to the network %s", container.ID, networkName)
  1034  		}
  1035  		delete(container.NetworkSettings.Networks, networkName)
  1036  	} else if err == nil && !daemon.isNetworkHotPluggable() {
  1037  		return fmt.Errorf(runtime.GOOS + " does not support connecting a running container to a network")
  1038  	} else if err == nil {
  1039  		if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
  1040  			return runconfig.ErrConflictHostNetwork
  1041  		}
  1042  
  1043  		if err := daemon.disconnectFromNetwork(container, n, false); err != nil {
  1044  			return err
  1045  		}
  1046  	} else {
  1047  		return err
  1048  	}
  1049  
  1050  	if err := container.CheckpointTo(daemon.containersReplica); err != nil {
  1051  		return err
  1052  	}
  1053  
  1054  	if n != nil {
  1055  		daemon.LogNetworkEventWithAttributes(n, "disconnect", map[string]string{
  1056  			"container": container.ID,
  1057  		})
  1058  	}
  1059  
  1060  	return nil
  1061  }
  1062  
  1063  // ActivateContainerServiceBinding puts this container into load balancer active rotation and DNS response
  1064  func (daemon *Daemon) ActivateContainerServiceBinding(containerName string) error {
  1065  	container, err := daemon.GetContainer(containerName)
  1066  	if err != nil {
  1067  		return err
  1068  	}
  1069  	sb := daemon.getNetworkSandbox(container)
  1070  	if sb == nil {
  1071  		return fmt.Errorf("network sandbox does not exist for container %s", containerName)
  1072  	}
  1073  	return sb.EnableService()
  1074  }
  1075  
  1076  // DeactivateContainerServiceBinding removes this container from load balancer active rotation, and DNS response
  1077  func (daemon *Daemon) DeactivateContainerServiceBinding(containerName string) error {
  1078  	container, err := daemon.GetContainer(containerName)
  1079  	if err != nil {
  1080  		return err
  1081  	}
  1082  	sb := daemon.getNetworkSandbox(container)
  1083  	if sb == nil {
  1084  		// If the network sandbox is not found, then there is nothing to deactivate
  1085  		logrus.Debugf("Could not find network sandbox for container %s on service binding deactivation request", containerName)
  1086  		return nil
  1087  	}
  1088  	return sb.DisableService()
  1089  }