github.com/tonistiigi/docker@v0.10.1-0.20240229224939-974013b0dc6a/daemon/container_operations.go (about)

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