|
@@ -1,14 +1,11 @@
|
|
|
package ipam
|
|
|
|
|
|
import (
|
|
|
- "encoding/json"
|
|
|
"fmt"
|
|
|
"net"
|
|
|
- "strings"
|
|
|
"sync"
|
|
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
|
-
|
|
|
"github.com/docker/libkv/store"
|
|
|
"github.com/docker/libnetwork/bitseq"
|
|
|
"github.com/docker/libnetwork/datastore"
|
|
@@ -34,209 +31,86 @@ type Allocator struct {
|
|
|
// Predefined pools for default address spaces
|
|
|
predefined map[string][]*net.IPNet
|
|
|
// Static subnet information
|
|
|
- subnets map[SubnetKey]*PoolData
|
|
|
+ localSubnets *PoolsConfig
|
|
|
+ globalSubnets *PoolsConfig
|
|
|
// Allocated addresses in each address space's subnet
|
|
|
addresses map[SubnetKey]*bitseq.Handle
|
|
|
// Datastore
|
|
|
- store datastore.DataStore
|
|
|
- dbIndex uint64
|
|
|
- dbExists bool
|
|
|
+ addrSpace2Configs map[string]*PoolsConfig
|
|
|
sync.Mutex
|
|
|
}
|
|
|
|
|
|
// NewAllocator returns an instance of libnetwork ipam
|
|
|
func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
|
|
|
a := &Allocator{}
|
|
|
- a.subnets = make(map[SubnetKey]*PoolData)
|
|
|
- a.addresses = make(map[SubnetKey]*bitseq.Handle)
|
|
|
- a.predefined = make(map[string][]*net.IPNet, 2)
|
|
|
- a.predefined[localAddressSpace] = initLocalPredefinedPools()
|
|
|
- a.predefined[globalAddressSpace] = initGlobalPredefinedPools()
|
|
|
- a.store = glDs
|
|
|
-
|
|
|
- if a.store == nil {
|
|
|
- return a, nil
|
|
|
- }
|
|
|
-
|
|
|
- // Register for status changes
|
|
|
- a.watchForChanges()
|
|
|
-
|
|
|
- // Get the initial subnet configs status from the ds if present.
|
|
|
- kvPair, err := a.store.KVStore().Get(datastore.Key(a.Key()...))
|
|
|
- if err != nil {
|
|
|
- if err != store.ErrKeyNotFound {
|
|
|
- return nil, fmt.Errorf("failed to retrieve the ipam subnet configs from datastore: %v", err)
|
|
|
- }
|
|
|
- return a, nil
|
|
|
- }
|
|
|
- a.subnetConfigFromStore(kvPair)
|
|
|
-
|
|
|
- // Now retrieve the bitmasks for the master pools
|
|
|
- var inserterList []func() error
|
|
|
- a.Lock()
|
|
|
- for k, v := range a.subnets {
|
|
|
- if v.Range == nil {
|
|
|
- inserterList = append(inserterList, func() error { return a.insertBitMask(k, v.Pool) })
|
|
|
- }
|
|
|
- }
|
|
|
- a.Unlock()
|
|
|
-
|
|
|
- // Add the bitmasks, data could come from datastore
|
|
|
- for _, f := range inserterList {
|
|
|
- if err := f(); err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return a, nil
|
|
|
-}
|
|
|
-
|
|
|
-func (a *Allocator) subnetConfigFromStore(kvPair *store.KVPair) {
|
|
|
- a.Lock()
|
|
|
- if a.dbIndex < kvPair.LastIndex {
|
|
|
- a.SetValue(kvPair.Value)
|
|
|
- a.dbIndex = kvPair.LastIndex
|
|
|
- a.dbExists = true
|
|
|
- }
|
|
|
- a.Unlock()
|
|
|
-}
|
|
|
-
|
|
|
-// SubnetKey is the pointer to the configured pools in each address space
|
|
|
-type SubnetKey struct {
|
|
|
- AddressSpace string
|
|
|
- Subnet string
|
|
|
- ChildSubnet string
|
|
|
-}
|
|
|
-
|
|
|
-// String returns the string form of the SubnetKey object
|
|
|
-func (s *SubnetKey) String() string {
|
|
|
- k := fmt.Sprintf("%s/%s", s.AddressSpace, s.Subnet)
|
|
|
- if s.ChildSubnet != "" {
|
|
|
- k = fmt.Sprintf("%s/%s", k, s.ChildSubnet)
|
|
|
- }
|
|
|
- return k
|
|
|
-}
|
|
|
|
|
|
-// FromString populate the SubnetKey object reading it from string
|
|
|
-func (s *SubnetKey) FromString(str string) error {
|
|
|
- if str == "" || !strings.Contains(str, "/") {
|
|
|
- return fmt.Errorf("invalid string form for subnetkey: %s", str)
|
|
|
+ a.localSubnets = &PoolsConfig{
|
|
|
+ subnets: map[SubnetKey]*PoolData{},
|
|
|
+ id: dsConfigKey + "/Pools",
|
|
|
+ scope: datastore.LocalScope,
|
|
|
+ ds: lcDs,
|
|
|
+ alloc: a,
|
|
|
}
|
|
|
|
|
|
- p := strings.Split(str, "/")
|
|
|
- if len(p) != 3 && len(p) != 5 {
|
|
|
- return fmt.Errorf("invalid string form for subnetkey: %s", str)
|
|
|
- }
|
|
|
- s.AddressSpace = p[0]
|
|
|
- s.Subnet = fmt.Sprintf("%s/%s", p[1], p[2])
|
|
|
- if len(p) == 5 {
|
|
|
- s.ChildSubnet = fmt.Sprintf("%s/%s", p[3], p[4])
|
|
|
+ a.globalSubnets = &PoolsConfig{
|
|
|
+ subnets: map[SubnetKey]*PoolData{},
|
|
|
+ id: dsConfigKey + "/Pools",
|
|
|
+ scope: datastore.GlobalScope,
|
|
|
+ ds: glDs,
|
|
|
+ alloc: a,
|
|
|
}
|
|
|
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// AddressRange specifies first and last ip ordinal which
|
|
|
-// identify a range in a a pool of addresses
|
|
|
-type AddressRange struct {
|
|
|
- Sub *net.IPNet
|
|
|
- Start, End uint32
|
|
|
-}
|
|
|
-
|
|
|
-// String returns the string form of the AddressRange object
|
|
|
-func (r *AddressRange) String() string {
|
|
|
- return fmt.Sprintf("Sub: %s, range [%d, %d]", r.Sub, r.Start, r.End)
|
|
|
-}
|
|
|
-
|
|
|
-// MarshalJSON returns the JSON encoding of the Range object
|
|
|
-func (r *AddressRange) MarshalJSON() ([]byte, error) {
|
|
|
- m := map[string]interface{}{
|
|
|
- "Sub": r.Sub.String(),
|
|
|
- "Start": r.Start,
|
|
|
- "End": r.End,
|
|
|
+ a.predefined = map[string][]*net.IPNet{
|
|
|
+ localAddressSpace: initLocalPredefinedPools(),
|
|
|
+ globalAddressSpace: initGlobalPredefinedPools(),
|
|
|
}
|
|
|
- return json.Marshal(m)
|
|
|
-}
|
|
|
|
|
|
-// UnmarshalJSON decodes data into the Range object
|
|
|
-func (r *AddressRange) UnmarshalJSON(data []byte) error {
|
|
|
- m := map[string]interface{}{}
|
|
|
- err := json.Unmarshal(data, &m)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
+ a.addrSpace2Configs = map[string]*PoolsConfig{
|
|
|
+ localAddressSpace: a.localSubnets,
|
|
|
+ globalAddressSpace: a.globalSubnets,
|
|
|
}
|
|
|
- if r.Sub, err = types.ParseCIDR(m["Sub"].(string)); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- r.Start = uint32(m["Start"].(float64))
|
|
|
- r.End = uint32(m["End"].(float64))
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// PoolData contains the configured pool data
|
|
|
-type PoolData struct {
|
|
|
- ParentKey SubnetKey
|
|
|
- Pool *net.IPNet
|
|
|
- Range *AddressRange `json:",omitempty"`
|
|
|
- RefCount int
|
|
|
-}
|
|
|
|
|
|
-// String returns the string form of the PoolData object
|
|
|
-func (p *PoolData) String() string {
|
|
|
- return fmt.Sprintf("ParentKey: %s, Pool: %s, Range: %s, RefCount: %d",
|
|
|
- p.ParentKey.String(), p.Pool.String(), p.Range, p.RefCount)
|
|
|
-}
|
|
|
+ a.addresses = make(map[SubnetKey]*bitseq.Handle)
|
|
|
|
|
|
-// MarshalJSON returns the JSON encoding of the PoolData object
|
|
|
-func (p *PoolData) MarshalJSON() ([]byte, error) {
|
|
|
- m := map[string]interface{}{
|
|
|
- "ParentKey": p.ParentKey,
|
|
|
- "RefCount": p.RefCount,
|
|
|
- }
|
|
|
- if p.Pool != nil {
|
|
|
- m["Pool"] = p.Pool.String()
|
|
|
+ cfgs := []struct {
|
|
|
+ cfg *PoolsConfig
|
|
|
+ dsc string
|
|
|
+ }{
|
|
|
+ {a.localSubnets, "local"},
|
|
|
+ {a.globalSubnets, "global"},
|
|
|
}
|
|
|
- if p.Range != nil {
|
|
|
- m["Range"] = p.Range
|
|
|
- }
|
|
|
- return json.Marshal(m)
|
|
|
-}
|
|
|
-
|
|
|
-// UnmarshalJSON decodes data into the PoolData object
|
|
|
-func (p *PoolData) UnmarshalJSON(data []byte) error {
|
|
|
- var (
|
|
|
- err error
|
|
|
- t struct {
|
|
|
- ParentKey SubnetKey
|
|
|
- Pool string
|
|
|
- Range *AddressRange `json:",omitempty"`
|
|
|
- RefCount int
|
|
|
+ // Get the initial local/global pools configfrom the datastores
|
|
|
+ var inserterList []func() error
|
|
|
+ for _, e := range cfgs {
|
|
|
+ if e.cfg.ds == nil {
|
|
|
+ continue
|
|
|
}
|
|
|
- )
|
|
|
-
|
|
|
- if err = json.Unmarshal(data, &t); err != nil {
|
|
|
- return err
|
|
|
+ if err := e.cfg.watchForChanges(); err != nil {
|
|
|
+ log.Warnf("Error on registering watch for %s datastore: %v", e.dsc, err)
|
|
|
+ }
|
|
|
+ if err := e.cfg.readFromStore(); err != nil && err != store.ErrKeyNotFound {
|
|
|
+ return nil, fmt.Errorf("failed to retrieve the ipam %s pools config from datastore: %v", e.dsc, err)
|
|
|
+ }
|
|
|
+ e.cfg.Lock()
|
|
|
+ for k, v := range e.cfg.subnets {
|
|
|
+ if v.Range == nil {
|
|
|
+ inserterList = append(inserterList, func() error { return a.insertBitMask(e.cfg.ds, k, v.Pool) })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ e.cfg.Unlock()
|
|
|
}
|
|
|
-
|
|
|
- p.ParentKey = t.ParentKey
|
|
|
- p.Range = t.Range
|
|
|
- p.RefCount = t.RefCount
|
|
|
- if t.Pool != "" {
|
|
|
- if p.Pool, err = types.ParseCIDR(t.Pool); err != nil {
|
|
|
- return err
|
|
|
+ // Add the bitmasks (data could come from datastore)
|
|
|
+ if inserterList != nil {
|
|
|
+ for _, f := range inserterList {
|
|
|
+ if err := f(); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return nil
|
|
|
+ return a, nil
|
|
|
}
|
|
|
|
|
|
-type ipVersion int
|
|
|
-
|
|
|
-const (
|
|
|
- v4 = 4
|
|
|
- v6 = 6
|
|
|
-)
|
|
|
-
|
|
|
// GetDefaultAddressSpaces returns the local and global default address spaces
|
|
|
func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) {
|
|
|
return localAddressSpace, globalAddressSpace, nil
|
|
@@ -248,16 +122,22 @@ func (a *Allocator) RequestPool(addressSpace, pool, subPool string, options map[
|
|
|
if err != nil {
|
|
|
return "", nil, nil, ipamapi.ErrInvalidPool
|
|
|
}
|
|
|
+
|
|
|
+ cfg, err := a.getPoolsConfig(addressSpace)
|
|
|
+ if err != nil {
|
|
|
+ return "", nil, nil, err
|
|
|
+ }
|
|
|
+
|
|
|
retry:
|
|
|
- insert, err := a.updatePoolDBOnAdd(*k, nw, ipr)
|
|
|
+ insert, err := cfg.updatePoolDBOnAdd(*k, nw, ipr)
|
|
|
if err != nil {
|
|
|
return "", nil, nil, err
|
|
|
}
|
|
|
- if err := a.writeToStore(); err != nil {
|
|
|
+ if err := cfg.writeToStore(); err != nil {
|
|
|
if _, ok := err.(types.RetryError); !ok {
|
|
|
return "", nil, nil, types.InternalErrorf("pool configuration failed because of %s", err.Error())
|
|
|
}
|
|
|
- if erru := a.readFromStore(); erru != nil {
|
|
|
+ if erru := cfg.readFromStore(); erru != nil {
|
|
|
return "", nil, nil, fmt.Errorf("failed to get updated pool config from datastore (%v) after (%v)", erru, err)
|
|
|
}
|
|
|
goto retry
|
|
@@ -272,16 +152,21 @@ func (a *Allocator) ReleasePool(poolID string) error {
|
|
|
return types.BadRequestErrorf("invalid pool id: %s", poolID)
|
|
|
}
|
|
|
|
|
|
+ cfg, err := a.getPoolsConfig(k.AddressSpace)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
retry:
|
|
|
- remove, err := a.updatePoolDBOnRemoval(k)
|
|
|
+ remove, err := cfg.updatePoolDBOnRemoval(k)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- if err = a.writeToStore(); err != nil {
|
|
|
+ if err = cfg.writeToStore(); err != nil {
|
|
|
if _, ok := err.(types.RetryError); !ok {
|
|
|
return types.InternalErrorf("pool (%s) removal failed because of %v", poolID, err)
|
|
|
}
|
|
|
- if erru := a.readFromStore(); erru != nil {
|
|
|
+ if erru := cfg.readFromStore(); erru != nil {
|
|
|
return fmt.Errorf("failed to get updated pool config from datastore (%v) after (%v)", erru, err)
|
|
|
}
|
|
|
goto retry
|
|
@@ -290,6 +175,18 @@ retry:
|
|
|
return remove()
|
|
|
}
|
|
|
|
|
|
+// Given the address space, returns the local or global PoolConfig based on the
|
|
|
+// address space is local or global. AddressSpace locality is being registered with IPAM out of band.
|
|
|
+func (a *Allocator) getPoolsConfig(addrSpace string) (*PoolsConfig, error) {
|
|
|
+ a.Lock()
|
|
|
+ defer a.Unlock()
|
|
|
+ cfg, ok := a.addrSpace2Configs[addrSpace]
|
|
|
+ if !ok {
|
|
|
+ return nil, types.BadRequestErrorf("cannot find locality of address space: %s", addrSpace)
|
|
|
+ }
|
|
|
+ return cfg, nil
|
|
|
+}
|
|
|
+
|
|
|
func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool) (*SubnetKey, *net.IPNet, *net.IPNet, *AddressRange, error) {
|
|
|
var (
|
|
|
nw, aw *net.IPNet
|
|
@@ -327,89 +224,7 @@ func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool
|
|
|
return &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String(), ChildSubnet: subPool}, nw, aw, ipr, nil
|
|
|
}
|
|
|
|
|
|
-func (a *Allocator) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *AddressRange) (func() error, error) {
|
|
|
- a.Lock()
|
|
|
- defer a.Unlock()
|
|
|
-
|
|
|
- // Check if already allocated
|
|
|
- if p, ok := a.subnets[k]; ok {
|
|
|
- a.incRefCount(p, 1)
|
|
|
- return func() error { return nil }, nil
|
|
|
- }
|
|
|
-
|
|
|
- // If master pool, check for overlap
|
|
|
- if ipr == nil {
|
|
|
- if a.contains(k.AddressSpace, nw) {
|
|
|
- return nil, ipamapi.ErrPoolOverlap
|
|
|
- }
|
|
|
- // This is a new master pool, add it along with corresponding bitmask
|
|
|
- a.subnets[k] = &PoolData{Pool: nw, RefCount: 1}
|
|
|
- return func() error { return a.insertBitMask(k, nw) }, nil
|
|
|
- }
|
|
|
-
|
|
|
- // This is a new non-master pool
|
|
|
- p := &PoolData{
|
|
|
- ParentKey: SubnetKey{AddressSpace: k.AddressSpace, Subnet: k.Subnet},
|
|
|
- Pool: nw,
|
|
|
- Range: ipr,
|
|
|
- RefCount: 1,
|
|
|
- }
|
|
|
- a.subnets[k] = p
|
|
|
-
|
|
|
- // Look for parent pool
|
|
|
- pp, ok := a.subnets[p.ParentKey]
|
|
|
- if ok {
|
|
|
- a.incRefCount(pp, 1)
|
|
|
- return func() error { return nil }, nil
|
|
|
- }
|
|
|
-
|
|
|
- // Parent pool does not exist, add it along with corresponding bitmask
|
|
|
- a.subnets[p.ParentKey] = &PoolData{Pool: nw, RefCount: 1}
|
|
|
- return func() error { return a.insertBitMask(p.ParentKey, nw) }, nil
|
|
|
-}
|
|
|
-
|
|
|
-func (a *Allocator) updatePoolDBOnRemoval(k SubnetKey) (func() error, error) {
|
|
|
- a.Lock()
|
|
|
- defer a.Unlock()
|
|
|
-
|
|
|
- p, ok := a.subnets[k]
|
|
|
- if !ok {
|
|
|
- return nil, ipamapi.ErrBadPool
|
|
|
- }
|
|
|
-
|
|
|
- a.incRefCount(p, -1)
|
|
|
-
|
|
|
- c := p
|
|
|
- for ok {
|
|
|
- if c.RefCount == 0 {
|
|
|
- delete(a.subnets, k)
|
|
|
- if c.Range == nil {
|
|
|
- return func() error {
|
|
|
- bm, err := a.retrieveBitmask(k, c.Pool)
|
|
|
- if err != nil {
|
|
|
- return fmt.Errorf("could not find bitmask in datastore for pool %s removal: %v", k.String(), err)
|
|
|
- }
|
|
|
- return bm.Destroy()
|
|
|
- }, nil
|
|
|
- }
|
|
|
- }
|
|
|
- k = c.ParentKey
|
|
|
- c, ok = a.subnets[k]
|
|
|
- }
|
|
|
-
|
|
|
- return func() error { return nil }, nil
|
|
|
-}
|
|
|
-
|
|
|
-func (a *Allocator) incRefCount(p *PoolData, delta int) {
|
|
|
- c := p
|
|
|
- ok := true
|
|
|
- for ok {
|
|
|
- c.RefCount += delta
|
|
|
- c, ok = a.subnets[c.ParentKey]
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
|
|
|
+func (a *Allocator) insertBitMask(store datastore.DataStore, key SubnetKey, pool *net.IPNet) error {
|
|
|
log.Debugf("Inserting bitmask (%s, %s)", key.String(), pool.String())
|
|
|
ipVer := getAddressVersion(pool.IP)
|
|
|
ones, bits := pool.Mask.Size()
|
|
@@ -421,7 +236,7 @@ func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
|
|
|
}
|
|
|
|
|
|
// Generate the new address masks. AddressMask content may come from datastore
|
|
|
- h, err := bitseq.NewHandle(dsDataKey, a.store, key.String(), numAddresses)
|
|
|
+ h, err := bitseq.NewHandle(dsDataKey, store, key.String(), numAddresses)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
@@ -434,17 +249,16 @@ func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
|
|
|
a.Lock()
|
|
|
a.addresses[key] = h
|
|
|
a.Unlock()
|
|
|
-
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle, error) {
|
|
|
+func (a *Allocator) retrieveBitmask(ds datastore.DataStore, k SubnetKey, n *net.IPNet) (*bitseq.Handle, error) {
|
|
|
a.Lock()
|
|
|
bm, ok := a.addresses[k]
|
|
|
a.Unlock()
|
|
|
if !ok {
|
|
|
log.Debugf("Retrieving bitmask (%s, %s)", k.String(), n.String())
|
|
|
- if err := a.insertBitMask(k, n); err != nil {
|
|
|
+ if err := a.insertBitMask(ds, k, n); err != nil {
|
|
|
return nil, fmt.Errorf("could not find bitmask in datastore for %s", k.String())
|
|
|
}
|
|
|
a.Lock()
|
|
@@ -475,18 +289,23 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error)
|
|
|
return nil, fmt.Errorf("no default pool availbale for non-default addresss spaces")
|
|
|
}
|
|
|
|
|
|
+ cfg, err := a.getPoolsConfig(as)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
for _, nw := range a.getPredefineds(as) {
|
|
|
if v != getAddressVersion(nw.IP) {
|
|
|
continue
|
|
|
}
|
|
|
- a.Lock()
|
|
|
- _, ok := a.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]
|
|
|
- a.Unlock()
|
|
|
+ cfg.Lock()
|
|
|
+ _, ok := cfg.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]
|
|
|
+ cfg.Unlock()
|
|
|
if ok {
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
- if !a.contains(as, nw) {
|
|
|
+ if !cfg.contains(as, nw) {
|
|
|
if as == localAddressSpace {
|
|
|
if err := netutils.CheckRouteOverlaps(nw); err == nil {
|
|
|
return nw, nil
|
|
@@ -500,38 +319,6 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error)
|
|
|
return nil, types.NotFoundErrorf("could not find an available predefined network")
|
|
|
}
|
|
|
|
|
|
-// Check subnets size. In case configured subnet is v6 and host size is
|
|
|
-// greater than 32 bits, adjust subnet to /96.
|
|
|
-func adjustAndCheckSubnetSize(subnet *net.IPNet) (*net.IPNet, error) {
|
|
|
- ones, bits := subnet.Mask.Size()
|
|
|
- if v6 == getAddressVersion(subnet.IP) {
|
|
|
- if ones < minNetSizeV6 {
|
|
|
- return nil, ipamapi.ErrInvalidPool
|
|
|
- }
|
|
|
- if ones < minNetSizeV6Eff {
|
|
|
- newMask := net.CIDRMask(minNetSizeV6Eff, bits)
|
|
|
- return &net.IPNet{IP: subnet.IP, Mask: newMask}, nil
|
|
|
- }
|
|
|
- } else {
|
|
|
- if ones < minNetSize {
|
|
|
- return nil, ipamapi.ErrInvalidPool
|
|
|
- }
|
|
|
- }
|
|
|
- return subnet, nil
|
|
|
-}
|
|
|
-
|
|
|
-// Checks whether the passed subnet is a superset or subset of any of the subset in the db
|
|
|
-func (a *Allocator) contains(space string, nw *net.IPNet) bool {
|
|
|
- for k, v := range a.subnets {
|
|
|
- if space == k.AddressSpace && k.ChildSubnet == "" {
|
|
|
- if nw.Contains(v.Pool.IP) || v.Pool.Contains(nw.IP) {
|
|
|
- return true
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return false
|
|
|
-}
|
|
|
-
|
|
|
// 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) {
|
|
|
k := SubnetKey{}
|
|
@@ -539,26 +326,31 @@ func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[s
|
|
|
return nil, nil, types.BadRequestErrorf("invalid pool id: %s", poolID)
|
|
|
}
|
|
|
|
|
|
- a.Lock()
|
|
|
- p, ok := a.subnets[k]
|
|
|
+ cfg, err := a.getPoolsConfig(k.AddressSpace)
|
|
|
+ if err != nil {
|
|
|
+ return nil, nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ cfg.Lock()
|
|
|
+ p, ok := cfg.subnets[k]
|
|
|
if !ok {
|
|
|
- a.Unlock()
|
|
|
+ cfg.Unlock()
|
|
|
return nil, nil, types.NotFoundErrorf("cannot find address pool for poolID:%s", poolID)
|
|
|
}
|
|
|
|
|
|
if prefAddress != nil && !p.Pool.Contains(prefAddress) {
|
|
|
- a.Unlock()
|
|
|
+ cfg.Unlock()
|
|
|
return nil, nil, ipamapi.ErrIPOutOfRange
|
|
|
}
|
|
|
|
|
|
c := p
|
|
|
for c.Range != nil {
|
|
|
k = c.ParentKey
|
|
|
- c, ok = a.subnets[k]
|
|
|
+ c, ok = cfg.subnets[k]
|
|
|
}
|
|
|
- a.Unlock()
|
|
|
+ cfg.Unlock()
|
|
|
|
|
|
- bm, err := a.retrieveBitmask(k, c.Pool)
|
|
|
+ bm, err := a.retrieveBitmask(cfg.ds, k, c.Pool)
|
|
|
if err != nil {
|
|
|
return nil, nil, fmt.Errorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
|
|
|
k.String(), prefAddress, poolID, err)
|
|
@@ -578,24 +370,29 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
|
|
|
return types.BadRequestErrorf("invalid pool id: %s", poolID)
|
|
|
}
|
|
|
|
|
|
- a.Lock()
|
|
|
- p, ok := a.subnets[k]
|
|
|
+ cfg, err := a.getPoolsConfig(k.AddressSpace)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ cfg.Lock()
|
|
|
+ p, ok := cfg.subnets[k]
|
|
|
if !ok {
|
|
|
- a.Unlock()
|
|
|
+ cfg.Unlock()
|
|
|
return ipamapi.ErrBadPool
|
|
|
}
|
|
|
|
|
|
if address == nil || !p.Pool.Contains(address) {
|
|
|
- a.Unlock()
|
|
|
+ cfg.Unlock()
|
|
|
return ipamapi.ErrInvalidRequest
|
|
|
}
|
|
|
|
|
|
c := p
|
|
|
for c.Range != nil {
|
|
|
k = c.ParentKey
|
|
|
- c = a.subnets[k]
|
|
|
+ c = cfg.subnets[k]
|
|
|
}
|
|
|
- a.Unlock()
|
|
|
+ cfg.Unlock()
|
|
|
|
|
|
mask := p.Pool.Mask
|
|
|
if p.Range != nil {
|
|
@@ -606,7 +403,7 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
|
|
|
return fmt.Errorf("failed to release address %s: %v", address.String(), err)
|
|
|
}
|
|
|
|
|
|
- bm, err := a.retrieveBitmask(k, c.Pool)
|
|
|
+ bm, err := cfg.alloc.retrieveBitmask(cfg.ds, k, c.Pool)
|
|
|
if err != nil {
|
|
|
return fmt.Errorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v",
|
|
|
k.String(), address, poolID, err)
|
|
@@ -652,10 +449,19 @@ func (a *Allocator) DumpDatabase() string {
|
|
|
a.Lock()
|
|
|
defer a.Unlock()
|
|
|
|
|
|
- s := fmt.Sprintf("\n\nPoolData")
|
|
|
- for k, config := range a.subnets {
|
|
|
+ s := fmt.Sprintf("\n\nLocal Pool Config")
|
|
|
+ a.localSubnets.Lock()
|
|
|
+ for k, config := range a.localSubnets.subnets {
|
|
|
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
|
|
|
}
|
|
|
+ a.localSubnets.Unlock()
|
|
|
+
|
|
|
+ s = fmt.Sprintf("%s\n\nGlobal Pool Config", s)
|
|
|
+ a.globalSubnets.Lock()
|
|
|
+ for k, config := range a.globalSubnets.subnets {
|
|
|
+ s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
|
|
|
+ }
|
|
|
+ a.globalSubnets.Unlock()
|
|
|
|
|
|
s = fmt.Sprintf("%s\n\nBitmasks", s)
|
|
|
for k, bm := range a.addresses {
|
|
@@ -663,95 +469,3 @@ func (a *Allocator) DumpDatabase() string {
|
|
|
}
|
|
|
return s
|
|
|
}
|
|
|
-
|
|
|
-// It generates the ip address in the passed subnet specified by
|
|
|
-// the passed host address ordinal
|
|
|
-func generateAddress(ordinal uint32, network *net.IPNet) net.IP {
|
|
|
- var address [16]byte
|
|
|
-
|
|
|
- // Get network portion of IP
|
|
|
- if getAddressVersion(network.IP) == v4 {
|
|
|
- copy(address[:], network.IP.To4())
|
|
|
- } else {
|
|
|
- copy(address[:], network.IP)
|
|
|
- }
|
|
|
-
|
|
|
- end := len(network.Mask)
|
|
|
- addIntToIP(address[:end], ordinal)
|
|
|
-
|
|
|
- return net.IP(address[:end])
|
|
|
-}
|
|
|
-
|
|
|
-func getAddressVersion(ip net.IP) ipVersion {
|
|
|
- if ip.To4() == nil {
|
|
|
- return v6
|
|
|
- }
|
|
|
- return v4
|
|
|
-}
|
|
|
-
|
|
|
-// Adds the ordinal IP to the current array
|
|
|
-// 192.168.0.0 + 53 => 192.168.53
|
|
|
-func addIntToIP(array []byte, ordinal uint32) {
|
|
|
- for i := len(array) - 1; i >= 0; i-- {
|
|
|
- array[i] |= (byte)(ordinal & 0xff)
|
|
|
- ordinal >>= 8
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// Convert an ordinal to the respective IP address
|
|
|
-func ipToUint32(ip []byte) uint32 {
|
|
|
- value := uint32(0)
|
|
|
- for i := 0; i < len(ip); i++ {
|
|
|
- j := len(ip) - 1 - i
|
|
|
- value += uint32(ip[i]) << uint(j*8)
|
|
|
- }
|
|
|
- return value
|
|
|
-}
|
|
|
-
|
|
|
-func initLocalPredefinedPools() []*net.IPNet {
|
|
|
- pl := make([]*net.IPNet, 0, 274)
|
|
|
- mask := []byte{255, 255, 0, 0}
|
|
|
- for i := 17; i < 32; i++ {
|
|
|
- pl = append(pl, &net.IPNet{IP: []byte{172, byte(i), 0, 0}, Mask: mask})
|
|
|
- }
|
|
|
- for i := 0; i < 256; i++ {
|
|
|
- pl = append(pl, &net.IPNet{IP: []byte{10, byte(i), 0, 0}, Mask: mask})
|
|
|
- }
|
|
|
- mask24 := []byte{255, 255, 255, 0}
|
|
|
- for i := 42; i < 45; i++ {
|
|
|
- pl = append(pl, &net.IPNet{IP: []byte{192, 168, byte(i), 0}, Mask: mask24})
|
|
|
- }
|
|
|
- return pl
|
|
|
-}
|
|
|
-
|
|
|
-func initGlobalPredefinedPools() []*net.IPNet {
|
|
|
- pl := make([]*net.IPNet, 0, 256*256)
|
|
|
- mask := []byte{255, 255, 255, 0}
|
|
|
- for i := 0; i < 256; i++ {
|
|
|
- for j := 0; j < 256; j++ {
|
|
|
- pl = append(pl, &net.IPNet{IP: []byte{10, byte(i), byte(j), 0}, Mask: mask})
|
|
|
- }
|
|
|
- }
|
|
|
- return pl
|
|
|
-}
|
|
|
-
|
|
|
-func getAddressRange(pool string) (*AddressRange, error) {
|
|
|
- ip, nw, err := net.ParseCIDR(pool)
|
|
|
- if err != nil {
|
|
|
- return nil, ipamapi.ErrInvalidSubPool
|
|
|
- }
|
|
|
- lIP, e := types.GetHostPartIP(nw.IP, nw.Mask)
|
|
|
- if e != nil {
|
|
|
- return nil, fmt.Errorf("failed to compute range's lowest ip address: %v", e)
|
|
|
- }
|
|
|
- bIP, e := types.GetBroadcastIP(nw.IP, nw.Mask)
|
|
|
- if e != nil {
|
|
|
- return nil, fmt.Errorf("failed to compute range's broadcast ip address: %v", e)
|
|
|
- }
|
|
|
- hIP, e := types.GetHostPartIP(bIP, nw.Mask)
|
|
|
- if e != nil {
|
|
|
- return nil, fmt.Errorf("failed to compute range's highest ip address: %v", e)
|
|
|
- }
|
|
|
- nw.IP = ip
|
|
|
- return &AddressRange{nw, ipToUint32(types.GetMinimalIP(lIP)), ipToUint32(types.GetMinimalIP(hIP))}, nil
|
|
|
-}
|