Remove the need for watching for IPAM data
structures and add multi store support code and
data reorganization to simplify address space
management.
Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
| ... | ... |
@@ -57,9 +57,6 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32 |
| 57 | 57 |
return h, nil |
| 58 | 58 |
} |
| 59 | 59 |
|
| 60 |
- // Register for status changes |
|
| 61 |
- h.watchForChanges() |
|
| 62 |
- |
|
| 63 | 60 |
// Get the initial status from the ds if present. |
| 64 | 61 |
if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
|
| 65 | 62 |
return nil, err |
| ... | ... |
@@ -252,6 +249,12 @@ func (h *Handle) set(ordinal, start, end uint32, any bool, release bool) (uint32 |
| 252 | 252 |
) |
| 253 | 253 |
|
| 254 | 254 |
for {
|
| 255 |
+ if h.store != nil {
|
|
| 256 |
+ if err := h.store.GetObject(datastore.Key(h.Key()...), h); err != nil && err != datastore.ErrKeyNotFound {
|
|
| 257 |
+ return ret, err |
|
| 258 |
+ } |
|
| 259 |
+ } |
|
| 260 |
+ |
|
| 255 | 261 |
h.Lock() |
| 256 | 262 |
// Get position if available |
| 257 | 263 |
if release {
|
| ... | ... |
@@ -70,46 +70,47 @@ func (h *Handle) Exists() bool {
|
| 70 | 70 |
return h.dbExists |
| 71 | 71 |
} |
| 72 | 72 |
|
| 73 |
+// New method returns a handle based on the receiver handle |
|
| 74 |
+func (h *Handle) New() datastore.KVObject {
|
|
| 75 |
+ h.Lock() |
|
| 76 |
+ defer h.Unlock() |
|
| 77 |
+ |
|
| 78 |
+ return &Handle{
|
|
| 79 |
+ app: h.app, |
|
| 80 |
+ id: h.id, |
|
| 81 |
+ store: h.store, |
|
| 82 |
+ } |
|
| 83 |
+} |
|
| 84 |
+ |
|
| 85 |
+// CopyTo deep copies the handle into the passed destination object |
|
| 86 |
+func (h *Handle) CopyTo(o datastore.KVObject) error {
|
|
| 87 |
+ h.Lock() |
|
| 88 |
+ defer h.Unlock() |
|
| 89 |
+ |
|
| 90 |
+ dstH := o.(*Handle) |
|
| 91 |
+ dstH.bits = h.bits |
|
| 92 |
+ dstH.unselected = h.unselected |
|
| 93 |
+ dstH.head = h.head.getCopy() |
|
| 94 |
+ dstH.app = h.app |
|
| 95 |
+ dstH.id = h.id |
|
| 96 |
+ dstH.dbIndex = h.dbIndex |
|
| 97 |
+ dstH.dbExists = h.dbExists |
|
| 98 |
+ dstH.store = h.store |
|
| 99 |
+ |
|
| 100 |
+ return nil |
|
| 101 |
+} |
|
| 102 |
+ |
|
| 73 | 103 |
// Skip provides a way for a KV Object to avoid persisting it in the KV Store |
| 74 | 104 |
func (h *Handle) Skip() bool {
|
| 75 | 105 |
return false |
| 76 | 106 |
} |
| 77 | 107 |
|
| 78 | 108 |
// DataScope method returns the storage scope of the datastore |
| 79 |
-func (h *Handle) DataScope() datastore.DataScope {
|
|
| 80 |
- return datastore.GlobalScope |
|
| 81 |
-} |
|
| 82 |
- |
|
| 83 |
-func (h *Handle) watchForChanges() error {
|
|
| 109 |
+func (h *Handle) DataScope() string {
|
|
| 84 | 110 |
h.Lock() |
| 85 |
- store := h.store |
|
| 86 |
- h.Unlock() |
|
| 87 |
- |
|
| 88 |
- if store == nil {
|
|
| 89 |
- return nil |
|
| 90 |
- } |
|
| 111 |
+ defer h.Unlock() |
|
| 91 | 112 |
|
| 92 |
- kvpChan, err := store.KVStore().Watch(datastore.Key(h.Key()...), nil) |
|
| 93 |
- if err != nil {
|
|
| 94 |
- return err |
|
| 95 |
- } |
|
| 96 |
- go func() {
|
|
| 97 |
- for {
|
|
| 98 |
- select {
|
|
| 99 |
- case kvPair := <-kvpChan: |
|
| 100 |
- // Only process remote update |
|
| 101 |
- if kvPair != nil && (kvPair.LastIndex != h.Index()) {
|
|
| 102 |
- err := h.fromDsValue(kvPair.Value) |
|
| 103 |
- if err != nil {
|
|
| 104 |
- log.Warnf("Failed to reconstruct bitseq handle from ds watch: %s", err.Error())
|
|
| 105 |
- } else {
|
|
| 106 |
- h.SetIndex(kvPair.LastIndex) |
|
| 107 |
- } |
|
| 108 |
- } |
|
| 109 |
- } |
|
| 110 |
- } |
|
| 111 |
- }() |
|
| 112 |
- return nil |
|
| 113 |
+ return h.store.Scope() |
|
| 113 | 114 |
} |
| 114 | 115 |
|
| 115 | 116 |
func (h *Handle) fromDsValue(value []byte) error {
|
| ... | ... |
@@ -6,7 +6,6 @@ import ( |
| 6 | 6 |
"sync" |
| 7 | 7 |
|
| 8 | 8 |
log "github.com/Sirupsen/logrus" |
| 9 |
- "github.com/docker/libkv/store" |
|
| 10 | 9 |
"github.com/docker/libnetwork/bitseq" |
| 11 | 10 |
"github.com/docker/libnetwork/datastore" |
| 12 | 11 |
"github.com/docker/libnetwork/ipamapi" |
| ... | ... |
@@ -30,13 +29,10 @@ const ( |
| 30 | 30 |
type Allocator struct {
|
| 31 | 31 |
// Predefined pools for default address spaces |
| 32 | 32 |
predefined map[string][]*net.IPNet |
| 33 |
- // Static subnet information |
|
| 34 |
- localSubnets *PoolsConfig |
|
| 35 |
- globalSubnets *PoolsConfig |
|
| 33 |
+ addrSpaces map[string]*addrSpace |
|
| 34 |
+ // stores []datastore.Datastore |
|
| 36 | 35 |
// Allocated addresses in each address space's subnet |
| 37 | 36 |
addresses map[SubnetKey]*bitseq.Handle |
| 38 |
- // Datastore |
|
| 39 |
- addrSpace2Configs map[string]*PoolsConfig |
|
| 40 | 37 |
sync.Mutex |
| 41 | 38 |
} |
| 42 | 39 |
|
| ... | ... |
@@ -44,71 +40,84 @@ type Allocator struct {
|
| 44 | 44 |
func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
|
| 45 | 45 |
a := &Allocator{}
|
| 46 | 46 |
|
| 47 |
- a.localSubnets = &PoolsConfig{
|
|
| 48 |
- subnets: map[SubnetKey]*PoolData{},
|
|
| 49 |
- id: dsConfigKey + "/Pools", |
|
| 50 |
- scope: datastore.LocalScope, |
|
| 51 |
- ds: lcDs, |
|
| 52 |
- alloc: a, |
|
| 53 |
- } |
|
| 54 |
- |
|
| 55 |
- a.globalSubnets = &PoolsConfig{
|
|
| 56 |
- subnets: map[SubnetKey]*PoolData{},
|
|
| 57 |
- id: dsConfigKey + "/Pools", |
|
| 58 |
- scope: datastore.GlobalScope, |
|
| 59 |
- ds: glDs, |
|
| 60 |
- alloc: a, |
|
| 61 |
- } |
|
| 62 |
- |
|
| 47 |
+ // Load predefined subnet pools |
|
| 63 | 48 |
a.predefined = map[string][]*net.IPNet{
|
| 64 | 49 |
localAddressSpace: initLocalPredefinedPools(), |
| 65 | 50 |
globalAddressSpace: initGlobalPredefinedPools(), |
| 66 | 51 |
} |
| 67 | 52 |
|
| 68 |
- a.addrSpace2Configs = map[string]*PoolsConfig{
|
|
| 69 |
- localAddressSpace: a.localSubnets, |
|
| 70 |
- globalAddressSpace: a.globalSubnets, |
|
| 71 |
- } |
|
| 72 |
- |
|
| 53 |
+ // Initialize bitseq map |
|
| 73 | 54 |
a.addresses = make(map[SubnetKey]*bitseq.Handle) |
| 74 | 55 |
|
| 75 |
- cfgs := []struct {
|
|
| 76 |
- cfg *PoolsConfig |
|
| 77 |
- dsc string |
|
| 56 |
+ // Initialize address spaces |
|
| 57 |
+ a.addrSpaces = make(map[string]*addrSpace) |
|
| 58 |
+ for _, aspc := range []struct {
|
|
| 59 |
+ as string |
|
| 60 |
+ ds datastore.DataStore |
|
| 78 | 61 |
}{
|
| 79 |
- {a.localSubnets, "local"},
|
|
| 80 |
- {a.globalSubnets, "global"},
|
|
| 81 |
- } |
|
| 82 |
- // Get the initial local/global pools configfrom the datastores |
|
| 83 |
- var inserterList []func() error |
|
| 84 |
- for _, e := range cfgs {
|
|
| 85 |
- if e.cfg.ds == nil {
|
|
| 62 |
+ {localAddressSpace, lcDs},
|
|
| 63 |
+ {globalAddressSpace, glDs},
|
|
| 64 |
+ } {
|
|
| 65 |
+ if aspc.ds == nil {
|
|
| 86 | 66 |
continue |
| 87 | 67 |
} |
| 88 |
- if err := e.cfg.watchForChanges(); err != nil {
|
|
| 89 |
- log.Warnf("Error on registering watch for %s datastore: %v", e.dsc, err)
|
|
| 90 |
- } |
|
| 91 |
- if err := e.cfg.readFromStore(); err != nil && err != store.ErrKeyNotFound {
|
|
| 92 |
- return nil, fmt.Errorf("failed to retrieve the ipam %s pools config from datastore: %v", e.dsc, err)
|
|
| 68 |
+ |
|
| 69 |
+ a.addrSpaces[aspc.as] = &addrSpace{
|
|
| 70 |
+ subnets: map[SubnetKey]*PoolData{},
|
|
| 71 |
+ id: dsConfigKey + "/" + aspc.as, |
|
| 72 |
+ scope: aspc.ds.Scope(), |
|
| 73 |
+ ds: aspc.ds, |
|
| 74 |
+ alloc: a, |
|
| 93 | 75 |
} |
| 94 |
- e.cfg.Lock() |
|
| 95 |
- for k, v := range e.cfg.subnets {
|
|
| 96 |
- if v.Range == nil {
|
|
| 97 |
- inserterList = append(inserterList, func() error { return a.insertBitMask(e.cfg.ds, k, v.Pool) })
|
|
| 98 |
- } |
|
| 76 |
+ } |
|
| 77 |
+ |
|
| 78 |
+ return a, nil |
|
| 79 |
+} |
|
| 80 |
+ |
|
| 81 |
+func (a *Allocator) refresh(as string) error {
|
|
| 82 |
+ aSpace, err := a.getAddressSpaceFromStore(as) |
|
| 83 |
+ if err != nil {
|
|
| 84 |
+ return fmt.Errorf("error getting pools config from store during init: %v",
|
|
| 85 |
+ err) |
|
| 86 |
+ } |
|
| 87 |
+ |
|
| 88 |
+ if aSpace == nil {
|
|
| 89 |
+ return nil |
|
| 90 |
+ } |
|
| 91 |
+ |
|
| 92 |
+ if err := a.updateBitMasks(aSpace); err != nil {
|
|
| 93 |
+ return fmt.Errorf("error updating bit masks during init: %v", err)
|
|
| 94 |
+ } |
|
| 95 |
+ |
|
| 96 |
+ a.Lock() |
|
| 97 |
+ a.addrSpaces[as] = aSpace |
|
| 98 |
+ a.Unlock() |
|
| 99 |
+ |
|
| 100 |
+ return nil |
|
| 101 |
+} |
|
| 102 |
+ |
|
| 103 |
+func (a *Allocator) updateBitMasks(aSpace *addrSpace) error {
|
|
| 104 |
+ var inserterList []func() error |
|
| 105 |
+ |
|
| 106 |
+ aSpace.Lock() |
|
| 107 |
+ for k, v := range aSpace.subnets {
|
|
| 108 |
+ if v.Range == nil {
|
|
| 109 |
+ inserterList = append(inserterList, |
|
| 110 |
+ func() error { return a.insertBitMask(k, v.Pool) })
|
|
| 99 | 111 |
} |
| 100 |
- e.cfg.Unlock() |
|
| 101 | 112 |
} |
| 113 |
+ aSpace.Unlock() |
|
| 114 |
+ |
|
| 102 | 115 |
// Add the bitmasks (data could come from datastore) |
| 103 | 116 |
if inserterList != nil {
|
| 104 | 117 |
for _, f := range inserterList {
|
| 105 | 118 |
if err := f(); err != nil {
|
| 106 |
- return nil, err |
|
| 119 |
+ return err |
|
| 107 | 120 |
} |
| 108 | 121 |
} |
| 109 | 122 |
} |
| 110 | 123 |
|
| 111 |
- return a, nil |
|
| 124 |
+ return nil |
|
| 112 | 125 |
} |
| 113 | 126 |
|
| 114 | 127 |
// GetDefaultAddressSpaces returns the local and global default address spaces |
| ... | ... |
@@ -123,25 +132,29 @@ func (a *Allocator) RequestPool(addressSpace, pool, subPool string, options map[ |
| 123 | 123 |
return "", nil, nil, ipamapi.ErrInvalidPool |
| 124 | 124 |
} |
| 125 | 125 |
|
| 126 |
- cfg, err := a.getPoolsConfig(addressSpace) |
|
| 126 |
+retry: |
|
| 127 |
+ if err := a.refresh(addressSpace); err != nil {
|
|
| 128 |
+ return "", nil, nil, err |
|
| 129 |
+ } |
|
| 130 |
+ |
|
| 131 |
+ aSpace, err := a.getAddrSpace(addressSpace) |
|
| 127 | 132 |
if err != nil {
|
| 128 | 133 |
return "", nil, nil, err |
| 129 | 134 |
} |
| 130 | 135 |
|
| 131 |
-retry: |
|
| 132 |
- insert, err := cfg.updatePoolDBOnAdd(*k, nw, ipr) |
|
| 136 |
+ insert, err := aSpace.updatePoolDBOnAdd(*k, nw, ipr) |
|
| 133 | 137 |
if err != nil {
|
| 134 | 138 |
return "", nil, nil, err |
| 135 | 139 |
} |
| 136 |
- if err := cfg.writeToStore(); err != nil {
|
|
| 140 |
+ |
|
| 141 |
+ if err := a.writeToStore(aSpace); err != nil {
|
|
| 137 | 142 |
if _, ok := err.(types.RetryError); !ok {
|
| 138 | 143 |
return "", nil, nil, types.InternalErrorf("pool configuration failed because of %s", err.Error())
|
| 139 | 144 |
} |
| 140 |
- if erru := cfg.readFromStore(); erru != nil {
|
|
| 141 |
- return "", nil, nil, fmt.Errorf("failed to get updated pool config from datastore (%v) after (%v)", erru, err)
|
|
| 142 |
- } |
|
| 145 |
+ |
|
| 143 | 146 |
goto retry |
| 144 | 147 |
} |
| 148 |
+ |
|
| 145 | 149 |
return k.String(), aw, nil, insert() |
| 146 | 150 |
} |
| 147 | 151 |
|
| ... | ... |
@@ -152,23 +165,25 @@ func (a *Allocator) ReleasePool(poolID string) error {
|
| 152 | 152 |
return types.BadRequestErrorf("invalid pool id: %s", poolID)
|
| 153 | 153 |
} |
| 154 | 154 |
|
| 155 |
- cfg, err := a.getPoolsConfig(k.AddressSpace) |
|
| 155 |
+retry: |
|
| 156 |
+ if err := a.refresh(k.AddressSpace); err != nil {
|
|
| 157 |
+ return err |
|
| 158 |
+ } |
|
| 159 |
+ |
|
| 160 |
+ aSpace, err := a.getAddrSpace(k.AddressSpace) |
|
| 156 | 161 |
if err != nil {
|
| 157 | 162 |
return err |
| 158 | 163 |
} |
| 159 | 164 |
|
| 160 |
-retry: |
|
| 161 |
- remove, err := cfg.updatePoolDBOnRemoval(k) |
|
| 165 |
+ remove, err := aSpace.updatePoolDBOnRemoval(k) |
|
| 162 | 166 |
if err != nil {
|
| 163 | 167 |
return err |
| 164 | 168 |
} |
| 165 |
- if err = cfg.writeToStore(); err != nil {
|
|
| 169 |
+ |
|
| 170 |
+ if err = a.writeToStore(aSpace); err != nil {
|
|
| 166 | 171 |
if _, ok := err.(types.RetryError); !ok {
|
| 167 | 172 |
return types.InternalErrorf("pool (%s) removal failed because of %v", poolID, err)
|
| 168 | 173 |
} |
| 169 |
- if erru := cfg.readFromStore(); erru != nil {
|
|
| 170 |
- return fmt.Errorf("failed to get updated pool config from datastore (%v) after (%v)", erru, err)
|
|
| 171 |
- } |
|
| 172 | 174 |
goto retry |
| 173 | 175 |
} |
| 174 | 176 |
|
| ... | ... |
@@ -177,14 +192,14 @@ retry: |
| 177 | 177 |
|
| 178 | 178 |
// Given the address space, returns the local or global PoolConfig based on the |
| 179 | 179 |
// address space is local or global. AddressSpace locality is being registered with IPAM out of band. |
| 180 |
-func (a *Allocator) getPoolsConfig(addrSpace string) (*PoolsConfig, error) {
|
|
| 180 |
+func (a *Allocator) getAddrSpace(as string) (*addrSpace, error) {
|
|
| 181 | 181 |
a.Lock() |
| 182 | 182 |
defer a.Unlock() |
| 183 |
- cfg, ok := a.addrSpace2Configs[addrSpace] |
|
| 183 |
+ aSpace, ok := a.addrSpaces[as] |
|
| 184 | 184 |
if !ok {
|
| 185 |
- return nil, types.BadRequestErrorf("cannot find locality of address space: %s", addrSpace)
|
|
| 185 |
+ return nil, types.BadRequestErrorf("cannot find locality of address space: %s", as)
|
|
| 186 | 186 |
} |
| 187 |
- return cfg, nil |
|
| 187 |
+ return aSpace, nil |
|
| 188 | 188 |
} |
| 189 | 189 |
|
| 190 | 190 |
func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool) (*SubnetKey, *net.IPNet, *net.IPNet, *AddressRange, error) {
|
| ... | ... |
@@ -224,8 +239,14 @@ func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool |
| 224 | 224 |
return &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String(), ChildSubnet: subPool}, nw, aw, ipr, nil
|
| 225 | 225 |
} |
| 226 | 226 |
|
| 227 |
-func (a *Allocator) insertBitMask(store datastore.DataStore, key SubnetKey, pool *net.IPNet) error {
|
|
| 227 |
+func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
|
|
| 228 | 228 |
log.Debugf("Inserting bitmask (%s, %s)", key.String(), pool.String())
|
| 229 |
+ |
|
| 230 |
+ store := a.getStore(key.AddressSpace) |
|
| 231 |
+ if store == nil {
|
|
| 232 |
+ return fmt.Errorf("could not find store for address space %s while inserting bit mask", key.AddressSpace)
|
|
| 233 |
+ } |
|
| 234 |
+ |
|
| 229 | 235 |
ipVer := getAddressVersion(pool.IP) |
| 230 | 236 |
ones, bits := pool.Mask.Size() |
| 231 | 237 |
numAddresses := uint32(1 << uint(bits-ones)) |
| ... | ... |
@@ -252,13 +273,13 @@ func (a *Allocator) insertBitMask(store datastore.DataStore, key SubnetKey, pool |
| 252 | 252 |
return nil |
| 253 | 253 |
} |
| 254 | 254 |
|
| 255 |
-func (a *Allocator) retrieveBitmask(ds datastore.DataStore, k SubnetKey, n *net.IPNet) (*bitseq.Handle, error) {
|
|
| 255 |
+func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle, error) {
|
|
| 256 | 256 |
a.Lock() |
| 257 | 257 |
bm, ok := a.addresses[k] |
| 258 | 258 |
a.Unlock() |
| 259 | 259 |
if !ok {
|
| 260 | 260 |
log.Debugf("Retrieving bitmask (%s, %s)", k.String(), n.String())
|
| 261 |
- if err := a.insertBitMask(ds, k, n); err != nil {
|
|
| 261 |
+ if err := a.insertBitMask(k, n); err != nil {
|
|
| 262 | 262 |
return nil, fmt.Errorf("could not find bitmask in datastore for %s", k.String())
|
| 263 | 263 |
} |
| 264 | 264 |
a.Lock() |
| ... | ... |
@@ -289,7 +310,7 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) |
| 289 | 289 |
return nil, fmt.Errorf("no default pool availbale for non-default addresss spaces")
|
| 290 | 290 |
} |
| 291 | 291 |
|
| 292 |
- cfg, err := a.getPoolsConfig(as) |
|
| 292 |
+ aSpace, err := a.getAddrSpace(as) |
|
| 293 | 293 |
if err != nil {
|
| 294 | 294 |
return nil, err |
| 295 | 295 |
} |
| ... | ... |
@@ -298,14 +319,14 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) |
| 298 | 298 |
if v != getAddressVersion(nw.IP) {
|
| 299 | 299 |
continue |
| 300 | 300 |
} |
| 301 |
- cfg.Lock() |
|
| 302 |
- _, ok := cfg.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]
|
|
| 303 |
- cfg.Unlock() |
|
| 301 |
+ aSpace.Lock() |
|
| 302 |
+ _, ok := aSpace.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]
|
|
| 303 |
+ aSpace.Unlock() |
|
| 304 | 304 |
if ok {
|
| 305 | 305 |
continue |
| 306 | 306 |
} |
| 307 | 307 |
|
| 308 |
- if !cfg.contains(as, nw) {
|
|
| 308 |
+ if !aSpace.contains(as, nw) {
|
|
| 309 | 309 |
if as == localAddressSpace {
|
| 310 | 310 |
if err := netutils.CheckRouteOverlaps(nw); err == nil {
|
| 311 | 311 |
return nw, nil |
| ... | ... |
@@ -326,31 +347,35 @@ func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[s |
| 326 | 326 |
return nil, nil, types.BadRequestErrorf("invalid pool id: %s", poolID)
|
| 327 | 327 |
} |
| 328 | 328 |
|
| 329 |
- cfg, err := a.getPoolsConfig(k.AddressSpace) |
|
| 329 |
+ if err := a.refresh(k.AddressSpace); err != nil {
|
|
| 330 |
+ return nil, nil, err |
|
| 331 |
+ } |
|
| 332 |
+ |
|
| 333 |
+ aSpace, err := a.getAddrSpace(k.AddressSpace) |
|
| 330 | 334 |
if err != nil {
|
| 331 | 335 |
return nil, nil, err |
| 332 | 336 |
} |
| 333 | 337 |
|
| 334 |
- cfg.Lock() |
|
| 335 |
- p, ok := cfg.subnets[k] |
|
| 338 |
+ aSpace.Lock() |
|
| 339 |
+ p, ok := aSpace.subnets[k] |
|
| 336 | 340 |
if !ok {
|
| 337 |
- cfg.Unlock() |
|
| 341 |
+ aSpace.Unlock() |
|
| 338 | 342 |
return nil, nil, types.NotFoundErrorf("cannot find address pool for poolID:%s", poolID)
|
| 339 | 343 |
} |
| 340 | 344 |
|
| 341 | 345 |
if prefAddress != nil && !p.Pool.Contains(prefAddress) {
|
| 342 |
- cfg.Unlock() |
|
| 346 |
+ aSpace.Unlock() |
|
| 343 | 347 |
return nil, nil, ipamapi.ErrIPOutOfRange |
| 344 | 348 |
} |
| 345 | 349 |
|
| 346 | 350 |
c := p |
| 347 | 351 |
for c.Range != nil {
|
| 348 | 352 |
k = c.ParentKey |
| 349 |
- c, ok = cfg.subnets[k] |
|
| 353 |
+ c, ok = aSpace.subnets[k] |
|
| 350 | 354 |
} |
| 351 |
- cfg.Unlock() |
|
| 355 |
+ aSpace.Unlock() |
|
| 352 | 356 |
|
| 353 |
- bm, err := a.retrieveBitmask(cfg.ds, k, c.Pool) |
|
| 357 |
+ bm, err := a.retrieveBitmask(k, c.Pool) |
|
| 354 | 358 |
if err != nil {
|
| 355 | 359 |
return nil, nil, fmt.Errorf("could not find bitmask in datastore for %s on address %v request from pool %s: %v",
|
| 356 | 360 |
k.String(), prefAddress, poolID, err) |
| ... | ... |
@@ -370,29 +395,33 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
|
| 370 | 370 |
return types.BadRequestErrorf("invalid pool id: %s", poolID)
|
| 371 | 371 |
} |
| 372 | 372 |
|
| 373 |
- cfg, err := a.getPoolsConfig(k.AddressSpace) |
|
| 373 |
+ if err := a.refresh(k.AddressSpace); err != nil {
|
|
| 374 |
+ return err |
|
| 375 |
+ } |
|
| 376 |
+ |
|
| 377 |
+ aSpace, err := a.getAddrSpace(k.AddressSpace) |
|
| 374 | 378 |
if err != nil {
|
| 375 | 379 |
return err |
| 376 | 380 |
} |
| 377 | 381 |
|
| 378 |
- cfg.Lock() |
|
| 379 |
- p, ok := cfg.subnets[k] |
|
| 382 |
+ aSpace.Lock() |
|
| 383 |
+ p, ok := aSpace.subnets[k] |
|
| 380 | 384 |
if !ok {
|
| 381 |
- cfg.Unlock() |
|
| 385 |
+ aSpace.Unlock() |
|
| 382 | 386 |
return ipamapi.ErrBadPool |
| 383 | 387 |
} |
| 384 | 388 |
|
| 385 | 389 |
if address == nil || !p.Pool.Contains(address) {
|
| 386 |
- cfg.Unlock() |
|
| 390 |
+ aSpace.Unlock() |
|
| 387 | 391 |
return ipamapi.ErrInvalidRequest |
| 388 | 392 |
} |
| 389 | 393 |
|
| 390 | 394 |
c := p |
| 391 | 395 |
for c.Range != nil {
|
| 392 | 396 |
k = c.ParentKey |
| 393 |
- c = cfg.subnets[k] |
|
| 397 |
+ c = aSpace.subnets[k] |
|
| 394 | 398 |
} |
| 395 |
- cfg.Unlock() |
|
| 399 |
+ aSpace.Unlock() |
|
| 396 | 400 |
|
| 397 | 401 |
mask := p.Pool.Mask |
| 398 | 402 |
if p.Range != nil {
|
| ... | ... |
@@ -403,7 +432,7 @@ func (a *Allocator) ReleaseAddress(poolID string, address net.IP) error {
|
| 403 | 403 |
return fmt.Errorf("failed to release address %s: %v", address.String(), err)
|
| 404 | 404 |
} |
| 405 | 405 |
|
| 406 |
- bm, err := cfg.alloc.retrieveBitmask(cfg.ds, k, c.Pool) |
|
| 406 |
+ bm, err := a.retrieveBitmask(k, c.Pool) |
|
| 407 | 407 |
if err != nil {
|
| 408 | 408 |
return fmt.Errorf("could not find bitmask in datastore for %s on address %v release from pool %s: %v",
|
| 409 | 409 |
k.String(), address, poolID, err) |
| ... | ... |
@@ -449,23 +478,20 @@ func (a *Allocator) DumpDatabase() string {
|
| 449 | 449 |
a.Lock() |
| 450 | 450 |
defer a.Unlock() |
| 451 | 451 |
|
| 452 |
- s := fmt.Sprintf("\n\nLocal Pool Config")
|
|
| 453 |
- a.localSubnets.Lock() |
|
| 454 |
- for k, config := range a.localSubnets.subnets {
|
|
| 455 |
- s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
|
|
| 456 |
- } |
|
| 457 |
- a.localSubnets.Unlock() |
|
| 458 |
- |
|
| 459 |
- s = fmt.Sprintf("%s\n\nGlobal Pool Config", s)
|
|
| 460 |
- a.globalSubnets.Lock() |
|
| 461 |
- for k, config := range a.globalSubnets.subnets {
|
|
| 462 |
- s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
|
|
| 452 |
+ var s string |
|
| 453 |
+ for as, aSpace := range a.addrSpaces {
|
|
| 454 |
+ s = fmt.Sprintf("\n\n%s Config", as)
|
|
| 455 |
+ aSpace.Lock() |
|
| 456 |
+ for k, config := range aSpace.subnets {
|
|
| 457 |
+ s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
|
|
| 458 |
+ } |
|
| 459 |
+ aSpace.Unlock() |
|
| 463 | 460 |
} |
| 464 |
- a.globalSubnets.Unlock() |
|
| 465 | 461 |
|
| 466 | 462 |
s = fmt.Sprintf("%s\n\nBitmasks", s)
|
| 467 | 463 |
for k, bm := range a.addresses {
|
| 468 | 464 |
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n\t%s: %s\n\t%d", k, bm, bm.Unselected()))
|
| 469 | 465 |
} |
| 466 |
+ |
|
| 470 | 467 |
return s |
| 471 | 468 |
} |
| ... | ... |
@@ -11,7 +11,6 @@ import ( |
| 11 | 11 |
|
| 12 | 12 |
"github.com/docker/libkv/store" |
| 13 | 13 |
"github.com/docker/libnetwork/bitseq" |
| 14 |
- "github.com/docker/libnetwork/config" |
|
| 15 | 14 |
"github.com/docker/libnetwork/datastore" |
| 16 | 15 |
"github.com/docker/libnetwork/ipamapi" |
| 17 | 16 |
"github.com/docker/libnetwork/netutils" |
| ... | ... |
@@ -32,9 +31,9 @@ func randomLocalStore() (datastore.DataStore, error) {
|
| 32 | 32 |
if err := tmp.Close(); err != nil {
|
| 33 | 33 |
return nil, fmt.Errorf("Error closing temp file: %v", err)
|
| 34 | 34 |
} |
| 35 |
- return datastore.NewDataStore(&config.DatastoreCfg{
|
|
| 35 |
+ return datastore.NewDataStore(datastore.LocalScope, &datastore.ScopeCfg{
|
|
| 36 | 36 |
Embedded: true, |
| 37 |
- Client: config.DatastoreClientCfg{
|
|
| 37 |
+ Client: datastore.ScopeClientCfg{
|
|
| 38 | 38 |
Provider: "boltdb", |
| 39 | 39 |
Address: defaultPrefix + tmp.Name(), |
| 40 | 40 |
Config: &store.Config{
|
| ... | ... |
@@ -191,7 +190,11 @@ func TestSubnetsMarshal(t *testing.T) {
|
| 191 | 191 |
t.Fatal(err) |
| 192 | 192 |
} |
| 193 | 193 |
|
| 194 |
- cfg := a.localSubnets |
|
| 194 |
+ cfg, err := a.getAddrSpace(localAddressSpace) |
|
| 195 |
+ if err != nil {
|
|
| 196 |
+ t.Fatal(err) |
|
| 197 |
+ } |
|
| 198 |
+ |
|
| 195 | 199 |
ba := cfg.Value() |
| 196 | 200 |
if err := cfg.SetValue(ba); err != nil {
|
| 197 | 201 |
t.Fatal(err) |
| ... | ... |
@@ -221,7 +224,7 @@ func TestAddSubnets(t *testing.T) {
|
| 221 | 221 |
if err != nil {
|
| 222 | 222 |
t.Fatal(err) |
| 223 | 223 |
} |
| 224 |
- a.addrSpace2Configs["abc"] = a.addrSpace2Configs[localAddressSpace] |
|
| 224 |
+ a.addrSpaces["abc"] = a.addrSpaces[localAddressSpace] |
|
| 225 | 225 |
|
| 226 | 226 |
pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) |
| 227 | 227 |
if err != nil {
|
| ... | ... |
@@ -290,7 +293,13 @@ func TestAddReleasePoolID(t *testing.T) {
|
| 290 | 290 |
if err != nil {
|
| 291 | 291 |
t.Fatal(err) |
| 292 | 292 |
} |
| 293 |
- subnets := a.localSubnets.subnets |
|
| 293 |
+ |
|
| 294 |
+ aSpace, err := a.getAddrSpace(localAddressSpace) |
|
| 295 |
+ if err != nil {
|
|
| 296 |
+ t.Fatal(err) |
|
| 297 |
+ } |
|
| 298 |
+ |
|
| 299 |
+ subnets := aSpace.subnets |
|
| 294 | 300 |
pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) |
| 295 | 301 |
if err != nil {
|
| 296 | 302 |
t.Fatalf("Unexpected failure in adding pool")
|
| ... | ... |
@@ -298,6 +307,14 @@ func TestAddReleasePoolID(t *testing.T) {
|
| 298 | 298 |
if err := k0.FromString(pid0); err != nil {
|
| 299 | 299 |
t.Fatal(err) |
| 300 | 300 |
} |
| 301 |
+ |
|
| 302 |
+ aSpace, err = a.getAddrSpace(localAddressSpace) |
|
| 303 |
+ if err != nil {
|
|
| 304 |
+ t.Fatal(err) |
|
| 305 |
+ } |
|
| 306 |
+ |
|
| 307 |
+ subnets = aSpace.subnets |
|
| 308 |
+ |
|
| 301 | 309 |
if subnets[k0].RefCount != 1 {
|
| 302 | 310 |
t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
|
| 303 | 311 |
} |
| ... | ... |
@@ -309,6 +326,13 @@ func TestAddReleasePoolID(t *testing.T) {
|
| 309 | 309 |
if err := k1.FromString(pid1); err != nil {
|
| 310 | 310 |
t.Fatal(err) |
| 311 | 311 |
} |
| 312 |
+ |
|
| 313 |
+ aSpace, err = a.getAddrSpace(localAddressSpace) |
|
| 314 |
+ if err != nil {
|
|
| 315 |
+ t.Fatal(err) |
|
| 316 |
+ } |
|
| 317 |
+ |
|
| 318 |
+ subnets = aSpace.subnets |
|
| 312 | 319 |
if subnets[k1].RefCount != 1 {
|
| 313 | 320 |
t.Fatalf("Unexpected ref count for %s: %d", k1, subnets[k1].RefCount)
|
| 314 | 321 |
} |
| ... | ... |
@@ -323,6 +347,13 @@ func TestAddReleasePoolID(t *testing.T) {
|
| 323 | 323 |
if err := k2.FromString(pid2); err != nil {
|
| 324 | 324 |
t.Fatal(err) |
| 325 | 325 |
} |
| 326 |
+ |
|
| 327 |
+ aSpace, err = a.getAddrSpace(localAddressSpace) |
|
| 328 |
+ if err != nil {
|
|
| 329 |
+ t.Fatal(err) |
|
| 330 |
+ } |
|
| 331 |
+ |
|
| 332 |
+ subnets = aSpace.subnets |
|
| 326 | 333 |
if subnets[k2].RefCount != 2 {
|
| 327 | 334 |
t.Fatalf("Unexpected ref count for %s: %d", k2, subnets[k2].RefCount)
|
| 328 | 335 |
} |
| ... | ... |
@@ -334,12 +365,26 @@ func TestAddReleasePoolID(t *testing.T) {
|
| 334 | 334 |
if err := a.ReleasePool(pid1); err != nil {
|
| 335 | 335 |
t.Fatal(err) |
| 336 | 336 |
} |
| 337 |
+ |
|
| 338 |
+ aSpace, err = a.getAddrSpace(localAddressSpace) |
|
| 339 |
+ if err != nil {
|
|
| 340 |
+ t.Fatal(err) |
|
| 341 |
+ } |
|
| 342 |
+ |
|
| 343 |
+ subnets = aSpace.subnets |
|
| 337 | 344 |
if subnets[k0].RefCount != 2 {
|
| 338 | 345 |
t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
|
| 339 | 346 |
} |
| 340 | 347 |
if err := a.ReleasePool(pid0); err != nil {
|
| 341 | 348 |
t.Fatal(err) |
| 342 | 349 |
} |
| 350 |
+ |
|
| 351 |
+ aSpace, err = a.getAddrSpace(localAddressSpace) |
|
| 352 |
+ if err != nil {
|
|
| 353 |
+ t.Fatal(err) |
|
| 354 |
+ } |
|
| 355 |
+ |
|
| 356 |
+ subnets = aSpace.subnets |
|
| 343 | 357 |
if subnets[k0].RefCount != 1 {
|
| 344 | 358 |
t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
|
| 345 | 359 |
} |
| ... | ... |
@@ -351,6 +396,13 @@ func TestAddReleasePoolID(t *testing.T) {
|
| 351 | 351 |
if pid00 != pid0 {
|
| 352 | 352 |
t.Fatalf("main pool should still exist")
|
| 353 | 353 |
} |
| 354 |
+ |
|
| 355 |
+ aSpace, err = a.getAddrSpace(localAddressSpace) |
|
| 356 |
+ if err != nil {
|
|
| 357 |
+ t.Fatal(err) |
|
| 358 |
+ } |
|
| 359 |
+ |
|
| 360 |
+ subnets = aSpace.subnets |
|
| 354 | 361 |
if subnets[k0].RefCount != 2 {
|
| 355 | 362 |
t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
|
| 356 | 363 |
} |
| ... | ... |
@@ -358,6 +410,13 @@ func TestAddReleasePoolID(t *testing.T) {
|
| 358 | 358 |
if err := a.ReleasePool(pid2); err != nil {
|
| 359 | 359 |
t.Fatal(err) |
| 360 | 360 |
} |
| 361 |
+ |
|
| 362 |
+ aSpace, err = a.getAddrSpace(localAddressSpace) |
|
| 363 |
+ if err != nil {
|
|
| 364 |
+ t.Fatal(err) |
|
| 365 |
+ } |
|
| 366 |
+ |
|
| 367 |
+ subnets = aSpace.subnets |
|
| 361 | 368 |
if subnets[k0].RefCount != 1 {
|
| 362 | 369 |
t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
|
| 363 | 370 |
} |
| ... | ... |
@@ -365,6 +424,13 @@ func TestAddReleasePoolID(t *testing.T) {
|
| 365 | 365 |
if err := a.ReleasePool(pid00); err != nil {
|
| 366 | 366 |
t.Fatal(err) |
| 367 | 367 |
} |
| 368 |
+ |
|
| 369 |
+ aSpace, err = a.getAddrSpace(localAddressSpace) |
|
| 370 |
+ if err != nil {
|
|
| 371 |
+ t.Fatal(err) |
|
| 372 |
+ } |
|
| 373 |
+ |
|
| 374 |
+ subnets = aSpace.subnets |
|
| 368 | 375 |
if bp, ok := subnets[k0]; ok {
|
| 369 | 376 |
t.Fatalf("Base pool %s is still present: %v", k0, bp)
|
| 370 | 377 |
} |
| ... | ... |
@@ -373,6 +439,13 @@ func TestAddReleasePoolID(t *testing.T) {
|
| 373 | 373 |
if err != nil {
|
| 374 | 374 |
t.Fatalf("Unexpected failure in adding pool")
|
| 375 | 375 |
} |
| 376 |
+ |
|
| 377 |
+ aSpace, err = a.getAddrSpace(localAddressSpace) |
|
| 378 |
+ if err != nil {
|
|
| 379 |
+ t.Fatal(err) |
|
| 380 |
+ } |
|
| 381 |
+ |
|
| 382 |
+ subnets = aSpace.subnets |
|
| 376 | 383 |
if subnets[k0].RefCount != 1 {
|
| 377 | 384 |
t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
|
| 378 | 385 |
} |
| ... | ... |
@@ -417,18 +490,6 @@ func TestPredefinedPool(t *testing.T) {
|
| 417 | 417 |
if nw != a.predefined[localAddressSpace][i] {
|
| 418 | 418 |
t.Fatalf("Unexpected default network returned: %s", nw)
|
| 419 | 419 |
} |
| 420 |
- |
|
| 421 |
- i, available, err = getFirstAvailablePool(a, globalAddressSpace, 2) |
|
| 422 |
- if err != nil {
|
|
| 423 |
- t.Skip(err) |
|
| 424 |
- } |
|
| 425 |
- nw, err = a.getPredefinedPool(globalAddressSpace, false) |
|
| 426 |
- if err != nil {
|
|
| 427 |
- t.Fatal(err) |
|
| 428 |
- } |
|
| 429 |
- if nw != available {
|
|
| 430 |
- t.Fatalf("Unexpected default network returned: %s", nw)
|
|
| 431 |
- } |
|
| 432 | 420 |
} |
| 433 | 421 |
|
| 434 | 422 |
func getFirstAvailablePool(a *Allocator, as string, atLeast int) (int, *net.IPNet, error) {
|
| ... | ... |
@@ -475,7 +536,13 @@ func TestRemoveSubnet(t *testing.T) {
|
| 475 | 475 |
if err != nil {
|
| 476 | 476 |
t.Fatal(err) |
| 477 | 477 |
} |
| 478 |
- a.addrSpace2Configs["splane"] = a.addrSpace2Configs[localAddressSpace] |
|
| 478 |
+ a.addrSpaces["splane"] = &addrSpace{
|
|
| 479 |
+ id: dsConfigKey + "/" + "splane", |
|
| 480 |
+ ds: a.addrSpaces[localAddressSpace].ds, |
|
| 481 |
+ alloc: a.addrSpaces[localAddressSpace].alloc, |
|
| 482 |
+ scope: a.addrSpaces[localAddressSpace].scope, |
|
| 483 |
+ subnets: map[SubnetKey]*PoolData{},
|
|
| 484 |
+ } |
|
| 479 | 485 |
|
| 480 | 486 |
input := []struct {
|
| 481 | 487 |
addrSpace string |
| ... | ... |
@@ -512,7 +579,13 @@ func TestGetSameAddress(t *testing.T) {
|
| 512 | 512 |
if err != nil {
|
| 513 | 513 |
t.Fatal(err) |
| 514 | 514 |
} |
| 515 |
- a.addrSpace2Configs["giallo"] = a.addrSpace2Configs[localAddressSpace] |
|
| 515 |
+ a.addrSpaces["giallo"] = &addrSpace{
|
|
| 516 |
+ id: dsConfigKey + "/" + "giallo", |
|
| 517 |
+ ds: a.addrSpaces[localAddressSpace].ds, |
|
| 518 |
+ alloc: a.addrSpaces[localAddressSpace].alloc, |
|
| 519 |
+ scope: a.addrSpaces[localAddressSpace].scope, |
|
| 520 |
+ subnets: map[SubnetKey]*PoolData{},
|
|
| 521 |
+ } |
|
| 516 | 522 |
|
| 517 | 523 |
pid, _, _, err := a.RequestPool("giallo", "192.168.100.0/24", "", nil, false)
|
| 518 | 524 |
if err != nil {
|
| ... | ... |
@@ -536,7 +609,13 @@ func TestRequestReleaseAddressFromSubPool(t *testing.T) {
|
| 536 | 536 |
if err != nil {
|
| 537 | 537 |
t.Fatal(err) |
| 538 | 538 |
} |
| 539 |
- a.addrSpace2Configs["rosso"] = a.addrSpace2Configs[localAddressSpace] |
|
| 539 |
+ a.addrSpaces["rosso"] = &addrSpace{
|
|
| 540 |
+ id: dsConfigKey + "/" + "rosso", |
|
| 541 |
+ ds: a.addrSpaces[localAddressSpace].ds, |
|
| 542 |
+ alloc: a.addrSpaces[localAddressSpace].alloc, |
|
| 543 |
+ scope: a.addrSpaces[localAddressSpace].scope, |
|
| 544 |
+ subnets: map[SubnetKey]*PoolData{},
|
|
| 545 |
+ } |
|
| 540 | 546 |
|
| 541 | 547 |
poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false)
|
| 542 | 548 |
if err != nil {
|
| ... | ... |
@@ -615,17 +694,23 @@ func TestGetAddress(t *testing.T) {
|
| 615 | 615 |
|
| 616 | 616 |
func TestRequestSyntaxCheck(t *testing.T) {
|
| 617 | 617 |
var ( |
| 618 |
- pool = "192.168.0.0/16" |
|
| 619 |
- subPool = "192.168.0.0/24" |
|
| 620 |
- addrSpace = "green" |
|
| 621 |
- err error |
|
| 618 |
+ pool = "192.168.0.0/16" |
|
| 619 |
+ subPool = "192.168.0.0/24" |
|
| 620 |
+ as = "green" |
|
| 621 |
+ err error |
|
| 622 | 622 |
) |
| 623 | 623 |
|
| 624 | 624 |
a, err := getAllocator() |
| 625 | 625 |
if err != nil {
|
| 626 | 626 |
t.Fatal(err) |
| 627 | 627 |
} |
| 628 |
- a.addrSpace2Configs[addrSpace] = a.addrSpace2Configs[localAddressSpace] |
|
| 628 |
+ a.addrSpaces[as] = &addrSpace{
|
|
| 629 |
+ id: dsConfigKey + "/" + as, |
|
| 630 |
+ ds: a.addrSpaces[localAddressSpace].ds, |
|
| 631 |
+ alloc: a.addrSpaces[localAddressSpace].alloc, |
|
| 632 |
+ scope: a.addrSpaces[localAddressSpace].scope, |
|
| 633 |
+ subnets: map[SubnetKey]*PoolData{},
|
|
| 634 |
+ } |
|
| 629 | 635 |
|
| 630 | 636 |
_, _, _, err = a.RequestPool("", pool, "", nil, false)
|
| 631 | 637 |
if err == nil {
|
| ... | ... |
@@ -637,12 +722,12 @@ func TestRequestSyntaxCheck(t *testing.T) {
|
| 637 | 637 |
t.Fatalf("Failed to detect wrong request: empty address space")
|
| 638 | 638 |
} |
| 639 | 639 |
|
| 640 |
- _, _, _, err = a.RequestPool(addrSpace, "", subPool, nil, false) |
|
| 640 |
+ _, _, _, err = a.RequestPool(as, "", subPool, nil, false) |
|
| 641 | 641 |
if err == nil {
|
| 642 | 642 |
t.Fatalf("Failed to detect wrong request: subPool specified and no pool")
|
| 643 | 643 |
} |
| 644 | 644 |
|
| 645 |
- pid, _, _, err := a.RequestPool(addrSpace, pool, subPool, nil, false) |
|
| 645 |
+ pid, _, _, err := a.RequestPool(as, pool, subPool, nil, false) |
|
| 646 | 646 |
if err != nil {
|
| 647 | 647 |
t.Fatalf("Unexpected failure: %v", err)
|
| 648 | 648 |
} |
| ... | ... |
@@ -764,6 +849,7 @@ func TestRelease(t *testing.T) {
|
| 764 | 764 |
for i, inp := range toRelease {
|
| 765 | 765 |
ip0 := net.ParseIP(inp.address) |
| 766 | 766 |
a.ReleaseAddress(pid, ip0) |
| 767 |
+ bm = a.addresses[SubnetKey{localAddressSpace, subnet, ""}]
|
|
| 767 | 768 |
if bm.Unselected() != 1 {
|
| 768 | 769 |
t.Fatalf("Failed to update free address count after release. Expected %d, Found: %d", i+1, bm.Unselected())
|
| 769 | 770 |
} |
| ... | ... |
@@ -2,30 +2,30 @@ package ipam |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 |
+ "fmt" |
|
| 5 | 6 |
|
| 6 | 7 |
log "github.com/Sirupsen/logrus" |
| 7 |
- "github.com/docker/libkv/store" |
|
| 8 | 8 |
"github.com/docker/libnetwork/datastore" |
| 9 | 9 |
"github.com/docker/libnetwork/types" |
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 | 12 |
// Key provides the Key to be used in KV Store |
| 13 |
-func (cfg *PoolsConfig) Key() []string {
|
|
| 14 |
- cfg.Lock() |
|
| 15 |
- defer cfg.Unlock() |
|
| 16 |
- return []string{cfg.id}
|
|
| 13 |
+func (aSpace *addrSpace) Key() []string {
|
|
| 14 |
+ aSpace.Lock() |
|
| 15 |
+ defer aSpace.Unlock() |
|
| 16 |
+ return []string{aSpace.id}
|
|
| 17 | 17 |
} |
| 18 | 18 |
|
| 19 | 19 |
// KeyPrefix returns the immediate parent key that can be used for tree walk |
| 20 |
-func (cfg *PoolsConfig) KeyPrefix() []string {
|
|
| 21 |
- cfg.Lock() |
|
| 22 |
- defer cfg.Unlock() |
|
| 20 |
+func (aSpace *addrSpace) KeyPrefix() []string {
|
|
| 21 |
+ aSpace.Lock() |
|
| 22 |
+ defer aSpace.Unlock() |
|
| 23 | 23 |
return []string{dsConfigKey}
|
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 | 26 |
// Value marshals the data to be stored in the KV store |
| 27 |
-func (cfg *PoolsConfig) Value() []byte {
|
|
| 28 |
- b, err := json.Marshal(cfg) |
|
| 27 |
+func (aSpace *addrSpace) Value() []byte {
|
|
| 28 |
+ b, err := json.Marshal(aSpace) |
|
| 29 | 29 |
if err != nil {
|
| 30 | 30 |
log.Warnf("Failed to marshal ipam configured pools: %v", err)
|
| 31 | 31 |
return nil |
| ... | ... |
@@ -34,97 +34,94 @@ func (cfg *PoolsConfig) Value() []byte {
|
| 34 | 34 |
} |
| 35 | 35 |
|
| 36 | 36 |
// SetValue unmarshalls the data from the KV store. |
| 37 |
-func (cfg *PoolsConfig) SetValue(value []byte) error {
|
|
| 38 |
- rc := &PoolsConfig{subnets: make(map[SubnetKey]*PoolData)}
|
|
| 37 |
+func (aSpace *addrSpace) SetValue(value []byte) error {
|
|
| 38 |
+ rc := &addrSpace{subnets: make(map[SubnetKey]*PoolData)}
|
|
| 39 | 39 |
if err := json.Unmarshal(value, rc); err != nil {
|
| 40 | 40 |
return err |
| 41 | 41 |
} |
| 42 |
- cfg.subnets = rc.subnets |
|
| 42 |
+ aSpace.subnets = rc.subnets |
|
| 43 | 43 |
return nil |
| 44 | 44 |
} |
| 45 | 45 |
|
| 46 | 46 |
// Index returns the latest DB Index as seen by this object |
| 47 |
-func (cfg *PoolsConfig) Index() uint64 {
|
|
| 48 |
- cfg.Lock() |
|
| 49 |
- defer cfg.Unlock() |
|
| 50 |
- return cfg.dbIndex |
|
| 47 |
+func (aSpace *addrSpace) Index() uint64 {
|
|
| 48 |
+ aSpace.Lock() |
|
| 49 |
+ defer aSpace.Unlock() |
|
| 50 |
+ return aSpace.dbIndex |
|
| 51 | 51 |
} |
| 52 | 52 |
|
| 53 | 53 |
// SetIndex method allows the datastore to store the latest DB Index into this object |
| 54 |
-func (cfg *PoolsConfig) SetIndex(index uint64) {
|
|
| 55 |
- cfg.Lock() |
|
| 56 |
- cfg.dbIndex = index |
|
| 57 |
- cfg.dbExists = true |
|
| 58 |
- cfg.Unlock() |
|
| 54 |
+func (aSpace *addrSpace) SetIndex(index uint64) {
|
|
| 55 |
+ aSpace.Lock() |
|
| 56 |
+ aSpace.dbIndex = index |
|
| 57 |
+ aSpace.dbExists = true |
|
| 58 |
+ aSpace.Unlock() |
|
| 59 | 59 |
} |
| 60 | 60 |
|
| 61 | 61 |
// Exists method is true if this object has been stored in the DB. |
| 62 |
-func (cfg *PoolsConfig) Exists() bool {
|
|
| 63 |
- cfg.Lock() |
|
| 64 |
- defer cfg.Unlock() |
|
| 65 |
- return cfg.dbExists |
|
| 62 |
+func (aSpace *addrSpace) Exists() bool {
|
|
| 63 |
+ aSpace.Lock() |
|
| 64 |
+ defer aSpace.Unlock() |
|
| 65 |
+ return aSpace.dbExists |
|
| 66 | 66 |
} |
| 67 | 67 |
|
| 68 | 68 |
// Skip provides a way for a KV Object to avoid persisting it in the KV Store |
| 69 |
-func (cfg *PoolsConfig) Skip() bool {
|
|
| 69 |
+func (aSpace *addrSpace) Skip() bool {
|
|
| 70 | 70 |
return false |
| 71 | 71 |
} |
| 72 | 72 |
|
| 73 |
-func (cfg *PoolsConfig) watchForChanges() error {
|
|
| 74 |
- if cfg.ds == nil {
|
|
| 75 |
- return nil |
|
| 76 |
- } |
|
| 77 |
- kvpChan, err := cfg.ds.KVStore().Watch(datastore.Key(cfg.Key()...), nil) |
|
| 78 |
- if err != nil {
|
|
| 79 |
- return err |
|
| 73 |
+func (a *Allocator) getStore(as string) datastore.DataStore {
|
|
| 74 |
+ a.Lock() |
|
| 75 |
+ defer a.Unlock() |
|
| 76 |
+ |
|
| 77 |
+ return a.addrSpaces[as].ds |
|
| 78 |
+} |
|
| 79 |
+ |
|
| 80 |
+func (a *Allocator) getAddressSpaceFromStore(as string) (*addrSpace, error) {
|
|
| 81 |
+ store := a.getStore(as) |
|
| 82 |
+ if store == nil {
|
|
| 83 |
+ return nil, fmt.Errorf("store for address space %s not found", as)
|
|
| 80 | 84 |
} |
| 81 |
- go func() {
|
|
| 82 |
- for {
|
|
| 83 |
- select {
|
|
| 84 |
- case kvPair := <-kvpChan: |
|
| 85 |
- if kvPair != nil {
|
|
| 86 |
- cfg.readFromKey(kvPair) |
|
| 87 |
- } |
|
| 88 |
- } |
|
| 85 |
+ |
|
| 86 |
+ pc := &addrSpace{id: dsConfigKey + "/" + as, ds: store, alloc: a}
|
|
| 87 |
+ if err := store.GetObject(datastore.Key(pc.Key()...), pc); err != nil {
|
|
| 88 |
+ if err == datastore.ErrKeyNotFound {
|
|
| 89 |
+ return nil, nil |
|
| 89 | 90 |
} |
| 90 |
- }() |
|
| 91 |
- return nil |
|
| 91 |
+ |
|
| 92 |
+ return nil, fmt.Errorf("could not get pools config from store: %v", err)
|
|
| 93 |
+ } |
|
| 94 |
+ |
|
| 95 |
+ return pc, nil |
|
| 92 | 96 |
} |
| 93 | 97 |
|
| 94 |
-func (cfg *PoolsConfig) writeToStore() error {
|
|
| 95 |
- if cfg.ds == nil {
|
|
| 96 |
- return nil |
|
| 98 |
+func (a *Allocator) writeToStore(aSpace *addrSpace) error {
|
|
| 99 |
+ store := aSpace.store() |
|
| 100 |
+ if store == nil {
|
|
| 101 |
+ return fmt.Errorf("invalid store while trying to write %s address space", aSpace.DataScope())
|
|
| 97 | 102 |
} |
| 98 |
- err := cfg.ds.PutObjectAtomic(cfg) |
|
| 103 |
+ |
|
| 104 |
+ err := store.PutObjectAtomic(aSpace) |
|
| 99 | 105 |
if err == datastore.ErrKeyModified {
|
| 100 | 106 |
return types.RetryErrorf("failed to perform atomic write (%v). retry might fix the error", err)
|
| 101 | 107 |
} |
| 102 |
- return err |
|
| 103 |
-} |
|
| 104 | 108 |
|
| 105 |
-func (cfg *PoolsConfig) readFromStore() error {
|
|
| 106 |
- if cfg.ds == nil {
|
|
| 107 |
- return nil |
|
| 108 |
- } |
|
| 109 |
- return cfg.ds.GetObject(datastore.Key(cfg.Key()...), cfg) |
|
| 109 |
+ return err |
|
| 110 | 110 |
} |
| 111 | 111 |
|
| 112 |
-func (cfg *PoolsConfig) readFromKey(kvPair *store.KVPair) {
|
|
| 113 |
- if cfg.dbIndex < kvPair.LastIndex {
|
|
| 114 |
- cfg.SetValue(kvPair.Value) |
|
| 115 |
- cfg.dbIndex = kvPair.LastIndex |
|
| 116 |
- cfg.dbExists = true |
|
| 112 |
+func (a *Allocator) deleteFromStore(aSpace *addrSpace) error {
|
|
| 113 |
+ store := aSpace.store() |
|
| 114 |
+ if store == nil {
|
|
| 115 |
+ return fmt.Errorf("invalid store while trying to delete %s address space", aSpace.DataScope())
|
|
| 117 | 116 |
} |
| 118 |
-} |
|
| 119 | 117 |
|
| 120 |
-func (cfg *PoolsConfig) deleteFromStore() error {
|
|
| 121 |
- if cfg.ds == nil {
|
|
| 122 |
- return nil |
|
| 123 |
- } |
|
| 124 |
- return cfg.ds.DeleteObjectAtomic(cfg) |
|
| 118 |
+ return store.DeleteObjectAtomic(aSpace) |
|
| 125 | 119 |
} |
| 126 | 120 |
|
| 127 | 121 |
// DataScope method returns the storage scope of the datastore |
| 128 |
-func (cfg *PoolsConfig) DataScope() datastore.DataScope {
|
|
| 129 |
- return cfg.scope |
|
| 122 |
+func (aSpace *addrSpace) DataScope() string {
|
|
| 123 |
+ aSpace.Lock() |
|
| 124 |
+ defer aSpace.Unlock() |
|
| 125 |
+ |
|
| 126 |
+ return aSpace.scope |
|
| 130 | 127 |
} |
| ... | ... |
@@ -27,13 +27,13 @@ type PoolData struct {
|
| 27 | 27 |
RefCount int |
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 |
-// PoolsConfig contains the pool configurations |
|
| 31 |
-type PoolsConfig struct {
|
|
| 30 |
+// addrSpace contains the pool configurations for the address space |
|
| 31 |
+type addrSpace struct {
|
|
| 32 | 32 |
subnets map[SubnetKey]*PoolData |
| 33 | 33 |
dbIndex uint64 |
| 34 | 34 |
dbExists bool |
| 35 | 35 |
id string |
| 36 |
- scope datastore.DataScope |
|
| 36 |
+ scope string |
|
| 37 | 37 |
ds datastore.DataStore |
| 38 | 38 |
alloc *Allocator |
| 39 | 39 |
sync.Mutex |
| ... | ... |
@@ -153,18 +153,18 @@ func (p *PoolData) UnmarshalJSON(data []byte) error {
|
| 153 | 153 |
return nil |
| 154 | 154 |
} |
| 155 | 155 |
|
| 156 |
-// MarshalJSON returns the JSON encoding of the PoolsConfig object |
|
| 157 |
-func (cfg *PoolsConfig) MarshalJSON() ([]byte, error) {
|
|
| 158 |
- cfg.Lock() |
|
| 159 |
- defer cfg.Unlock() |
|
| 156 |
+// MarshalJSON returns the JSON encoding of the addrSpace object |
|
| 157 |
+func (aSpace *addrSpace) MarshalJSON() ([]byte, error) {
|
|
| 158 |
+ aSpace.Lock() |
|
| 159 |
+ defer aSpace.Unlock() |
|
| 160 | 160 |
|
| 161 | 161 |
m := map[string]interface{}{
|
| 162 |
- "Scope": string(cfg.scope), |
|
| 162 |
+ "Scope": string(aSpace.scope), |
|
| 163 | 163 |
} |
| 164 | 164 |
|
| 165 |
- if cfg.subnets != nil {
|
|
| 165 |
+ if aSpace.subnets != nil {
|
|
| 166 | 166 |
s := map[string]*PoolData{}
|
| 167 |
- for k, v := range cfg.subnets {
|
|
| 167 |
+ for k, v := range aSpace.subnets {
|
|
| 168 | 168 |
s[k.String()] = v |
| 169 | 169 |
} |
| 170 | 170 |
m["Subnets"] = s |
| ... | ... |
@@ -173,10 +173,10 @@ func (cfg *PoolsConfig) MarshalJSON() ([]byte, error) {
|
| 173 | 173 |
return json.Marshal(m) |
| 174 | 174 |
} |
| 175 | 175 |
|
| 176 |
-// UnmarshalJSON decodes data into the PoolsConfig object |
|
| 177 |
-func (cfg *PoolsConfig) UnmarshalJSON(data []byte) error {
|
|
| 178 |
- cfg.Lock() |
|
| 179 |
- defer cfg.Unlock() |
|
| 176 |
+// UnmarshalJSON decodes data into the addrSpace object |
|
| 177 |
+func (aSpace *addrSpace) UnmarshalJSON(data []byte) error {
|
|
| 178 |
+ aSpace.Lock() |
|
| 179 |
+ defer aSpace.Unlock() |
|
| 180 | 180 |
|
| 181 | 181 |
m := map[string]interface{}{}
|
| 182 | 182 |
err := json.Unmarshal(data, &m) |
| ... | ... |
@@ -184,10 +184,10 @@ func (cfg *PoolsConfig) UnmarshalJSON(data []byte) error {
|
| 184 | 184 |
return err |
| 185 | 185 |
} |
| 186 | 186 |
|
| 187 |
- cfg.scope = datastore.LocalScope |
|
| 187 |
+ aSpace.scope = datastore.LocalScope |
|
| 188 | 188 |
s := m["Scope"].(string) |
| 189 | 189 |
if s == string(datastore.GlobalScope) {
|
| 190 |
- cfg.scope = datastore.GlobalScope |
|
| 190 |
+ aSpace.scope = datastore.GlobalScope |
|
| 191 | 191 |
} |
| 192 | 192 |
|
| 193 | 193 |
if v, ok := m["Subnets"]; ok {
|
| ... | ... |
@@ -200,31 +200,81 @@ func (cfg *PoolsConfig) UnmarshalJSON(data []byte) error {
|
| 200 | 200 |
for ks, v := range s {
|
| 201 | 201 |
k := SubnetKey{}
|
| 202 | 202 |
k.FromString(ks) |
| 203 |
- cfg.subnets[k] = v |
|
| 203 |
+ aSpace.subnets[k] = v |
|
| 204 | 204 |
} |
| 205 | 205 |
} |
| 206 | 206 |
|
| 207 | 207 |
return nil |
| 208 | 208 |
} |
| 209 | 209 |
|
| 210 |
-func (cfg *PoolsConfig) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *AddressRange) (func() error, error) {
|
|
| 211 |
- cfg.Lock() |
|
| 212 |
- defer cfg.Unlock() |
|
| 210 |
+// CopyTo deep copies the pool data to the destination pooldata |
|
| 211 |
+func (p *PoolData) CopyTo(dstP *PoolData) error {
|
|
| 212 |
+ dstP.ParentKey = p.ParentKey |
|
| 213 |
+ dstP.Pool = types.GetIPNetCopy(p.Pool) |
|
| 214 |
+ |
|
| 215 |
+ if p.Range != nil {
|
|
| 216 |
+ dstP.Range = &AddressRange{}
|
|
| 217 |
+ dstP.Range.Sub = types.GetIPNetCopy(p.Range.Sub) |
|
| 218 |
+ dstP.Range.Start = p.Range.Start |
|
| 219 |
+ dstP.Range.End = p.Range.End |
|
| 220 |
+ } |
|
| 221 |
+ |
|
| 222 |
+ dstP.RefCount = p.RefCount |
|
| 223 |
+ return nil |
|
| 224 |
+} |
|
| 225 |
+ |
|
| 226 |
+func (aSpace *addrSpace) CopyTo(o datastore.KVObject) error {
|
|
| 227 |
+ aSpace.Lock() |
|
| 228 |
+ defer aSpace.Unlock() |
|
| 229 |
+ |
|
| 230 |
+ dstAspace := o.(*addrSpace) |
|
| 231 |
+ |
|
| 232 |
+ dstAspace.id = aSpace.id |
|
| 233 |
+ dstAspace.ds = aSpace.ds |
|
| 234 |
+ dstAspace.alloc = aSpace.alloc |
|
| 235 |
+ dstAspace.scope = aSpace.scope |
|
| 236 |
+ dstAspace.dbIndex = aSpace.dbIndex |
|
| 237 |
+ dstAspace.dbExists = aSpace.dbExists |
|
| 238 |
+ |
|
| 239 |
+ dstAspace.subnets = make(map[SubnetKey]*PoolData) |
|
| 240 |
+ for k, v := range aSpace.subnets {
|
|
| 241 |
+ dstAspace.subnets[k] = &PoolData{}
|
|
| 242 |
+ v.CopyTo(dstAspace.subnets[k]) |
|
| 243 |
+ } |
|
| 244 |
+ |
|
| 245 |
+ return nil |
|
| 246 |
+} |
|
| 247 |
+ |
|
| 248 |
+func (aSpace *addrSpace) New() datastore.KVObject {
|
|
| 249 |
+ aSpace.Lock() |
|
| 250 |
+ defer aSpace.Unlock() |
|
| 251 |
+ |
|
| 252 |
+ return &addrSpace{
|
|
| 253 |
+ id: aSpace.id, |
|
| 254 |
+ ds: aSpace.ds, |
|
| 255 |
+ alloc: aSpace.alloc, |
|
| 256 |
+ scope: aSpace.scope, |
|
| 257 |
+ } |
|
| 258 |
+} |
|
| 259 |
+ |
|
| 260 |
+func (aSpace *addrSpace) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *AddressRange) (func() error, error) {
|
|
| 261 |
+ aSpace.Lock() |
|
| 262 |
+ defer aSpace.Unlock() |
|
| 213 | 263 |
|
| 214 | 264 |
// Check if already allocated |
| 215 |
- if p, ok := cfg.subnets[k]; ok {
|
|
| 216 |
- cfg.incRefCount(p, 1) |
|
| 265 |
+ if p, ok := aSpace.subnets[k]; ok {
|
|
| 266 |
+ aSpace.incRefCount(p, 1) |
|
| 217 | 267 |
return func() error { return nil }, nil
|
| 218 | 268 |
} |
| 219 | 269 |
|
| 220 | 270 |
// If master pool, check for overlap |
| 221 | 271 |
if ipr == nil {
|
| 222 |
- if cfg.contains(k.AddressSpace, nw) {
|
|
| 272 |
+ if aSpace.contains(k.AddressSpace, nw) {
|
|
| 223 | 273 |
return nil, ipamapi.ErrPoolOverlap |
| 224 | 274 |
} |
| 225 | 275 |
// This is a new master pool, add it along with corresponding bitmask |
| 226 |
- cfg.subnets[k] = &PoolData{Pool: nw, RefCount: 1}
|
|
| 227 |
- return func() error { return cfg.alloc.insertBitMask(cfg.ds, k, nw) }, nil
|
|
| 276 |
+ aSpace.subnets[k] = &PoolData{Pool: nw, RefCount: 1}
|
|
| 277 |
+ return func() error { return aSpace.alloc.insertBitMask(k, nw) }, nil
|
|
| 228 | 278 |
} |
| 229 | 279 |
|
| 230 | 280 |
// This is a new non-master pool |
| ... | ... |
@@ -234,38 +284,38 @@ func (cfg *PoolsConfig) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *Addre |
| 234 | 234 |
Range: ipr, |
| 235 | 235 |
RefCount: 1, |
| 236 | 236 |
} |
| 237 |
- cfg.subnets[k] = p |
|
| 237 |
+ aSpace.subnets[k] = p |
|
| 238 | 238 |
|
| 239 | 239 |
// Look for parent pool |
| 240 |
- pp, ok := cfg.subnets[p.ParentKey] |
|
| 240 |
+ pp, ok := aSpace.subnets[p.ParentKey] |
|
| 241 | 241 |
if ok {
|
| 242 |
- cfg.incRefCount(pp, 1) |
|
| 242 |
+ aSpace.incRefCount(pp, 1) |
|
| 243 | 243 |
return func() error { return nil }, nil
|
| 244 | 244 |
} |
| 245 | 245 |
|
| 246 | 246 |
// Parent pool does not exist, add it along with corresponding bitmask |
| 247 |
- cfg.subnets[p.ParentKey] = &PoolData{Pool: nw, RefCount: 1}
|
|
| 248 |
- return func() error { return cfg.alloc.insertBitMask(cfg.ds, p.ParentKey, nw) }, nil
|
|
| 247 |
+ aSpace.subnets[p.ParentKey] = &PoolData{Pool: nw, RefCount: 1}
|
|
| 248 |
+ return func() error { return aSpace.alloc.insertBitMask(p.ParentKey, nw) }, nil
|
|
| 249 | 249 |
} |
| 250 | 250 |
|
| 251 |
-func (cfg *PoolsConfig) updatePoolDBOnRemoval(k SubnetKey) (func() error, error) {
|
|
| 252 |
- cfg.Lock() |
|
| 253 |
- defer cfg.Unlock() |
|
| 251 |
+func (aSpace *addrSpace) updatePoolDBOnRemoval(k SubnetKey) (func() error, error) {
|
|
| 252 |
+ aSpace.Lock() |
|
| 253 |
+ defer aSpace.Unlock() |
|
| 254 | 254 |
|
| 255 |
- p, ok := cfg.subnets[k] |
|
| 255 |
+ p, ok := aSpace.subnets[k] |
|
| 256 | 256 |
if !ok {
|
| 257 | 257 |
return nil, ipamapi.ErrBadPool |
| 258 | 258 |
} |
| 259 | 259 |
|
| 260 |
- cfg.incRefCount(p, -1) |
|
| 260 |
+ aSpace.incRefCount(p, -1) |
|
| 261 | 261 |
|
| 262 | 262 |
c := p |
| 263 | 263 |
for ok {
|
| 264 | 264 |
if c.RefCount == 0 {
|
| 265 |
- delete(cfg.subnets, k) |
|
| 265 |
+ delete(aSpace.subnets, k) |
|
| 266 | 266 |
if c.Range == nil {
|
| 267 | 267 |
return func() error {
|
| 268 |
- bm, err := cfg.alloc.retrieveBitmask(cfg.ds, k, c.Pool) |
|
| 268 |
+ bm, err := aSpace.alloc.retrieveBitmask(k, c.Pool) |
|
| 269 | 269 |
if err != nil {
|
| 270 | 270 |
return fmt.Errorf("could not find bitmask in datastore for pool %s removal: %v", k.String(), err)
|
| 271 | 271 |
} |
| ... | ... |
@@ -274,24 +324,24 @@ func (cfg *PoolsConfig) updatePoolDBOnRemoval(k SubnetKey) (func() error, error) |
| 274 | 274 |
} |
| 275 | 275 |
} |
| 276 | 276 |
k = c.ParentKey |
| 277 |
- c, ok = cfg.subnets[k] |
|
| 277 |
+ c, ok = aSpace.subnets[k] |
|
| 278 | 278 |
} |
| 279 | 279 |
|
| 280 | 280 |
return func() error { return nil }, nil
|
| 281 | 281 |
} |
| 282 | 282 |
|
| 283 |
-func (cfg *PoolsConfig) incRefCount(p *PoolData, delta int) {
|
|
| 283 |
+func (aSpace *addrSpace) incRefCount(p *PoolData, delta int) {
|
|
| 284 | 284 |
c := p |
| 285 | 285 |
ok := true |
| 286 | 286 |
for ok {
|
| 287 | 287 |
c.RefCount += delta |
| 288 |
- c, ok = cfg.subnets[c.ParentKey] |
|
| 288 |
+ c, ok = aSpace.subnets[c.ParentKey] |
|
| 289 | 289 |
} |
| 290 | 290 |
} |
| 291 | 291 |
|
| 292 | 292 |
// Checks whether the passed subnet is a superset or subset of any of the subset in this config db |
| 293 |
-func (cfg *PoolsConfig) contains(space string, nw *net.IPNet) bool {
|
|
| 294 |
- for k, v := range cfg.subnets {
|
|
| 293 |
+func (aSpace *addrSpace) contains(space string, nw *net.IPNet) bool {
|
|
| 294 |
+ for k, v := range aSpace.subnets {
|
|
| 295 | 295 |
if space == k.AddressSpace && k.ChildSubnet == "" {
|
| 296 | 296 |
if nw.Contains(v.Pool.IP) || v.Pool.Contains(nw.IP) {
|
| 297 | 297 |
return true |
| ... | ... |
@@ -300,3 +350,10 @@ func (cfg *PoolsConfig) contains(space string, nw *net.IPNet) bool {
|
| 300 | 300 |
} |
| 301 | 301 |
return false |
| 302 | 302 |
} |
| 303 |
+ |
|
| 304 |
+func (aSpace *addrSpace) store() datastore.DataStore {
|
|
| 305 |
+ aSpace.Lock() |
|
| 306 |
+ defer aSpace.Unlock() |
|
| 307 |
+ |
|
| 308 |
+ return aSpace.ds |
|
| 309 |
+} |