github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/daemon/network.go (about)

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