github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/ipam/allocator.go (about)

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