2015-06-12 19:43:18 +00:00
package ipam
import (
"fmt"
"net"
2016-04-16 00:28:59 +00:00
"sort"
2015-06-12 22:36:28 +00:00
"sync"
2015-06-12 19:43:18 +00:00
"github.com/docker/libnetwork/bitseq"
2015-06-15 18:43:02 +00:00
"github.com/docker/libnetwork/datastore"
2016-01-28 00:37:47 +00:00
"github.com/docker/libnetwork/discoverapi"
2015-09-22 20:20:55 +00:00
"github.com/docker/libnetwork/ipamapi"
2015-10-04 21:31:01 +00:00
"github.com/docker/libnetwork/ipamutils"
2015-06-16 01:28:00 +00:00
"github.com/docker/libnetwork/types"
2017-07-26 21:18:31 +00:00
"github.com/sirupsen/logrus"
2015-06-12 19:43:18 +00:00
)
const (
2015-09-22 20:20:55 +00:00
localAddressSpace = "LocalDefault"
globalAddressSpace = "GlobalDefault"
2015-06-12 19:43:18 +00:00
// The biggest configurable host subnets
2015-10-09 03:04:13 +00:00
minNetSize = 8
minNetSizeV6 = 64
2015-06-25 02:11:44 +00:00
// datastore keyes for ipam objects
2015-09-22 20:20:55 +00:00
dsConfigKey = "ipam/" + ipamapi . DefaultIPAM + "/config"
dsDataKey = "ipam/" + ipamapi . DefaultIPAM + "/data"
2015-06-12 19:43:18 +00:00
)
// Allocator provides per address space ipv4/ipv6 book keeping
type Allocator struct {
2015-09-22 20:20:55 +00:00
// Predefined pools for default address spaces
2018-05-30 19:32:11 +00:00
// Separate from the addrSpace because they should not be serialized
predefined map [ string ] [ ] * net . IPNet
predefinedStartIndices map [ string ] int
// The (potentially serialized) address spaces
2015-10-05 11:24:44 +00:00
addrSpaces map [ string ] * addrSpace
// stores []datastore.Datastore
2015-09-22 20:20:55 +00:00
// Allocated addresses in each address space's subnet
addresses map [ SubnetKey ] * bitseq . Handle
2015-06-12 22:36:28 +00:00
sync . Mutex
2015-06-12 19:43:18 +00:00
}
// NewAllocator returns an instance of libnetwork ipam
2015-09-22 20:20:55 +00:00
func NewAllocator ( lcDs , glDs datastore . DataStore ) ( * Allocator , error ) {
2015-06-12 19:43:18 +00:00
a := & Allocator { }
2015-06-16 00:13:49 +00:00
2015-10-05 11:24:44 +00:00
// Load predefined subnet pools
2015-10-04 01:51:53 +00:00
a . predefined = map [ string ] [ ] * net . IPNet {
2018-07-24 19:46:59 +00:00
localAddressSpace : ipamutils . PredefinedLocalScopeDefaultNetworks ,
globalAddressSpace : ipamutils . PredefinedGlobalScopeDefaultNetworks ,
2015-06-16 21:46:51 +00:00
}
2015-09-22 20:20:55 +00:00
2018-05-30 19:32:11 +00:00
// Initialize asIndices map
a . predefinedStartIndices = make ( map [ string ] int )
2015-10-05 11:24:44 +00:00
// Initialize bitseq map
2015-10-04 01:51:53 +00:00
a . addresses = make ( map [ SubnetKey ] * bitseq . Handle )
2015-09-22 20:20:55 +00:00
2015-10-05 11:24:44 +00:00
// Initialize address spaces
a . addrSpaces = make ( map [ string ] * addrSpace )
for _ , aspc := range [ ] struct {
as string
ds datastore . DataStore
2015-10-04 01:51:53 +00:00
} {
2015-10-05 11:24:44 +00:00
{ localAddressSpace , lcDs } ,
{ globalAddressSpace , glDs } ,
} {
2016-01-28 00:37:47 +00:00
a . initializeAddressSpace ( aspc . as , aspc . ds )
2015-10-05 11:24:44 +00:00
}
return a , nil
}
func ( a * Allocator ) refresh ( as string ) error {
aSpace , err := a . getAddressSpaceFromStore ( as )
if err != nil {
2015-10-21 00:05:01 +00:00
return types . InternalErrorf ( "error getting pools config from store: %v" , err )
2015-10-05 11:24:44 +00:00
}
if aSpace == nil {
return nil
}
a . Lock ( )
a . addrSpaces [ as ] = aSpace
a . Unlock ( )
return nil
}
func ( a * Allocator ) updateBitMasks ( aSpace * addrSpace ) error {
var inserterList [ ] func ( ) error
aSpace . Lock ( )
for k , v := range aSpace . subnets {
if v . Range == nil {
2015-10-05 21:53:25 +00:00
kk := k
vv := v
inserterList = append ( inserterList , func ( ) error { return a . insertBitMask ( kk , vv . Pool ) } )
2015-10-04 01:51:53 +00:00
}
2015-09-22 20:20:55 +00:00
}
2015-10-05 11:24:44 +00:00
aSpace . Unlock ( )
2015-10-04 01:51:53 +00:00
// Add the bitmasks (data could come from datastore)
if inserterList != nil {
for _ , f := range inserterList {
if err := f ( ) ; err != nil {
2015-10-05 11:24:44 +00:00
return err
2015-10-04 01:51:53 +00:00
}
2015-09-22 20:20:55 +00:00
}
2015-06-16 21:46:51 +00:00
}
2015-09-22 20:20:55 +00:00
2015-10-05 11:24:44 +00:00
return nil
2015-06-12 19:43:18 +00:00
}
2016-01-28 00:37:47 +00:00
// Checks for and fixes damaged bitmask.
2016-01-14 16:26:14 +00:00
func ( a * Allocator ) checkConsistency ( as string ) {
2016-01-28 00:37:47 +00:00
var sKeyList [ ] SubnetKey
2016-01-14 16:26:14 +00:00
// Retrieve this address space's configuration and bitmasks from the datastore
a . refresh ( as )
2016-01-28 00:37:47 +00:00
a . Lock ( )
2016-01-14 16:26:14 +00:00
aSpace , ok := a . addrSpaces [ as ]
2016-01-28 00:37:47 +00:00
a . Unlock ( )
2016-01-14 16:26:14 +00:00
if ! ok {
return
}
a . updateBitMasks ( aSpace )
2016-01-28 00:37:47 +00:00
aSpace . Lock ( )
2016-01-14 16:26:14 +00:00
for sk , pd := range aSpace . subnets {
if pd . Range != nil {
continue
}
2016-01-28 00:37:47 +00:00
sKeyList = append ( sKeyList , sk )
}
aSpace . Unlock ( )
for _ , sk := range sKeyList {
a . Lock ( )
bm := a . addresses [ sk ]
a . Unlock ( )
if err := bm . CheckConsistency ( ) ; err != nil {
2016-11-01 04:26:14 +00:00
logrus . Warnf ( "Error while running consistency check for %s: %v" , sk , err )
2016-01-14 16:26:14 +00:00
}
}
}
2016-01-28 00:37:47 +00:00
func ( a * Allocator ) initializeAddressSpace ( as string , ds datastore . DataStore ) error {
2016-03-01 23:05:36 +00:00
scope := ""
if ds != nil {
scope = ds . Scope ( )
}
2016-01-28 00:37:47 +00:00
a . Lock ( )
2016-05-09 20:36:40 +00:00
if currAS , ok := a . addrSpaces [ as ] ; ok {
if currAS . ds != nil {
a . Unlock ( )
return types . ForbiddenErrorf ( "a datastore is already configured for the address space %s" , as )
}
2016-01-28 00:37:47 +00:00
}
a . addrSpaces [ as ] = & addrSpace {
subnets : map [ SubnetKey ] * PoolData { } ,
id : dsConfigKey + "/" + as ,
2016-03-01 23:05:36 +00:00
scope : scope ,
2016-01-28 00:37:47 +00:00
ds : ds ,
alloc : a ,
}
a . Unlock ( )
a . checkConsistency ( as )
return nil
}
// DiscoverNew informs the allocator about a new global scope datastore
func ( a * Allocator ) DiscoverNew ( dType discoverapi . DiscoveryType , data interface { } ) error {
if dType != discoverapi . DatastoreConfig {
return nil
}
dsc , ok := data . ( discoverapi . DatastoreConfigData )
if ! ok {
return types . InternalErrorf ( "incorrect data in datastore update notification: %v" , data )
}
ds , err := datastore . NewDataStoreFromConfig ( dsc )
if err != nil {
return err
}
return a . initializeAddressSpace ( globalAddressSpace , ds )
}
// DiscoverDelete is a notification of no interest for the allocator
func ( a * Allocator ) DiscoverDelete ( dType discoverapi . DiscoveryType , data interface { } ) error {
return nil
}
2015-09-22 20:20:55 +00:00
// GetDefaultAddressSpaces returns the local and global default address spaces
func ( a * Allocator ) GetDefaultAddressSpaces ( ) ( string , string , error ) {
return localAddressSpace , globalAddressSpace , nil
}
2015-06-12 19:43:18 +00:00
2015-09-22 20:20:55 +00:00
// RequestPool returns an address pool along with its unique id.
2018-05-23 15:21:31 +00:00
// addressSpace must be a valid address space name and must not be the empty string.
// 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.
// If subPool is not empty, it must be a valid IP address and length in CIDR notation which is a sub-range of pool.
// subPool must be empty if pool is empty.
2015-09-22 20:20:55 +00:00
func ( a * Allocator ) RequestPool ( addressSpace , pool , subPool string , options map [ string ] string , v6 bool ) ( string , * net . IPNet , map [ string ] string , error ) {
2016-11-01 04:26:14 +00:00
logrus . Debugf ( "RequestPool(%s, %s, %s, %v, %t)" , addressSpace , pool , subPool , options , v6 )
2016-05-25 22:02:44 +00:00
k , nw , ipr , err := a . parsePoolRequest ( addressSpace , pool , subPool , v6 )
2015-06-12 19:43:18 +00:00
if err != nil {
2015-10-12 17:52:58 +00:00
return "" , nil , nil , types . InternalErrorf ( "failed to parse pool request for address space %q pool %q subpool %q: %v" , addressSpace , pool , subPool , err )
2015-06-12 19:43:18 +00:00
}
2015-10-04 01:51:53 +00:00
2016-05-25 22:02:44 +00:00
pdf := k == nil
retry :
if pdf {
if nw , err = a . getPredefinedPool ( addressSpace , v6 ) ; err != nil {
return "" , nil , nil , err
}
k = & SubnetKey { AddressSpace : addressSpace , Subnet : nw . String ( ) }
}
2015-10-05 11:24:44 +00:00
if err := a . refresh ( addressSpace ) ; err != nil {
return "" , nil , nil , err
}
aSpace , err := a . getAddrSpace ( addressSpace )
2015-10-04 01:51:53 +00:00
if err != nil {
return "" , nil , nil , err
}
2016-01-22 18:46:05 +00:00
insert , err := aSpace . updatePoolDBOnAdd ( * k , nw , ipr , pdf )
2015-06-16 21:46:51 +00:00
if err != nil {
2016-01-22 18:46:05 +00:00
if _ , ok := err . ( types . MaskableError ) ; ok {
2016-11-01 04:26:14 +00:00
logrus . Debugf ( "Retrying predefined pool search: %v" , err )
2016-01-22 18:46:05 +00:00
goto retry
}
2015-09-22 20:20:55 +00:00
return "" , nil , nil , err
}
2015-10-05 11:24:44 +00:00
if err := a . writeToStore ( aSpace ) ; err != nil {
2015-06-16 21:46:51 +00:00
if _ , ok := err . ( types . RetryError ) ; ! ok {
2015-09-22 20:20:55 +00:00
return "" , nil , nil , types . InternalErrorf ( "pool configuration failed because of %s" , err . Error ( ) )
2015-06-16 21:46:51 +00:00
}
2015-10-05 11:24:44 +00:00
2015-06-16 21:46:51 +00:00
goto retry
}
2015-10-05 11:24:44 +00:00
2015-10-09 03:04:13 +00:00
return k . String ( ) , nw , nil , insert ( )
2015-06-16 21:46:51 +00:00
}
2015-06-12 19:43:18 +00:00
2015-09-22 20:20:55 +00:00
// ReleasePool releases the address pool identified by the passed id
func ( a * Allocator ) ReleasePool ( poolID string ) error {
2016-11-01 04:26:14 +00:00
logrus . Debugf ( "ReleasePool(%s)" , poolID )
2015-09-22 20:20:55 +00:00
k := SubnetKey { }
if err := k . FromString ( poolID ) ; err != nil {
return types . BadRequestErrorf ( "invalid pool id: %s" , poolID )
}
2015-08-12 02:22:38 +00:00
2015-10-05 11:24:44 +00:00
retry :
if err := a . refresh ( k . AddressSpace ) ; err != nil {
return err
}
aSpace , err := a . getAddrSpace ( k . AddressSpace )
2015-10-04 01:51:53 +00:00
if err != nil {
return err
}
2015-10-05 11:24:44 +00:00
remove , err := aSpace . updatePoolDBOnRemoval ( k )
2015-09-22 20:20:55 +00:00
if err != nil {
return err
}
2015-10-05 11:24:44 +00:00
if err = a . writeToStore ( aSpace ) ; err != nil {
2015-09-22 20:20:55 +00:00
if _ , ok := err . ( types . RetryError ) ; ! ok {
return types . InternalErrorf ( "pool (%s) removal failed because of %v" , poolID , err )
2015-08-12 02:22:38 +00:00
}
2015-09-22 20:20:55 +00:00
goto retry
}
2015-08-12 02:22:38 +00:00
2015-09-22 20:20:55 +00:00
return remove ( )
}
2015-08-12 02:22:38 +00:00
2018-05-23 15:21:31 +00:00
// Given the address space, returns the local or global PoolConfig based on whether the
// address space is local or global. AddressSpace locality is registered with IPAM out of band.
2015-10-05 11:24:44 +00:00
func ( a * Allocator ) getAddrSpace ( as string ) ( * addrSpace , error ) {
2015-10-04 01:51:53 +00:00
a . Lock ( )
defer a . Unlock ( )
2015-10-05 11:24:44 +00:00
aSpace , ok := a . addrSpaces [ as ]
2015-10-04 01:51:53 +00:00
if ! ok {
2015-10-30 17:18:50 +00:00
return nil , types . BadRequestErrorf ( "cannot find address space %s (most likely the backing datastore is not configured)" , as )
2015-10-04 01:51:53 +00:00
}
2015-10-05 11:24:44 +00:00
return aSpace , nil
2015-10-04 01:51:53 +00:00
}
2018-05-23 15:21:31 +00:00
// parsePoolRequest parses and validates a request to create a new pool under addressSpace and returns
// a SubnetKey, network and range describing the request.
2016-05-25 22:02:44 +00:00
func ( a * Allocator ) parsePoolRequest ( addressSpace , pool , subPool string , v6 bool ) ( * SubnetKey , * net . IPNet , * AddressRange , error ) {
2015-09-22 20:20:55 +00:00
var (
2015-10-09 03:04:13 +00:00
nw * net . IPNet
ipr * AddressRange
err error
2015-09-22 20:20:55 +00:00
)
if addressSpace == "" {
2016-05-25 22:02:44 +00:00
return nil , nil , nil , ipamapi . ErrInvalidAddressSpace
2015-06-12 19:43:18 +00:00
}
2015-09-22 20:20:55 +00:00
if pool == "" && subPool != "" {
2016-05-25 22:02:44 +00:00
return nil , nil , nil , ipamapi . ErrInvalidSubPool
2015-09-22 20:20:55 +00:00
}
2016-05-25 22:02:44 +00:00
if pool == "" {
return nil , nil , nil , nil
}
if _ , nw , err = net . ParseCIDR ( pool ) ; err != nil {
return nil , nil , nil , ipamapi . ErrInvalidPool
}
if subPool != "" {
if ipr , err = getAddressRange ( subPool , nw ) ; err != nil {
return nil , nil , nil , err
2015-06-12 19:43:18 +00:00
}
}
2015-09-22 20:20:55 +00:00
2016-05-25 22:02:44 +00:00
return & SubnetKey { AddressSpace : addressSpace , Subnet : nw . String ( ) , ChildSubnet : subPool } , nw , ipr , nil
2015-06-12 19:43:18 +00:00
}
2015-10-05 11:24:44 +00:00
func ( a * Allocator ) insertBitMask ( key SubnetKey , pool * net . IPNet ) error {
2016-11-01 04:26:14 +00:00
//logrus.Debugf("Inserting bitmask (%s, %s)", key.String(), pool.String())
2015-10-05 11:24:44 +00:00
store := a . getStore ( key . AddressSpace )
2015-09-22 20:20:55 +00:00
ipVer := getAddressVersion ( pool . IP )
ones , bits := pool . Mask . Size ( )
2015-10-09 03:04:13 +00:00
numAddresses := uint64 ( 1 << uint ( bits - ones ) )
2015-09-22 20:20:55 +00:00
2015-10-09 03:04:13 +00:00
// Allow /64 subnet
if ipVer == v6 && numAddresses == 0 {
numAddresses --
}
2015-09-22 20:20:55 +00:00
// Generate the new address masks. AddressMask content may come from datastore
2015-10-04 01:51:53 +00:00
h , err := bitseq . NewHandle ( dsDataKey , store , key . String ( ) , numAddresses )
2015-06-13 20:12:24 +00:00
if err != nil {
return err
}
2015-10-09 03:04:13 +00:00
// Do not let network identifier address be reserved
// Do the same for IPv6 so that bridge ip starts with XXXX...::1
h . Set ( 0 )
2015-06-12 19:43:18 +00:00
2015-10-22 19:58:45 +00:00
// Do not let broadcast address be reserved
if ipVer == v4 {
h . Set ( numAddresses - 1 )
}
2015-09-22 20:20:55 +00:00
a . Lock ( )
a . addresses [ key ] = h
a . Unlock ( )
2015-06-12 19:43:18 +00:00
return nil
}
2015-10-05 11:24:44 +00:00
func ( a * Allocator ) retrieveBitmask ( k SubnetKey , n * net . IPNet ) ( * bitseq . Handle , error ) {
2015-09-22 20:20:55 +00:00
a . Lock ( )
bm , ok := a . addresses [ k ]
a . Unlock ( )
if ! ok {
2016-11-01 04:26:14 +00:00
logrus . Debugf ( "Retrieving bitmask (%s, %s)" , k . String ( ) , n . String ( ) )
2015-10-05 11:24:44 +00:00
if err := a . insertBitMask ( k , n ) ; err != nil {
2015-10-21 00:05:01 +00:00
return nil , types . InternalErrorf ( "could not find bitmask in datastore for %s" , k . String ( ) )
2015-09-22 20:20:55 +00:00
}
a . Lock ( )
bm = a . addresses [ k ]
a . Unlock ( )
}
return bm , nil
2015-06-12 19:43:18 +00:00
}
2015-09-22 20:20:55 +00:00
func ( a * Allocator ) getPredefineds ( as string ) [ ] * net . IPNet {
a . Lock ( )
defer a . Unlock ( )
2018-05-30 19:32:11 +00:00
p := a . predefined [ as ]
i := a . predefinedStartIndices [ as ]
// defensive in case the list changed since last update
if i >= len ( p ) {
i = 0
2015-06-12 19:43:18 +00:00
}
2018-05-30 19:32:11 +00:00
return append ( p [ i : ] , p [ : i ] ... )
}
func ( a * Allocator ) updateStartIndex ( as string , amt int ) {
a . Lock ( )
i := a . predefinedStartIndices [ as ] + amt
if i < 0 || i >= len ( a . predefined [ as ] ) {
i = 0
}
a . predefinedStartIndices [ as ] = i
a . Unlock ( )
2015-09-22 20:20:55 +00:00
}
2015-06-12 19:43:18 +00:00
2015-09-22 20:20:55 +00:00
func ( a * Allocator ) getPredefinedPool ( as string , ipV6 bool ) ( * net . IPNet , error ) {
var v ipVersion
v = v4
if ipV6 {
v = v6
2015-06-12 19:43:18 +00:00
}
2015-09-22 20:20:55 +00:00
if as != localAddressSpace && as != globalAddressSpace {
2018-05-23 10:02:11 +00:00
return nil , types . NotImplementedErrorf ( "no default pool available for non-default address spaces" )
2015-06-12 19:43:18 +00:00
}
2015-10-05 11:24:44 +00:00
aSpace , err := a . getAddrSpace ( as )
2015-10-04 01:51:53 +00:00
if err != nil {
return nil , err
}
2018-05-30 19:32:11 +00:00
predefined := a . getPredefineds ( as )
aSpace . Lock ( )
for i , nw := range predefined {
2015-09-22 20:20:55 +00:00
if v != getAddressVersion ( nw . IP ) {
continue
}
2018-05-30 19:32:11 +00:00
// Checks whether pool has already been allocated
2018-03-08 18:38:52 +00:00
if _ , ok := aSpace . subnets [ SubnetKey { AddressSpace : as , Subnet : nw . String ( ) } ] ; ok {
2015-09-22 20:20:55 +00:00
continue
}
2018-05-30 19:32:11 +00:00
// Shouldn't be necessary, but check prevents IP collisions should
// predefined pools overlap for any reason.
2015-10-05 11:24:44 +00:00
if ! aSpace . contains ( as , nw ) {
2018-03-08 18:38:52 +00:00
aSpace . Unlock ( )
2018-05-30 19:32:11 +00:00
a . updateStartIndex ( as , i + 1 )
2015-09-22 20:20:55 +00:00
return nw , nil
}
2015-06-12 19:43:18 +00:00
}
2018-05-30 19:32:11 +00:00
aSpace . Unlock ( )
2015-06-12 19:43:18 +00:00
2016-11-04 16:14:35 +00:00
return nil , types . NotFoundErrorf ( "could not find an available, non-overlapping IPv%d address pool among the defaults to assign to the network" , v )
2015-06-12 19:43:18 +00:00
}
2015-09-22 20:20:55 +00:00
// RequestAddress returns an address from the specified pool ID
func ( a * Allocator ) RequestAddress ( poolID string , prefAddress net . IP , opts map [ string ] string ) ( * net . IPNet , map [ string ] string , error ) {
2016-11-01 04:26:14 +00:00
logrus . Debugf ( "RequestAddress(%s, %v, %v)" , poolID , prefAddress , opts )
2015-09-22 20:20:55 +00:00
k := SubnetKey { }
if err := k . FromString ( poolID ) ; err != nil {
return nil , nil , types . BadRequestErrorf ( "invalid pool id: %s" , poolID )
2015-06-12 19:43:18 +00:00
}
2015-06-25 02:11:44 +00:00
2015-10-05 11:24:44 +00:00
if err := a . refresh ( k . AddressSpace ) ; err != nil {
return nil , nil , err
}
aSpace , err := a . getAddrSpace ( k . AddressSpace )
2015-10-04 01:51:53 +00:00
if err != nil {
return nil , nil , err
}
2015-10-05 11:24:44 +00:00
aSpace . Lock ( )
p , ok := aSpace . subnets [ k ]
2015-09-22 20:20:55 +00:00
if ! ok {
2015-10-05 11:24:44 +00:00
aSpace . Unlock ( )
2015-09-22 20:20:55 +00:00
return nil , nil , types . NotFoundErrorf ( "cannot find address pool for poolID:%s" , poolID )
2015-06-12 19:43:18 +00:00
}
2015-06-25 02:11:44 +00:00
2015-09-22 20:20:55 +00:00
if prefAddress != nil && ! p . Pool . Contains ( prefAddress ) {
2015-10-05 11:24:44 +00:00
aSpace . Unlock ( )
2015-09-22 20:20:55 +00:00
return nil , nil , ipamapi . ErrIPOutOfRange
2015-06-12 19:43:18 +00:00
}
2015-09-22 20:20:55 +00:00
c := p
for c . Range != nil {
k = c . ParentKey
2017-06-12 18:30:30 +00:00
c = aSpace . subnets [ k ]
2015-06-25 02:11:44 +00:00
}
2015-10-05 11:24:44 +00:00
aSpace . Unlock ( )
2015-06-25 02:11:44 +00:00
2015-10-05 11:24:44 +00:00
bm , err := a . retrieveBitmask ( k , c . Pool )
2015-06-25 02:11:44 +00:00
if err != nil {
2015-10-21 00:05:01 +00:00
return nil , nil , types . InternalErrorf ( "could not find bitmask in datastore for %s on address %v request from pool %s: %v" ,
2015-09-22 20:20:55 +00:00
k . String ( ) , prefAddress , poolID , err )
2015-06-25 02:11:44 +00:00
}
2017-06-01 02:41:21 +00:00
// In order to request for a serial ip address allocation, callers can pass in the option to request
// IP allocation serially or first available IP in the subnet
var serial bool
if opts != nil {
if val , ok := opts [ ipamapi . AllocSerialPrefix ] ; ok {
serial = ( val == "true" )
}
}
ip , err := a . getAddress ( p . Pool , bm , prefAddress , p . Range , serial )
2015-09-22 20:20:55 +00:00
if err != nil {
return nil , nil , err
2015-06-25 02:11:44 +00:00
}
2015-09-22 20:20:55 +00:00
return & net . IPNet { IP : ip , Mask : p . Pool . Mask } , nil , nil
2015-06-12 19:43:18 +00:00
}
2015-09-22 20:20:55 +00:00
// ReleaseAddress releases the address from the specified pool ID
func ( a * Allocator ) ReleaseAddress ( poolID string , address net . IP ) error {
2016-11-01 04:26:14 +00:00
logrus . Debugf ( "ReleaseAddress(%s, %v)" , poolID , address )
2015-09-22 20:20:55 +00:00
k := SubnetKey { }
if err := k . FromString ( poolID ) ; err != nil {
return types . BadRequestErrorf ( "invalid pool id: %s" , poolID )
}
2015-06-12 19:43:18 +00:00
2015-10-05 11:24:44 +00:00
if err := a . refresh ( k . AddressSpace ) ; err != nil {
return err
}
aSpace , err := a . getAddrSpace ( k . AddressSpace )
2015-10-04 01:51:53 +00:00
if err != nil {
return err
}
2015-10-05 11:24:44 +00:00
aSpace . Lock ( )
p , ok := aSpace . subnets [ k ]
2015-09-22 20:20:55 +00:00
if ! ok {
2015-10-05 11:24:44 +00:00
aSpace . Unlock ( )
2015-10-21 00:05:01 +00:00
return types . NotFoundErrorf ( "cannot find address pool for poolID:%s" , poolID )
2015-06-12 19:43:18 +00:00
}
2015-10-07 03:29:30 +00:00
if address == nil {
2015-10-05 11:24:44 +00:00
aSpace . Unlock ( )
2015-10-21 00:05:01 +00:00
return types . BadRequestErrorf ( "invalid address: nil" )
2015-06-12 19:43:18 +00:00
}
2015-10-07 03:29:30 +00:00
if ! p . Pool . Contains ( address ) {
aSpace . Unlock ( )
return ipamapi . ErrIPOutOfRange
}
2015-09-22 20:20:55 +00:00
c := p
for c . Range != nil {
k = c . ParentKey
2015-10-05 11:24:44 +00:00
c = aSpace . subnets [ k ]
2015-06-12 19:43:18 +00:00
}
2015-10-05 11:24:44 +00:00
aSpace . Unlock ( )
2015-09-22 20:20:55 +00:00
mask := p . Pool . Mask
2015-10-09 03:04:13 +00:00
2015-09-22 20:20:55 +00:00
h , err := types . GetHostPartIP ( address , mask )
if err != nil {
2015-10-21 00:05:01 +00:00
return types . InternalErrorf ( "failed to release address %s: %v" , address . String ( ) , err )
2015-09-22 20:20:55 +00:00
}
2015-10-05 11:24:44 +00:00
bm , err := a . retrieveBitmask ( k , c . Pool )
2015-09-22 20:20:55 +00:00
if err != nil {
2015-10-21 00:05:01 +00:00
return types . InternalErrorf ( "could not find bitmask in datastore for %s on address %v release from pool %s: %v" ,
2015-09-22 20:20:55 +00:00
k . String ( ) , address , poolID , err )
}
2018-05-10 18:09:12 +00:00
defer logrus . Debugf ( "Released address PoolID:%s, Address:%v Sequence:%s" , poolID , address , bm . String ( ) )
2015-10-09 03:04:13 +00:00
return bm . Unset ( ipToUint64 ( h ) )
2015-06-12 19:43:18 +00:00
}
2017-06-01 02:41:21 +00:00
func ( a * Allocator ) getAddress ( nw * net . IPNet , bitmask * bitseq . Handle , prefAddress net . IP , ipr * AddressRange , serial bool ) ( net . IP , error ) {
2015-06-12 19:43:18 +00:00
var (
2015-10-09 03:04:13 +00:00
ordinal uint64
2015-06-24 22:02:08 +00:00
err error
2015-09-22 20:20:55 +00:00
base * net . IPNet
2015-06-12 19:43:18 +00:00
)
2018-05-10 18:09:12 +00:00
logrus . Debugf ( "Request address PoolID:%v %s Serial:%v PrefAddress:%v " , nw , bitmask . String ( ) , serial , prefAddress )
2015-09-22 20:20:55 +00:00
base = types . GetIPNetCopy ( nw )
2015-08-12 02:22:38 +00:00
if bitmask . Unselected ( ) <= 0 {
2015-09-22 20:20:55 +00:00
return nil , ipamapi . ErrNoAvailableIPs
2015-08-12 02:22:38 +00:00
}
2015-09-22 20:20:55 +00:00
if ipr == nil && prefAddress == nil {
2017-06-01 02:41:21 +00:00
ordinal , err = bitmask . SetAny ( serial )
2015-10-05 07:40:17 +00:00
} else if prefAddress != nil {
2015-09-22 20:20:55 +00:00
hostPart , e := types . GetHostPartIP ( prefAddress , base . Mask )
2015-08-12 02:22:38 +00:00
if e != nil {
2016-01-26 15:09:29 +00:00
return nil , types . InternalErrorf ( "failed to allocate requested address %s: %v" , prefAddress . String ( ) , e )
2015-06-16 21:46:51 +00:00
}
2015-10-09 03:04:13 +00:00
ordinal = ipToUint64 ( types . GetMinimalIP ( hostPart ) )
2015-08-12 02:22:38 +00:00
err = bitmask . Set ( ordinal )
2015-10-05 07:40:17 +00:00
} else {
2017-06-01 02:41:21 +00:00
ordinal , err = bitmask . SetAnyInRange ( ipr . Start , ipr . End , serial )
2015-08-12 02:22:38 +00:00
}
2015-10-21 00:05:01 +00:00
switch err {
case nil :
// Convert IP ordinal for this subnet into IP address
return generateAddress ( ordinal , base ) , nil
case bitseq . ErrBitAllocated :
return nil , ipamapi . ErrIPAlreadyAllocated
case bitseq . ErrNoBitAvailable :
2015-09-22 20:20:55 +00:00
return nil , ipamapi . ErrNoAvailableIPs
2015-10-21 00:05:01 +00:00
default :
return nil , err
2015-06-12 19:43:18 +00:00
}
}
// DumpDatabase dumps the internal info
2015-09-22 20:20:55 +00:00
func ( a * Allocator ) DumpDatabase ( ) string {
2015-06-12 22:36:28 +00:00
a . Lock ( )
2015-12-13 08:35:05 +00:00
aspaces := make ( map [ string ] * addrSpace , len ( a . addrSpaces ) )
2016-04-16 00:28:59 +00:00
orderedAS := make ( [ ] string , 0 , len ( a . addrSpaces ) )
2015-12-13 08:35:05 +00:00
for as , aSpace := range a . addrSpaces {
2016-04-16 00:28:59 +00:00
orderedAS = append ( orderedAS , as )
2015-12-13 08:35:05 +00:00
aspaces [ as ] = aSpace
}
a . Unlock ( )
2015-09-22 20:20:55 +00:00
2016-04-16 00:28:59 +00:00
sort . Strings ( orderedAS )
2015-10-05 11:24:44 +00:00
var s string
2016-04-16 00:28:59 +00:00
for _ , as := range orderedAS {
aSpace := aspaces [ as ]
2015-10-05 11:24:44 +00:00
s = fmt . Sprintf ( "\n\n%s Config" , as )
aSpace . Lock ( )
for k , config := range aSpace . subnets {
2017-05-09 23:07:09 +00:00
s += fmt . Sprintf ( "\n%v: %v" , k , config )
2015-12-13 08:35:05 +00:00
if config . Range == nil {
a . retrieveBitmask ( k , config . Pool )
}
2015-10-05 11:24:44 +00:00
}
aSpace . Unlock ( )
2015-10-04 01:51:53 +00:00
}
2015-06-12 19:43:18 +00:00
2015-09-22 20:20:55 +00:00
s = fmt . Sprintf ( "%s\n\nBitmasks" , s )
for k , bm := range a . addresses {
2017-05-09 23:07:09 +00:00
s += fmt . Sprintf ( "\n%s: %s" , k , bm )
2015-09-22 20:20:55 +00:00
}
2015-10-05 11:24:44 +00:00
2015-09-22 20:20:55 +00:00
return s
2015-08-12 02:22:38 +00:00
}
2016-12-19 03:56:34 +00:00
// IsBuiltIn returns true for builtin drivers
func ( a * Allocator ) IsBuiltIn ( ) bool {
return true
}