github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/ipam/allocator.go (about)

     1  package ipam
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"sort"
     7  	"sync"
     8  
     9  	"github.com/docker/libnetwork/bitseq"
    10  	"github.com/docker/libnetwork/datastore"
    11  	"github.com/docker/libnetwork/discoverapi"
    12  	"github.com/docker/libnetwork/ipamapi"
    13  	"github.com/docker/libnetwork/ipamutils"
    14  	"github.com/docker/libnetwork/types"
    15  	"github.com/sirupsen/logrus"
    16  )
    17  
    18  const (
    19  	localAddressSpace  = "LocalDefault"
    20  	globalAddressSpace = "GlobalDefault"
    21  	// The biggest configurable host subnets
    22  	minNetSize   = 8
    23  	minNetSizeV6 = 64
    24  	// datastore keyes for ipam objects
    25  	dsConfigKey = "ipam/" + ipamapi.DefaultIPAM + "/config"
    26  	dsDataKey   = "ipam/" + ipamapi.DefaultIPAM + "/data"
    27  )
    28  
    29  // Allocator provides per address space ipv4/ipv6 book keeping
    30  type Allocator struct {
    31  	// Predefined pools for default address spaces
    32  	// Separate from the addrSpace because they should not be serialized
    33  	predefined             map[string][]*net.IPNet
    34  	predefinedStartIndices map[string]int
    35  	// The (potentially serialized) address spaces
    36  	addrSpaces map[string]*addrSpace
    37  	// stores        []datastore.Datastore
    38  	// Allocated addresses in each address space's subnet
    39  	addresses map[SubnetKey]*bitseq.Handle
    40  	sync.Mutex
    41  }
    42  
    43  // NewAllocator returns an instance of libnetwork ipam
    44  func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
    45  	a := &Allocator{}
    46  
    47  	// Load predefined subnet pools
    48  
    49  	a.predefined = map[string][]*net.IPNet{
    50  		localAddressSpace:  ipamutils.GetLocalScopeDefaultNetworks(),
    51  		globalAddressSpace: ipamutils.GetGlobalScopeDefaultNetworks(),
    52  	}
    53  
    54  	// Initialize asIndices map
    55  	a.predefinedStartIndices = make(map[string]int)
    56  
    57  	// Initialize bitseq map
    58  	a.addresses = make(map[SubnetKey]*bitseq.Handle)
    59  
    60  	// Initialize address spaces
    61  	a.addrSpaces = make(map[string]*addrSpace)
    62  	for _, aspc := range []struct {
    63  		as string
    64  		ds datastore.DataStore
    65  	}{
    66  		{localAddressSpace, lcDs},
    67  		{globalAddressSpace, glDs},
    68  	} {
    69  		a.initializeAddressSpace(aspc.as, aspc.ds)
    70  	}
    71  
    72  	return a, nil
    73  }
    74  
    75  func (a *Allocator) refresh(as string) error {
    76  	aSpace, err := a.getAddressSpaceFromStore(as)
    77  	if err != nil {
    78  		return types.InternalErrorf("error getting pools config from store: %v", err)
    79  	}
    80  
    81  	if aSpace == nil {
    82  		return nil
    83  	}
    84  
    85  	a.Lock()
    86  	a.addrSpaces[as] = aSpace
    87  	a.Unlock()
    88  
    89  	return nil
    90  }
    91  
    92  func (a *Allocator) updateBitMasks(aSpace *addrSpace) error {
    93  	var inserterList []func() error
    94  
    95  	aSpace.Lock()
    96  	for k, v := range aSpace.subnets {
    97  		if v.Range == nil {
    98  			kk := k
    99  			vv := v
   100  			inserterList = append(inserterList, func() error { return a.insertBitMask(kk, vv.Pool) })
   101  		}
   102  	}
   103  	aSpace.Unlock()
   104  
   105  	// Add the bitmasks (data could come from datastore)
   106  	if inserterList != nil {
   107  		for _, f := range inserterList {
   108  			if err := f(); err != nil {
   109  				return err
   110  			}
   111  		}
   112  	}
   113  
   114  	return nil
   115  }
   116  
   117  // Checks for and fixes damaged bitmask.
   118  func (a *Allocator) checkConsistency(as string) {
   119  	var sKeyList []SubnetKey
   120  
   121  	// Retrieve this address space's configuration and bitmasks from the datastore
   122  	a.refresh(as)
   123  	a.Lock()
   124  	aSpace, ok := a.addrSpaces[as]
   125  	a.Unlock()
   126  	if !ok {
   127  		return
   128  	}
   129  	a.updateBitMasks(aSpace)
   130  
   131  	aSpace.Lock()
   132  	for sk, pd := range aSpace.subnets {
   133  		if pd.Range != nil {
   134  			continue
   135  		}
   136  		sKeyList = append(sKeyList, sk)
   137  	}
   138  	aSpace.Unlock()
   139  
   140  	for _, sk := range sKeyList {
   141  		a.Lock()
   142  		bm := a.addresses[sk]
   143  		a.Unlock()
   144  		if err := bm.CheckConsistency(); err != nil {
   145  			logrus.Warnf("Error while running consistency check for %s: %v", sk, err)
   146  		}
   147  	}
   148  }
   149  
   150  func (a *Allocator) initializeAddressSpace(as string, ds datastore.DataStore) error {
   151  	scope := ""
   152  	if ds != nil {
   153  		scope = ds.Scope()
   154  	}
   155  
   156  	a.Lock()
   157  	if currAS, ok := a.addrSpaces[as]; ok {
   158  		if currAS.ds != nil {
   159  			a.Unlock()
   160  			return types.ForbiddenErrorf("a datastore is already configured for the address space %s", as)
   161  		}
   162  	}
   163  	a.addrSpaces[as] = &addrSpace{
   164  		subnets: map[SubnetKey]*PoolData{},
   165  		id:      dsConfigKey + "/" + as,
   166  		scope:   scope,
   167  		ds:      ds,
   168  		alloc:   a,
   169  	}
   170  	a.Unlock()
   171  
   172  	a.checkConsistency(as)
   173  
   174  	return nil
   175  }
   176  
   177  // DiscoverNew informs the allocator about a new global scope datastore
   178  func (a *Allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
   179  	if dType != discoverapi.DatastoreConfig {
   180  		return nil
   181  	}
   182  
   183  	dsc, ok := data.(discoverapi.DatastoreConfigData)
   184  	if !ok {
   185  		return types.InternalErrorf("incorrect data in datastore update notification: %v", data)
   186  	}
   187  
   188  	ds, err := datastore.NewDataStoreFromConfig(dsc)
   189  	if err != nil {
   190  		return err
   191  	}
   192  
   193  	return a.initializeAddressSpace(globalAddressSpace, ds)
   194  }
   195  
   196  // DiscoverDelete is a notification of no interest for the allocator
   197  func (a *Allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
   198  	return nil
   199  }
   200  
   201  // GetDefaultAddressSpaces returns the local and global default address spaces
   202  func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) {
   203  	return localAddressSpace, globalAddressSpace, nil
   204  }
   205  
   206  // RequestPool returns an address pool along with its unique id.
   207  // addressSpace must be a valid address space name and must not be the empty string.
   208  // If pool is the empty string then the default predefined pool for addressSpace will be used, otherwise pool must be a valid IP address and length in CIDR notation.
   209  // If subPool is not empty, it must be a valid IP address and length in CIDR notation which is a sub-range of pool.
   210  // subPool must be empty if pool is empty.
   211  func (a *Allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
   212  	logrus.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6)
   213  
   214  	k, nw, ipr, err := a.parsePoolRequest(addressSpace, pool, subPool, v6)
   215  	if err != nil {
   216  		return "", nil, nil, types.InternalErrorf("failed to parse pool request for address space %q pool %q subpool %q: %v", addressSpace, pool, subPool, err)
   217  	}
   218  
   219  	pdf := k == nil
   220  
   221  retry:
   222  	if pdf {
   223  		if nw, err = a.getPredefinedPool(addressSpace, v6); err != nil {
   224  			return "", nil, nil, err
   225  		}
   226  		k = &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String()}
   227  	}
   228  
   229  	if err := a.refresh(addressSpace); err != nil {
   230  		return "", nil, nil, err
   231  	}
   232  
   233  	aSpace, err := a.getAddrSpace(addressSpace)
   234  	if err != nil {
   235  		return "", nil, nil, err
   236  	}
   237  
   238  	insert, err := aSpace.updatePoolDBOnAdd(*k, nw, ipr, pdf)
   239  	if err != nil {
   240  		if _, ok := err.(types.MaskableError); ok {
   241  			logrus.Debugf("Retrying predefined pool search: %v", err)
   242  			goto retry
   243  		}
   244  		return "", nil, nil, err
   245  	}
   246  
   247  	if err := a.writeToStore(aSpace); err != nil {
   248  		if _, ok := err.(types.RetryError); !ok {
   249  			return "", nil, nil, types.InternalErrorf("pool configuration failed because of %s", err.Error())
   250  		}
   251  
   252  		goto retry
   253  	}
   254  
   255  	return k.String(), nw, nil, insert()
   256  }
   257  
   258  // ReleasePool releases the address pool identified by the passed id
   259  func (a *Allocator) ReleasePool(poolID string) error {
   260  	logrus.Debugf("ReleasePool(%s)", poolID)
   261  	k := SubnetKey{}
   262  	if err := k.FromString(poolID); err != nil {
   263  		return types.BadRequestErrorf("invalid pool id: %s", poolID)
   264  	}
   265  
   266  retry:
   267  	if err := a.refresh(k.AddressSpace); err != nil {
   268  		return err
   269  	}
   270  
   271  	aSpace, err := a.getAddrSpace(k.AddressSpace)
   272  	if err != nil {
   273  		return err
   274  	}
   275  
   276  	remove, err := aSpace.updatePoolDBOnRemoval(k)
   277  	if err != nil {
   278  		return err
   279  	}
   280  
   281  	if err = a.writeToStore(aSpace); err != nil {
   282  		if _, ok := err.(types.RetryError); !ok {
   283  			return types.InternalErrorf("pool (%s) removal failed because of %v", poolID, err)
   284  		}
   285  		goto retry
   286  	}
   287  
   288  	return remove()
   289  }
   290  
   291  // Given the address space, returns the local or global PoolConfig based on whether the
   292  // address space is local or global. AddressSpace locality is registered with IPAM out of band.
   293  func (a *Allocator) getAddrSpace(as string) (*addrSpace, error) {
   294  	a.Lock()
   295  	defer a.Unlock()
   296  	aSpace, ok := a.addrSpaces[as]
   297  	if !ok {
   298  		return nil, types.BadRequestErrorf("cannot find address space %s (most likely the backing datastore is not configured)", as)
   299  	}
   300  	return aSpace, nil
   301  }
   302  
   303  // parsePoolRequest parses and validates a request to create a new pool under addressSpace and returns
   304  // a SubnetKey, network and range describing the request.
   305  func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool) (*SubnetKey, *net.IPNet, *AddressRange, error) {
   306  	var (
   307  		nw  *net.IPNet
   308  		ipr *AddressRange
   309  		err error
   310  	)
   311  
   312  	if addressSpace == "" {
   313  		return nil, nil, nil, ipamapi.ErrInvalidAddressSpace
   314  	}
   315  
   316  	if pool == "" && subPool != "" {
   317  		return nil, nil, nil, ipamapi.ErrInvalidSubPool
   318  	}
   319  
   320  	if pool == "" {
   321  		return nil, nil, nil, nil
   322  	}
   323  
   324  	if _, nw, err = net.ParseCIDR(pool); err != nil {
   325  		return nil, nil, nil, ipamapi.ErrInvalidPool
   326  	}
   327  
   328  	if subPool != "" {
   329  		if ipr, err = getAddressRange(subPool, nw); err != nil {
   330  			return nil, nil, nil, err
   331  		}
   332  	}
   333  
   334  	return &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String(), ChildSubnet: subPool}, nw, ipr, nil
   335  }
   336  
   337  func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
   338  	//logrus.Debugf("Inserting bitmask (%s, %s)", key.String(), pool.String())
   339  
   340  	store := a.getStore(key.AddressSpace)
   341  	ipVer := getAddressVersion(pool.IP)
   342  	ones, bits := pool.Mask.Size()
   343  	numAddresses := uint64(1 << uint(bits-ones))
   344  
   345  	// Allow /64 subnet
   346  	if ipVer == v6 && numAddresses == 0 {
   347  		numAddresses--
   348  	}
   349  
   350  	// Generate the new address masks. AddressMask content may come from datastore
   351  	h, err := bitseq.NewHandle(dsDataKey, store, key.String(), numAddresses)
   352  	if err != nil {
   353  		return err
   354  	}
   355  
   356  	// Do not let network identifier address be reserved
   357  	// Do the same for IPv6 so that bridge ip starts with XXXX...::1
   358  	h.Set(0)
   359  
   360  	// Do not let broadcast address be reserved
   361  	if ipVer == v4 {
   362  		h.Set(numAddresses - 1)
   363  	}
   364  
   365  	a.Lock()
   366  	a.addresses[key] = h
   367  	a.Unlock()
   368  	return nil
   369  }
   370  
   371  func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle, error) {
   372  	a.Lock()
   373  	bm, ok := a.addresses[k]
   374  	a.Unlock()
   375  	if !ok {
   376  		logrus.Debugf("Retrieving bitmask (%s, %s)", k.String(), n.String())
   377  		if err := a.insertBitMask(k, n); err != nil {
   378  			return nil, types.InternalErrorf("could not find bitmask in datastore for %s", k.String())
   379  		}
   380  		a.Lock()
   381  		bm = a.addresses[k]
   382  		a.Unlock()
   383  	}
   384  	return bm, nil
   385  }
   386  
   387  func (a *Allocator) getPredefineds(as string) []*net.IPNet {
   388  	a.Lock()
   389  	defer a.Unlock()
   390  
   391  	p := a.predefined[as]
   392  	i := a.predefinedStartIndices[as]
   393  	// defensive in case the list changed since last update
   394  	if i >= len(p) {
   395  		i = 0
   396  	}
   397  	return append(p[i:], p[:i]...)
   398  }
   399  
   400  func (a *Allocator) updateStartIndex(as string, amt int) {
   401  	a.Lock()
   402  	i := a.predefinedStartIndices[as] + amt
   403  	if i < 0 || i >= len(a.predefined[as]) {
   404  		i = 0
   405  	}
   406  	a.predefinedStartIndices[as] = i
   407  	a.Unlock()
   408  }
   409  
   410  func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) {
   411  	var v ipVersion
   412  	v = v4
   413  	if ipV6 {
   414  		v = v6
   415  	}
   416  
   417  	if as != localAddressSpace && as != globalAddressSpace {
   418  		return nil, types.NotImplementedErrorf("no default pool available for non-default address spaces")
   419  	}
   420  
   421  	aSpace, err := a.getAddrSpace(as)
   422  	if err != nil {
   423  		return nil, err
   424  	}
   425  
   426  	predefined := a.getPredefineds(as)
   427  
   428  	aSpace.Lock()
   429  	for i, nw := range predefined {
   430  		if v != getAddressVersion(nw.IP) {
   431  			continue
   432  		}
   433  		// Checks whether pool has already been allocated
   434  		if _, ok := aSpace.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]; ok {
   435  			continue
   436  		}
   437  		// Shouldn't be necessary, but check prevents IP collisions should
   438  		// predefined pools overlap for any reason.
   439  		if !aSpace.contains(as, nw) {
   440  			aSpace.Unlock()
   441  			a.updateStartIndex(as, i+1)
   442  			return nw, nil
   443  		}
   444  	}
   445  	aSpace.Unlock()
   446  
   447  	return nil, types.NotFoundErrorf("could not find an available, non-overlapping IPv%d address pool among the defaults to assign to the network", v)
   448  }
   449  
   450  // RequestAddress returns an address from the specified pool ID
   451  func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
   452  	logrus.Debugf("RequestAddress(%s, %v, %v)", poolID, prefAddress, opts)
   453  	k := SubnetKey{}
   454  	if err := k.FromString(poolID); err != nil {
   455  		return nil, nil, types.BadRequestErrorf("invalid pool id: %s", poolID)
   456  	}
   457  
   458  	if err := a.refresh(k.AddressSpace); err != nil {
   459  		return nil, nil, err
   460  	}
   461  
   462  	aSpace, err := a.getAddrSpace(k.AddressSpace)
   463  	if err != nil {
   464  		return nil, nil, err
   465  	}
   466  
   467  	aSpace.Lock()
   468  	p, ok := aSpace.subnets[k]
   469  	if !ok {
   470  		aSpace.Unlock()
   471  		return nil, nil, types.NotFoundErrorf("cannot find address pool for poolID:%s", poolID)
   472  	}
   473  
   474  	if prefAddress != nil && !p.Pool.Contains(prefAddress) {
   475  		aSpace.Unlock()
   476  		return nil, nil, ipamapi.ErrIPOutOfRange
   477  	}
   478  
   479  	c := p
   480  	for c.Range != nil {
   481  		k = c.ParentKey
   482  		c = aSpace.subnets[k]
   483  	}
   484  	aSpace.Unlock()
   485  
   486  	bm, err := a.retrieveBitmask(k, c.Pool)
   487  	if err != nil {
   488  		return nil, nil, types.InternalErrorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
   489  			k.String(), prefAddress, poolID, err)
   490  	}
   491  	// In order to request for a serial ip address allocation, callers can pass in the option to request
   492  	// IP allocation serially or first available IP in the subnet
   493  	var serial bool
   494  	if opts != nil {
   495  		if val, ok := opts[ipamapi.AllocSerialPrefix]; ok {
   496  			serial = (val == "true")
   497  		}
   498  	}
   499  	ip, err := a.getAddress(p.Pool, bm, prefAddress, p.Range, serial)
   500  	if err != nil {
   501  		return nil, nil, err
   502  	}
   503  
   504  	return &net.IPNet{IP: ip, Mask: p.Pool.Mask}, nil, nil
   505  }
   506  
   507  // ReleaseAddress releases the address from the specified pool ID
   508  func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
   509  	logrus.Debugf("ReleaseAddress(%s, %v)", poolID, address)
   510  	k := SubnetKey{}
   511  	if err := k.FromString(poolID); err != nil {
   512  		return types.BadRequestErrorf("invalid pool id: %s", poolID)
   513  	}
   514  
   515  	if err := a.refresh(k.AddressSpace); err != nil {
   516  		return err
   517  	}
   518  
   519  	aSpace, err := a.getAddrSpace(k.AddressSpace)
   520  	if err != nil {
   521  		return err
   522  	}
   523  
   524  	aSpace.Lock()
   525  	p, ok := aSpace.subnets[k]
   526  	if !ok {
   527  		aSpace.Unlock()
   528  		return types.NotFoundErrorf("cannot find address pool for poolID:%s", poolID)
   529  	}
   530  
   531  	if address == nil {
   532  		aSpace.Unlock()
   533  		return types.BadRequestErrorf("invalid address: nil")
   534  	}
   535  
   536  	if !p.Pool.Contains(address) {
   537  		aSpace.Unlock()
   538  		return ipamapi.ErrIPOutOfRange
   539  	}
   540  
   541  	c := p
   542  	for c.Range != nil {
   543  		k = c.ParentKey
   544  		c = aSpace.subnets[k]
   545  	}
   546  	aSpace.Unlock()
   547  
   548  	mask := p.Pool.Mask
   549  
   550  	h, err := types.GetHostPartIP(address, mask)
   551  	if err != nil {
   552  		return types.InternalErrorf("failed to release address %s: %v", address.String(), err)
   553  	}
   554  
   555  	bm, err := a.retrieveBitmask(k, c.Pool)
   556  	if err != nil {
   557  		return types.InternalErrorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v",
   558  			k.String(), address, poolID, err)
   559  	}
   560  	defer logrus.Debugf("Released address PoolID:%s, Address:%v Sequence:%s", poolID, address, bm.String())
   561  
   562  	return bm.Unset(ipToUint64(h))
   563  }
   564  
   565  func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddress net.IP, ipr *AddressRange, serial bool) (net.IP, error) {
   566  	var (
   567  		ordinal uint64
   568  		err     error
   569  		base    *net.IPNet
   570  	)
   571  
   572  	logrus.Debugf("Request address PoolID:%v %s Serial:%v PrefAddress:%v ", nw, bitmask.String(), serial, prefAddress)
   573  	base = types.GetIPNetCopy(nw)
   574  
   575  	if bitmask.Unselected() <= 0 {
   576  		return nil, ipamapi.ErrNoAvailableIPs
   577  	}
   578  	if ipr == nil && prefAddress == nil {
   579  		ordinal, err = bitmask.SetAny(serial)
   580  	} else if prefAddress != nil {
   581  		hostPart, e := types.GetHostPartIP(prefAddress, base.Mask)
   582  		if e != nil {
   583  			return nil, types.InternalErrorf("failed to allocate requested address %s: %v", prefAddress.String(), e)
   584  		}
   585  		ordinal = ipToUint64(types.GetMinimalIP(hostPart))
   586  		err = bitmask.Set(ordinal)
   587  	} else {
   588  		ordinal, err = bitmask.SetAnyInRange(ipr.Start, ipr.End, serial)
   589  	}
   590  
   591  	switch err {
   592  	case nil:
   593  		// Convert IP ordinal for this subnet into IP address
   594  		return generateAddress(ordinal, base), nil
   595  	case bitseq.ErrBitAllocated:
   596  		return nil, ipamapi.ErrIPAlreadyAllocated
   597  	case bitseq.ErrNoBitAvailable:
   598  		return nil, ipamapi.ErrNoAvailableIPs
   599  	default:
   600  		return nil, err
   601  	}
   602  }
   603  
   604  // DumpDatabase dumps the internal info
   605  func (a *Allocator) DumpDatabase() string {
   606  	a.Lock()
   607  	aspaces := make(map[string]*addrSpace, len(a.addrSpaces))
   608  	orderedAS := make([]string, 0, len(a.addrSpaces))
   609  	for as, aSpace := range a.addrSpaces {
   610  		orderedAS = append(orderedAS, as)
   611  		aspaces[as] = aSpace
   612  	}
   613  	a.Unlock()
   614  
   615  	sort.Strings(orderedAS)
   616  
   617  	var s string
   618  	for _, as := range orderedAS {
   619  		aSpace := aspaces[as]
   620  		s = fmt.Sprintf("\n\n%s Config", as)
   621  		aSpace.Lock()
   622  		for k, config := range aSpace.subnets {
   623  			s += fmt.Sprintf("\n%v: %v", k, config)
   624  			if config.Range == nil {
   625  				a.retrieveBitmask(k, config.Pool)
   626  			}
   627  		}
   628  		aSpace.Unlock()
   629  	}
   630  
   631  	s = fmt.Sprintf("%s\n\nBitmasks", s)
   632  	for k, bm := range a.addresses {
   633  		s += fmt.Sprintf("\n%s: %s", k, bm)
   634  	}
   635  
   636  	return s
   637  }
   638  
   639  // IsBuiltIn returns true for builtin drivers
   640  func (a *Allocator) IsBuiltIn() bool {
   641  	return true
   642  }