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