github.com/moby/docker@v26.1.3+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  	networkOptions := make(map[string]string)
   309  	for k, v := range create.Options {
   310  		networkOptions[k] = v
   311  	}
   312  	if defaultOpts, ok := cfg.DefaultNetworkOpts[driver]; create.ConfigFrom == nil && ok {
   313  		for k, v := range defaultOpts {
   314  			if _, ok := networkOptions[k]; !ok {
   315  				log.G(context.TODO()).WithFields(log.Fields{"driver": driver, "network": id, k: v}).Debug("Applying network default option")
   316  				networkOptions[k] = v
   317  			}
   318  		}
   319  	}
   320  
   321  	nwOptions := []libnetwork.NetworkOption{
   322  		libnetwork.NetworkOptionEnableIPv6(create.EnableIPv6),
   323  		libnetwork.NetworkOptionDriverOpts(networkOptions),
   324  		libnetwork.NetworkOptionLabels(create.Labels),
   325  		libnetwork.NetworkOptionAttachable(create.Attachable),
   326  		libnetwork.NetworkOptionIngress(create.Ingress),
   327  		libnetwork.NetworkOptionScope(create.Scope),
   328  	}
   329  
   330  	if create.ConfigOnly {
   331  		nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigOnly())
   332  	}
   333  
   334  	if err := network.ValidateIPAM(create.IPAM, create.EnableIPv6); err != nil {
   335  		if agent {
   336  			// This function is called with agent=false for all networks. For swarm-scoped
   337  			// networks, the configuration is validated but ManagerRedirectError is returned
   338  			// and the network is not created. Then, each time a swarm-scoped network is
   339  			// needed, this function is called again with agent=true.
   340  			//
   341  			// Non-swarm networks created before ValidateIPAM was introduced continue to work
   342  			// as they did before-upgrade, even if they would fail the new checks on creation
   343  			// (for example, by having host-bits set in their subnet). Those networks are not
   344  			// seen again here.
   345  			//
   346  			// By dropping errors for agent networks, existing swarm-scoped networks also
   347  			// continue to behave as they did before upgrade - but new networks are still
   348  			// validated.
   349  			log.G(context.TODO()).WithFields(log.Fields{
   350  				"error":   err,
   351  				"network": create.Name,
   352  			}).Warn("Continuing with validation errors in agent IPAM")
   353  		} else {
   354  			return nil, errdefs.InvalidParameter(err)
   355  		}
   356  	}
   357  
   358  	if create.IPAM != nil {
   359  		ipam := create.IPAM
   360  		v4Conf, v6Conf, err := getIpamConfig(ipam.Config)
   361  		if err != nil {
   362  			return nil, err
   363  		}
   364  		nwOptions = append(nwOptions, libnetwork.NetworkOptionIpam(ipam.Driver, "", v4Conf, v6Conf, ipam.Options))
   365  	}
   366  
   367  	if create.Internal {
   368  		nwOptions = append(nwOptions, libnetwork.NetworkOptionInternalNetwork())
   369  	}
   370  	if agent {
   371  		nwOptions = append(nwOptions, libnetwork.NetworkOptionDynamic())
   372  		nwOptions = append(nwOptions, libnetwork.NetworkOptionPersist(false))
   373  	}
   374  
   375  	if create.ConfigFrom != nil {
   376  		nwOptions = append(nwOptions, libnetwork.NetworkOptionConfigFrom(create.ConfigFrom.Network))
   377  	}
   378  
   379  	if agent && driver == "overlay" {
   380  		nodeIP, exists := daemon.GetAttachmentStore().GetIPForNetwork(id)
   381  		if !exists {
   382  			return nil, fmt.Errorf("failed to find a load balancer IP to use for network: %v", id)
   383  		}
   384  
   385  		nwOptions = append(nwOptions, libnetwork.NetworkOptionLBEndpoint(nodeIP))
   386  	}
   387  
   388  	n, err := c.NewNetwork(driver, create.Name, id, nwOptions...)
   389  	if err != nil {
   390  		return nil, err
   391  	}
   392  
   393  	daemon.pluginRefCount(driver, driverapi.NetworkPluginEndpointType, plugingetter.Acquire)
   394  	if create.IPAM != nil {
   395  		daemon.pluginRefCount(create.IPAM.Driver, ipamapi.PluginEndpointType, plugingetter.Acquire)
   396  	}
   397  	daemon.LogNetworkEvent(n, events.ActionCreate)
   398  
   399  	return &types.NetworkCreateResponse{
   400  		ID: n.ID(),
   401  	}, nil
   402  }
   403  
   404  func (daemon *Daemon) pluginRefCount(driver, capability string, mode int) {
   405  	var builtinDrivers []string
   406  
   407  	if capability == driverapi.NetworkPluginEndpointType {
   408  		builtinDrivers = daemon.netController.BuiltinDrivers()
   409  	} else if capability == ipamapi.PluginEndpointType {
   410  		builtinDrivers = daemon.netController.BuiltinIPAMDrivers()
   411  	}
   412  
   413  	for _, d := range builtinDrivers {
   414  		if d == driver {
   415  			return
   416  		}
   417  	}
   418  
   419  	if daemon.PluginStore != nil {
   420  		_, err := daemon.PluginStore.Get(driver, capability, mode)
   421  		if err != nil {
   422  			log.G(context.TODO()).WithError(err).WithFields(log.Fields{"mode": mode, "driver": driver}).Error("Error handling plugin refcount operation")
   423  		}
   424  	}
   425  }
   426  
   427  func getIpamConfig(data []network.IPAMConfig) ([]*libnetwork.IpamConf, []*libnetwork.IpamConf, error) {
   428  	ipamV4Cfg := []*libnetwork.IpamConf{}
   429  	ipamV6Cfg := []*libnetwork.IpamConf{}
   430  	for _, d := range data {
   431  		iCfg := libnetwork.IpamConf{}
   432  		iCfg.PreferredPool = d.Subnet
   433  		iCfg.SubPool = d.IPRange
   434  		iCfg.Gateway = d.Gateway
   435  		iCfg.AuxAddresses = d.AuxAddress
   436  		ip, _, err := net.ParseCIDR(d.Subnet)
   437  		if err != nil {
   438  			return nil, nil, fmt.Errorf("Invalid subnet %s : %v", d.Subnet, err)
   439  		}
   440  		if ip.To4() != nil {
   441  			ipamV4Cfg = append(ipamV4Cfg, &iCfg)
   442  		} else {
   443  			ipamV6Cfg = append(ipamV6Cfg, &iCfg)
   444  		}
   445  	}
   446  	return ipamV4Cfg, ipamV6Cfg, nil
   447  }
   448  
   449  // UpdateContainerServiceConfig updates a service configuration.
   450  func (daemon *Daemon) UpdateContainerServiceConfig(containerName string, serviceConfig *clustertypes.ServiceConfig) error {
   451  	ctr, err := daemon.GetContainer(containerName)
   452  	if err != nil {
   453  		return err
   454  	}
   455  
   456  	ctr.NetworkSettings.Service = serviceConfig
   457  	return nil
   458  }
   459  
   460  // ConnectContainerToNetwork connects the given container to the given
   461  // network. If either cannot be found, an err is returned. If the
   462  // network cannot be set up, an err is returned.
   463  func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error {
   464  	ctr, err := daemon.GetContainer(containerName)
   465  	if err != nil {
   466  		return err
   467  	}
   468  	return daemon.ConnectToNetwork(ctr, networkName, endpointConfig)
   469  }
   470  
   471  // DisconnectContainerFromNetwork disconnects the given container from
   472  // the given network. If either cannot be found, an err is returned.
   473  func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error {
   474  	ctr, err := daemon.GetContainer(containerName)
   475  	if err != nil {
   476  		if force {
   477  			return daemon.ForceEndpointDelete(containerName, networkName)
   478  		}
   479  		return err
   480  	}
   481  	return daemon.DisconnectFromNetwork(ctr, networkName, force)
   482  }
   483  
   484  // GetNetworkDriverList returns the list of plugins drivers
   485  // registered for network.
   486  func (daemon *Daemon) GetNetworkDriverList(ctx context.Context) []string {
   487  	if !daemon.NetworkControllerEnabled() {
   488  		return nil
   489  	}
   490  
   491  	pluginList := daemon.netController.BuiltinDrivers()
   492  
   493  	managedPlugins := daemon.PluginStore.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType)
   494  
   495  	for _, plugin := range managedPlugins {
   496  		pluginList = append(pluginList, plugin.Name())
   497  	}
   498  
   499  	pluginMap := make(map[string]bool)
   500  	for _, plugin := range pluginList {
   501  		pluginMap[plugin] = true
   502  	}
   503  
   504  	networks := daemon.netController.Networks(ctx)
   505  
   506  	for _, nw := range networks {
   507  		if !pluginMap[nw.Type()] {
   508  			pluginList = append(pluginList, nw.Type())
   509  			pluginMap[nw.Type()] = true
   510  		}
   511  	}
   512  
   513  	sort.Strings(pluginList)
   514  
   515  	return pluginList
   516  }
   517  
   518  // DeleteManagedNetwork deletes an agent network.
   519  // The requirement of networkID is enforced.
   520  func (daemon *Daemon) DeleteManagedNetwork(networkID string) error {
   521  	n, err := daemon.GetNetworkByID(networkID)
   522  	if err != nil {
   523  		return err
   524  	}
   525  	return daemon.deleteNetwork(n, true)
   526  }
   527  
   528  // DeleteNetwork destroys a network unless it's one of docker's predefined networks.
   529  func (daemon *Daemon) DeleteNetwork(networkID string) error {
   530  	n, err := daemon.GetNetworkByID(networkID)
   531  	if err != nil {
   532  		return fmt.Errorf("could not find network by ID: %w", err)
   533  	}
   534  	return daemon.deleteNetwork(n, false)
   535  }
   536  
   537  func (daemon *Daemon) deleteNetwork(nw *libnetwork.Network, dynamic bool) error {
   538  	if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic {
   539  		err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name())
   540  		return errdefs.Forbidden(err)
   541  	}
   542  
   543  	if dynamic && !nw.Dynamic() {
   544  		if runconfig.IsPreDefinedNetwork(nw.Name()) {
   545  			// Predefined networks now support swarm services. Make this
   546  			// a no-op when cluster requests to remove the predefined network.
   547  			return nil
   548  		}
   549  		err := fmt.Errorf("%s is not a dynamic network", nw.Name())
   550  		return errdefs.Forbidden(err)
   551  	}
   552  
   553  	if err := nw.Delete(); err != nil {
   554  		return fmt.Errorf("error while removing network: %w", err)
   555  	}
   556  
   557  	// If this is not a configuration only network, we need to
   558  	// update the corresponding remote drivers' reference counts
   559  	if !nw.ConfigOnly() {
   560  		daemon.pluginRefCount(nw.Type(), driverapi.NetworkPluginEndpointType, plugingetter.Release)
   561  		ipamType, _, _, _ := nw.IpamConfig()
   562  		daemon.pluginRefCount(ipamType, ipamapi.PluginEndpointType, plugingetter.Release)
   563  		daemon.LogNetworkEvent(nw, events.ActionDestroy)
   564  	}
   565  
   566  	return nil
   567  }
   568  
   569  // GetNetworks returns a list of all networks
   570  func (daemon *Daemon) GetNetworks(filter filters.Args, config backend.NetworkListConfig) (networks []types.NetworkResource, err error) {
   571  	var idx map[string]*libnetwork.Network
   572  	if config.Detailed {
   573  		idx = make(map[string]*libnetwork.Network)
   574  	}
   575  
   576  	allNetworks := daemon.getAllNetworks()
   577  	networks = make([]types.NetworkResource, 0, len(allNetworks))
   578  	for _, n := range allNetworks {
   579  		nr := buildNetworkResource(n)
   580  		networks = append(networks, nr)
   581  		if config.Detailed {
   582  			idx[nr.ID] = n
   583  		}
   584  	}
   585  
   586  	networks, err = internalnetwork.FilterNetworks(networks, filter)
   587  	if err != nil {
   588  		return nil, err
   589  	}
   590  
   591  	if config.Detailed {
   592  		for i, nw := range networks {
   593  			networks[i].Containers = buildContainerAttachments(idx[nw.ID])
   594  			if config.Verbose {
   595  				networks[i].Services = buildServiceAttachments(idx[nw.ID])
   596  			}
   597  		}
   598  	}
   599  
   600  	return networks, nil
   601  }
   602  
   603  // buildNetworkResource builds a [types.NetworkResource] from the given
   604  // [libnetwork.Network], to be returned by the API.
   605  func buildNetworkResource(nw *libnetwork.Network) types.NetworkResource {
   606  	if nw == nil {
   607  		return types.NetworkResource{}
   608  	}
   609  
   610  	return types.NetworkResource{
   611  		Name:       nw.Name(),
   612  		ID:         nw.ID(),
   613  		Created:    nw.Created(),
   614  		Scope:      nw.Scope(),
   615  		Driver:     nw.Type(),
   616  		EnableIPv6: nw.IPv6Enabled(),
   617  		IPAM:       buildIPAMResources(nw),
   618  		Internal:   nw.Internal(),
   619  		Attachable: nw.Attachable(),
   620  		Ingress:    nw.Ingress(),
   621  		ConfigFrom: network.ConfigReference{Network: nw.ConfigFrom()},
   622  		ConfigOnly: nw.ConfigOnly(),
   623  		Containers: map[string]types.EndpointResource{},
   624  		Options:    nw.DriverOptions(),
   625  		Labels:     nw.Labels(),
   626  		Peers:      buildPeerInfoResources(nw.Peers()),
   627  	}
   628  }
   629  
   630  // buildContainerAttachments creates a [types.EndpointResource] map of all
   631  // containers attached to the network. It is used when listing networks in
   632  // detailed mode.
   633  func buildContainerAttachments(nw *libnetwork.Network) map[string]types.EndpointResource {
   634  	containers := make(map[string]types.EndpointResource)
   635  	for _, e := range nw.Endpoints() {
   636  		ei := e.Info()
   637  		if ei == nil {
   638  			continue
   639  		}
   640  		if sb := ei.Sandbox(); sb != nil {
   641  			containers[sb.ContainerID()] = buildEndpointResource(e, ei)
   642  		} else {
   643  			containers["ep-"+e.ID()] = buildEndpointResource(e, ei)
   644  		}
   645  	}
   646  	return containers
   647  }
   648  
   649  // buildServiceAttachments creates a [network.ServiceInfo] map of all services
   650  // attached to the network. It is used when listing networks in "verbose" mode.
   651  func buildServiceAttachments(nw *libnetwork.Network) map[string]network.ServiceInfo {
   652  	services := make(map[string]network.ServiceInfo)
   653  	for name, service := range nw.Services() {
   654  		tasks := make([]network.Task, 0, len(service.Tasks))
   655  		for _, t := range service.Tasks {
   656  			tasks = append(tasks, network.Task{
   657  				Name:       t.Name,
   658  				EndpointID: t.EndpointID,
   659  				EndpointIP: t.EndpointIP,
   660  				Info:       t.Info,
   661  			})
   662  		}
   663  		services[name] = network.ServiceInfo{
   664  			VIP:          service.VIP,
   665  			Ports:        service.Ports,
   666  			Tasks:        tasks,
   667  			LocalLBIndex: service.LocalLBIndex,
   668  		}
   669  	}
   670  	return services
   671  }
   672  
   673  // buildPeerInfoResources converts a list of [networkdb.PeerInfo] to a
   674  // [network.PeerInfo] for inclusion in API responses. It returns nil if
   675  // the list of peers is empty.
   676  func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo {
   677  	if len(peers) == 0 {
   678  		return nil
   679  	}
   680  	peerInfo := make([]network.PeerInfo, 0, len(peers))
   681  	for _, peer := range peers {
   682  		peerInfo = append(peerInfo, network.PeerInfo(peer))
   683  	}
   684  	return peerInfo
   685  }
   686  
   687  // buildIPAMResources constructs a [network.IPAM] from the network's
   688  // IPAM information for inclusion in API responses.
   689  func buildIPAMResources(nw *libnetwork.Network) network.IPAM {
   690  	var ipamConfig []network.IPAMConfig
   691  
   692  	ipamDriver, ipamOptions, ipv4Conf, ipv6Conf := nw.IpamConfig()
   693  
   694  	hasIPv4Config := false
   695  	for _, cfg := range ipv4Conf {
   696  		if cfg.PreferredPool == "" {
   697  			continue
   698  		}
   699  		hasIPv4Config = true
   700  		ipamConfig = append(ipamConfig, network.IPAMConfig{
   701  			Subnet:     cfg.PreferredPool,
   702  			IPRange:    cfg.SubPool,
   703  			Gateway:    cfg.Gateway,
   704  			AuxAddress: cfg.AuxAddresses,
   705  		})
   706  	}
   707  
   708  	hasIPv6Config := false
   709  	for _, cfg := range ipv6Conf {
   710  		if cfg.PreferredPool == "" {
   711  			continue
   712  		}
   713  		hasIPv6Config = true
   714  		ipamConfig = append(ipamConfig, network.IPAMConfig{
   715  			Subnet:     cfg.PreferredPool,
   716  			IPRange:    cfg.SubPool,
   717  			Gateway:    cfg.Gateway,
   718  			AuxAddress: cfg.AuxAddresses,
   719  		})
   720  	}
   721  
   722  	if !hasIPv4Config || !hasIPv6Config {
   723  		ipv4Info, ipv6Info := nw.IpamInfo()
   724  		if !hasIPv4Config {
   725  			for _, info := range ipv4Info {
   726  				var gw string
   727  				if info.IPAMData.Gateway != nil {
   728  					gw = info.IPAMData.Gateway.IP.String()
   729  				}
   730  				ipamConfig = append(ipamConfig, network.IPAMConfig{
   731  					Subnet:  info.IPAMData.Pool.String(),
   732  					Gateway: gw,
   733  				})
   734  			}
   735  		}
   736  
   737  		if !hasIPv6Config {
   738  			for _, info := range ipv6Info {
   739  				if info.IPAMData.Pool == nil {
   740  					continue
   741  				}
   742  				ipamConfig = append(ipamConfig, network.IPAMConfig{
   743  					Subnet:  info.IPAMData.Pool.String(),
   744  					Gateway: info.IPAMData.Gateway.String(),
   745  				})
   746  			}
   747  		}
   748  	}
   749  
   750  	return network.IPAM{
   751  		Driver:  ipamDriver,
   752  		Options: ipamOptions,
   753  		Config:  ipamConfig,
   754  	}
   755  }
   756  
   757  // buildEndpointResource combines information from the endpoint and additional
   758  // endpoint-info into a [types.EndpointResource].
   759  func buildEndpointResource(ep *libnetwork.Endpoint, info libnetwork.EndpointInfo) types.EndpointResource {
   760  	er := types.EndpointResource{
   761  		EndpointID: ep.ID(),
   762  		Name:       ep.Name(),
   763  	}
   764  	if iface := info.Iface(); iface != nil {
   765  		if mac := iface.MacAddress(); mac != nil {
   766  			er.MacAddress = mac.String()
   767  		}
   768  		if ip := iface.Address(); ip != nil && len(ip.IP) > 0 {
   769  			er.IPv4Address = ip.String()
   770  		}
   771  		if ip := iface.AddressIPv6(); ip != nil && len(ip.IP) > 0 {
   772  			er.IPv6Address = ip.String()
   773  		}
   774  	}
   775  	return er
   776  }
   777  
   778  // clearAttachableNetworks removes the attachable networks
   779  // after disconnecting any connected container
   780  func (daemon *Daemon) clearAttachableNetworks() {
   781  	for _, n := range daemon.getAllNetworks() {
   782  		if !n.Attachable() {
   783  			continue
   784  		}
   785  		for _, ep := range n.Endpoints() {
   786  			epInfo := ep.Info()
   787  			if epInfo == nil {
   788  				continue
   789  			}
   790  			sb := epInfo.Sandbox()
   791  			if sb == nil {
   792  				continue
   793  			}
   794  			containerID := sb.ContainerID()
   795  			if err := daemon.DisconnectContainerFromNetwork(containerID, n.ID(), true); err != nil {
   796  				log.G(context.TODO()).Warnf("Failed to disconnect container %s from swarm network %s on cluster leave: %v",
   797  					containerID, n.Name(), err)
   798  			}
   799  		}
   800  		if err := daemon.DeleteManagedNetwork(n.ID()); err != nil {
   801  			log.G(context.TODO()).Warnf("Failed to remove swarm network %s on cluster leave: %v", n.Name(), err)
   802  		}
   803  	}
   804  }
   805  
   806  // buildCreateEndpointOptions builds endpoint options from a given network.
   807  func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, epConfig *internalnetwork.EndpointSettings, sb *libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
   808  	var createOptions []libnetwork.EndpointOption
   809  	var genericOptions = make(options.Generic)
   810  
   811  	nwName := n.Name()
   812  
   813  	if epConfig != nil {
   814  		if ipam := epConfig.IPAMConfig; ipam != nil {
   815  			var ipList []net.IP
   816  			for _, ips := range ipam.LinkLocalIPs {
   817  				linkIP := net.ParseIP(ips)
   818  				if linkIP == nil && ips != "" {
   819  					return nil, fmt.Errorf("invalid link-local IP address: %s", ipam.LinkLocalIPs)
   820  				}
   821  				ipList = append(ipList, linkIP)
   822  			}
   823  
   824  			ip := net.ParseIP(ipam.IPv4Address)
   825  			if ip == nil && ipam.IPv4Address != "" {
   826  				return nil, fmt.Errorf("invalid IPv4 address: %s", ipam.IPv4Address)
   827  			}
   828  
   829  			ip6 := net.ParseIP(ipam.IPv6Address)
   830  			if ip6 == nil && ipam.IPv6Address != "" {
   831  				return nil, fmt.Errorf("invalid IPv6 address: %s", ipam.IPv6Address)
   832  			}
   833  
   834  			createOptions = append(createOptions, libnetwork.CreateOptionIpam(ip, ip6, ipList, nil))
   835  		}
   836  
   837  		createOptions = append(createOptions, libnetwork.CreateOptionDNSNames(epConfig.DNSNames))
   838  
   839  		for k, v := range epConfig.DriverOpts {
   840  			createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
   841  		}
   842  
   843  		if epConfig.DesiredMacAddress != "" {
   844  			mac, err := net.ParseMAC(epConfig.DesiredMacAddress)
   845  			if err != nil {
   846  				return nil, err
   847  			}
   848  			genericOptions[netlabel.MacAddress] = mac
   849  		}
   850  	}
   851  
   852  	if svcCfg := c.NetworkSettings.Service; svcCfg != nil {
   853  		nwID := n.ID()
   854  
   855  		var vip net.IP
   856  		if virtualAddress := svcCfg.VirtualAddresses[nwID]; virtualAddress != nil {
   857  			vip = net.ParseIP(virtualAddress.IPv4)
   858  		}
   859  
   860  		var portConfigs []*libnetwork.PortConfig
   861  		for _, portConfig := range svcCfg.ExposedPorts {
   862  			portConfigs = append(portConfigs, &libnetwork.PortConfig{
   863  				Name:          portConfig.Name,
   864  				Protocol:      libnetwork.PortConfig_Protocol(portConfig.Protocol),
   865  				TargetPort:    portConfig.TargetPort,
   866  				PublishedPort: portConfig.PublishedPort,
   867  			})
   868  		}
   869  
   870  		createOptions = append(createOptions, libnetwork.CreateOptionService(svcCfg.Name, svcCfg.ID, vip, portConfigs, svcCfg.Aliases[nwID]))
   871  	}
   872  
   873  	if !containertypes.NetworkMode(nwName).IsUserDefined() {
   874  		createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
   875  	}
   876  
   877  	opts, err := buildPortsRelatedCreateEndpointOptions(c, n, sb)
   878  	if err != nil {
   879  		return nil, err
   880  	}
   881  	createOptions = append(createOptions, opts...)
   882  
   883  	// On Windows, DNS config is a per-adapter config option whereas on Linux, it's a sandbox-wide parameter; hence why
   884  	// we're dealing with DNS config both here and in buildSandboxOptions. Following DNS options are only honored by
   885  	// Windows netdrivers, whereas DNS options in buildSandboxOptions are only honored by Linux netdrivers.
   886  	if !n.Internal() {
   887  		if len(c.HostConfig.DNS) > 0 {
   888  			createOptions = append(createOptions, libnetwork.CreateOptionDNS(c.HostConfig.DNS))
   889  		} else if len(daemonDNS) > 0 {
   890  			createOptions = append(createOptions, libnetwork.CreateOptionDNS(daemonDNS))
   891  		}
   892  	}
   893  
   894  	createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOptions))
   895  
   896  	return createOptions, nil
   897  }
   898  
   899  // buildPortsRelatedCreateEndpointOptions returns the appropriate endpoint options to apply config related to port
   900  // mapping and exposed ports.
   901  func buildPortsRelatedCreateEndpointOptions(c *container.Container, n *libnetwork.Network, sb *libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) {
   902  	// Port-mapping rules belong to the container & applicable only to non-internal networks.
   903  	//
   904  	// TODO(thaJeztah): Look if we can provide a more minimal function for getPortMapInfo, as it does a lot, and we only need the "length".
   905  	if n.Internal() || len(getPortMapInfo(sb)) > 0 {
   906  		return nil, nil
   907  	}
   908  
   909  	bindings := make(nat.PortMap)
   910  	if c.HostConfig.PortBindings != nil {
   911  		for p, b := range c.HostConfig.PortBindings {
   912  			bindings[p] = []nat.PortBinding{}
   913  			for _, bb := range b {
   914  				bindings[p] = append(bindings[p], nat.PortBinding{
   915  					HostIP:   bb.HostIP,
   916  					HostPort: bb.HostPort,
   917  				})
   918  			}
   919  		}
   920  	}
   921  
   922  	// TODO(thaJeztah): Move this code to a method on nat.PortSet.
   923  	ports := make([]nat.Port, 0, len(c.Config.ExposedPorts))
   924  	for p := range c.Config.ExposedPorts {
   925  		ports = append(ports, p)
   926  	}
   927  	nat.SortPortMap(ports, bindings)
   928  
   929  	var (
   930  		exposedPorts   []networktypes.TransportPort
   931  		publishedPorts []networktypes.PortBinding
   932  	)
   933  	for _, port := range ports {
   934  		portProto := networktypes.ParseProtocol(port.Proto())
   935  		portNum := uint16(port.Int())
   936  		exposedPorts = append(exposedPorts, networktypes.TransportPort{
   937  			Proto: portProto,
   938  			Port:  portNum,
   939  		})
   940  
   941  		for _, binding := range bindings[port] {
   942  			newP, err := nat.NewPort(nat.SplitProtoPort(binding.HostPort))
   943  			var portStart, portEnd int
   944  			if err == nil {
   945  				portStart, portEnd, err = newP.Range()
   946  			}
   947  			if err != nil {
   948  				return nil, fmt.Errorf("error parsing HostPort value (%s): %w", binding.HostPort, err)
   949  			}
   950  			publishedPorts = append(publishedPorts, networktypes.PortBinding{
   951  				Proto:       portProto,
   952  				Port:        portNum,
   953  				HostIP:      net.ParseIP(binding.HostIP),
   954  				HostPort:    uint16(portStart),
   955  				HostPortEnd: uint16(portEnd),
   956  			})
   957  		}
   958  
   959  		if c.HostConfig.PublishAllPorts && len(bindings[port]) == 0 {
   960  			publishedPorts = append(publishedPorts, networktypes.PortBinding{
   961  				Proto: portProto,
   962  				Port:  portNum,
   963  			})
   964  		}
   965  	}
   966  
   967  	return []libnetwork.EndpointOption{
   968  		libnetwork.CreateOptionPortMapping(publishedPorts),
   969  		libnetwork.CreateOptionExposedPorts(exposedPorts),
   970  	}, nil
   971  }
   972  
   973  // getPortMapInfo retrieves the current port-mapping programmed for the given sandbox
   974  func getPortMapInfo(sb *libnetwork.Sandbox) nat.PortMap {
   975  	pm := nat.PortMap{}
   976  	if sb == nil {
   977  		return pm
   978  	}
   979  
   980  	for _, ep := range sb.Endpoints() {
   981  		pm, _ = getEndpointPortMapInfo(ep)
   982  		if len(pm) > 0 {
   983  			break
   984  		}
   985  	}
   986  	return pm
   987  }
   988  
   989  func getEndpointPortMapInfo(ep *libnetwork.Endpoint) (nat.PortMap, error) {
   990  	pm := nat.PortMap{}
   991  	driverInfo, err := ep.DriverInfo()
   992  	if err != nil {
   993  		return pm, err
   994  	}
   995  
   996  	if driverInfo == nil {
   997  		// It is not an error for epInfo to be nil
   998  		return pm, nil
   999  	}
  1000  
  1001  	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
  1002  		if exposedPorts, ok := expData.([]networktypes.TransportPort); ok {
  1003  			for _, tp := range exposedPorts {
  1004  				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
  1005  				if err != nil {
  1006  					return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
  1007  				}
  1008  				pm[natPort] = nil
  1009  			}
  1010  		}
  1011  	}
  1012  
  1013  	mapData, ok := driverInfo[netlabel.PortMap]
  1014  	if !ok {
  1015  		return pm, nil
  1016  	}
  1017  
  1018  	if portMapping, ok := mapData.([]networktypes.PortBinding); ok {
  1019  		for _, pp := range portMapping {
  1020  			natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
  1021  			if err != nil {
  1022  				return pm, err
  1023  			}
  1024  			natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
  1025  			pm[natPort] = append(pm[natPort], natBndg)
  1026  		}
  1027  	}
  1028  
  1029  	return pm, nil
  1030  }
  1031  
  1032  // buildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
  1033  func buildEndpointInfo(networkSettings *internalnetwork.Settings, n *libnetwork.Network, ep *libnetwork.Endpoint) error {
  1034  	if ep == nil {
  1035  		return errors.New("endpoint cannot be nil")
  1036  	}
  1037  
  1038  	if networkSettings == nil {
  1039  		return errors.New("network cannot be nil")
  1040  	}
  1041  
  1042  	epInfo := ep.Info()
  1043  	if epInfo == nil {
  1044  		// It is not an error to get an empty endpoint info
  1045  		return nil
  1046  	}
  1047  
  1048  	nwName := n.Name()
  1049  	if _, ok := networkSettings.Networks[nwName]; !ok {
  1050  		networkSettings.Networks[nwName] = &internalnetwork.EndpointSettings{
  1051  			EndpointSettings: &network.EndpointSettings{},
  1052  		}
  1053  	}
  1054  	networkSettings.Networks[nwName].NetworkID = n.ID()
  1055  	networkSettings.Networks[nwName].EndpointID = ep.ID()
  1056  
  1057  	iface := epInfo.Iface()
  1058  	if iface == nil {
  1059  		return nil
  1060  	}
  1061  
  1062  	if iface.MacAddress() != nil {
  1063  		networkSettings.Networks[nwName].MacAddress = iface.MacAddress().String()
  1064  	}
  1065  
  1066  	if iface.Address() != nil {
  1067  		ones, _ := iface.Address().Mask.Size()
  1068  		networkSettings.Networks[nwName].IPAddress = iface.Address().IP.String()
  1069  		networkSettings.Networks[nwName].IPPrefixLen = ones
  1070  	}
  1071  
  1072  	if iface.AddressIPv6() != nil && iface.AddressIPv6().IP.To16() != nil {
  1073  		onesv6, _ := iface.AddressIPv6().Mask.Size()
  1074  		networkSettings.Networks[nwName].GlobalIPv6Address = iface.AddressIPv6().IP.String()
  1075  		networkSettings.Networks[nwName].GlobalIPv6PrefixLen = onesv6
  1076  	}
  1077  
  1078  	return nil
  1079  }
  1080  
  1081  // buildJoinOptions builds endpoint Join options from a given network.
  1082  func buildJoinOptions(networkSettings *internalnetwork.Settings, n interface{ Name() string }) ([]libnetwork.EndpointOption, error) {
  1083  	var joinOptions []libnetwork.EndpointOption
  1084  	if epConfig, ok := networkSettings.Networks[n.Name()]; ok {
  1085  		for _, str := range epConfig.Links {
  1086  			name, alias, err := opts.ParseLink(str)
  1087  			if err != nil {
  1088  				return nil, err
  1089  			}
  1090  			joinOptions = append(joinOptions, libnetwork.CreateOptionAlias(name, alias))
  1091  		}
  1092  		for k, v := range epConfig.DriverOpts {
  1093  			joinOptions = append(joinOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
  1094  		}
  1095  	}
  1096  
  1097  	return joinOptions, nil
  1098  }