github.com/devdivbcp/moby@v17.12.0-ce-rc1.0.20200726071732-2d4bfdc789ad+incompatible/daemon/container_operations.go (about)

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