github.com/rish1988/moby@v25.0.2+incompatible/daemon/network.go (about)

     1  package daemon // import "github.com/docker/docker/daemon"
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net"
     8  	"sort"
     9  	"strconv"
    10  	"strings"
    11  	"sync"
    12  
    13  	"github.com/containerd/log"
    14  	"github.com/docker/docker/api/types"
    15  	"github.com/docker/docker/api/types/backend"
    16  	containertypes "github.com/docker/docker/api/types/container"
    17  	"github.com/docker/docker/api/types/events"
    18  	"github.com/docker/docker/api/types/filters"
    19  	"github.com/docker/docker/api/types/network"
    20  	"github.com/docker/docker/container"
    21  	clustertypes "github.com/docker/docker/daemon/cluster/provider"
    22  	"github.com/docker/docker/daemon/config"
    23  	internalnetwork "github.com/docker/docker/daemon/network"
    24  	"github.com/docker/docker/errdefs"
    25  	"github.com/docker/docker/libnetwork"
    26  	lncluster "github.com/docker/docker/libnetwork/cluster"
    27  	"github.com/docker/docker/libnetwork/driverapi"
    28  	"github.com/docker/docker/libnetwork/ipamapi"
    29  	"github.com/docker/docker/libnetwork/netlabel"
    30  	"github.com/docker/docker/libnetwork/networkdb"
    31  	"github.com/docker/docker/libnetwork/options"
    32  	networktypes "github.com/docker/docker/libnetwork/types"
    33  	"github.com/docker/docker/opts"
    34  	"github.com/docker/docker/pkg/plugingetter"
    35  	"github.com/docker/docker/runconfig"
    36  	"github.com/docker/go-connections/nat"
    37  )
    38  
    39  // PredefinedNetworkError is returned when user tries to create predefined network that already exists.
    40  type PredefinedNetworkError string
    41  
    42  func (pnr PredefinedNetworkError) Error() string {
    43  	return fmt.Sprintf("operation is not permitted on predefined %s network ", string(pnr))
    44  }
    45  
    46  // Forbidden denotes the type of this error
    47  func (pnr PredefinedNetworkError) Forbidden() {}
    48  
    49  // NetworkControllerEnabled checks if the networking stack is enabled.
    50  // This feature depends on OS primitives and it's disabled in systems like Windows.
    51  func (daemon *Daemon) NetworkControllerEnabled() bool {
    52  	return daemon.netController != nil
    53  }
    54  
    55  // NetworkController returns the network controller created by the daemon.
    56  func (daemon *Daemon) NetworkController() *libnetwork.Controller {
    57  	return daemon.netController
    58  }
    59  
    60  // FindNetwork returns a network based on:
    61  // 1. Full ID
    62  // 2. Full Name
    63  // 3. Partial ID
    64  // as long as there is no ambiguity
    65  func (daemon *Daemon) FindNetwork(term string) (*libnetwork.Network, error) {
    66  	var listByFullName, listByPartialID []*libnetwork.Network
    67  	for _, nw := range daemon.getAllNetworks() {
    68  		nwID := nw.ID()
    69  		if nwID == term {
    70  			return nw, nil
    71  		}
    72  		if strings.HasPrefix(nw.ID(), term) {
    73  			listByPartialID = append(listByPartialID, nw)
    74  		}
    75  		if nw.Name() == term {
    76  			listByFullName = append(listByFullName, nw)
    77  		}
    78  	}
    79  	switch {
    80  	case len(listByFullName) == 1:
    81  		return listByFullName[0], nil
    82  	case len(listByFullName) > 1:
    83  		return nil, errdefs.InvalidParameter(fmt.Errorf("network %s is ambiguous (%d matches found on name)", term, len(listByFullName)))
    84  	case len(listByPartialID) == 1:
    85  		return listByPartialID[0], nil
    86  	case len(listByPartialID) > 1:
    87  		return nil, errdefs.InvalidParameter(fmt.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID)))
    88  	}
    89  
    90  	// Be very careful to change the error type here, the
    91  	// libnetwork.ErrNoSuchNetwork error is used by the controller
    92  	// to retry the creation of the network as managed through the swarm manager
    93  	return nil, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term))
    94  }
    95  
    96  // GetNetworkByID function returns a network whose ID matches the given ID.
    97  // It fails with an error if no matching network is found.
    98  func (daemon *Daemon) GetNetworkByID(id string) (*libnetwork.Network, error) {
    99  	c := daemon.netController
   100  	if c == nil {
   101  		return nil, fmt.Errorf("netcontroller is nil: %w", libnetwork.ErrNoSuchNetwork(id))
   102  	}
   103  	return c.NetworkByID(id)
   104  }
   105  
   106  // GetNetworkByName function returns a network for a given network name.
   107  // If no network name is given, the default network is returned.
   108  func (daemon *Daemon) GetNetworkByName(name string) (*libnetwork.Network, error) {
   109  	c := daemon.netController
   110  	if c == nil {
   111  		return nil, libnetwork.ErrNoSuchNetwork(name)
   112  	}
   113  	if name == "" {
   114  		name = c.Config().DefaultNetwork
   115  	}
   116  	return c.NetworkByName(name)
   117  }
   118  
   119  // GetNetworksByIDPrefix returns a list of networks whose ID partially matches zero or more networks
   120  func (daemon *Daemon) GetNetworksByIDPrefix(partialID string) []*libnetwork.Network {
   121  	c := daemon.netController
   122  	if c == nil {
   123  		return nil
   124  	}
   125  	list := []*libnetwork.Network{}
   126  	l := func(nw *libnetwork.Network) bool {
   127  		if strings.HasPrefix(nw.ID(), partialID) {
   128  			list = append(list, nw)
   129  		}
   130  		return false
   131  	}
   132  	c.WalkNetworks(l)
   133  
   134  	return list
   135  }
   136  
   137  // getAllNetworks returns a list containing all networks
   138  func (daemon *Daemon) getAllNetworks() []*libnetwork.Network {
   139  	c := daemon.netController
   140  	if c == nil {
   141  		return nil
   142  	}
   143  	ctx := context.TODO()
   144  	return c.Networks(ctx)
   145  }
   146  
   147  type ingressJob struct {
   148  	create  *clustertypes.NetworkCreateRequest
   149  	ip      net.IP
   150  	jobDone chan struct{}
   151  }
   152  
   153  var (
   154  	ingressWorkerOnce  sync.Once
   155  	ingressJobsChannel chan *ingressJob
   156  	ingressID          string
   157  )
   158  
   159  func (daemon *Daemon) startIngressWorker() {
   160  	ingressJobsChannel = make(chan *ingressJob, 100)
   161  	go func() {
   162  		//nolint: gosimple
   163  		for {
   164  			select {
   165  			case r := <-ingressJobsChannel:
   166  				if r.create != nil {
   167  					daemon.setupIngress(&daemon.config().Config, r.create, r.ip, ingressID)
   168  					ingressID = r.create.ID
   169  				} else {
   170  					daemon.releaseIngress(ingressID)
   171  					ingressID = ""
   172  				}
   173  				close(r.jobDone)
   174  			}
   175  		}
   176  	}()
   177  }
   178  
   179  // enqueueIngressJob adds a ingress add/rm request to the worker queue.
   180  // It guarantees the worker is started.
   181  func (daemon *Daemon) enqueueIngressJob(job *ingressJob) {
   182  	ingressWorkerOnce.Do(daemon.startIngressWorker)
   183  	ingressJobsChannel <- job
   184  }
   185  
   186  // SetupIngress setups ingress networking.
   187  // The function returns a channel which will signal the caller when the programming is completed.
   188  func (daemon *Daemon) SetupIngress(create clustertypes.NetworkCreateRequest, nodeIP string) (<-chan struct{}, error) {
   189  	ip, _, err := net.ParseCIDR(nodeIP)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	done := make(chan struct{})
   194  	daemon.enqueueIngressJob(&ingressJob{&create, ip, done})
   195  	return done, nil
   196  }
   197  
   198  // ReleaseIngress releases the ingress networking.
   199  // The function returns a channel which will signal the caller when the programming is completed.
   200  func (daemon *Daemon) ReleaseIngress() (<-chan struct{}, error) {
   201  	done := make(chan struct{})
   202  	daemon.enqueueIngressJob(&ingressJob{nil, nil, done})
   203  	return done, nil
   204  }
   205  
   206  func (daemon *Daemon) setupIngress(cfg *config.Config, create *clustertypes.NetworkCreateRequest, ip net.IP, staleID string) {
   207  	controller := daemon.netController
   208  	controller.AgentInitWait()
   209  
   210  	if staleID != "" && staleID != create.ID {
   211  		daemon.releaseIngress(staleID)
   212  	}
   213  
   214  	if _, err := daemon.createNetwork(cfg, create.NetworkCreateRequest, create.ID, true); err != nil {
   215  		// If it is any other error other than already
   216  		// exists error log error and return.
   217  		if _, ok := err.(libnetwork.NetworkNameError); !ok {
   218  			log.G(context.TODO()).Errorf("Failed creating ingress network: %v", err)
   219  			return
   220  		}
   221  		// Otherwise continue down the call to create or recreate sandbox.
   222  	}
   223  
   224  	_, err := daemon.GetNetworkByID(create.ID)
   225  	if err != nil {
   226  		log.G(context.TODO()).Errorf("Failed getting ingress network by id after creating: %v", err)
   227  	}
   228  }
   229  
   230  func (daemon *Daemon) releaseIngress(id string) {
   231  	controller := daemon.netController
   232  
   233  	if id == "" {
   234  		return
   235  	}
   236  
   237  	n, err := controller.NetworkByID(id)
   238  	if err != nil {
   239  		log.G(context.TODO()).Errorf("failed to retrieve ingress network %s: %v", id, err)
   240  		return
   241  	}
   242  
   243  	if err := n.Delete(libnetwork.NetworkDeleteOptionRemoveLB); err != nil {
   244  		log.G(context.TODO()).Errorf("Failed to delete ingress network %s: %v", n.ID(), err)
   245  		return
   246  	}
   247  }
   248  
   249  // SetNetworkBootstrapKeys sets the bootstrap keys.
   250  func (daemon *Daemon) SetNetworkBootstrapKeys(keys []*networktypes.EncryptionKey) error {
   251  	if err := daemon.netController.SetKeys(keys); err != nil {
   252  		return err
   253  	}
   254  	// Upon successful key setting dispatch the keys available event
   255  	daemon.cluster.SendClusterEvent(lncluster.EventNetworkKeysAvailable)
   256  	return nil
   257  }
   258  
   259  // UpdateAttachment notifies the attacher about the attachment config.
   260  func (daemon *Daemon) UpdateAttachment(networkName, networkID, containerID string, config *network.NetworkingConfig) error {
   261  	if daemon.clusterProvider == nil {
   262  		return fmt.Errorf("cluster provider is not initialized")
   263  	}
   264  
   265  	if err := daemon.clusterProvider.UpdateAttachment(networkName, containerID, config); err != nil {
   266  		return daemon.clusterProvider.UpdateAttachment(networkID, containerID, config)
   267  	}
   268  
   269  	return nil
   270  }
   271  
   272  // WaitForDetachment makes the cluster manager wait for detachment of
   273  // the container from the network.
   274  func (daemon *Daemon) WaitForDetachment(ctx context.Context, networkName, networkID, taskID, containerID string) error {
   275  	if daemon.clusterProvider == nil {
   276  		return fmt.Errorf("cluster provider is not initialized")
   277  	}
   278  
   279  	return daemon.clusterProvider.WaitForDetachment(ctx, networkName, networkID, taskID, containerID)
   280  }
   281  
   282  // CreateManagedNetwork creates an agent network.
   283  func (daemon *Daemon) CreateManagedNetwork(create clustertypes.NetworkCreateRequest) error {
   284  	_, err := daemon.createNetwork(&daemon.config().Config, create.NetworkCreateRequest, create.ID, true)
   285  	return err
   286  }
   287  
   288  // CreateNetwork creates a network with the given name, driver and other optional parameters
   289  func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) {
   290  	return daemon.createNetwork(&daemon.config().Config, create, "", false)
   291  }
   292  
   293  func (daemon *Daemon) createNetwork(cfg *config.Config, create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) {
   294  	if runconfig.IsPreDefinedNetwork(create.Name) {
   295  		return nil, PredefinedNetworkError(create.Name)
   296  	}
   297  
   298  	c := daemon.netController
   299  	driver := create.Driver
   300  	if driver == "" {
   301  		driver = c.Config().DefaultDriver
   302  	}
   303  
   304  	if driver == "overlay" && !daemon.cluster.IsManager() && !agent {
   305  		return nil, errdefs.Forbidden(errors.New(`This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.`))
   306  	}
   307  
   308  	if network.HasIPv6Subnets(create.IPAM) {
   309  		create.EnableIPv6 = true
   310  	}
   311  
   312  	networkOptions := make(map[string]string)
   313  	for k, v := range create.Options {
   314  		networkOptions[k] = v
   315  	}
   316  	if defaultOpts, ok := cfg.DefaultNetworkOpts[driver]; create.ConfigFrom == nil && ok {
   317  		for k, v := range defaultOpts {
   318  			if _, ok := networkOptions[k]; !ok {
   319  				log.G(context.TODO()).WithFields(log.Fields{"driver": driver, "network": id, k: v}).Debug("Applying network default option")
   320  				networkOptions[k] = v
   321  			}
   322  		}
   323  	}
   324  
   325  	nwOptions := []libnetwork.NetworkOption{
   326  		libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6),
   327  		libnetwork.NetworkOptionDriverOpts(networkOptions),
   328  		libnetwork.NetworkOptionLabels(create.Labels),
   329  		libnetwork.NetworkOptionAttachable(create.Attachable),
   330  		libnetwork.NetworkOptionIngress(create.Ingress),
   331  		libnetwork.NetworkOptionScope(create.Scope),
   332  	}
   333  
   334  	if create.ConfigOnly {
   335  		nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigOnly())
   336  	}
   337  
   338  	if err := network.ValidateIPAM(create.IPAM); err != nil {
   339  		return nil, errdefs.InvalidParameter(err)
   340  	}
   341  
   342  	if create.IPAM != nil {
   343  		ipam := create.IPAM
   344  		v4Conf, v6Conf, err := getIpamConfig(ipam.Config)
   345  		if err != nil {
   346  			return nil, err
   347  		}
   348  		nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options))
   349  	}
   350  
   351  	if create.Internal {
   352  		nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork())
   353  	}
   354  	if agent {
   355  		nwOptions = append(nwOptions, libnetwork.NetworkOptionDynamic())
   356  		nwOptions = append(nwOptions, libnetwork.NetworkOptionPersist(false))
   357  	}
   358  
   359  	if create.ConfigFrom != nil {
   360  		nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigFrom(create.ConfigFrom.Network))
   361  	}
   362  
   363  	if agent && driver == "overlay" {
   364  		nodeIP, exists := daemon.GetAttachmentStore().GetIPForNetwork(id)
   365  		if !exists {
   366  			return nil, fmt.Errorf("failed to find a load balancer IP to use for network: %v", id)
   367  		}
   368  
   369  		nwOptions = append(nwOptions, libnetwork.NetworkOptionLBEndpoint(nodeIP))
   370  	}
   371  
   372  	n, err := c.NewNetwork(driver, create.Name, id, nwOptions...)
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  
   377  	daemon.pluginRefCount(driver, driverapi.NetworkPluginEndpointType, plugingetter.Acquire)
   378  	if create.IPAM != nil {
   379  		daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.Acquire)
   380  	}
   381  	daemon.LogNetworkEvent(n, events.ActionCreate)
   382  
   383  	return &types.NetworkCreateResponse{
   384  		ID: n.ID(),
   385  	}, nil
   386  }
   387  
   388  func (daemon *Daemon) pluginRefCount(driver, capability string, mode int) {
   389  	var builtinDrivers []string
   390  
   391  	if capability == driverapi.NetworkPluginEndpointType {
   392  		builtinDrivers = daemon.netController.BuiltinDrivers()
   393  	} else if capability == ipamapi.PluginEndpointType {
   394  		builtinDrivers = daemon.netController.BuiltinIPAMDrivers()
   395  	}
   396  
   397  	for _, d := range builtinDrivers {
   398  		if d == driver {
   399  			return
   400  		}
   401  	}
   402  
   403  	if daemon.PluginStore != nil {
   404  		_, err := daemon.PluginStore.Get(driver, capability, mode)
   405  		if err != nil {
   406  			log.G(context.TODO()).WithError(err).WithFields(log.Fields{"mode": mode, "driver": driver}).Error("Error handling plugin refcount operation")
   407  		}
   408  	}
   409  }
   410  
   411  func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) {
   412  	ipamV4Cfg := []*libnetwork.IpamConf{}
   413  	ipamV6Cfg := []*libnetwork.IpamConf{}
   414  	for _, d := range data {
   415  		iCfg := libnetwork.IpamConf{}
   416  		iCfg.PreferredPool = d.Subnet
   417  		iCfg.SubPool = d.IPRange
   418  		iCfg.Gateway = d.Gateway
   419  		iCfg.AuxAddresses = d.AuxAddress
   420  		ip, _, err := net.ParseCIDR(d.Subnet)
   421  		if err != nil {
   422  			return nil, nil, fmt.Errorf("Invalid subnet %s : %v", d.Subnet, err)
   423  		}
   424  		if ip.To4() != nil {
   425  			ipamV4Cfg = append(ipamV4Cfg, &iCfg)
   426  		} else {
   427  			ipamV6Cfg = append(ipamV6Cfg, &iCfg)
   428  		}
   429  	}
   430  	return ipamV4Cfg, ipamV6Cfg, nil
   431  }
   432  
   433  // UpdateContainerServiceConfig updates a service configuration.
   434  func (daemon *Daemon) UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error {
   435  	ctr, err := daemon.GetContainer(containerName)
   436  	if err != nil {
   437  		return err
   438  	}
   439  
   440  	ctr.NetworkSettings.Service = serviceConfig
   441  	return nil
   442  }
   443  
   444  // ConnectContainerToNetwork connects the given container to the given
   445  // network. If either cannot be found, an err is returned. If the
   446  // network cannot be set up, an err is returned.
   447  func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error {
   448  	ctr, err := daemon.GetContainer(containerName)
   449  	if err != nil {
   450  		return err
   451  	}
   452  	return daemon.ConnectToNetwork(ctr, networkName, endpointConfig)
   453  }
   454  
   455  // DisconnectContainerFromNetwork disconnects the given container from
   456  // the given network. If either cannot be found, an err is returned.
   457  func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error {
   458  	ctr, err := daemon.GetContainer(containerName)
   459  	if err != nil {
   460  		if force {
   461  			return daemon.ForceEndpointDelete(containerName, networkName)
   462  		}
   463  		return err
   464  	}
   465  	return daemon.DisconnectFromNetwork(ctr, networkName, force)
   466  }
   467  
   468  // GetNetworkDriverList returns the list of plugins drivers
   469  // registered for network.
   470  func (daemon *Daemon) GetNetworkDriverList(ctx context.Context) []string {
   471  	if !daemon.NetworkControllerEnabled() {
   472  		return nil
   473  	}
   474  
   475  	pluginList := daemon.netController.BuiltinDrivers()
   476  
   477  	managedPlugins := daemon.PluginStore.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType)
   478  
   479  	for _, plugin := range managedPlugins {
   480  		pluginList = append(pluginList, plugin.Name())
   481  	}
   482  
   483  	pluginMap := make(map[string]bool)
   484  	for _, plugin := range pluginList {
   485  		pluginMap[plugin] = true
   486  	}
   487  
   488  	networks := daemon.netController.Networks(ctx)
   489  
   490  	for _, nw := range networks {
   491  		if !pluginMap[nw.Type()] {
   492  			pluginList = append(pluginList, nw.Type())
   493  			pluginMap[nw.Type()] = true
   494  		}
   495  	}
   496  
   497  	sort.Strings(pluginList)
   498  
   499  	return pluginList
   500  }
   501  
   502  // DeleteManagedNetwork deletes an agent network.
   503  // The requirement of networkID is enforced.
   504  func (daemon *Daemon) DeleteManagedNetwork(networkID string) error {
   505  	n, err := daemon.GetNetworkByID(networkID)
   506  	if err != nil {
   507  		return err
   508  	}
   509  	return daemon.deleteNetwork(n, true)
   510  }
   511  
   512  // DeleteNetwork destroys a network unless it's one of docker's predefined networks.
   513  func (daemon *Daemon) DeleteNetwork(networkID string) error {
   514  	n, err := daemon.GetNetworkByID(networkID)
   515  	if err != nil {
   516  		return fmt.Errorf("could not find network by ID: %w", err)
   517  	}
   518  	return daemon.deleteNetwork(n, false)
   519  }
   520  
   521  func (daemon *Daemon) deleteNetwork(nw *libnetwork.Network, dynamic bool) error {
   522  	if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic {
   523  		err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name())
   524  		return errdefs.Forbidden(err)
   525  	}
   526  
   527  	if dynamic && !nw.Dynamic() {
   528  		if runconfig.IsPreDefinedNetwork(nw.Name()) {
   529  			// Predefined networks now support swarm services. Make this
   530  			// a no-op when cluster requests to remove the predefined network.
   531  			return nil
   532  		}
   533  		err := fmt.Errorf("%s is not a dynamic network", nw.Name())
   534  		return errdefs.Forbidden(err)
   535  	}
   536  
   537  	if err := nw.Delete(); err != nil {
   538  		return fmt.Errorf("error while removing network: %w", err)
   539  	}
   540  
   541  	// If this is not a configuration only network, we need to
   542  	// update the corresponding remote drivers' reference counts
   543  	if !nw.ConfigOnly() {
   544  		daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.Release)
   545  		ipamType, _, _, _ := nw.IpamConfig()
   546  		daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.Release)
   547  		daemon.LogNetworkEvent(nw, events.ActionDestroy)
   548  	}
   549  
   550  	return nil
   551  }
   552  
   553  // GetNetworks returns a list of all networks
   554  func (daemon *Daemon) GetNetworks(filter filters.Args, config backend.NetworkListConfig) (networks []types.NetworkResource, err error) {
   555  	var idx map[string]*libnetwork.Network
   556  	if config.Detailed {
   557  		idx = make(map[string]*libnetwork.Network)
   558  	}
   559  
   560  	allNetworks := daemon.getAllNetworks()
   561  	networks = make([]types.NetworkResource, 0, len(allNetworks))
   562  	for _, n := range allNetworks {
   563  		nr := buildNetworkResource(n)
   564  		networks = append(networks, nr)
   565  		if config.Detailed {
   566  			idx[nr.ID] = n
   567  		}
   568  	}
   569  
   570  	networks, err = internalnetwork.FilterNetworks(networks, filter)
   571  	if err != nil {
   572  		return nil, err
   573  	}
   574  
   575  	if config.Detailed {
   576  		for i, nw := range networks {
   577  			networks[i].Containers = buildContainerAttachments(idx[nw.ID])
   578  			if config.Verbose {
   579  				networks[i].Services = buildServiceAttachments(idx[nw.ID])
   580  			}
   581  		}
   582  	}
   583  
   584  	return networks, nil
   585  }
   586  
   587  // buildNetworkResource builds a [types.NetworkResource] from the given
   588  // [libnetwork.Network], to be returned by the API.
   589  func buildNetworkResource(nw *libnetwork.Network) types.NetworkResource {
   590  	if nw == nil {
   591  		return types.NetworkResource{}
   592  	}
   593  
   594  	return types.NetworkResource{
   595  		Name:       nw.Name(),
   596  		ID:         nw.ID(),
   597  		Created:    nw.Created(),
   598  		Scope:      nw.Scope(),
   599  		Driver:     nw.Type(),
   600  		EnableIPv6: nw.IPv6Enabled(),
   601  		IPAM:       buildIPAMResources(nw),
   602  		Internal:   nw.Internal(),
   603  		Attachable: nw.Attachable(),
   604  		Ingress:    nw.Ingress(),
   605  		ConfigFrom: network.ConfigReference{Network: nw.ConfigFrom()},
   606  		ConfigOnly: nw.ConfigOnly(),
   607  		Containers: map[string]types.EndpointResource{},
   608  		Options:    nw.DriverOptions(),
   609  		Labels:     nw.Labels(),
   610  		Peers:      buildPeerInfoResources(nw.Peers()),
   611  	}
   612  }
   613  
   614  // buildContainerAttachments creates a [types.EndpointResource] map of all
   615  // containers attached to the network. It is used when listing networks in
   616  // detailed mode.
   617  func buildContainerAttachments(nw *libnetwork.Network) map[string]types.EndpointResource {
   618  	containers := make(map[string]types.EndpointResource)
   619  	for _, e := range nw.Endpoints() {
   620  		ei := e.Info()
   621  		if ei == nil {
   622  			continue
   623  		}
   624  		if sb := ei.Sandbox(); sb != nil {
   625  			containers[sb.ContainerID()] = buildEndpointResource(e, ei)
   626  		} else {
   627  			containers["ep-"+e.ID()] = buildEndpointResource(e, ei)
   628  		}
   629  	}
   630  	return containers
   631  }
   632  
   633  // buildServiceAttachments creates a [network.ServiceInfo] map of all services
   634  // attached to the network. It is used when listing networks in "verbose" mode.
   635  func buildServiceAttachments(nw *libnetwork.Network) map[string]network.ServiceInfo {
   636  	services := make(map[string]network.ServiceInfo)
   637  	for name, service := range nw.Services() {
   638  		tasks := make([]network.Task, 0, len(service.Tasks))
   639  		for _, t := range service.Tasks {
   640  			tasks = append(tasks, network.Task{
   641  				Name:       t.Name,
   642  				EndpointID: t.EndpointID,
   643  				EndpointIP: t.EndpointIP,
   644  				Info:       t.Info,
   645  			})
   646  		}
   647  		services[name] = network.ServiceInfo{
   648  			VIP:          service.VIP,
   649  			Ports:        service.Ports,
   650  			Tasks:        tasks,
   651  			LocalLBIndex: service.LocalLBIndex,
   652  		}
   653  	}
   654  	return services
   655  }
   656  
   657  // buildPeerInfoResources converts a list of [networkdb.PeerInfo] to a
   658  // [network.PeerInfo] for inclusion in API responses. It returns nil if
   659  // the list of peers is empty.
   660  func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo {
   661  	if len(peers) == 0 {
   662  		return nil
   663  	}
   664  	peerInfo := make([]network.PeerInfo, 0, len(peers))
   665  	for _, peer := range peers {
   666  		peerInfo = append(peerInfo, network.PeerInfo(peer))
   667  	}
   668  	return peerInfo
   669  }
   670  
   671  // buildIPAMResources constructs a [network.IPAM] from the network's
   672  // IPAM information for inclusion in API responses.
   673  func buildIPAMResources(nw *libnetwork.Network) network.IPAM {
   674  	var ipamConfig []network.IPAMConfig
   675  
   676  	ipamDriver, ipamOptions, ipv4Conf, ipv6Conf := nw.IpamConfig()
   677  
   678  	hasIPv4Config := false
   679  	for _, cfg := range ipv4Conf {
   680  		if cfg.PreferredPool == "" {
   681  			continue
   682  		}
   683  		hasIPv4Config = true
   684  		ipamConfig = append(ipamConfig, network.IPAMConfig{
   685  			Subnet:     cfg.PreferredPool,
   686  			IPRange:    cfg.SubPool,
   687  			Gateway:    cfg.Gateway,
   688  			AuxAddress: cfg.AuxAddresses,
   689  		})
   690  	}
   691  
   692  	hasIPv6Config := false
   693  	for _, cfg := range ipv6Conf {
   694  		if cfg.PreferredPool == "" {
   695  			continue
   696  		}
   697  		hasIPv6Config = true
   698  		ipamConfig = append(ipamConfig, network.IPAMConfig{
   699  			Subnet:     cfg.PreferredPool,
   700  			IPRange:    cfg.SubPool,
   701  			Gateway:    cfg.Gateway,
   702  			AuxAddress: cfg.AuxAddresses,
   703  		})
   704  	}
   705  
   706  	if !hasIPv4Config || !hasIPv6Config {
   707  		ipv4Info, ipv6Info := nw.IpamInfo()
   708  		if !hasIPv4Config {
   709  			for _, info := range ipv4Info {
   710  				var gw string
   711  				if info.IPAMData.Gateway != nil {
   712  					gw = info.IPAMData.Gateway.IP.String()
   713  				}
   714  				ipamConfig = append(ipamConfig, network.IPAMConfig{
   715  					Subnet:  info.IPAMData.Pool.String(),
   716  					Gateway: gw,
   717  				})
   718  			}
   719  		}
   720  
   721  		if !hasIPv6Config {
   722  			for _, info := range ipv6Info {
   723  				if info.IPAMData.Pool == nil {
   724  					continue
   725  				}
   726  				ipamConfig = append(ipamConfig, network.IPAMConfig{
   727  					Subnet:  info.IPAMData.Pool.String(),
   728  					Gateway: info.IPAMData.Gateway.String(),
   729  				})
   730  			}
   731  		}
   732  	}
   733  
   734  	return network.IPAM{
   735  		Driver:  ipamDriver,
   736  		Options: ipamOptions,
   737  		Config:  ipamConfig,
   738  	}
   739  }
   740  
   741  // buildEndpointResource combines information from the endpoint and additional
   742  // endpoint-info into a [types.EndpointResource].
   743  func buildEndpointResource(ep *libnetwork.Endpoint, info libnetwork.EndpointInfo) types.EndpointResource {
   744  	er := types.EndpointResource{
   745  		EndpointID: ep.ID(),
   746  		Name:       ep.Name(),
   747  	}
   748  	if iface := info.Iface(); iface != nil {
   749  		if mac := iface.MacAddress(); mac != nil {
   750  			er.MacAddress = mac.String()
   751  		}
   752  		if ip := iface.Address(); ip != nil && len(ip.IP) > 0 {
   753  			er.IPv4Address = ip.String()
   754  		}
   755  		if ip := iface.AddressIPv6(); ip != nil && len(ip.IP) > 0 {
   756  			er.IPv6Address = ip.String()
   757  		}
   758  	}
   759  	return er
   760  }
   761  
   762  // clearAttachableNetworks removes the attachable networks
   763  // after disconnecting any connected container
   764  func (daemon *Daemon) clearAttachableNetworks() {
   765  	for _, n := range daemon.getAllNetworks() {
   766  		if !n.Attachable() {
   767  			continue
   768  		}
   769  		for _, ep := range n.Endpoints() {
   770  			epInfo := ep.Info()
   771  			if epInfo == nil {
   772  				continue
   773  			}
   774  			sb := epInfo.Sandbox()
   775  			if sb == nil {
   776  				continue
   777  			}
   778  			containerID := sb.ContainerID()
   779  			if err := daemon.DisconnectContainerFromNetwork(containerID, n.ID(), true); err != nil {
   780  				log.G(context.TODO()).Warnf("Failed to disconnect container %s from swarm network %s on cluster leave: %v",
   781  					containerID, n.Name(), err)
   782  			}
   783  		}
   784  		if err := daemon.DeleteManagedNetwork(n.ID()); err != nil {
   785  			log.G(context.TODO()).Warnf("Failed to remove swarm network %s on cluster leave: %v", n.Name(), err)
   786  		}
   787  	}
   788  }
   789  
   790  // buildCreateEndpointOptions builds endpoint options from a given network.
   791  func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, epConfig *network.EndpointSettings, sb *libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
   792  	var createOptions []libnetwork.EndpointOption
   793  	var genericOptions = make(options.Generic)
   794  
   795  	nwName := n.Name()
   796  
   797  	if epConfig != nil {
   798  		if ipam := epConfig.IPAMConfig; ipam != nil {
   799  			var ipList []net.IP
   800  			for _, ips := range ipam.LinkLocalIPs {
   801  				linkIP := net.ParseIP(ips)
   802  				if linkIP == nil && ips != "" {
   803  					return nil, fmt.Errorf("invalid link-local IP address: %s", ipam.LinkLocalIPs)
   804  				}
   805  				ipList = append(ipList, linkIP)
   806  			}
   807  
   808  			ip := net.ParseIP(ipam.IPv4Address)
   809  			if ip == nil && ipam.IPv4Address != "" {
   810  				return nil, fmt.Errorf("invalid IPv4 address: %s", ipam.IPv4Address)
   811  			}
   812  
   813  			ip6 := net.ParseIP(ipam.IPv6Address)
   814  			if ip6 == nil && ipam.IPv6Address != "" {
   815  				return nil, fmt.Errorf("invalid IPv6 address: %s", ipam.IPv6Address)
   816  			}
   817  
   818  			createOptions = append(createOptions, libnetwork.CreateOptionIpam(ip, ip6, ipList, nil))
   819  		}
   820  
   821  		createOptions = append(createOptions, libnetwork.CreateOptionDNSNames(epConfig.DNSNames))
   822  
   823  		for k, v := range epConfig.DriverOpts {
   824  			createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
   825  		}
   826  
   827  		if epConfig.MacAddress != "" {
   828  			mac, err := net.ParseMAC(epConfig.MacAddress)
   829  			if err != nil {
   830  				return nil, err
   831  			}
   832  			genericOptions[netlabel.MacAddress] = mac
   833  		}
   834  	}
   835  
   836  	if svcCfg := c.NetworkSettings.Service; svcCfg != nil {
   837  		nwID := n.ID()
   838  
   839  		var vip net.IP
   840  		if virtualAddress := svcCfg.VirtualAddresses[nwID]; virtualAddress != nil {
   841  			vip = net.ParseIP(virtualAddress.IPv4)
   842  		}
   843  
   844  		var portConfigs []*libnetwork.PortConfig
   845  		for _, portConfig := range svcCfg.ExposedPorts {
   846  			portConfigs = append(portConfigs, &libnetwork.PortConfig{
   847  				Name:          portConfig.Name,
   848  				Protocol:      libnetwork.PortConfig_Protocol(portConfig.Protocol),
   849  				TargetPort:    portConfig.TargetPort,
   850  				PublishedPort: portConfig.PublishedPort,
   851  			})
   852  		}
   853  
   854  		createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, vip, portConfigs, svcCfg.Aliases[nwID]))
   855  	}
   856  
   857  	if !containertypes.NetworkMode(nwName).IsUserDefined() {
   858  		createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
   859  	}
   860  
   861  	opts, err := buildPortsRelatedCreateEndpointOptions(c, n, sb)
   862  	if err != nil {
   863  		return nil, err
   864  	}
   865  	createOptions = append(createOptions, opts...)
   866  
   867  	// On Windows, DNS config is a per-adapter config option whereas on Linux, it's a sandbox-wide parameter; hence why
   868  	// we're dealing with DNS config both here and in buildSandboxOptions. Following DNS options are only honored by
   869  	// Windows netdrivers, whereas DNS options in buildSandboxOptions are only honored by Linux netdrivers.
   870  	if !n.Internal() {
   871  		if len(c.HostConfig.DNS) > 0 {
   872  			createOptions = append(createOptions, libnetwork.CreateOptionDNS(c.HostConfig.DNS))
   873  		} else if len(daemonDNS) > 0 {
   874  			createOptions = append(createOptions, libnetwork.CreateOptionDNS(daemonDNS))
   875  		}
   876  	}
   877  
   878  	createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOptions))
   879  
   880  	return createOptions, nil
   881  }
   882  
   883  // buildPortsRelatedCreateEndpointOptions returns the appropriate endpoint options to apply config related to port
   884  // mapping and exposed ports.
   885  func buildPortsRelatedCreateEndpointOptions(c *container.Container, n *libnetwork.Network, sb *libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) {
   886  	// Port-mapping rules belong to the container & applicable only to non-internal networks.
   887  	//
   888  	// TODO(thaJeztah): Look if we can provide a more minimal function for getPortMapInfo, as it does a lot, and we only need the "length".
   889  	if n.Internal() || len(getPortMapInfo(sb)) > 0 {
   890  		return nil, nil
   891  	}
   892  
   893  	bindings := make(nat.PortMap)
   894  	if c.HostConfig.PortBindings != nil {
   895  		for p, b := range c.HostConfig.PortBindings {
   896  			bindings[p] = []nat.PortBinding{}
   897  			for _, bb := range b {
   898  				bindings[p] = append(bindings[p], nat.PortBinding{
   899  					HostIP:   bb.HostIP,
   900  					HostPort: bb.HostPort,
   901  				})
   902  			}
   903  		}
   904  	}
   905  
   906  	// TODO(thaJeztah): Move this code to a method on nat.PortSet.
   907  	ports := make([]nat.Port, 0, len(c.Config.ExposedPorts))
   908  	for p := range c.Config.ExposedPorts {
   909  		ports = append(ports, p)
   910  	}
   911  	nat.SortPortMap(ports, bindings)
   912  
   913  	var (
   914  		exposedPorts   []networktypes.TransportPort
   915  		publishedPorts []networktypes.PortBinding
   916  	)
   917  	for _, port := range ports {
   918  		portProto := networktypes.ParseProtocol(port.Proto())
   919  		portNum := uint16(port.Int())
   920  		exposedPorts = append(exposedPorts, networktypes.TransportPort{
   921  			Proto: portProto,
   922  			Port:  portNum,
   923  		})
   924  
   925  		for _, binding := range bindings[port] {
   926  			newP, err := nat.NewPort(nat.SplitProtoPort(binding.HostPort))
   927  			var portStart, portEnd int
   928  			if err == nil {
   929  				portStart, portEnd, err = newP.Range()
   930  			}
   931  			if err != nil {
   932  				return nil, fmt.Errorf("error parsing HostPort value (%s): %w", binding.HostPort, err)
   933  			}
   934  			publishedPorts = append(publishedPorts, networktypes.PortBinding{
   935  				Proto:       portProto,
   936  				Port:        portNum,
   937  				HostIP:      net.ParseIP(binding.HostIP),
   938  				HostPort:    uint16(portStart),
   939  				HostPortEnd: uint16(portEnd),
   940  			})
   941  		}
   942  
   943  		if c.HostConfig.PublishAllPorts && len(bindings[port]) == 0 {
   944  			publishedPorts = append(publishedPorts, networktypes.PortBinding{
   945  				Proto: portProto,
   946  				Port:  portNum,
   947  			})
   948  		}
   949  	}
   950  
   951  	return []libnetwork.EndpointOption{
   952  		libnetwork.CreateOptionPortMapping(publishedPorts),
   953  		libnetwork.CreateOptionExposedPorts(exposedPorts),
   954  	}, nil
   955  }
   956  
   957  // getPortMapInfo retrieves the current port-mapping programmed for the given sandbox
   958  func getPortMapInfo(sb *libnetwork.Sandbox) nat.PortMap {
   959  	pm := nat.PortMap{}
   960  	if sb == nil {
   961  		return pm
   962  	}
   963  
   964  	for _, ep := range sb.Endpoints() {
   965  		pm, _ = getEndpointPortMapInfo(ep)
   966  		if len(pm) > 0 {
   967  			break
   968  		}
   969  	}
   970  	return pm
   971  }
   972  
   973  func getEndpointPortMapInfo(ep *libnetwork.Endpoint) (nat.PortMap, error) {
   974  	pm := nat.PortMap{}
   975  	driverInfo, err := ep.DriverInfo()
   976  	if err != nil {
   977  		return pm, err
   978  	}
   979  
   980  	if driverInfo == nil {
   981  		// It is not an error for epInfo to be nil
   982  		return pm, nil
   983  	}
   984  
   985  	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
   986  		if exposedPorts, ok := expData.([]networktypes.TransportPort); ok {
   987  			for _, tp := range exposedPorts {
   988  				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
   989  				if err != nil {
   990  					return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
   991  				}
   992  				pm[natPort] = nil
   993  			}
   994  		}
   995  	}
   996  
   997  	mapData, ok := driverInfo[netlabel.PortMap]
   998  	if !ok {
   999  		return pm, nil
  1000  	}
  1001  
  1002  	if portMapping, ok := mapData.([]networktypes.PortBinding); ok {
  1003  		for _, pp := range portMapping {
  1004  			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
  1005  			if err != nil {
  1006  				return pm, err
  1007  			}
  1008  			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
  1009  			pm[natPort] = append(pm[natPort], natBndg)
  1010  		}
  1011  	}
  1012  
  1013  	return pm, nil
  1014  }
  1015  
  1016  // buildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
  1017  func buildEndpointInfo(networkSettings *internalnetwork.Settings, n *libnetwork.Network, ep *libnetwork.Endpoint) error {
  1018  	if ep == nil {
  1019  		return errors.New("endpoint cannot be nil")
  1020  	}
  1021  
  1022  	if networkSettings == nil {
  1023  		return errors.New("network cannot be nil")
  1024  	}
  1025  
  1026  	epInfo := ep.Info()
  1027  	if epInfo == nil {
  1028  		// It is not an error to get an empty endpoint info
  1029  		return nil
  1030  	}
  1031  
  1032  	nwName := n.Name()
  1033  	if _, ok := networkSettings.Networks[nwName]; !ok {
  1034  		networkSettings.Networks[nwName] = &internalnetwork.EndpointSettings{
  1035  			EndpointSettings: &network.EndpointSettings{},
  1036  		}
  1037  	}
  1038  	networkSettings.Networks[nwName].NetworkID = n.ID()
  1039  	networkSettings.Networks[nwName].EndpointID = ep.ID()
  1040  
  1041  	iface := epInfo.Iface()
  1042  	if iface == nil {
  1043  		return nil
  1044  	}
  1045  
  1046  	if iface.MacAddress() != nil {
  1047  		networkSettings.Networks[nwName].MacAddress = iface.MacAddress().String()
  1048  	}
  1049  
  1050  	if iface.Address() != nil {
  1051  		ones, _ := iface.Address().Mask.Size()
  1052  		networkSettings.Networks[nwName].IPAddress = iface.Address().IP.String()
  1053  		networkSettings.Networks[nwName].IPPrefixLen = ones
  1054  	}
  1055  
  1056  	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
  1057  		onesv6, _ := iface.AddressIPv6().Mask.Size()
  1058  		networkSettings.Networks[nwName].GlobalIPv6Address = iface.AddressIPv6().IP.String()
  1059  		networkSettings.Networks[nwName].GlobalIPv6PrefixLen = onesv6
  1060  	}
  1061  
  1062  	return nil
  1063  }
  1064  
  1065  // buildJoinOptions builds endpoint Join options from a given network.
  1066  func buildJoinOptions(networkSettings *internalnetwork.Settings, n interface{ Name() string }) ([]libnetwork.EndpointOption, error) {
  1067  	var joinOptions []libnetwork.EndpointOption
  1068  	if epConfig, ok := networkSettings.Networks[n.Name()]; ok {
  1069  		for _, str := range epConfig.Links {
  1070  			name, alias, err := opts.ParseLink(str)
  1071  			if err != nil {
  1072  				return nil, err
  1073  			}
  1074  			joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
  1075  		}
  1076  		for k, v := range epConfig.DriverOpts {
  1077  			joinOptions = append(joinOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
  1078  		}
  1079  	}
  1080  
  1081  	return joinOptions, nil
  1082  }