github.com/rumpl/bof@v23.0.0-rc.2+incompatible/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 1060 subnet := "192.168.0.2/31" 1061 1062 outsideTheRangeAddresses := []struct { 1063 address string 1064 }{ 1065 {"192.168.0.1"}, 1066 {"192.168.0.4"}, 1067 {"192.168.0.100"}, 1068 } 1069 1070 expectedAddresses := []struct { 1071 address string 1072 }{ 1073 {"192.168.0.2"}, 1074 {"192.168.0.3"}, 1075 } 1076 1077 for _, store := range []bool{false, true} { 1078 1079 allocator, err := getAllocator(store) 1080 if err != nil { 1081 t.Fatal(err) 1082 } 1083 1084 // 1085 // IPv4 /31 blocks. See RFC 3021. 1086 // 1087 1088 pool, _, _, err := allocator.RequestPool(localAddressSpace, subnet, "", nil, false) 1089 if err != nil { 1090 t.Fatal(err) 1091 } 1092 1093 // Outside-the-range 1094 1095 for _, outside := range outsideTheRangeAddresses { 1096 _, _, errx := allocator.RequestAddress(pool, net.ParseIP(outside.address), nil) 1097 if errx != ipamapi.ErrIPOutOfRange { 1098 t.Fatalf("Address %s failed to throw expected error: %s", outside.address, errx.Error()) 1099 } 1100 } 1101 1102 // Should get just these two IPs followed by exhaustion on the next request 1103 1104 for _, expected := range expectedAddresses { 1105 got, _, errx := allocator.RequestAddress(pool, nil, nil) 1106 if errx != nil { 1107 t.Fatalf("Failed to obtain the address: %s", errx.Error()) 1108 } 1109 expectedIP := net.ParseIP(expected.address) 1110 gotIP := got.IP 1111 if !gotIP.Equal(expectedIP) { 1112 t.Fatalf("Failed to obtain sequentialaddress. Expected: %s, Got: %s", expectedIP, gotIP) 1113 } 1114 } 1115 1116 _, _, err = allocator.RequestAddress(pool, nil, nil) 1117 if err != ipamapi.ErrNoAvailableIPs { 1118 t.Fatal("Did not get expected error when pool is exhausted.") 1119 } 1120 1121 } 1122 } 1123 1124 func TestRelease(t *testing.T) { 1125 var ( 1126 subnet = "192.168.0.0/23" 1127 ) 1128 1129 for _, store := range []bool{false, true} { 1130 a, err := getAllocator(store) 1131 assert.NilError(t, err) 1132 1133 pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false) 1134 if err != nil { 1135 t.Fatal(err) 1136 } 1137 1138 // Allocate all addresses 1139 for err != ipamapi.ErrNoAvailableIPs { 1140 _, _, err = a.RequestAddress(pid, nil, nil) 1141 } 1142 1143 toRelease := []struct { 1144 address string 1145 }{ 1146 {"192.168.0.1"}, 1147 {"192.168.0.2"}, 1148 {"192.168.0.3"}, 1149 {"192.168.0.4"}, 1150 {"192.168.0.5"}, 1151 {"192.168.0.6"}, 1152 {"192.168.0.7"}, 1153 {"192.168.0.8"}, 1154 {"192.168.0.9"}, 1155 {"192.168.0.10"}, 1156 {"192.168.0.30"}, 1157 {"192.168.0.31"}, 1158 {"192.168.1.32"}, 1159 1160 {"192.168.0.254"}, 1161 {"192.168.1.1"}, 1162 {"192.168.1.2"}, 1163 1164 {"192.168.1.3"}, 1165 1166 {"192.168.1.253"}, 1167 {"192.168.1.254"}, 1168 } 1169 1170 // One by one, release the address and request again. We should get the same IP 1171 for i, inp := range toRelease { 1172 ip0 := net.ParseIP(inp.address) 1173 a.ReleaseAddress(pid, ip0) 1174 bm := a.addresses[SubnetKey{localAddressSpace, subnet, ""}] 1175 if bm.Unselected() != 1 { 1176 t.Fatalf("Failed to update free address count after release. Expected %d, Found: %d", i+1, bm.Unselected()) 1177 } 1178 1179 nw, _, err := a.RequestAddress(pid, nil, nil) 1180 if err != nil { 1181 t.Fatalf("Failed to obtain the address: %s", err.Error()) 1182 } 1183 ip := nw.IP 1184 if !ip0.Equal(ip) { 1185 t.Fatalf("Failed to obtain the same address. Expected: %s, Got: %s", ip0, ip) 1186 } 1187 } 1188 } 1189 } 1190 1191 func assertGetAddress(t *testing.T, subnet string) { 1192 var ( 1193 err error 1194 printTime = false 1195 a = &Allocator{} 1196 ) 1197 1198 _, sub, _ := net.ParseCIDR(subnet) 1199 ones, bits := sub.Mask.Size() 1200 zeroes := bits - ones 1201 numAddresses := 1 << uint(zeroes) 1202 1203 bm, err := bitseq.NewHandle("ipam_test", nil, "default/"+subnet, uint64(numAddresses)) 1204 if err != nil { 1205 t.Fatal(err) 1206 } 1207 1208 start := time.Now() 1209 run := 0 1210 for err != ipamapi.ErrNoAvailableIPs { 1211 _, err = a.getAddress(sub, bm, nil, nil, false) 1212 run++ 1213 } 1214 if printTime { 1215 fmt.Printf("\nTaken %v, to allocate all addresses on %s. (nemAddresses: %d. Runs: %d)", time.Since(start), subnet, numAddresses, run) 1216 } 1217 if bm.Unselected() != 0 { 1218 t.Fatalf("Unexpected free count after reserving all addresses: %d", bm.Unselected()) 1219 } 1220 /* 1221 if bm.Head.Block != expectedMax || bm.Head.Count != numBlocks { 1222 t.Fatalf("Failed to effectively reserve all addresses on %s. Expected (0x%x, %d) as first sequence. Found (0x%x,%d)", 1223 subnet, expectedMax, numBlocks, bm.Head.Block, bm.Head.Count) 1224 } 1225 */ 1226 } 1227 1228 func assertNRequests(t *testing.T, subnet string, numReq int, lastExpectedIP string) { 1229 var ( 1230 nw *net.IPNet 1231 printTime = false 1232 ) 1233 1234 lastIP := net.ParseIP(lastExpectedIP) 1235 for _, store := range []bool{false, true} { 1236 a, err := getAllocator(store) 1237 assert.NilError(t, err) 1238 1239 pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false) 1240 if err != nil { 1241 t.Fatal(err) 1242 } 1243 1244 i := 0 1245 start := time.Now() 1246 for ; i < numReq; i++ { 1247 nw, _, err = a.RequestAddress(pid, nil, nil) 1248 } 1249 if printTime { 1250 fmt.Printf("\nTaken %v, to allocate %d addresses on %s\n", time.Since(start), numReq, subnet) 1251 } 1252 1253 if !lastIP.Equal(nw.IP) { 1254 t.Fatalf("Wrong last IP. Expected %s. Got: %s (err: %v, ind: %d)", lastExpectedIP, nw.IP.String(), err, i) 1255 } 1256 } 1257 } 1258 1259 func benchmarkRequest(b *testing.B, a *Allocator, subnet string) { 1260 pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false) 1261 for err != ipamapi.ErrNoAvailableIPs { 1262 _, _, err = a.RequestAddress(pid, nil, nil) 1263 } 1264 } 1265 1266 func BenchmarkRequest(b *testing.B) { 1267 1268 subnets := []string{ 1269 "10.0.0.0/24", 1270 "10.0.0.0/16", 1271 "10.0.0.0/8", 1272 } 1273 1274 for _, subnet := range subnets { 1275 name := fmt.Sprintf("%vSubnet", subnet) 1276 b.Run(name, func(b *testing.B) { 1277 a, _ := getAllocator(true) 1278 benchmarkRequest(b, a, subnet) 1279 }) 1280 } 1281 } 1282 1283 func TestAllocateRandomDeallocate(t *testing.T) { 1284 for _, store := range []bool{false, true} { 1285 testAllocateRandomDeallocate(t, "172.25.0.0/16", "", 384, store) 1286 testAllocateRandomDeallocate(t, "172.25.0.0/16", "172.25.252.0/22", 384, store) 1287 } 1288 } 1289 1290 func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, store bool) { 1291 ds, err := randomLocalStore(store) 1292 assert.NilError(t, err) 1293 1294 a, err := NewAllocator(ds, nil) 1295 if err != nil { 1296 t.Fatal(err) 1297 } 1298 1299 pid, _, _, err := a.RequestPool(localAddressSpace, pool, subPool, nil, false) 1300 if err != nil { 1301 t.Fatal(err) 1302 } 1303 1304 // Allocate num ip addresses 1305 indices := make(map[int]*net.IPNet, num) 1306 allocated := make(map[string]bool, num) 1307 for i := 0; i < num; i++ { 1308 ip, _, err := a.RequestAddress(pid, nil, nil) 1309 if err != nil { 1310 t.Fatal(err) 1311 } 1312 ips := ip.String() 1313 if _, ok := allocated[ips]; ok { 1314 t.Fatalf("Address %s is already allocated", ips) 1315 } 1316 allocated[ips] = true 1317 indices[i] = ip 1318 } 1319 if len(indices) != len(allocated) || len(indices) != num { 1320 t.Fatalf("Unexpected number of allocated addresses: (%d,%d).", len(indices), len(allocated)) 1321 } 1322 1323 seed := time.Now().Unix() 1324 rand.Seed(seed) 1325 1326 // Deallocate half of the allocated addresses following a random pattern 1327 pattern := rand.Perm(num) 1328 for i := 0; i < num/2; i++ { 1329 idx := pattern[i] 1330 ip := indices[idx] 1331 err := a.ReleaseAddress(pid, ip.IP) 1332 if err != nil { 1333 t.Fatalf("Unexpected failure on deallocation of %s: %v.\nSeed: %d.", ip, err, seed) 1334 } 1335 delete(indices, idx) 1336 delete(allocated, ip.String()) 1337 } 1338 1339 // Request a quarter of addresses 1340 for i := 0; i < num/2; i++ { 1341 ip, _, err := a.RequestAddress(pid, nil, nil) 1342 if err != nil { 1343 t.Fatal(err) 1344 } 1345 ips := ip.String() 1346 if _, ok := allocated[ips]; ok { 1347 t.Fatalf("\nAddress %s is already allocated.\nSeed: %d.", ips, seed) 1348 } 1349 allocated[ips] = true 1350 } 1351 if len(allocated) != num { 1352 t.Fatalf("Unexpected number of allocated addresses: %d.\nSeed: %d.", len(allocated), seed) 1353 } 1354 } 1355 1356 func TestRetrieveFromStore(t *testing.T) { 1357 num := 200 1358 ds, err := randomLocalStore(true) 1359 if err != nil { 1360 t.Fatal(err) 1361 } 1362 a, err := NewAllocator(ds, nil) 1363 if err != nil { 1364 t.Fatal(err) 1365 } 1366 pid, _, _, err := a.RequestPool(localAddressSpace, "172.25.0.0/16", "", nil, false) 1367 if err != nil { 1368 t.Fatal(err) 1369 } 1370 for i := 0; i < num; i++ { 1371 if _, _, err := a.RequestAddress(pid, nil, nil); err != nil { 1372 t.Fatal(err) 1373 } 1374 } 1375 1376 // Restore 1377 a1, err := NewAllocator(ds, nil) 1378 if err != nil { 1379 t.Fatal(err) 1380 } 1381 a1.refresh(localAddressSpace) 1382 db := a.DumpDatabase() 1383 db1 := a1.DumpDatabase() 1384 if db != db1 { 1385 t.Fatalf("Unexpected db change.\nExpected:%s\nGot:%s", db, db1) 1386 } 1387 checkDBEquality(a, a1, t) 1388 pid, _, _, err = a1.RequestPool(localAddressSpace, "172.25.0.0/16", "172.25.1.0/24", nil, false) 1389 if err != nil { 1390 t.Fatal(err) 1391 } 1392 for i := 0; i < num/2; i++ { 1393 if _, _, err := a1.RequestAddress(pid, nil, nil); err != nil { 1394 t.Fatal(err) 1395 } 1396 } 1397 1398 // Restore 1399 a2, err := NewAllocator(ds, nil) 1400 if err != nil { 1401 t.Fatal(err) 1402 } 1403 a2.refresh(localAddressSpace) 1404 checkDBEquality(a1, a2, t) 1405 pid, _, _, err = a2.RequestPool(localAddressSpace, "172.25.0.0/16", "172.25.2.0/24", nil, false) 1406 if err != nil { 1407 t.Fatal(err) 1408 } 1409 for i := 0; i < num/2; i++ { 1410 if _, _, err := a2.RequestAddress(pid, nil, nil); err != nil { 1411 t.Fatal(err) 1412 } 1413 } 1414 1415 // Restore 1416 a3, err := NewAllocator(ds, nil) 1417 if err != nil { 1418 t.Fatal(err) 1419 } 1420 a3.refresh(localAddressSpace) 1421 checkDBEquality(a2, a3, t) 1422 pid, _, _, err = a3.RequestPool(localAddressSpace, "172.26.0.0/16", "", nil, false) 1423 if err != nil { 1424 t.Fatal(err) 1425 } 1426 for i := 0; i < num/2; i++ { 1427 if _, _, err := a3.RequestAddress(pid, nil, nil); err != nil { 1428 t.Fatal(err) 1429 } 1430 } 1431 1432 // Restore 1433 a4, err := NewAllocator(ds, nil) 1434 if err != nil { 1435 t.Fatal(err) 1436 } 1437 a4.refresh(localAddressSpace) 1438 checkDBEquality(a3, a4, t) 1439 } 1440 1441 func checkDBEquality(a1, a2 *Allocator, t *testing.T) { 1442 for k, cnf1 := range a1.addrSpaces[localAddressSpace].subnets { 1443 cnf2 := a2.addrSpaces[localAddressSpace].subnets[k] 1444 if cnf1.String() != cnf2.String() { 1445 t.Fatalf("%s\n%s", cnf1, cnf2) 1446 } 1447 if cnf1.Range == nil { 1448 a2.retrieveBitmask(k, cnf1.Pool) 1449 } 1450 } 1451 1452 for k, bm1 := range a1.addresses { 1453 bm2 := a2.addresses[k] 1454 if bm1.String() != bm2.String() { 1455 t.Fatalf("%s\n%s", bm1, bm2) 1456 } 1457 } 1458 } 1459 1460 const ( 1461 numInstances = 5 1462 first = 0 1463 last = numInstances - 1 1464 ) 1465 1466 var ( 1467 allocator *Allocator 1468 start = make(chan struct{}) 1469 done = make(chan chan struct{}, numInstances-1) 1470 pools = make([]*net.IPNet, numInstances) 1471 ) 1472 1473 func runParallelTests(t *testing.T, instance int) { 1474 var err error 1475 1476 t.Parallel() 1477 1478 pTest := flag.Lookup("test.parallel") 1479 if pTest == nil { 1480 t.Skip("Skipped because test.parallel flag not set;") 1481 } 1482 numParallel, err := strconv.Atoi(pTest.Value.String()) 1483 if err != nil { 1484 t.Fatal(err) 1485 } 1486 if numParallel < numInstances { 1487 t.Skip("Skipped because t.parallel was less than ", numInstances) 1488 } 1489 1490 // The first instance creates the allocator, gives the start 1491 // and finally checks the pools each instance was assigned 1492 if instance == first { 1493 allocator, err = getAllocator(true) 1494 if err != nil { 1495 t.Fatal(err) 1496 } 1497 close(start) 1498 } 1499 1500 if instance != first { 1501 <-start 1502 instDone := make(chan struct{}) 1503 done <- instDone 1504 defer close(instDone) 1505 1506 if instance == last { 1507 defer close(done) 1508 } 1509 } 1510 1511 _, pools[instance], _, err = allocator.RequestPool(localAddressSpace, "", "", nil, false) 1512 if err != nil { 1513 t.Fatal(err) 1514 } 1515 1516 if instance == first { 1517 for instDone := range done { 1518 <-instDone 1519 } 1520 // Now check each instance got a different pool 1521 for i := 0; i < numInstances; i++ { 1522 for j := i + 1; j < numInstances; j++ { 1523 if types.CompareIPNet(pools[i], pools[j]) { 1524 t.Fatalf("Instance %d and %d were given the same predefined pool: %v", i, j, pools) 1525 } 1526 } 1527 } 1528 } 1529 } 1530 1531 func TestRequestReleaseAddressDuplicate(t *testing.T) { 1532 a, err := getAllocator(false) 1533 if err != nil { 1534 t.Fatal(err) 1535 } 1536 type IP struct { 1537 ip *net.IPNet 1538 ref int 1539 } 1540 ips := []IP{} 1541 allocatedIPs := []*net.IPNet{} 1542 a.addrSpaces["rosso"] = &addrSpace{ 1543 id: dsConfigKey + "/" + "rosso", 1544 ds: a.addrSpaces[localAddressSpace].ds, 1545 alloc: a.addrSpaces[localAddressSpace].alloc, 1546 scope: a.addrSpaces[localAddressSpace].scope, 1547 subnets: map[SubnetKey]*PoolData{}, 1548 } 1549 1550 opts := map[string]string{ 1551 ipamapi.AllocSerialPrefix: "true", 1552 } 1553 var l sync.Mutex 1554 1555 poolID, _, _, err := a.RequestPool("rosso", "198.168.0.0/23", "", nil, false) 1556 if err != nil { 1557 t.Fatal(err) 1558 } 1559 1560 group := new(errgroup.Group) 1561 for err == nil { 1562 var c *net.IPNet 1563 if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil { 1564 l.Lock() 1565 ips = append(ips, IP{c, 1}) 1566 l.Unlock() 1567 allocatedIPs = append(allocatedIPs, c) 1568 if len(allocatedIPs) > 500 { 1569 i := rand.Intn(len(allocatedIPs) - 1) 1570 ip := allocatedIPs[i] 1571 group.Go(func() error { 1572 if err = a.ReleaseAddress(poolID, ip.IP); err != nil { 1573 return err 1574 } 1575 l.Lock() 1576 ips = append(ips, IP{ip, -1}) 1577 l.Unlock() 1578 return nil 1579 }) 1580 1581 allocatedIPs = append(allocatedIPs[:i], allocatedIPs[i+1:]...) 1582 } 1583 } 1584 } 1585 1586 if err := group.Wait(); err != nil { 1587 t.Fatal(err) 1588 } 1589 1590 refMap := make(map[string]int) 1591 for _, ip := range ips { 1592 refMap[ip.ip.String()] = refMap[ip.ip.String()] + ip.ref 1593 if refMap[ip.ip.String()] < 0 { 1594 t.Fatalf("IP %s was previously released", ip.ip.String()) 1595 } 1596 if refMap[ip.ip.String()] > 1 { 1597 t.Fatalf("IP %s was previously allocated", ip.ip.String()) 1598 } 1599 } 1600 } 1601 1602 func TestParallelPredefinedRequest1(t *testing.T) { 1603 runParallelTests(t, 0) 1604 } 1605 1606 func TestParallelPredefinedRequest2(t *testing.T) { 1607 runParallelTests(t, 1) 1608 } 1609 1610 func TestParallelPredefinedRequest3(t *testing.T) { 1611 runParallelTests(t, 2) 1612 } 1613 1614 func TestParallelPredefinedRequest4(t *testing.T) { 1615 runParallelTests(t, 3) 1616 } 1617 1618 func TestParallelPredefinedRequest5(t *testing.T) { 1619 runParallelTests(t, 4) 1620 }