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