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