github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/ipam/allocator_test.go (about) 1 package ipam 2 3 import ( 4 "encoding/json" 5 "flag" 6 "fmt" 7 "math/rand" 8 "net" 9 "os" 10 "path/filepath" 11 "strconv" 12 "sync" 13 "testing" 14 "time" 15 16 "github.com/docker/docker/libnetwork/bitseq" 17 "github.com/docker/docker/libnetwork/datastore" 18 "github.com/docker/docker/libnetwork/ipamapi" 19 "github.com/docker/docker/libnetwork/types" 20 "github.com/docker/libkv/store" 21 "github.com/docker/libkv/store/boltdb" 22 "golang.org/x/sync/errgroup" 23 "gotest.tools/v3/assert" 24 is "gotest.tools/v3/assert/cmp" 25 ) 26 27 var ( 28 defaultPrefix = filepath.Join(os.TempDir(), "libnetwork", "test", "ipam") 29 ) 30 31 func init() { 32 boltdb.Register() 33 } 34 35 // OptionBoltdbWithRandomDBFile function returns a random dir for local store backend 36 func randomLocalStore(needStore bool) (datastore.DataStore, error) { 37 if !needStore { 38 return nil, nil 39 } 40 tmp, err := os.CreateTemp("", "libnetwork-") 41 if err != nil { 42 return nil, fmt.Errorf("Error creating temp file: %v", err) 43 } 44 if err := tmp.Close(); err != nil { 45 return nil, fmt.Errorf("Error closing temp file: %v", err) 46 } 47 return datastore.NewDataStore(datastore.LocalScope, &datastore.ScopeCfg{ 48 Client: datastore.ScopeClientCfg{ 49 Provider: "boltdb", 50 Address: filepath.Join(defaultPrefix, filepath.Base(tmp.Name())), 51 Config: &store.Config{ 52 Bucket: "libnetwork", 53 ConnectionTimeout: 3 * time.Second, 54 }, 55 }, 56 }) 57 } 58 59 func getAllocator(store bool) (*Allocator, error) { 60 ds, err := randomLocalStore(store) 61 if err != nil { 62 return nil, err 63 } 64 return NewAllocator(ds, nil) 65 } 66 67 func TestInt2IP2IntConversion(t *testing.T) { 68 for i := uint64(0); i < 256*256*256; i++ { 69 var array [4]byte // new array at each cycle 70 addIntToIP(array[:], i) 71 j := ipToUint64(array[:]) 72 if j != i { 73 t.Fatalf("Failed to convert ordinal %d to IP % x and back to ordinal. Got %d", i, array, j) 74 } 75 } 76 } 77 78 func TestGetAddressVersion(t *testing.T) { 79 if v4 != getAddressVersion(net.ParseIP("172.28.30.112")) { 80 t.Fatal("Failed to detect IPv4 version") 81 } 82 if v4 != getAddressVersion(net.ParseIP("0.0.0.1")) { 83 t.Fatal("Failed to detect IPv4 version") 84 } 85 if v6 != getAddressVersion(net.ParseIP("ff01::1")) { 86 t.Fatal("Failed to detect IPv6 version") 87 } 88 if v6 != getAddressVersion(net.ParseIP("2001:db8::76:51")) { 89 t.Fatal("Failed to detect IPv6 version") 90 } 91 } 92 93 func TestKeyString(t *testing.T) { 94 k := &SubnetKey{AddressSpace: "default", Subnet: "172.27.0.0/16"} 95 expected := "default/172.27.0.0/16" 96 if expected != k.String() { 97 t.Fatalf("Unexpected key string: %s", k.String()) 98 } 99 100 k2 := &SubnetKey{} 101 err := k2.FromString(expected) 102 if err != nil { 103 t.Fatal(err) 104 } 105 if k2.AddressSpace != k.AddressSpace || k2.Subnet != k.Subnet { 106 t.Fatalf("SubnetKey.FromString() failed. Expected %v. Got %v", k, k2) 107 } 108 109 expected = fmt.Sprintf("%s/%s", expected, "172.27.3.0/24") 110 k.ChildSubnet = "172.27.3.0/24" 111 if expected != k.String() { 112 t.Fatalf("Unexpected key string: %s", k.String()) 113 } 114 115 err = k2.FromString(expected) 116 if err != nil { 117 t.Fatal(err) 118 } 119 if k2.AddressSpace != k.AddressSpace || k2.Subnet != k.Subnet || k2.ChildSubnet != k.ChildSubnet { 120 t.Fatalf("SubnetKey.FromString() failed. Expected %v. Got %v", k, k2) 121 } 122 } 123 124 func TestPoolDataMarshal(t *testing.T) { 125 _, nw, err := net.ParseCIDR("172.28.30.1/24") 126 if err != nil { 127 t.Fatal(err) 128 } 129 130 p := &PoolData{ 131 ParentKey: SubnetKey{AddressSpace: "Blue", Subnet: "172.28.0.0/16"}, 132 Pool: nw, 133 Range: &AddressRange{Sub: &net.IPNet{IP: net.IP{172, 28, 20, 0}, Mask: net.IPMask{255, 255, 255, 0}}, Start: 0, End: 255}, 134 RefCount: 4, 135 } 136 137 ba, err := json.Marshal(p) 138 if err != nil { 139 t.Fatal(err) 140 } 141 var q PoolData 142 err = json.Unmarshal(ba, &q) 143 if err != nil { 144 t.Fatal(err) 145 } 146 147 if p.ParentKey != q.ParentKey || !types.CompareIPNet(p.Range.Sub, q.Range.Sub) || 148 p.Range.Start != q.Range.Start || p.Range.End != q.Range.End || p.RefCount != q.RefCount || 149 !types.CompareIPNet(p.Pool, q.Pool) { 150 t.Fatalf("\n%#v\n%#v", p, &q) 151 } 152 153 p = &PoolData{ 154 ParentKey: SubnetKey{AddressSpace: "Blue", Subnet: "172.28.0.0/16"}, 155 Pool: nw, 156 RefCount: 4, 157 } 158 159 ba, err = json.Marshal(p) 160 if err != nil { 161 t.Fatal(err) 162 } 163 err = json.Unmarshal(ba, &q) 164 if err != nil { 165 t.Fatal(err) 166 } 167 168 if q.Range != nil { 169 t.Fatal("Unexpected Range") 170 } 171 } 172 173 func TestSubnetsMarshal(t *testing.T) { 174 for _, store := range []bool{false, true} { 175 a, err := getAllocator(store) 176 if err != nil { 177 t.Fatal(err) 178 } 179 pid0, _, _, err := a.RequestPool(localAddressSpace, "192.168.0.0/16", "", nil, false) 180 if err != nil { 181 t.Fatal(err) 182 } 183 pid1, _, _, err := a.RequestPool(localAddressSpace, "192.169.0.0/16", "", nil, false) 184 if err != nil { 185 t.Fatal(err) 186 } 187 _, _, err = a.RequestAddress(pid0, nil, nil) 188 if err != nil { 189 t.Fatal(err) 190 } 191 192 cfg, err := a.getAddrSpace(localAddressSpace) 193 if err != nil { 194 t.Fatal(err) 195 } 196 197 ba := cfg.Value() 198 if err := cfg.SetValue(ba); err != nil { 199 t.Fatal(err) 200 } 201 202 expIP := &net.IPNet{IP: net.IP{192, 168, 0, 2}, Mask: net.IPMask{255, 255, 0, 0}} 203 ip, _, err := a.RequestAddress(pid0, nil, nil) 204 if err != nil { 205 t.Fatal(err) 206 } 207 if !types.CompareIPNet(expIP, ip) { 208 t.Fatalf("Got unexpected ip after pool config restore: %s", ip) 209 } 210 211 expIP = &net.IPNet{IP: net.IP{192, 169, 0, 1}, Mask: net.IPMask{255, 255, 0, 0}} 212 ip, _, err = a.RequestAddress(pid1, nil, nil) 213 if err != nil { 214 t.Fatal(err) 215 } 216 if !types.CompareIPNet(expIP, ip) { 217 t.Fatalf("Got unexpected ip after pool config restore: %s", ip) 218 } 219 } 220 } 221 222 func TestAddSubnets(t *testing.T) { 223 for _, store := range []bool{false, true} { 224 a, err := getAllocator(store) 225 if err != nil { 226 t.Fatal(err) 227 } 228 a.addrSpaces["abc"] = a.addrSpaces[localAddressSpace] 229 230 pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) 231 if err != nil { 232 t.Fatal("Unexpected failure in adding subnet") 233 } 234 235 pid1, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false) 236 if err != nil { 237 t.Fatalf("Unexpected failure in adding overlapping subnets to different address spaces: %v", err) 238 } 239 240 if pid0 == pid1 { 241 t.Fatal("returned same pool id for same subnets in different namespaces") 242 } 243 244 _, _, _, err = a.RequestPool("abc", "10.0.0.0/8", "", nil, false) 245 if err == nil { 246 t.Fatalf("Expected failure requesting existing subnet") 247 } 248 249 _, _, _, err = a.RequestPool("abc", "10.128.0.0/9", "", nil, false) 250 if err == nil { 251 t.Fatal("Expected failure on adding overlapping base subnet") 252 } 253 254 _, _, _, err = a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false) 255 if err != nil { 256 t.Fatalf("Unexpected failure on adding sub pool: %v", err) 257 } 258 _, _, _, err = a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false) 259 if err == nil { 260 t.Fatalf("Expected failure on adding overlapping sub pool") 261 } 262 263 _, _, _, err = a.RequestPool(localAddressSpace, "10.20.2.0/24", "", nil, false) 264 if err == nil { 265 t.Fatal("Failed to detect overlapping subnets") 266 } 267 268 _, _, _, err = a.RequestPool(localAddressSpace, "10.128.0.0/9", "", nil, false) 269 if err == nil { 270 t.Fatal("Failed to detect overlapping subnets") 271 } 272 273 _, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3:4:5:6::/112", "", nil, false) 274 if err != nil { 275 t.Fatalf("Failed to add v6 subnet: %s", err.Error()) 276 } 277 278 _, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3::/64", "", nil, false) 279 if err == nil { 280 t.Fatal("Failed to detect overlapping v6 subnet") 281 } 282 } 283 } 284 285 // TestDoublePoolRelease tests that releasing a pool which has already 286 // been released raises an error. 287 func TestDoublePoolRelease(t *testing.T) { 288 for _, store := range []bool{false, true} { 289 a, err := getAllocator(store) 290 assert.NilError(t, err) 291 292 pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) 293 assert.NilError(t, err) 294 295 err = a.ReleasePool(pid0) 296 assert.NilError(t, err) 297 298 err = a.ReleasePool(pid0) 299 assert.Check(t, is.ErrorContains(err, "")) 300 } 301 } 302 303 func TestAddReleasePoolID(t *testing.T) { 304 for _, store := range []bool{false, true} { 305 a, err := getAllocator(store) 306 assert.NilError(t, err) 307 308 var k0, k1 SubnetKey 309 _, err = a.getAddrSpace(localAddressSpace) 310 if err != nil { 311 t.Fatal(err) 312 } 313 314 pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) 315 if err != nil { 316 t.Fatal("Unexpected failure in adding pool") 317 } 318 if err := k0.FromString(pid0); err != nil { 319 t.Fatal(err) 320 } 321 322 aSpace, err := a.getAddrSpace(localAddressSpace) 323 if err != nil { 324 t.Fatal(err) 325 } 326 327 subnets := aSpace.subnets 328 329 if subnets[k0].RefCount != 1 { 330 t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) 331 } 332 333 pid1, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false) 334 if err != nil { 335 t.Fatal("Unexpected failure in adding sub pool") 336 } 337 if err := k1.FromString(pid1); err != nil { 338 t.Fatal(err) 339 } 340 341 if pid0 == pid1 { 342 t.Fatalf("Incorrect poolIDs returned %s, %s", pid0, pid1) 343 } 344 345 aSpace, err = a.getAddrSpace(localAddressSpace) 346 if err != nil { 347 t.Fatal(err) 348 } 349 350 subnets = aSpace.subnets 351 if subnets[k1].RefCount != 1 { 352 t.Fatalf("Unexpected ref count for %s: %d", k1, subnets[k1].RefCount) 353 } 354 355 _, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false) 356 if err == nil { 357 t.Fatal("Expected failure in adding sub pool") 358 } 359 360 aSpace, err = a.getAddrSpace(localAddressSpace) 361 if err != nil { 362 t.Fatal(err) 363 } 364 365 subnets = aSpace.subnets 366 367 if subnets[k0].RefCount != 2 { 368 t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) 369 } 370 371 if err := a.ReleasePool(pid1); err != nil { 372 t.Fatal(err) 373 } 374 375 aSpace, err = a.getAddrSpace(localAddressSpace) 376 if err != nil { 377 t.Fatal(err) 378 } 379 380 subnets = aSpace.subnets 381 if subnets[k0].RefCount != 1 { 382 t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) 383 } 384 if err := a.ReleasePool(pid0); err != nil { 385 t.Fatal(err) 386 } 387 388 pid00, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) 389 if err != nil { 390 t.Fatal("Unexpected failure in adding pool") 391 } 392 if pid00 != pid0 { 393 t.Fatal("main pool should still exist") 394 } 395 396 aSpace, err = a.getAddrSpace(localAddressSpace) 397 if err != nil { 398 t.Fatal(err) 399 } 400 401 subnets = aSpace.subnets 402 if subnets[k0].RefCount != 1 { 403 t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) 404 } 405 406 if err := a.ReleasePool(pid00); err != nil { 407 t.Fatal(err) 408 } 409 410 aSpace, err = a.getAddrSpace(localAddressSpace) 411 if err != nil { 412 t.Fatal(err) 413 } 414 415 subnets = aSpace.subnets 416 if bp, ok := subnets[k0]; ok { 417 t.Fatalf("Base pool %s is still present: %v", k0, bp) 418 } 419 420 _, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false) 421 if err != nil { 422 t.Fatal("Unexpected failure in adding pool") 423 } 424 425 aSpace, err = a.getAddrSpace(localAddressSpace) 426 if err != nil { 427 t.Fatal(err) 428 } 429 430 subnets = aSpace.subnets 431 if subnets[k0].RefCount != 1 { 432 t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount) 433 } 434 } 435 } 436 437 func TestPredefinedPool(t *testing.T) { 438 for _, store := range []bool{false, true} { 439 a, err := getAllocator(store) 440 assert.NilError(t, err) 441 442 if _, err := a.getPredefinedPool("blue", false); err == nil { 443 t.Fatal("Expected failure for non default addr space") 444 } 445 446 pid, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false) 447 if err != nil { 448 t.Fatal(err) 449 } 450 451 nw2, err := a.getPredefinedPool(localAddressSpace, false) 452 if err != nil { 453 t.Fatal(err) 454 } 455 if types.CompareIPNet(nw, nw2) { 456 t.Fatalf("Unexpected default network returned: %s = %s", nw2, nw) 457 } 458 459 if err := a.ReleasePool(pid); err != nil { 460 t.Fatal(err) 461 } 462 } 463 } 464 465 func TestRemoveSubnet(t *testing.T) { 466 for _, store := range []bool{false, true} { 467 a, err := getAllocator(store) 468 assert.NilError(t, err) 469 470 a.addrSpaces["splane"] = &addrSpace{ 471 id: dsConfigKey + "/" + "splane", 472 ds: a.addrSpaces[localAddressSpace].ds, 473 alloc: a.addrSpaces[localAddressSpace].alloc, 474 scope: a.addrSpaces[localAddressSpace].scope, 475 subnets: map[SubnetKey]*PoolData{}, 476 } 477 478 input := []struct { 479 addrSpace string 480 subnet string 481 v6 bool 482 }{ 483 {localAddressSpace, "192.168.0.0/16", false}, 484 {localAddressSpace, "172.17.0.0/16", false}, 485 {localAddressSpace, "10.0.0.0/8", false}, 486 {localAddressSpace, "2001:db8:1:2:3:4:ffff::/112", false}, 487 {"splane", "172.17.0.0/16", false}, 488 {"splane", "10.0.0.0/8", false}, 489 {"splane", "2001:db8:1:2:3:4:5::/112", true}, 490 {"splane", "2001:db8:1:2:3:4:ffff::/112", true}, 491 } 492 493 poolIDs := make([]string, len(input)) 494 495 for ind, i := range input { 496 if poolIDs[ind], _, _, err = a.RequestPool(i.addrSpace, i.subnet, "", nil, i.v6); err != nil { 497 t.Fatalf("Failed to apply input. Can't proceed: %s", err.Error()) 498 } 499 } 500 501 for ind, id := range poolIDs { 502 if err := a.ReleasePool(id); err != nil { 503 t.Fatalf("Failed to release poolID %s (%d)", id, ind) 504 } 505 } 506 } 507 } 508 509 func TestGetSameAddress(t *testing.T) { 510 for _, store := range []bool{false, true} { 511 a, err := getAllocator(store) 512 assert.NilError(t, err) 513 514 a.addrSpaces["giallo"] = &addrSpace{ 515 id: dsConfigKey + "/" + "giallo", 516 ds: a.addrSpaces[localAddressSpace].ds, 517 alloc: a.addrSpaces[localAddressSpace].alloc, 518 scope: a.addrSpaces[localAddressSpace].scope, 519 subnets: map[SubnetKey]*PoolData{}, 520 } 521 522 pid, _, _, err := a.RequestPool("giallo", "192.168.100.0/24", "", nil, false) 523 if err != nil { 524 t.Fatal(err) 525 } 526 527 ip := net.ParseIP("192.168.100.250") 528 _, _, err = a.RequestAddress(pid, ip, nil) 529 if err != nil { 530 t.Fatal(err) 531 } 532 533 _, _, err = a.RequestAddress(pid, ip, nil) 534 if err == nil { 535 t.Fatal(err) 536 } 537 } 538 } 539 540 func TestPoolAllocationReuse(t *testing.T) { 541 for _, store := range []bool{false, true} { 542 a, err := getAllocator(store) 543 assert.NilError(t, err) 544 545 // First get all pools until they are exhausted to 546 pList := []string{} 547 pool, _, _, err := a.RequestPool(localAddressSpace, "", "", nil, false) 548 for err == nil { 549 pList = append(pList, pool) 550 pool, _, _, err = a.RequestPool(localAddressSpace, "", "", nil, false) 551 } 552 nPools := len(pList) 553 for _, pool := range pList { 554 if err := a.ReleasePool(pool); err != nil { 555 t.Fatal(err) 556 } 557 } 558 559 // Now try to allocate then free nPool pools sequentially. 560 // Verify that we don't see any repeat networks even though 561 // we have freed them. 562 seen := map[string]bool{} 563 for i := 0; i < nPools; i++ { 564 pool, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false) 565 if err != nil { 566 t.Fatal(err) 567 } 568 if _, ok := seen[nw.String()]; ok { 569 t.Fatalf("Network %s was reused before exhausing the pool list", nw.String()) 570 } 571 seen[nw.String()] = true 572 if err := a.ReleasePool(pool); err != nil { 573 t.Fatal(err) 574 } 575 } 576 } 577 } 578 579 func TestGetAddressSubPoolEqualPool(t *testing.T) { 580 for _, store := range []bool{false, true} { 581 a, err := getAllocator(store) 582 assert.NilError(t, err) 583 584 // Requesting a subpool of same size of the master pool should not cause any problem on ip allocation 585 pid, _, _, err := a.RequestPool(localAddressSpace, "172.18.0.0/16", "172.18.0.0/16", nil, false) 586 if err != nil { 587 t.Fatal(err) 588 } 589 590 _, _, err = a.RequestAddress(pid, nil, nil) 591 if err != nil { 592 t.Fatal(err) 593 } 594 } 595 } 596 597 func TestRequestReleaseAddressFromSubPool(t *testing.T) { 598 for _, store := range []bool{false, true} { 599 a, err := getAllocator(store) 600 assert.NilError(t, err) 601 602 a.addrSpaces["rosso"] = &addrSpace{ 603 id: dsConfigKey + "/" + "rosso", 604 ds: a.addrSpaces[localAddressSpace].ds, 605 alloc: a.addrSpaces[localAddressSpace].alloc, 606 scope: a.addrSpaces[localAddressSpace].scope, 607 subnets: map[SubnetKey]*PoolData{}, 608 } 609 610 poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false) 611 if err != nil { 612 t.Fatal(err) 613 } 614 615 var ip *net.IPNet 616 expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}} 617 for err == nil { 618 var c *net.IPNet 619 if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil { 620 ip = c 621 } 622 } 623 if err != ipamapi.ErrNoAvailableIPs { 624 t.Fatal(err) 625 } 626 if !types.CompareIPNet(expected, ip) { 627 t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) 628 } 629 rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}} 630 if err = a.ReleaseAddress(poolID, rp.IP); err != nil { 631 t.Fatal(err) 632 } 633 if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil { 634 t.Fatal(err) 635 } 636 if !types.CompareIPNet(rp, ip) { 637 t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) 638 } 639 640 _, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false) 641 if err != nil { 642 t.Fatal(err) 643 } 644 poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false) 645 if err != nil { 646 t.Fatal(err) 647 } 648 expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}} 649 for err == nil { 650 var c *net.IPNet 651 if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil { 652 ip = c 653 } 654 } 655 if err != ipamapi.ErrNoAvailableIPs { 656 t.Fatal(err) 657 } 658 if !types.CompareIPNet(expected, ip) { 659 t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) 660 } 661 rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}} 662 if err = a.ReleaseAddress(poolID, rp.IP); err != nil { 663 t.Fatal(err) 664 } 665 if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil { 666 t.Fatal(err) 667 } 668 if !types.CompareIPNet(rp, ip) { 669 t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) 670 } 671 672 // Request any addresses from subpool after explicit address request 673 unoExp, _ := types.ParseCIDR("10.2.2.0/16") 674 dueExp, _ := types.ParseCIDR("10.2.2.2/16") 675 treExp, _ := types.ParseCIDR("10.2.2.1/16") 676 677 if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil { 678 t.Fatal(err) 679 } 680 tre, _, err := a.RequestAddress(poolID, treExp.IP, nil) 681 if err != nil { 682 t.Fatal(err) 683 } 684 if !types.CompareIPNet(tre, treExp) { 685 t.Fatalf("Unexpected address: %v", tre) 686 } 687 688 uno, _, err := a.RequestAddress(poolID, nil, nil) 689 if err != nil { 690 t.Fatal(err) 691 } 692 if !types.CompareIPNet(uno, unoExp) { 693 t.Fatalf("Unexpected address: %v", uno) 694 } 695 696 due, _, err := a.RequestAddress(poolID, nil, nil) 697 if err != nil { 698 t.Fatal(err) 699 } 700 if !types.CompareIPNet(due, dueExp) { 701 t.Fatalf("Unexpected address: %v", due) 702 } 703 704 if err = a.ReleaseAddress(poolID, uno.IP); err != nil { 705 t.Fatal(err) 706 } 707 uno, _, err = a.RequestAddress(poolID, nil, nil) 708 if err != nil { 709 t.Fatal(err) 710 } 711 if !types.CompareIPNet(uno, unoExp) { 712 t.Fatalf("Unexpected address: %v", uno) 713 } 714 715 if err = a.ReleaseAddress(poolID, tre.IP); err != nil { 716 t.Fatal(err) 717 } 718 tre, _, err = a.RequestAddress(poolID, nil, nil) 719 if err != nil { 720 t.Fatal(err) 721 } 722 if !types.CompareIPNet(tre, treExp) { 723 t.Fatalf("Unexpected address: %v", tre) 724 } 725 } 726 } 727 728 func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) { 729 opts := map[string]string{ 730 ipamapi.AllocSerialPrefix: "true"} 731 for _, store := range []bool{false, true} { 732 a, err := getAllocator(store) 733 assert.NilError(t, err) 734 735 a.addrSpaces["rosso"] = &addrSpace{ 736 id: dsConfigKey + "/" + "rosso", 737 ds: a.addrSpaces[localAddressSpace].ds, 738 alloc: a.addrSpaces[localAddressSpace].alloc, 739 scope: a.addrSpaces[localAddressSpace].scope, 740 subnets: map[SubnetKey]*PoolData{}, 741 } 742 743 poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false) 744 if err != nil { 745 t.Fatal(err) 746 } 747 748 var ip *net.IPNet 749 expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}} 750 for err == nil { 751 var c *net.IPNet 752 if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil { 753 ip = c 754 } 755 } 756 if err != ipamapi.ErrNoAvailableIPs { 757 t.Fatal(err) 758 } 759 if !types.CompareIPNet(expected, ip) { 760 t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) 761 } 762 rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}} 763 if err = a.ReleaseAddress(poolID, rp.IP); err != nil { 764 t.Fatal(err) 765 } 766 if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil { 767 t.Fatal(err) 768 } 769 if !types.CompareIPNet(rp, ip) { 770 t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) 771 } 772 773 _, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false) 774 if err != nil { 775 t.Fatal(err) 776 } 777 poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false) 778 if err != nil { 779 t.Fatal(err) 780 } 781 expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}} 782 for err == nil { 783 var c *net.IPNet 784 if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil { 785 ip = c 786 } 787 } 788 if err != ipamapi.ErrNoAvailableIPs { 789 t.Fatal(err) 790 } 791 if !types.CompareIPNet(expected, ip) { 792 t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip) 793 } 794 rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}} 795 if err = a.ReleaseAddress(poolID, rp.IP); err != nil { 796 t.Fatal(err) 797 } 798 if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil { 799 t.Fatal(err) 800 } 801 if !types.CompareIPNet(rp, ip) { 802 t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip) 803 } 804 805 // Request any addresses from subpool after explicit address request 806 unoExp, _ := types.ParseCIDR("10.2.2.0/16") 807 dueExp, _ := types.ParseCIDR("10.2.2.2/16") 808 treExp, _ := types.ParseCIDR("10.2.2.1/16") 809 quaExp, _ := types.ParseCIDR("10.2.2.3/16") 810 fivExp, _ := types.ParseCIDR("10.2.2.4/16") 811 if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil { 812 t.Fatal(err) 813 } 814 tre, _, err := a.RequestAddress(poolID, treExp.IP, opts) 815 if err != nil { 816 t.Fatal(err) 817 } 818 if !types.CompareIPNet(tre, treExp) { 819 t.Fatalf("Unexpected address: %v", tre) 820 } 821 822 uno, _, err := a.RequestAddress(poolID, nil, opts) 823 if err != nil { 824 t.Fatal(err) 825 } 826 if !types.CompareIPNet(uno, unoExp) { 827 t.Fatalf("Unexpected address: %v", uno) 828 } 829 830 due, _, err := a.RequestAddress(poolID, nil, opts) 831 if err != nil { 832 t.Fatal(err) 833 } 834 if !types.CompareIPNet(due, dueExp) { 835 t.Fatalf("Unexpected address: %v", due) 836 } 837 838 if err = a.ReleaseAddress(poolID, uno.IP); err != nil { 839 t.Fatal(err) 840 } 841 uno, _, err = a.RequestAddress(poolID, nil, opts) 842 if err != nil { 843 t.Fatal(err) 844 } 845 if !types.CompareIPNet(uno, quaExp) { 846 t.Fatalf("Unexpected address: %v", uno) 847 } 848 849 if err = a.ReleaseAddress(poolID, tre.IP); err != nil { 850 t.Fatal(err) 851 } 852 tre, _, err = a.RequestAddress(poolID, nil, opts) 853 if err != nil { 854 t.Fatal(err) 855 } 856 if !types.CompareIPNet(tre, fivExp) { 857 t.Fatalf("Unexpected address: %v", tre) 858 } 859 } 860 } 861 862 func TestGetAddress(t *testing.T) { 863 input := []string{ 864 /*"10.0.0.0/8", "10.0.0.0/9", "10.0.0.0/10",*/ "10.0.0.0/11", "10.0.0.0/12", "10.0.0.0/13", "10.0.0.0/14", 865 "10.0.0.0/15", "10.0.0.0/16", "10.0.0.0/17", "10.0.0.0/18", "10.0.0.0/19", "10.0.0.0/20", "10.0.0.0/21", 866 "10.0.0.0/22", "10.0.0.0/23", "10.0.0.0/24", "10.0.0.0/25", "10.0.0.0/26", "10.0.0.0/27", "10.0.0.0/28", 867 "10.0.0.0/29", "10.0.0.0/30", "10.0.0.0/31"} 868 869 for _, subnet := range input { 870 assertGetAddress(t, subnet) 871 } 872 } 873 874 func TestRequestSyntaxCheck(t *testing.T) { 875 var ( 876 pool = "192.168.0.0/16" 877 subPool = "192.168.0.0/24" 878 as = "green" 879 ) 880 881 for _, store := range []bool{false, true} { 882 a, err := getAllocator(store) 883 assert.NilError(t, err) 884 885 a.addrSpaces[as] = &addrSpace{ 886 id: dsConfigKey + "/" + as, 887 ds: a.addrSpaces[localAddressSpace].ds, 888 alloc: a.addrSpaces[localAddressSpace].alloc, 889 scope: a.addrSpaces[localAddressSpace].scope, 890 subnets: map[SubnetKey]*PoolData{}, 891 } 892 893 _, _, _, err = a.RequestPool("", pool, "", nil, false) 894 if err == nil { 895 t.Fatal("Failed to detect wrong request: empty address space") 896 } 897 898 _, _, _, err = a.RequestPool("", pool, subPool, nil, false) 899 if err == nil { 900 t.Fatal("Failed to detect wrong request: empty address space") 901 } 902 903 _, _, _, err = a.RequestPool(as, "", subPool, nil, false) 904 if err == nil { 905 t.Fatal("Failed to detect wrong request: subPool specified and no pool") 906 } 907 908 pid, _, _, err := a.RequestPool(as, pool, subPool, nil, false) 909 if err != nil { 910 t.Fatalf("Unexpected failure: %v", err) 911 } 912 913 _, _, err = a.RequestAddress("", nil, nil) 914 if err == nil { 915 t.Fatal("Failed to detect wrong request: no pool id specified") 916 } 917 918 ip := net.ParseIP("172.17.0.23") 919 _, _, err = a.RequestAddress(pid, ip, nil) 920 if err == nil { 921 t.Fatal("Failed to detect wrong request: requested IP from different subnet") 922 } 923 924 ip = net.ParseIP("192.168.0.50") 925 _, _, err = a.RequestAddress(pid, ip, nil) 926 if err != nil { 927 t.Fatalf("Unexpected failure: %v", err) 928 } 929 930 err = a.ReleaseAddress("", ip) 931 if err == nil { 932 t.Fatal("Failed to detect wrong request: no pool id specified") 933 } 934 935 err = a.ReleaseAddress(pid, nil) 936 if err == nil { 937 t.Fatal("Failed to detect wrong request: no pool id specified") 938 } 939 940 err = a.ReleaseAddress(pid, ip) 941 if err != nil { 942 t.Fatalf("Unexpected failure: %v: %s, %s", err, pid, ip) 943 } 944 } 945 } 946 947 func TestRequest(t *testing.T) { 948 // Request N addresses from different size subnets, verifying last request 949 // returns expected address. Internal subnet host size is Allocator's default, 16 950 input := []struct { 951 subnet string 952 numReq int 953 lastIP string 954 }{ 955 {"192.168.59.0/24", 254, "192.168.59.254"}, 956 {"192.168.240.0/20", 255, "192.168.240.255"}, 957 {"192.168.0.0/16", 255, "192.168.0.255"}, 958 {"192.168.0.0/16", 256, "192.168.1.0"}, 959 {"10.16.0.0/16", 255, "10.16.0.255"}, 960 {"10.128.0.0/12", 255, "10.128.0.255"}, 961 {"10.0.0.0/8", 256, "10.0.1.0"}, 962 963 {"192.168.128.0/18", 4*256 - 1, "192.168.131.255"}, 964 /* 965 {"192.168.240.0/20", 16*256 - 2, "192.168.255.254"}, 966 967 {"192.168.0.0/16", 256*256 - 2, "192.168.255.254"}, 968 {"10.0.0.0/8", 2 * 256, "10.0.2.0"}, 969 {"10.0.0.0/8", 5 * 256, "10.0.5.0"}, 970 {"10.0.0.0/8", 100 * 256 * 254, "10.99.255.254"}, 971 */ 972 } 973 974 for _, d := range input { 975 assertNRequests(t, d.subnet, d.numReq, d.lastIP) 976 } 977 } 978 979 // TestOverlappingRequests tests that overlapping subnets cannot be allocated. 980 // Requests for subnets which are supersets or subsets of existing allocations, 981 // or which overlap at the beginning or end, should not be permitted. 982 func TestOverlappingRequests(t *testing.T) { 983 input := []struct { 984 environment []string 985 subnet string 986 ok bool 987 }{ 988 // IPv4 989 // Previously allocated network does not overlap with request 990 {[]string{"10.0.0.0/8"}, "11.0.0.0/8", true}, 991 {[]string{"74.0.0.0/7"}, "9.111.99.72/30", true}, 992 {[]string{"110.192.0.0/10"}, "16.0.0.0/10", true}, 993 994 // Previously allocated network entirely contains request 995 {[]string{"10.0.0.0/8"}, "10.0.0.0/8", false}, // exact overlap 996 {[]string{"0.0.0.0/1"}, "16.182.0.0/15", false}, 997 {[]string{"16.0.0.0/4"}, "17.11.66.0/23", false}, 998 999 // Previously allocated network overlaps beginning of request 1000 {[]string{"0.0.0.0/1"}, "0.0.0.0/0", false}, 1001 {[]string{"64.0.0.0/6"}, "64.0.0.0/3", false}, 1002 {[]string{"112.0.0.0/6"}, "112.0.0.0/4", false}, 1003 1004 // Previously allocated network overlaps end of request 1005 {[]string{"96.0.0.0/3"}, "0.0.0.0/1", false}, 1006 {[]string{"192.0.0.0/2"}, "128.0.0.0/1", false}, 1007 {[]string{"95.0.0.0/8"}, "92.0.0.0/6", false}, 1008 1009 // Previously allocated network entirely contained within request 1010 {[]string{"10.0.0.0/8"}, "10.0.0.0/6", false}, // non-canonical 1011 {[]string{"10.0.0.0/8"}, "8.0.0.0/6", false}, // canonical 1012 {[]string{"25.173.144.0/20"}, "0.0.0.0/0", false}, 1013 1014 // IPv6 1015 // Previously allocated network entirely contains request 1016 {[]string{"::/0"}, "f656:3484:c878:a05:e540:a6ed:4d70:3740/123", false}, 1017 {[]string{"8000::/1"}, "8fe8:e7c4:5779::/49", false}, 1018 {[]string{"f000::/4"}, "ffc7:6000::/19", false}, 1019 1020 // Previously allocated network overlaps beginning of request 1021 {[]string{"::/2"}, "::/0", false}, 1022 {[]string{"::/3"}, "::/1", false}, 1023 {[]string{"::/6"}, "::/5", false}, 1024 1025 // Previously allocated network overlaps end of request 1026 {[]string{"c000::/2"}, "8000::/1", false}, 1027 {[]string{"7c00::/6"}, "::/1", false}, 1028 {[]string{"cf80::/9"}, "c000::/4", false}, 1029 1030 // Previously allocated network entirely contained within request 1031 {[]string{"ff77:93f8::/29"}, "::/0", false}, 1032 {[]string{"9287:2e20:5134:fab6:9061:a0c6:bfe3:9400/119"}, "8000::/1", false}, 1033 {[]string{"3ea1:bfa9:8691:d1c6:8c46:519b:db6d:e700/120"}, "3000::/4", false}, 1034 } 1035 1036 for _, store := range []bool{false, true} { 1037 for _, tc := range input { 1038 a, err := getAllocator(store) 1039 assert.NilError(t, err) 1040 1041 // Set up some existing allocations. This should always succeed. 1042 for _, env := range tc.environment { 1043 _, _, _, err = a.RequestPool(localAddressSpace, env, "", nil, false) 1044 assert.NilError(t, err) 1045 } 1046 1047 // Make the test allocation. 1048 _, _, _, err = a.RequestPool(localAddressSpace, tc.subnet, "", nil, false) 1049 if tc.ok { 1050 assert.NilError(t, err) 1051 } else { 1052 assert.Check(t, is.ErrorContains(err, "")) 1053 } 1054 } 1055 } 1056 } 1057 1058 func TestUnusualSubnets(t *testing.T) { 1059 subnet := "192.168.0.2/31" 1060 1061 outsideTheRangeAddresses := []struct { 1062 address string 1063 }{ 1064 {"192.168.0.1"}, 1065 {"192.168.0.4"}, 1066 {"192.168.0.100"}, 1067 } 1068 1069 expectedAddresses := []struct { 1070 address string 1071 }{ 1072 {"192.168.0.2"}, 1073 {"192.168.0.3"}, 1074 } 1075 1076 for _, store := range []bool{false, true} { 1077 allocator, err := getAllocator(store) 1078 if err != nil { 1079 t.Fatal(err) 1080 } 1081 1082 // 1083 // IPv4 /31 blocks. See RFC 3021. 1084 // 1085 1086 pool, _, _, err := allocator.RequestPool(localAddressSpace, subnet, "", nil, false) 1087 if err != nil { 1088 t.Fatal(err) 1089 } 1090 1091 // Outside-the-range 1092 1093 for _, outside := range outsideTheRangeAddresses { 1094 _, _, errx := allocator.RequestAddress(pool, net.ParseIP(outside.address), nil) 1095 if errx != ipamapi.ErrIPOutOfRange { 1096 t.Fatalf("Address %s failed to throw expected error: %s", outside.address, errx.Error()) 1097 } 1098 } 1099 1100 // Should get just these two IPs followed by exhaustion on the next request 1101 1102 for _, expected := range expectedAddresses { 1103 got, _, errx := allocator.RequestAddress(pool, nil, nil) 1104 if errx != nil { 1105 t.Fatalf("Failed to obtain the address: %s", errx.Error()) 1106 } 1107 expectedIP := net.ParseIP(expected.address) 1108 gotIP := got.IP 1109 if !gotIP.Equal(expectedIP) { 1110 t.Fatalf("Failed to obtain sequentialaddress. Expected: %s, Got: %s", expectedIP, gotIP) 1111 } 1112 } 1113 1114 _, _, err = allocator.RequestAddress(pool, nil, nil) 1115 if err != ipamapi.ErrNoAvailableIPs { 1116 t.Fatal("Did not get expected error when pool is exhausted.") 1117 } 1118 } 1119 } 1120 1121 func TestRelease(t *testing.T) { 1122 var ( 1123 subnet = "192.168.0.0/23" 1124 ) 1125 1126 for _, store := range []bool{false, true} { 1127 a, err := getAllocator(store) 1128 assert.NilError(t, err) 1129 1130 pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false) 1131 if err != nil { 1132 t.Fatal(err) 1133 } 1134 1135 // Allocate all addresses 1136 for err != ipamapi.ErrNoAvailableIPs { 1137 _, _, err = a.RequestAddress(pid, nil, nil) 1138 } 1139 1140 toRelease := []struct { 1141 address string 1142 }{ 1143 {"192.168.0.1"}, 1144 {"192.168.0.2"}, 1145 {"192.168.0.3"}, 1146 {"192.168.0.4"}, 1147 {"192.168.0.5"}, 1148 {"192.168.0.6"}, 1149 {"192.168.0.7"}, 1150 {"192.168.0.8"}, 1151 {"192.168.0.9"}, 1152 {"192.168.0.10"}, 1153 {"192.168.0.30"}, 1154 {"192.168.0.31"}, 1155 {"192.168.1.32"}, 1156 1157 {"192.168.0.254"}, 1158 {"192.168.1.1"}, 1159 {"192.168.1.2"}, 1160 1161 {"192.168.1.3"}, 1162 1163 {"192.168.1.253"}, 1164 {"192.168.1.254"}, 1165 } 1166 1167 // One by one, release the address and request again. We should get the same IP 1168 for i, inp := range toRelease { 1169 ip0 := net.ParseIP(inp.address) 1170 a.ReleaseAddress(pid, ip0) 1171 bm := a.addresses[SubnetKey{localAddressSpace, subnet, ""}] 1172 if bm.Unselected() != 1 { 1173 t.Fatalf("Failed to update free address count after release. Expected %d, Found: %d", i+1, bm.Unselected()) 1174 } 1175 1176 nw, _, err := a.RequestAddress(pid, nil, nil) 1177 if err != nil { 1178 t.Fatalf("Failed to obtain the address: %s", err.Error()) 1179 } 1180 ip := nw.IP 1181 if !ip0.Equal(ip) { 1182 t.Fatalf("Failed to obtain the same address. Expected: %s, Got: %s", ip0, ip) 1183 } 1184 } 1185 } 1186 } 1187 1188 func assertGetAddress(t *testing.T, subnet string) { 1189 var ( 1190 err error 1191 printTime = false 1192 a = &Allocator{} 1193 ) 1194 1195 _, sub, _ := net.ParseCIDR(subnet) 1196 ones, bits := sub.Mask.Size() 1197 zeroes := bits - ones 1198 numAddresses := 1 << uint(zeroes) 1199 1200 bm, err := bitseq.NewHandle("ipam_test", nil, "default/"+subnet, uint64(numAddresses)) 1201 if err != nil { 1202 t.Fatal(err) 1203 } 1204 1205 start := time.Now() 1206 run := 0 1207 for err != ipamapi.ErrNoAvailableIPs { 1208 _, err = a.getAddress(sub, bm, nil, nil, false) 1209 run++ 1210 } 1211 if printTime { 1212 fmt.Printf("\nTaken %v, to allocate all addresses on %s. (nemAddresses: %d. Runs: %d)", time.Since(start), subnet, numAddresses, run) 1213 } 1214 if bm.Unselected() != 0 { 1215 t.Fatalf("Unexpected free count after reserving all addresses: %d", bm.Unselected()) 1216 } 1217 /* 1218 if bm.Head.Block != expectedMax || bm.Head.Count != numBlocks { 1219 t.Fatalf("Failed to effectively reserve all addresses on %s. Expected (0x%x, %d) as first sequence. Found (0x%x,%d)", 1220 subnet, expectedMax, numBlocks, bm.Head.Block, bm.Head.Count) 1221 } 1222 */ 1223 } 1224 1225 func assertNRequests(t *testing.T, subnet string, numReq int, lastExpectedIP string) { 1226 var ( 1227 nw *net.IPNet 1228 printTime = false 1229 ) 1230 1231 lastIP := net.ParseIP(lastExpectedIP) 1232 for _, store := range []bool{false, true} { 1233 a, err := getAllocator(store) 1234 assert.NilError(t, err) 1235 1236 pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false) 1237 if err != nil { 1238 t.Fatal(err) 1239 } 1240 1241 i := 0 1242 start := time.Now() 1243 for ; i < numReq; i++ { 1244 nw, _, err = a.RequestAddress(pid, nil, nil) 1245 } 1246 if printTime { 1247 fmt.Printf("\nTaken %v, to allocate %d addresses on %s\n", time.Since(start), numReq, subnet) 1248 } 1249 1250 if !lastIP.Equal(nw.IP) { 1251 t.Fatalf("Wrong last IP. Expected %s. Got: %s (err: %v, ind: %d)", lastExpectedIP, nw.IP.String(), err, i) 1252 } 1253 } 1254 } 1255 1256 func benchmarkRequest(b *testing.B, a *Allocator, subnet string) { 1257 pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false) 1258 for err != ipamapi.ErrNoAvailableIPs { 1259 _, _, err = a.RequestAddress(pid, nil, nil) 1260 } 1261 } 1262 1263 func BenchmarkRequest(b *testing.B) { 1264 subnets := []string{ 1265 "10.0.0.0/24", 1266 "10.0.0.0/16", 1267 "10.0.0.0/8", 1268 } 1269 1270 for _, subnet := range subnets { 1271 name := fmt.Sprintf("%vSubnet", subnet) 1272 b.Run(name, func(b *testing.B) { 1273 a, _ := getAllocator(true) 1274 benchmarkRequest(b, a, subnet) 1275 }) 1276 } 1277 } 1278 1279 func TestAllocateRandomDeallocate(t *testing.T) { 1280 for _, store := range []bool{false, true} { 1281 testAllocateRandomDeallocate(t, "172.25.0.0/16", "", 384, store) 1282 testAllocateRandomDeallocate(t, "172.25.0.0/16", "172.25.252.0/22", 384, store) 1283 } 1284 } 1285 1286 func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, store bool) { 1287 ds, err := randomLocalStore(store) 1288 assert.NilError(t, err) 1289 1290 a, err := NewAllocator(ds, nil) 1291 if err != nil { 1292 t.Fatal(err) 1293 } 1294 1295 pid, _, _, err := a.RequestPool(localAddressSpace, pool, subPool, nil, false) 1296 if err != nil { 1297 t.Fatal(err) 1298 } 1299 1300 // Allocate num ip addresses 1301 indices := make(map[int]*net.IPNet, num) 1302 allocated := make(map[string]bool, num) 1303 for i := 0; i < num; i++ { 1304 ip, _, err := a.RequestAddress(pid, nil, nil) 1305 if err != nil { 1306 t.Fatal(err) 1307 } 1308 ips := ip.String() 1309 if _, ok := allocated[ips]; ok { 1310 t.Fatalf("Address %s is already allocated", ips) 1311 } 1312 allocated[ips] = true 1313 indices[i] = ip 1314 } 1315 if len(indices) != len(allocated) || len(indices) != num { 1316 t.Fatalf("Unexpected number of allocated addresses: (%d,%d).", len(indices), len(allocated)) 1317 } 1318 1319 seed := time.Now().Unix() 1320 rand.Seed(seed) 1321 1322 // Deallocate half of the allocated addresses following a random pattern 1323 pattern := rand.Perm(num) 1324 for i := 0; i < num/2; i++ { 1325 idx := pattern[i] 1326 ip := indices[idx] 1327 err := a.ReleaseAddress(pid, ip.IP) 1328 if err != nil { 1329 t.Fatalf("Unexpected failure on deallocation of %s: %v.\nSeed: %d.", ip, err, seed) 1330 } 1331 delete(indices, idx) 1332 delete(allocated, ip.String()) 1333 } 1334 1335 // Request a quarter of addresses 1336 for i := 0; i < num/2; i++ { 1337 ip, _, err := a.RequestAddress(pid, nil, nil) 1338 if err != nil { 1339 t.Fatal(err) 1340 } 1341 ips := ip.String() 1342 if _, ok := allocated[ips]; ok { 1343 t.Fatalf("\nAddress %s is already allocated.\nSeed: %d.", ips, seed) 1344 } 1345 allocated[ips] = true 1346 } 1347 if len(allocated) != num { 1348 t.Fatalf("Unexpected number of allocated addresses: %d.\nSeed: %d.", len(allocated), seed) 1349 } 1350 } 1351 1352 func TestRetrieveFromStore(t *testing.T) { 1353 num := 200 1354 ds, err := randomLocalStore(true) 1355 if err != nil { 1356 t.Fatal(err) 1357 } 1358 a, err := NewAllocator(ds, nil) 1359 if err != nil { 1360 t.Fatal(err) 1361 } 1362 pid, _, _, err := a.RequestPool(localAddressSpace, "172.25.0.0/16", "", nil, false) 1363 if err != nil { 1364 t.Fatal(err) 1365 } 1366 for i := 0; i < num; i++ { 1367 if _, _, err := a.RequestAddress(pid, nil, nil); err != nil { 1368 t.Fatal(err) 1369 } 1370 } 1371 1372 // Restore 1373 a1, err := NewAllocator(ds, nil) 1374 if err != nil { 1375 t.Fatal(err) 1376 } 1377 a1.refresh(localAddressSpace) 1378 db := a.DumpDatabase() 1379 db1 := a1.DumpDatabase() 1380 if db != db1 { 1381 t.Fatalf("Unexpected db change.\nExpected:%s\nGot:%s", db, db1) 1382 } 1383 checkDBEquality(a, a1, t) 1384 pid, _, _, err = a1.RequestPool(localAddressSpace, "172.25.0.0/16", "172.25.1.0/24", nil, false) 1385 if err != nil { 1386 t.Fatal(err) 1387 } 1388 for i := 0; i < num/2; i++ { 1389 if _, _, err := a1.RequestAddress(pid, nil, nil); err != nil { 1390 t.Fatal(err) 1391 } 1392 } 1393 1394 // Restore 1395 a2, err := NewAllocator(ds, nil) 1396 if err != nil { 1397 t.Fatal(err) 1398 } 1399 a2.refresh(localAddressSpace) 1400 checkDBEquality(a1, a2, t) 1401 pid, _, _, err = a2.RequestPool(localAddressSpace, "172.25.0.0/16", "172.25.2.0/24", nil, false) 1402 if err != nil { 1403 t.Fatal(err) 1404 } 1405 for i := 0; i < num/2; i++ { 1406 if _, _, err := a2.RequestAddress(pid, nil, nil); err != nil { 1407 t.Fatal(err) 1408 } 1409 } 1410 1411 // Restore 1412 a3, err := NewAllocator(ds, nil) 1413 if err != nil { 1414 t.Fatal(err) 1415 } 1416 a3.refresh(localAddressSpace) 1417 checkDBEquality(a2, a3, t) 1418 pid, _, _, err = a3.RequestPool(localAddressSpace, "172.26.0.0/16", "", nil, false) 1419 if err != nil { 1420 t.Fatal(err) 1421 } 1422 for i := 0; i < num/2; i++ { 1423 if _, _, err := a3.RequestAddress(pid, nil, nil); err != nil { 1424 t.Fatal(err) 1425 } 1426 } 1427 1428 // Restore 1429 a4, err := NewAllocator(ds, nil) 1430 if err != nil { 1431 t.Fatal(err) 1432 } 1433 a4.refresh(localAddressSpace) 1434 checkDBEquality(a3, a4, t) 1435 } 1436 1437 func checkDBEquality(a1, a2 *Allocator, t *testing.T) { 1438 for k, cnf1 := range a1.addrSpaces[localAddressSpace].subnets { 1439 cnf2 := a2.addrSpaces[localAddressSpace].subnets[k] 1440 if cnf1.String() != cnf2.String() { 1441 t.Fatalf("%s\n%s", cnf1, cnf2) 1442 } 1443 if cnf1.Range == nil { 1444 a2.retrieveBitmask(k, cnf1.Pool) 1445 } 1446 } 1447 1448 for k, bm1 := range a1.addresses { 1449 bm2 := a2.addresses[k] 1450 if bm1.String() != bm2.String() { 1451 t.Fatalf("%s\n%s", bm1, bm2) 1452 } 1453 } 1454 } 1455 1456 const ( 1457 numInstances = 5 1458 first = 0 1459 last = numInstances - 1 1460 ) 1461 1462 var ( 1463 allocator *Allocator 1464 start = make(chan struct{}) 1465 done = make(chan chan struct{}, numInstances-1) 1466 pools = make([]*net.IPNet, numInstances) 1467 ) 1468 1469 func runParallelTests(t *testing.T, instance int) { 1470 var err error 1471 1472 t.Parallel() 1473 1474 pTest := flag.Lookup("test.parallel") 1475 if pTest == nil { 1476 t.Skip("Skipped because test.parallel flag not set;") 1477 } 1478 numParallel, err := strconv.Atoi(pTest.Value.String()) 1479 if err != nil { 1480 t.Fatal(err) 1481 } 1482 if numParallel < numInstances { 1483 t.Skip("Skipped because t.parallel was less than ", numInstances) 1484 } 1485 1486 // The first instance creates the allocator, gives the start 1487 // and finally checks the pools each instance was assigned 1488 if instance == first { 1489 allocator, err = getAllocator(true) 1490 if err != nil { 1491 t.Fatal(err) 1492 } 1493 close(start) 1494 } 1495 1496 if instance != first { 1497 <-start 1498 instDone := make(chan struct{}) 1499 done <- instDone 1500 defer close(instDone) 1501 1502 if instance == last { 1503 defer close(done) 1504 } 1505 } 1506 1507 _, pools[instance], _, err = allocator.RequestPool(localAddressSpace, "", "", nil, false) 1508 if err != nil { 1509 t.Fatal(err) 1510 } 1511 1512 if instance == first { 1513 for instDone := range done { 1514 <-instDone 1515 } 1516 // Now check each instance got a different pool 1517 for i := 0; i < numInstances; i++ { 1518 for j := i + 1; j < numInstances; j++ { 1519 if types.CompareIPNet(pools[i], pools[j]) { 1520 t.Fatalf("Instance %d and %d were given the same predefined pool: %v", i, j, pools) 1521 } 1522 } 1523 } 1524 } 1525 } 1526 1527 func TestRequestReleaseAddressDuplicate(t *testing.T) { 1528 a, err := getAllocator(false) 1529 if err != nil { 1530 t.Fatal(err) 1531 } 1532 type IP struct { 1533 ip *net.IPNet 1534 ref int 1535 } 1536 ips := []IP{} 1537 allocatedIPs := []*net.IPNet{} 1538 a.addrSpaces["rosso"] = &addrSpace{ 1539 id: dsConfigKey + "/" + "rosso", 1540 ds: a.addrSpaces[localAddressSpace].ds, 1541 alloc: a.addrSpaces[localAddressSpace].alloc, 1542 scope: a.addrSpaces[localAddressSpace].scope, 1543 subnets: map[SubnetKey]*PoolData{}, 1544 } 1545 1546 opts := map[string]string{ 1547 ipamapi.AllocSerialPrefix: "true", 1548 } 1549 var l sync.Mutex 1550 1551 poolID, _, _, err := a.RequestPool("rosso", "198.168.0.0/23", "", nil, false) 1552 if err != nil { 1553 t.Fatal(err) 1554 } 1555 1556 group := new(errgroup.Group) 1557 for err == nil { 1558 var c *net.IPNet 1559 if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil { 1560 l.Lock() 1561 ips = append(ips, IP{c, 1}) 1562 l.Unlock() 1563 allocatedIPs = append(allocatedIPs, c) 1564 if len(allocatedIPs) > 500 { 1565 i := rand.Intn(len(allocatedIPs) - 1) 1566 ip := allocatedIPs[i] 1567 group.Go(func() error { 1568 if err = a.ReleaseAddress(poolID, ip.IP); err != nil { 1569 return err 1570 } 1571 l.Lock() 1572 ips = append(ips, IP{ip, -1}) 1573 l.Unlock() 1574 return nil 1575 }) 1576 1577 allocatedIPs = append(allocatedIPs[:i], allocatedIPs[i+1:]...) 1578 } 1579 } 1580 } 1581 1582 if err := group.Wait(); err != nil { 1583 t.Fatal(err) 1584 } 1585 1586 refMap := make(map[string]int) 1587 for _, ip := range ips { 1588 refMap[ip.ip.String()] = refMap[ip.ip.String()] + ip.ref 1589 if refMap[ip.ip.String()] < 0 { 1590 t.Fatalf("IP %s was previously released", ip.ip.String()) 1591 } 1592 if refMap[ip.ip.String()] > 1 { 1593 t.Fatalf("IP %s was previously allocated", ip.ip.String()) 1594 } 1595 } 1596 } 1597 1598 func TestParallelPredefinedRequest1(t *testing.T) { 1599 runParallelTests(t, 0) 1600 } 1601 1602 func TestParallelPredefinedRequest2(t *testing.T) { 1603 runParallelTests(t, 1) 1604 } 1605 1606 func TestParallelPredefinedRequest3(t *testing.T) { 1607 runParallelTests(t, 2) 1608 } 1609 1610 func TestParallelPredefinedRequest4(t *testing.T) { 1611 runParallelTests(t, 3) 1612 } 1613 1614 func TestParallelPredefinedRequest5(t *testing.T) { 1615 runParallelTests(t, 4) 1616 }