github.com/moby/docker@v26.1.3+incompatible/libnetwork/cnmallocator/networkallocator.go (about)

     1  package cnmallocator
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net"
     7  	"strings"
     8  
     9  	"github.com/containerd/log"
    10  	"github.com/docker/docker/libnetwork/driverapi"
    11  	"github.com/docker/docker/libnetwork/drivers/remote"
    12  	"github.com/docker/docker/libnetwork/drvregistry"
    13  	"github.com/docker/docker/libnetwork/ipamapi"
    14  	remoteipam "github.com/docker/docker/libnetwork/ipams/remote"
    15  	"github.com/docker/docker/libnetwork/netlabel"
    16  	"github.com/docker/docker/libnetwork/scope"
    17  	"github.com/docker/docker/pkg/plugingetter"
    18  	"github.com/moby/swarmkit/v2/api"
    19  	"github.com/moby/swarmkit/v2/manager/allocator/networkallocator"
    20  	"github.com/pkg/errors"
    21  )
    22  
    23  const (
    24  	// DefaultDriver defines the name of the driver to be used by
    25  	// default if a network without any driver name specified is
    26  	// created.
    27  	DefaultDriver = "overlay"
    28  )
    29  
    30  // cnmNetworkAllocator acts as the controller for all network related operations
    31  // like managing network and IPAM drivers and also creating and
    32  // deleting networks and the associated resources.
    33  type cnmNetworkAllocator struct {
    34  	// The plugin getter instance used to get network and IPAM driver plugins.
    35  	pg plugingetter.PluginGetter
    36  
    37  	// The driver registry for all internal and external IPAM drivers.
    38  	ipamRegistry drvregistry.IPAMs
    39  
    40  	// The driver registry for all internal and external network drivers.
    41  	networkRegistry drvregistry.Networks
    42  
    43  	// Local network state used by cnmNetworkAllocator to do network management.
    44  	networks map[string]*network
    45  
    46  	// Allocator state to indicate if allocation has been
    47  	// successfully completed for this service.
    48  	services map[string]struct{}
    49  
    50  	// Allocator state to indicate if allocation has been
    51  	// successfully completed for this task.
    52  	tasks map[string]struct{}
    53  
    54  	// Allocator state to indicate if allocation has been
    55  	// successfully completed for this node on this network.
    56  	// outer map key: node id
    57  	// inner map key: network id
    58  	nodes map[string]map[string]struct{}
    59  }
    60  
    61  // Local in-memory state related to network that need to be tracked by cnmNetworkAllocator
    62  type network struct {
    63  	// A local cache of the store object.
    64  	nw *api.Network
    65  
    66  	// pools is used to save the internal poolIDs needed when
    67  	// releasing the pool.
    68  	pools map[string]string
    69  
    70  	// endpoints is a map of endpoint IP to the poolID from which it
    71  	// was allocated.
    72  	endpoints map[string]string
    73  
    74  	// isNodeLocal indicates whether the scope of the network's resources
    75  	// is local to the node. If true, it means the resources can only be
    76  	// allocated locally by the node where the network will be deployed.
    77  	// In this the swarm manager will skip the allocations.
    78  	isNodeLocal bool
    79  }
    80  
    81  type networkDriver struct {
    82  	driver     driverapi.Driver
    83  	name       string
    84  	capability *driverapi.Capability
    85  }
    86  
    87  // NewAllocator returns a new NetworkAllocator handle
    88  func (p *Provider) NewAllocator(netConfig *networkallocator.Config) (networkallocator.NetworkAllocator, error) {
    89  	na := &cnmNetworkAllocator{
    90  		networks: make(map[string]*network),
    91  		services: make(map[string]struct{}),
    92  		tasks:    make(map[string]struct{}),
    93  		nodes:    make(map[string]map[string]struct{}),
    94  		pg:       p.pg,
    95  	}
    96  
    97  	for ntype, i := range initializers {
    98  		if err := i(&na.networkRegistry); err != nil {
    99  			return nil, fmt.Errorf("failed to register %q network driver: %w", ntype, err)
   100  		}
   101  	}
   102  	if err := remote.Register(&na.networkRegistry, p.pg); err != nil {
   103  		return nil, fmt.Errorf("failed to initialize network driver plugins: %w", err)
   104  	}
   105  
   106  	if err := initIPAMDrivers(&na.ipamRegistry, netConfig); err != nil {
   107  		return nil, err
   108  	}
   109  	if err := remoteipam.Register(&na.ipamRegistry, p.pg); err != nil {
   110  		return nil, fmt.Errorf("failed to initialize IPAM driver plugins: %w", err)
   111  	}
   112  
   113  	return na, nil
   114  }
   115  
   116  // Allocate allocates all the necessary resources both general
   117  // and driver-specific which may be specified in the NetworkSpec
   118  func (na *cnmNetworkAllocator) Allocate(n *api.Network) error {
   119  	if _, ok := na.networks[n.ID]; ok {
   120  		return fmt.Errorf("network %s already allocated", n.ID)
   121  	}
   122  
   123  	d, err := na.resolveDriver(n)
   124  	if err != nil {
   125  		return err
   126  	}
   127  
   128  	nw := &network{
   129  		nw:          n,
   130  		endpoints:   make(map[string]string),
   131  		isNodeLocal: d.capability.DataScope == scope.Local,
   132  	}
   133  
   134  	// No swarm-level allocation can be provided by the network driver for
   135  	// node-local networks. Only thing needed is populating the driver's name
   136  	// in the driver's state.
   137  	if nw.isNodeLocal {
   138  		n.DriverState = &api.Driver{
   139  			Name: d.name,
   140  		}
   141  		// In order to support backward compatibility with older daemon
   142  		// versions which assumes the network attachment to contains
   143  		// non nil IPAM attribute, passing an empty object
   144  		n.IPAM = &api.IPAMOptions{Driver: &api.Driver{}}
   145  	} else {
   146  		nw.pools, err = na.allocatePools(n)
   147  		if err != nil {
   148  			return errors.Wrapf(err, "failed allocating pools and gateway IP for network %s", n.ID)
   149  		}
   150  
   151  		if err := na.allocateDriverState(n); err != nil {
   152  			na.freePools(n, nw.pools)
   153  			return errors.Wrapf(err, "failed while allocating driver state for network %s", n.ID)
   154  		}
   155  	}
   156  
   157  	na.networks[n.ID] = nw
   158  
   159  	return nil
   160  }
   161  
   162  func (na *cnmNetworkAllocator) getNetwork(id string) *network {
   163  	return na.networks[id]
   164  }
   165  
   166  // Deallocate frees all the general and driver specific resources
   167  // which were assigned to the passed network.
   168  func (na *cnmNetworkAllocator) Deallocate(n *api.Network) error {
   169  	localNet := na.getNetwork(n.ID)
   170  	if localNet == nil {
   171  		return fmt.Errorf("could not get networker state for network %s", n.ID)
   172  	}
   173  
   174  	// No swarm-level resource deallocation needed for node-local networks
   175  	if localNet.isNodeLocal {
   176  		delete(na.networks, n.ID)
   177  		return nil
   178  	}
   179  
   180  	if err := na.freeDriverState(n); err != nil {
   181  		return errors.Wrapf(err, "failed to free driver state for network %s", n.ID)
   182  	}
   183  
   184  	delete(na.networks, n.ID)
   185  
   186  	return na.freePools(n, localNet.pools)
   187  }
   188  
   189  // AllocateService allocates all the network resources such as virtual
   190  // IP needed by the service.
   191  func (na *cnmNetworkAllocator) AllocateService(s *api.Service) (err error) {
   192  	defer func() {
   193  		if err != nil {
   194  			na.DeallocateService(s)
   195  		}
   196  	}()
   197  
   198  	if s.Endpoint == nil {
   199  		s.Endpoint = &api.Endpoint{}
   200  	}
   201  	s.Endpoint.Spec = s.Spec.Endpoint.Copy()
   202  
   203  	// If ResolutionMode is DNSRR do not try allocating VIPs, but
   204  	// free any VIP from previous state.
   205  	if s.Spec.Endpoint != nil && s.Spec.Endpoint.Mode == api.ResolutionModeDNSRoundRobin {
   206  		for _, vip := range s.Endpoint.VirtualIPs {
   207  			if err := na.deallocateVIP(vip); err != nil {
   208  				// don't bail here, deallocate as many as possible.
   209  				log.L.WithError(err).
   210  					WithField("vip.network", vip.NetworkID).
   211  					WithField("vip.addr", vip.Addr).Error("error deallocating vip")
   212  			}
   213  		}
   214  
   215  		s.Endpoint.VirtualIPs = nil
   216  
   217  		delete(na.services, s.ID)
   218  		return nil
   219  	}
   220  
   221  	specNetworks := serviceNetworks(s)
   222  
   223  	// Allocate VIPs for all the pre-populated endpoint attachments
   224  	eVIPs := s.Endpoint.VirtualIPs[:0]
   225  
   226  vipLoop:
   227  	for _, eAttach := range s.Endpoint.VirtualIPs {
   228  		if na.IsVIPOnIngressNetwork(eAttach) && networkallocator.IsIngressNetworkNeeded(s) {
   229  			if err = na.allocateVIP(eAttach); err != nil {
   230  				return err
   231  			}
   232  			eVIPs = append(eVIPs, eAttach)
   233  			continue vipLoop
   234  
   235  		}
   236  		for _, nAttach := range specNetworks {
   237  			if nAttach.Target == eAttach.NetworkID {
   238  				log.L.WithFields(log.Fields{"service_id": s.ID, "vip": eAttach.Addr}).Debug("allocate vip")
   239  				if err = na.allocateVIP(eAttach); err != nil {
   240  					return err
   241  				}
   242  				eVIPs = append(eVIPs, eAttach)
   243  				continue vipLoop
   244  			}
   245  		}
   246  		// If the network of the VIP is not part of the service spec,
   247  		// deallocate the vip
   248  		na.deallocateVIP(eAttach)
   249  	}
   250  
   251  networkLoop:
   252  	for _, nAttach := range specNetworks {
   253  		for _, vip := range s.Endpoint.VirtualIPs {
   254  			if vip.NetworkID == nAttach.Target {
   255  				continue networkLoop
   256  			}
   257  		}
   258  
   259  		vip := &api.Endpoint_VirtualIP{NetworkID: nAttach.Target}
   260  		if err = na.allocateVIP(vip); err != nil {
   261  			return err
   262  		}
   263  
   264  		eVIPs = append(eVIPs, vip)
   265  	}
   266  
   267  	if len(eVIPs) > 0 {
   268  		na.services[s.ID] = struct{}{}
   269  	} else {
   270  		delete(na.services, s.ID)
   271  	}
   272  
   273  	s.Endpoint.VirtualIPs = eVIPs
   274  	return nil
   275  }
   276  
   277  // DeallocateService de-allocates all the network resources such as
   278  // virtual IP associated with the service.
   279  func (na *cnmNetworkAllocator) DeallocateService(s *api.Service) error {
   280  	if s.Endpoint == nil {
   281  		return nil
   282  	}
   283  
   284  	for _, vip := range s.Endpoint.VirtualIPs {
   285  		if err := na.deallocateVIP(vip); err != nil {
   286  			// don't bail here, deallocate as many as possible.
   287  			log.L.WithError(err).
   288  				WithField("vip.network", vip.NetworkID).
   289  				WithField("vip.addr", vip.Addr).Error("error deallocating vip")
   290  		}
   291  	}
   292  	s.Endpoint.VirtualIPs = nil
   293  
   294  	delete(na.services, s.ID)
   295  
   296  	return nil
   297  }
   298  
   299  // IsAllocated returns if the passed network has been allocated or not.
   300  func (na *cnmNetworkAllocator) IsAllocated(n *api.Network) bool {
   301  	_, ok := na.networks[n.ID]
   302  	return ok
   303  }
   304  
   305  // IsTaskAllocated returns if the passed task has its network resources allocated or not.
   306  func (na *cnmNetworkAllocator) IsTaskAllocated(t *api.Task) bool {
   307  	// If the task is not found in the allocated set, then it is
   308  	// not allocated.
   309  	if _, ok := na.tasks[t.ID]; !ok {
   310  		return false
   311  	}
   312  
   313  	// If Networks is empty there is no way this Task is allocated.
   314  	if len(t.Networks) == 0 {
   315  		return false
   316  	}
   317  
   318  	// To determine whether the task has its resources allocated,
   319  	// we just need to look at one global scope network (in case of
   320  	// multi-network attachment).  This is because we make sure we
   321  	// allocate for every network or we allocate for none.
   322  
   323  	// Find the first global scope network
   324  	for _, nAttach := range t.Networks {
   325  		// If the network is not allocated, the task cannot be allocated.
   326  		localNet, ok := na.networks[nAttach.Network.ID]
   327  		if !ok {
   328  			return false
   329  		}
   330  
   331  		// Nothing else to check for local scope network
   332  		if localNet.isNodeLocal {
   333  			continue
   334  		}
   335  
   336  		// Addresses empty. Task is not allocated.
   337  		if len(nAttach.Addresses) == 0 {
   338  			return false
   339  		}
   340  
   341  		// The allocated IP address not found in local endpoint state. Not allocated.
   342  		if _, ok := localNet.endpoints[nAttach.Addresses[0]]; !ok {
   343  			return false
   344  		}
   345  	}
   346  
   347  	return true
   348  }
   349  
   350  // IsServiceAllocated returns false if the passed service needs to have network resources allocated/updated.
   351  func (na *cnmNetworkAllocator) IsServiceAllocated(s *api.Service, flags ...func(*networkallocator.ServiceAllocationOpts)) bool {
   352  	specNetworks := serviceNetworks(s)
   353  
   354  	// If endpoint mode is VIP and allocator does not have the
   355  	// service in VIP allocated set then it needs to be allocated.
   356  	if len(specNetworks) != 0 &&
   357  		(s.Spec.Endpoint == nil ||
   358  			s.Spec.Endpoint.Mode == api.ResolutionModeVirtualIP) {
   359  
   360  		if _, ok := na.services[s.ID]; !ok {
   361  			return false
   362  		}
   363  
   364  		if s.Endpoint == nil || len(s.Endpoint.VirtualIPs) == 0 {
   365  			return false
   366  		}
   367  
   368  		// If the spec has networks which don't have a corresponding VIP,
   369  		// the service needs to be allocated.
   370  	networkLoop:
   371  		for _, net := range specNetworks {
   372  			for _, vip := range s.Endpoint.VirtualIPs {
   373  				if vip.NetworkID == net.Target {
   374  					continue networkLoop
   375  				}
   376  			}
   377  			return false
   378  		}
   379  	}
   380  
   381  	// If the spec no longer has networks attached and has a vip allocated
   382  	// from previous spec the service needs to allocated.
   383  	if s.Endpoint != nil {
   384  	vipLoop:
   385  		for _, vip := range s.Endpoint.VirtualIPs {
   386  			if na.IsVIPOnIngressNetwork(vip) && networkallocator.IsIngressNetworkNeeded(s) {
   387  				// This checks the condition when ingress network is needed
   388  				// but allocation has not been done.
   389  				if _, ok := na.services[s.ID]; !ok {
   390  					return false
   391  				}
   392  				continue vipLoop
   393  			}
   394  			for _, net := range specNetworks {
   395  				if vip.NetworkID == net.Target {
   396  					continue vipLoop
   397  				}
   398  			}
   399  			return false
   400  		}
   401  	}
   402  
   403  	// If the endpoint mode is DNSRR and allocator has the service
   404  	// in VIP allocated set then we return to be allocated to make
   405  	// sure the allocator triggers networkallocator to free up the
   406  	// resources if any.
   407  	if s.Spec.Endpoint != nil && s.Spec.Endpoint.Mode == api.ResolutionModeDNSRoundRobin {
   408  		if _, ok := na.services[s.ID]; ok {
   409  			return false
   410  		}
   411  	}
   412  
   413  	return true
   414  }
   415  
   416  // AllocateTask allocates all the endpoint resources for all the
   417  // networks that a task is attached to.
   418  func (na *cnmNetworkAllocator) AllocateTask(t *api.Task) error {
   419  	for i, nAttach := range t.Networks {
   420  		if localNet := na.getNetwork(nAttach.Network.ID); localNet != nil && localNet.isNodeLocal {
   421  			continue
   422  		}
   423  		if err := na.allocateNetworkIPs(nAttach); err != nil {
   424  			if err := na.releaseEndpoints(t.Networks[:i]); err != nil {
   425  				log.G(context.TODO()).WithError(err).Errorf("failed to release IP addresses while rolling back allocation for task %s network %s", t.ID, nAttach.Network.ID)
   426  			}
   427  			return errors.Wrapf(err, "failed to allocate network IP for task %s network %s", t.ID, nAttach.Network.ID)
   428  		}
   429  	}
   430  
   431  	na.tasks[t.ID] = struct{}{}
   432  
   433  	return nil
   434  }
   435  
   436  // DeallocateTask releases all the endpoint resources for all the
   437  // networks that a task is attached to.
   438  func (na *cnmNetworkAllocator) DeallocateTask(t *api.Task) error {
   439  	delete(na.tasks, t.ID)
   440  	return na.releaseEndpoints(t.Networks)
   441  }
   442  
   443  // IsAttachmentAllocated returns if the passed node and network has resources allocated or not.
   444  func (na *cnmNetworkAllocator) IsAttachmentAllocated(node *api.Node, networkAttachment *api.NetworkAttachment) bool {
   445  	if node == nil {
   446  		return false
   447  	}
   448  
   449  	if networkAttachment == nil || networkAttachment.Network == nil {
   450  		return false
   451  	}
   452  
   453  	// If the node is not found in the allocated set, then it is
   454  	// not allocated.
   455  	if _, ok := na.nodes[node.ID]; !ok {
   456  		return false
   457  	}
   458  
   459  	// If the network is not found in the allocated set, then it is
   460  	// not allocated.
   461  	if _, ok := na.nodes[node.ID][networkAttachment.Network.ID]; !ok {
   462  		return false
   463  	}
   464  
   465  	// If the network is not allocated, the node cannot be allocated.
   466  	localNet, ok := na.networks[networkAttachment.Network.ID]
   467  	if !ok {
   468  		return false
   469  	}
   470  
   471  	// Addresses empty, not allocated.
   472  	if len(networkAttachment.Addresses) == 0 {
   473  		return false
   474  	}
   475  
   476  	// The allocated IP address not found in local endpoint state. Not allocated.
   477  	if _, ok := localNet.endpoints[networkAttachment.Addresses[0]]; !ok {
   478  		return false
   479  	}
   480  
   481  	return true
   482  }
   483  
   484  // AllocateAttachment allocates the IP addresses for a LB in a network
   485  // on a given node
   486  func (na *cnmNetworkAllocator) AllocateAttachment(node *api.Node, networkAttachment *api.NetworkAttachment) error {
   487  
   488  	if err := na.allocateNetworkIPs(networkAttachment); err != nil {
   489  		return err
   490  	}
   491  
   492  	if na.nodes[node.ID] == nil {
   493  		na.nodes[node.ID] = make(map[string]struct{})
   494  	}
   495  	na.nodes[node.ID][networkAttachment.Network.ID] = struct{}{}
   496  
   497  	return nil
   498  }
   499  
   500  // DeallocateAttachment deallocates the IP addresses for a LB in a network to
   501  // which the node is attached.
   502  func (na *cnmNetworkAllocator) DeallocateAttachment(node *api.Node, networkAttachment *api.NetworkAttachment) error {
   503  
   504  	delete(na.nodes[node.ID], networkAttachment.Network.ID)
   505  	if len(na.nodes[node.ID]) == 0 {
   506  		delete(na.nodes, node.ID)
   507  	}
   508  
   509  	return na.releaseEndpoints([]*api.NetworkAttachment{networkAttachment})
   510  }
   511  
   512  func (na *cnmNetworkAllocator) releaseEndpoints(networks []*api.NetworkAttachment) error {
   513  	for _, nAttach := range networks {
   514  		localNet := na.getNetwork(nAttach.Network.ID)
   515  		if localNet == nil {
   516  			return fmt.Errorf("could not find network allocator state for network %s", nAttach.Network.ID)
   517  		}
   518  
   519  		if localNet.isNodeLocal {
   520  			continue
   521  		}
   522  
   523  		ipam, _, _, err := na.resolveIPAM(nAttach.Network)
   524  		if err != nil {
   525  			return errors.Wrap(err, "failed to resolve IPAM while releasing")
   526  		}
   527  
   528  		// Do not fail and bail out if we fail to release IP
   529  		// address here. Keep going and try releasing as many
   530  		// addresses as possible.
   531  		for _, addr := range nAttach.Addresses {
   532  			// Retrieve the poolID and immediately nuke
   533  			// out the mapping.
   534  			poolID := localNet.endpoints[addr]
   535  			delete(localNet.endpoints, addr)
   536  
   537  			ip, _, err := net.ParseCIDR(addr)
   538  			if err != nil {
   539  				log.G(context.TODO()).Errorf("Could not parse IP address %s while releasing", addr)
   540  				continue
   541  			}
   542  
   543  			if err := ipam.ReleaseAddress(poolID, ip); err != nil {
   544  				log.G(context.TODO()).WithError(err).Errorf("IPAM failure while releasing IP address %s", addr)
   545  			}
   546  		}
   547  
   548  		// Clear out the address list when we are done with
   549  		// this network.
   550  		nAttach.Addresses = nil
   551  	}
   552  
   553  	return nil
   554  }
   555  
   556  // allocate virtual IP for a single endpoint attachment of the service.
   557  func (na *cnmNetworkAllocator) allocateVIP(vip *api.Endpoint_VirtualIP) error {
   558  	var opts map[string]string
   559  	localNet := na.getNetwork(vip.NetworkID)
   560  	if localNet == nil {
   561  		return errors.New("networkallocator: could not find local network state")
   562  	}
   563  
   564  	if localNet.isNodeLocal {
   565  		return nil
   566  	}
   567  
   568  	// If this IP is already allocated in memory we don't need to
   569  	// do anything.
   570  	if _, ok := localNet.endpoints[vip.Addr]; ok {
   571  		return nil
   572  	}
   573  
   574  	ipam, _, _, err := na.resolveIPAM(localNet.nw)
   575  	if err != nil {
   576  		return errors.Wrap(err, "failed to resolve IPAM while allocating")
   577  	}
   578  
   579  	var addr net.IP
   580  	if vip.Addr != "" {
   581  		var err error
   582  
   583  		addr, _, err = net.ParseCIDR(vip.Addr)
   584  		if err != nil {
   585  			return err
   586  		}
   587  	}
   588  	if localNet.nw.IPAM != nil && localNet.nw.IPAM.Driver != nil {
   589  		// set ipam allocation method to serial
   590  		opts = setIPAMSerialAlloc(localNet.nw.IPAM.Driver.Options)
   591  	}
   592  
   593  	for _, poolID := range localNet.pools {
   594  		ip, _, err := ipam.RequestAddress(poolID, addr, opts)
   595  		if err != nil && err != ipamapi.ErrNoAvailableIPs && err != ipamapi.ErrIPOutOfRange {
   596  			return errors.Wrap(err, "could not allocate VIP from IPAM")
   597  		}
   598  
   599  		// If we got an address then we are done.
   600  		if err == nil {
   601  			ipStr := ip.String()
   602  			localNet.endpoints[ipStr] = poolID
   603  			vip.Addr = ipStr
   604  			return nil
   605  		}
   606  	}
   607  
   608  	return errors.New("could not find an available IP while allocating VIP")
   609  }
   610  
   611  func (na *cnmNetworkAllocator) deallocateVIP(vip *api.Endpoint_VirtualIP) error {
   612  	localNet := na.getNetwork(vip.NetworkID)
   613  	if localNet == nil {
   614  		return errors.New("networkallocator: could not find local network state")
   615  	}
   616  	if localNet.isNodeLocal {
   617  		return nil
   618  	}
   619  	ipam, _, _, err := na.resolveIPAM(localNet.nw)
   620  	if err != nil {
   621  		return errors.Wrap(err, "failed to resolve IPAM while allocating")
   622  	}
   623  
   624  	// Retrieve the poolID and immediately nuke
   625  	// out the mapping.
   626  	poolID := localNet.endpoints[vip.Addr]
   627  	delete(localNet.endpoints, vip.Addr)
   628  
   629  	ip, _, err := net.ParseCIDR(vip.Addr)
   630  	if err != nil {
   631  		log.G(context.TODO()).Errorf("Could not parse VIP address %s while releasing", vip.Addr)
   632  		return err
   633  	}
   634  
   635  	if err := ipam.ReleaseAddress(poolID, ip); err != nil {
   636  		log.G(context.TODO()).WithError(err).Errorf("IPAM failure while releasing VIP address %s", vip.Addr)
   637  		return err
   638  	}
   639  
   640  	return nil
   641  }
   642  
   643  // allocate the IP addresses for a single network attachment of the task.
   644  func (na *cnmNetworkAllocator) allocateNetworkIPs(nAttach *api.NetworkAttachment) error {
   645  	var ip *net.IPNet
   646  	var opts map[string]string
   647  
   648  	ipam, _, _, err := na.resolveIPAM(nAttach.Network)
   649  	if err != nil {
   650  		return errors.Wrap(err, "failed to resolve IPAM while allocating")
   651  	}
   652  
   653  	localNet := na.getNetwork(nAttach.Network.ID)
   654  	if localNet == nil {
   655  		return fmt.Errorf("could not find network allocator state for network %s", nAttach.Network.ID)
   656  	}
   657  
   658  	addresses := nAttach.Addresses
   659  	if len(addresses) == 0 {
   660  		addresses = []string{""}
   661  	}
   662  
   663  	for i, rawAddr := range addresses {
   664  		var addr net.IP
   665  		if rawAddr != "" {
   666  			var err error
   667  			addr, _, err = net.ParseCIDR(rawAddr)
   668  			if err != nil {
   669  				addr = net.ParseIP(rawAddr)
   670  
   671  				if addr == nil {
   672  					return errors.Wrapf(err, "could not parse address string %s", rawAddr)
   673  				}
   674  			}
   675  		}
   676  		// Set the ipam options if the network has an ipam driver.
   677  		if localNet.nw.IPAM != nil && localNet.nw.IPAM.Driver != nil {
   678  			// set ipam allocation method to serial
   679  			opts = setIPAMSerialAlloc(localNet.nw.IPAM.Driver.Options)
   680  		}
   681  
   682  		for _, poolID := range localNet.pools {
   683  			var err error
   684  
   685  			ip, _, err = ipam.RequestAddress(poolID, addr, opts)
   686  			if err != nil && err != ipamapi.ErrNoAvailableIPs && err != ipamapi.ErrIPOutOfRange {
   687  				return errors.Wrap(err, "could not allocate IP from IPAM")
   688  			}
   689  
   690  			// If we got an address then we are done.
   691  			if err == nil {
   692  				ipStr := ip.String()
   693  				localNet.endpoints[ipStr] = poolID
   694  				addresses[i] = ipStr
   695  				nAttach.Addresses = addresses
   696  				return nil
   697  			}
   698  		}
   699  	}
   700  
   701  	return errors.New("could not find an available IP")
   702  }
   703  
   704  func (na *cnmNetworkAllocator) freeDriverState(n *api.Network) error {
   705  	d, err := na.resolveDriver(n)
   706  	if err != nil {
   707  		return err
   708  	}
   709  
   710  	return d.driver.NetworkFree(n.ID)
   711  }
   712  
   713  func (na *cnmNetworkAllocator) allocateDriverState(n *api.Network) error {
   714  	d, err := na.resolveDriver(n)
   715  	if err != nil {
   716  		return err
   717  	}
   718  
   719  	options := make(map[string]string)
   720  	// reconcile the driver specific options from the network spec
   721  	// and from the operational state retrieved from the store
   722  	if n.Spec.DriverConfig != nil {
   723  		for k, v := range n.Spec.DriverConfig.Options {
   724  			options[k] = v
   725  		}
   726  	}
   727  	if n.DriverState != nil {
   728  		for k, v := range n.DriverState.Options {
   729  			options[k] = v
   730  		}
   731  	}
   732  
   733  	// Construct IPAM data for driver consumption.
   734  	ipv4Data := make([]driverapi.IPAMData, 0, len(n.IPAM.Configs))
   735  	for _, ic := range n.IPAM.Configs {
   736  		if ic.Family == api.IPAMConfig_IPV6 {
   737  			continue
   738  		}
   739  
   740  		_, subnet, err := net.ParseCIDR(ic.Subnet)
   741  		if err != nil {
   742  			return errors.Wrapf(err, "error parsing subnet %s while allocating driver state", ic.Subnet)
   743  		}
   744  
   745  		gwIP := net.ParseIP(ic.Gateway)
   746  		gwNet := &net.IPNet{
   747  			IP:   gwIP,
   748  			Mask: subnet.Mask,
   749  		}
   750  
   751  		data := driverapi.IPAMData{
   752  			Pool:    subnet,
   753  			Gateway: gwNet,
   754  		}
   755  
   756  		ipv4Data = append(ipv4Data, data)
   757  	}
   758  
   759  	ds, err := d.driver.NetworkAllocate(n.ID, options, ipv4Data, nil)
   760  	if err != nil {
   761  		return err
   762  	}
   763  
   764  	// Update network object with the obtained driver state.
   765  	n.DriverState = &api.Driver{
   766  		Name:    d.name,
   767  		Options: ds,
   768  	}
   769  
   770  	return nil
   771  }
   772  
   773  // Resolve network driver
   774  func (na *cnmNetworkAllocator) resolveDriver(n *api.Network) (*networkDriver, error) {
   775  	dName := DefaultDriver
   776  	if n.Spec.DriverConfig != nil && n.Spec.DriverConfig.Name != "" {
   777  		dName = n.Spec.DriverConfig.Name
   778  	}
   779  
   780  	d, drvcap := na.networkRegistry.Driver(dName)
   781  	if d == nil {
   782  		err := na.loadDriver(dName)
   783  		if err != nil {
   784  			return nil, err
   785  		}
   786  
   787  		d, drvcap = na.networkRegistry.Driver(dName)
   788  		if d == nil {
   789  			return nil, fmt.Errorf("could not resolve network driver %s", dName)
   790  		}
   791  	}
   792  
   793  	return &networkDriver{driver: d, capability: &drvcap, name: dName}, nil
   794  }
   795  
   796  func (na *cnmNetworkAllocator) loadDriver(name string) error {
   797  	if na.pg == nil {
   798  		return errors.New("plugin store is uninitialized")
   799  	}
   800  	_, err := na.pg.Get(name, driverapi.NetworkPluginEndpointType, plugingetter.Lookup)
   801  	return err
   802  }
   803  
   804  // Resolve the IPAM driver
   805  func (na *cnmNetworkAllocator) resolveIPAM(n *api.Network) (ipamapi.Ipam, string, map[string]string, error) {
   806  	dName := ipamapi.DefaultIPAM
   807  	if n.Spec.IPAM != nil && n.Spec.IPAM.Driver != nil && n.Spec.IPAM.Driver.Name != "" {
   808  		dName = n.Spec.IPAM.Driver.Name
   809  	}
   810  
   811  	var dOptions map[string]string
   812  	if n.Spec.IPAM != nil && n.Spec.IPAM.Driver != nil && len(n.Spec.IPAM.Driver.Options) != 0 {
   813  		dOptions = n.Spec.IPAM.Driver.Options
   814  	}
   815  
   816  	ipam, _ := na.ipamRegistry.IPAM(dName)
   817  	if ipam == nil {
   818  		return nil, "", nil, fmt.Errorf("could not resolve IPAM driver %s", dName)
   819  	}
   820  
   821  	return ipam, dName, dOptions, nil
   822  }
   823  
   824  func (na *cnmNetworkAllocator) freePools(n *api.Network, pools map[string]string) error {
   825  	ipam, _, _, err := na.resolveIPAM(n)
   826  	if err != nil {
   827  		return errors.Wrapf(err, "failed to resolve IPAM while freeing pools for network %s", n.ID)
   828  	}
   829  
   830  	releasePools(ipam, n.IPAM.Configs, pools)
   831  	return nil
   832  }
   833  
   834  func releasePools(ipam ipamapi.Ipam, icList []*api.IPAMConfig, pools map[string]string) {
   835  	for _, ic := range icList {
   836  		if err := ipam.ReleaseAddress(pools[ic.Subnet], net.ParseIP(ic.Gateway)); err != nil {
   837  			log.G(context.TODO()).WithError(err).Errorf("Failed to release address %s", ic.Subnet)
   838  		}
   839  	}
   840  
   841  	for k, p := range pools {
   842  		if err := ipam.ReleasePool(p); err != nil {
   843  			log.G(context.TODO()).WithError(err).Errorf("Failed to release pool %s", k)
   844  		}
   845  	}
   846  }
   847  
   848  func (na *cnmNetworkAllocator) allocatePools(n *api.Network) (map[string]string, error) {
   849  	ipam, dName, dOptions, err := na.resolveIPAM(n)
   850  	if err != nil {
   851  		return nil, err
   852  	}
   853  
   854  	// We don't support user defined address spaces yet so just
   855  	// retrieve default address space names for the driver.
   856  	_, asName, err := ipam.GetDefaultAddressSpaces()
   857  	if err != nil {
   858  		return nil, err
   859  	}
   860  
   861  	pools := make(map[string]string)
   862  
   863  	var ipamConfigs []*api.IPAMConfig
   864  
   865  	// If there is non-nil IPAM state always prefer those subnet
   866  	// configs over Spec configs.
   867  	if n.IPAM != nil {
   868  		ipamConfigs = n.IPAM.Configs
   869  	} else if n.Spec.IPAM != nil {
   870  		ipamConfigs = make([]*api.IPAMConfig, len(n.Spec.IPAM.Configs))
   871  		copy(ipamConfigs, n.Spec.IPAM.Configs)
   872  	}
   873  
   874  	// Append an empty slot for subnet allocation if there are no
   875  	// IPAM configs from either spec or state.
   876  	if len(ipamConfigs) == 0 {
   877  		ipamConfigs = append(ipamConfigs, &api.IPAMConfig{Family: api.IPAMConfig_IPV4})
   878  	}
   879  
   880  	// Update the runtime IPAM configurations with initial state
   881  	n.IPAM = &api.IPAMOptions{
   882  		Driver:  &api.Driver{Name: dName, Options: dOptions},
   883  		Configs: ipamConfigs,
   884  	}
   885  
   886  	for i, ic := range ipamConfigs {
   887  		poolID, poolIP, meta, err := ipam.RequestPool(asName, ic.Subnet, ic.Range, dOptions, false)
   888  		if err != nil {
   889  			// Rollback by releasing all the resources allocated so far.
   890  			releasePools(ipam, ipamConfigs[:i], pools)
   891  			return nil, err
   892  		}
   893  		pools[poolIP.String()] = poolID
   894  
   895  		// The IPAM contract allows the IPAM driver to autonomously
   896  		// provide a network gateway in response to the pool request.
   897  		// But if the network spec contains a gateway, we will allocate
   898  		// it irrespective of whether the ipam driver returned one already.
   899  		// If none of the above is true, we need to allocate one now, and
   900  		// let the driver know this request is for the network gateway.
   901  		var (
   902  			gwIP *net.IPNet
   903  			ip   net.IP
   904  		)
   905  		if gws, ok := meta[netlabel.Gateway]; ok {
   906  			if ip, gwIP, err = net.ParseCIDR(gws); err != nil {
   907  				return nil, fmt.Errorf("failed to parse gateway address (%v) returned by ipam driver: %v", gws, err)
   908  			}
   909  			gwIP.IP = ip
   910  		}
   911  		if dOptions == nil {
   912  			dOptions = make(map[string]string)
   913  		}
   914  		dOptions[ipamapi.RequestAddressType] = netlabel.Gateway
   915  		// set ipam allocation method to serial
   916  		dOptions = setIPAMSerialAlloc(dOptions)
   917  		defer delete(dOptions, ipamapi.RequestAddressType)
   918  
   919  		if ic.Gateway != "" || gwIP == nil {
   920  			gwIP, _, err = ipam.RequestAddress(poolID, net.ParseIP(ic.Gateway), dOptions)
   921  			if err != nil {
   922  				// Rollback by releasing all the resources allocated so far.
   923  				releasePools(ipam, ipamConfigs[:i], pools)
   924  				return nil, err
   925  			}
   926  		}
   927  
   928  		if ic.Subnet == "" {
   929  			ic.Subnet = poolIP.String()
   930  		}
   931  
   932  		if ic.Gateway == "" {
   933  			ic.Gateway = gwIP.IP.String()
   934  		}
   935  
   936  	}
   937  
   938  	return pools, nil
   939  }
   940  
   941  func serviceNetworks(s *api.Service) []*api.NetworkAttachmentConfig {
   942  	// Always prefer NetworkAttachmentConfig in the TaskSpec
   943  	if len(s.Spec.Task.Networks) == 0 && len(s.Spec.Networks) != 0 {
   944  		return s.Spec.Networks
   945  	}
   946  	return s.Spec.Task.Networks
   947  }
   948  
   949  // IsVIPOnIngressNetwork check if the vip is in ingress network
   950  func (na *cnmNetworkAllocator) IsVIPOnIngressNetwork(vip *api.Endpoint_VirtualIP) bool {
   951  	if vip == nil {
   952  		return false
   953  	}
   954  
   955  	localNet := na.getNetwork(vip.NetworkID)
   956  	if localNet != nil && localNet.nw != nil {
   957  		return networkallocator.IsIngressNetwork(localNet.nw)
   958  	}
   959  	return false
   960  }
   961  
   962  // IsBuiltInDriver returns whether the passed driver is an internal network driver
   963  func IsBuiltInDriver(name string) bool {
   964  	n := strings.ToLower(name)
   965  	_, ok := initializers[n]
   966  	return ok
   967  }
   968  
   969  // setIPAMSerialAlloc sets the ipam allocation method to serial
   970  func setIPAMSerialAlloc(opts map[string]string) map[string]string {
   971  	if opts == nil {
   972  		opts = make(map[string]string)
   973  	}
   974  	if _, ok := opts[ipamapi.AllocSerialPrefix]; !ok {
   975  		opts[ipamapi.AllocSerialPrefix] = "true"
   976  	}
   977  	return opts
   978  }