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