github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/network/subnets/subnets_test.go (about) 1 package subnets_test 2 3 import ( 4 "net" 5 "runtime" 6 7 "github.com/cloudfoundry-incubator/garden-linux/linux_backend" 8 "github.com/cloudfoundry-incubator/garden-linux/network/subnets" 9 "github.com/pivotal-golang/lager" 10 "github.com/pivotal-golang/lager/lagertest" 11 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 ) 15 16 var _ = Describe("Subnet Pool", func() { 17 var subnetpool subnets.Subnets 18 var defaultSubnetPool *net.IPNet 19 var logger lager.Logger 20 21 JustBeforeEach(func() { 22 var err error 23 logger = lagertest.NewTestLogger("test") 24 subnetpool, err = subnets.NewSubnets(defaultSubnetPool) 25 Expect(err).ToNot(HaveOccurred()) 26 }) 27 28 Describe("Capacity", func() { 29 Context("when the dynamic allocation net is empty", func() { 30 BeforeEach(func() { 31 defaultSubnetPool = subnetPool("10.2.3.0/32") 32 }) 33 34 It("returns zero", func() { 35 Expect(subnetpool.Capacity()).To(Equal(0)) 36 }) 37 }) 38 39 Context("when the dynamic allocation net is non-empty", func() { 40 BeforeEach(func() { 41 defaultSubnetPool = subnetPool("10.2.3.0/27") 42 }) 43 44 It("returns the correct number of subnets initially and repeatedly", func() { 45 Expect(subnetpool.Capacity()).To(Equal(8)) 46 Expect(subnetpool.Capacity()).To(Equal(8)) 47 }) 48 49 It("returns the correct capacity after allocating subnets", func() { 50 cap := subnetpool.Capacity() 51 52 _, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 53 Expect(err).ToNot(HaveOccurred()) 54 55 Expect(subnetpool.Capacity()).To(Equal(cap)) 56 57 _, err = subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 58 Expect(err).ToNot(HaveOccurred()) 59 60 Expect(subnetpool.Capacity()).To(Equal(cap)) 61 }) 62 }) 63 }) 64 65 Describe("Allocating and Releasing", func() { 66 Describe("Static Subnet Allocation", func() { 67 Context("when the requested subnet is within the dynamic allocation range", func() { 68 BeforeEach(func() { 69 defaultSubnetPool = subnetPool("10.2.3.0/29") 70 }) 71 72 It("returns an appropriate error", func() { 73 _, static := networkParms("10.2.3.4/30") 74 75 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 76 Expect(err).To(MatchError("the requested subnet (10.2.3.4/30) overlaps the dynamic allocation range (10.2.3.0/29)")) 77 }) 78 }) 79 80 Context("when the requested subnet subsumes the dynamic allocation range", func() { 81 BeforeEach(func() { 82 defaultSubnetPool = subnetPool("10.2.3.4/30") 83 }) 84 85 It("returns an appropriate error", func() { 86 _, static := networkParms("10.2.3.0/24") 87 88 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 89 Expect(err).To(HaveOccurred()) 90 Expect(err).To(MatchError("the requested subnet (10.2.3.0/24) overlaps the dynamic allocation range (10.2.3.4/30)")) 91 }) 92 }) 93 94 Context("when the requested subnet is not within the dynamic allocation range", func() { 95 BeforeEach(func() { 96 defaultSubnetPool = subnetPool("10.2.3.0/29") 97 }) 98 99 Context("allocating a static subnet", func() { 100 Context("and a static IP", func() { 101 It("returns an error if the IP is not inside the subnet", func() { 102 _, static := networkParms("11.0.0.0/8") 103 104 ip := net.ParseIP("9.0.0.1") 105 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}, logger) 106 Expect(err).To(Equal(subnets.ErrInvalidIP)) 107 }) 108 109 It("returns the same subnet and IP if the IP is inside the subnet", func() { 110 _, static := networkParms("11.0.0.0/8") 111 112 ip := net.ParseIP("11.0.0.2") 113 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}, logger) 114 Expect(err).ToNot(HaveOccurred()) 115 116 Expect(network.Subnet).To(Equal(static)) 117 Expect(network.IP).To(Equal(ip)) 118 }) 119 120 It("does not allow the same IP to be requested twice", func() { 121 _, static := networkParms("11.0.0.0/8") 122 123 ip := net.ParseIP("11.0.0.2") 124 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}, logger) 125 Expect(err).ToNot(HaveOccurred()) 126 127 _, static = networkParms("11.0.0.0/8") // make sure we get a new pointer 128 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}, logger) 129 Expect(err).To(Equal(subnets.ErrIPAlreadyAcquired)) 130 }) 131 132 It("allows two IPs to be serially requested in the same subnet", func() { 133 _, static := networkParms("11.0.0.0/8") 134 135 ip := net.ParseIP("11.0.0.2") 136 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}, logger) 137 Expect(err).ToNot(HaveOccurred()) 138 Expect(network.Subnet).To(Equal(static)) 139 Expect(network.IP).To(Equal(ip)) 140 141 ip2 := net.ParseIP("11.0.0.3") 142 143 _, static = networkParms("11.0.0.0/8") // make sure we get a new pointer 144 network2, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip2}, logger) 145 Expect(err).ToNot(HaveOccurred()) 146 Expect(network2.Subnet).To(Equal(static)) 147 Expect(network2.IP).To(Equal(ip2)) 148 }) 149 150 It("when an IP is allocated from a subnet but released in between, it should be treated as new both times", func() { 151 _, static := networkParms("11.0.0.0/8") 152 153 ip := net.ParseIP("11.0.0.2") 154 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}, logger) 155 Expect(err).ToNot(HaveOccurred()) 156 Expect(network.Subnet).To(Equal(static)) 157 Expect(network.IP).To(Equal(ip)) 158 159 err = subnetpool.Release(network, logger) 160 Expect(err).ToNot(HaveOccurred()) 161 162 _, static = networkParms("11.0.0.0/8") // make sure we get a new pointer 163 network, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}, logger) 164 Expect(err).ToNot(HaveOccurred()) 165 Expect(network.Subnet).To(Equal(static)) 166 Expect(network.IP).To(Equal(ip)) 167 }) 168 169 It("prevents dynamic allocation of the same IP", func() { 170 _, static := networkParms("11.0.0.0/8") 171 172 ip := net.ParseIP("11.0.0.3") 173 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}, logger) 174 Expect(err).ToNot(HaveOccurred()) 175 176 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 177 Expect(err).ToNot(HaveOccurred()) 178 Expect(network.IP.String()).To(Equal("11.0.0.2")) 179 180 network, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 181 Expect(err).ToNot(HaveOccurred()) 182 Expect(network.IP.String()).To(Equal("11.0.0.4")) 183 }) 184 185 Describe("errors", func() { 186 It("fails if a static subnet is requested specifying an IP address which clashes with the gateway IP address", func() { 187 _, static := networkParms("11.0.0.0/8") 188 gateway := net.ParseIP("11.0.0.1") 189 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{gateway}, logger) 190 Expect(err).To(MatchError(subnets.ErrIPEqualsGateway)) 191 }) 192 193 It("fails if a static subnet is requested specifying an IP address which clashes with the broadcast IP address", func() { 194 _, static := networkParms("11.0.0.0/8") 195 max := net.ParseIP("11.255.255.255") 196 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{max}, logger) 197 Expect(err).To(MatchError(subnets.ErrIPEqualsBroadcast)) 198 }) 199 }) 200 }) 201 202 Context("and a dynamic IP", func() { 203 It("does not return an error", func() { 204 _, static := networkParms("11.0.0.0/8") 205 206 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 207 Expect(err).ToNot(HaveOccurred()) 208 }) 209 210 It("returns the first available IP", func() { 211 _, static := networkParms("11.0.0.0/8") 212 213 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 214 Expect(err).ToNot(HaveOccurred()) 215 216 Expect(network.IP.String()).To(Equal("11.0.0.2")) 217 }) 218 219 It("returns distinct IPs", func() { 220 _, static := networkParms("11.0.0.0/22") 221 222 seen := make(map[string]bool) 223 var err error 224 for err == nil { 225 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 226 227 if err != nil { 228 Expect(err).To(Equal(subnets.ErrInsufficientIPs)) 229 break 230 } 231 232 Expect(seen).ToNot(HaveKey(network.IP.String())) 233 seen[network.IP.String()] = true 234 } 235 }) 236 237 It("returns all IPs except gateway, minimum and broadcast", func() { 238 _, static := networkParms("11.0.0.0/23") 239 240 var err error 241 count := 0 242 for err == nil { 243 if _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger); err != nil { 244 Expect(err).To(Equal(subnets.ErrInsufficientIPs)) 245 } 246 247 count++ 248 } 249 250 Expect(count).To(Equal(510)) 251 }) 252 253 It("causes static alocation to fail if it tries to allocate the same IP afterwards", func() { 254 _, static := networkParms("11.0.0.0/8") 255 256 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 257 Expect(err).ToNot(HaveOccurred()) 258 259 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{network.IP}, logger) 260 Expect(err).To(Equal(subnets.ErrIPAlreadyAcquired)) 261 }) 262 }) 263 }) 264 265 Context("after all IPs are allocated from a subnet, a subsequent request for the same subnet", func() { 266 var ( 267 static *net.IPNet 268 ips [5]net.IP 269 ) 270 271 JustBeforeEach(func() { 272 var err error 273 _, static, err = net.ParseCIDR("10.9.3.0/29") 274 Expect(err).ToNot(HaveOccurred()) 275 276 for i := 0; i < 5; i++ { 277 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 278 Expect(err).ToNot(HaveOccurred()) 279 280 ips[i] = network.IP 281 } 282 }) 283 284 It("returns an appropriate error", func() { 285 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 286 Expect(err).To(HaveOccurred()) 287 Expect(err).To(Equal(subnets.ErrInsufficientIPs)) 288 }) 289 290 Context("but after it is released", func() { 291 It("dynamically allocates the released IP again", func() { 292 err := subnetpool.Release(&linux_backend.Network{static, ips[3]}, logger) 293 Expect(err).ToNot(HaveOccurred()) 294 295 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 296 Expect(err).ToNot(HaveOccurred()) 297 Expect(network.IP).To(Equal(ips[3])) 298 }) 299 300 It("allows static allocation again", func() { 301 err := subnetpool.Release(&linux_backend.Network{static, ips[3]}, logger) 302 Expect(err).ToNot(HaveOccurred()) 303 304 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ips[3]}, logger) 305 Expect(err).ToNot(HaveOccurred()) 306 }) 307 }) 308 }) 309 310 Context("after a subnet has been allocated, a subsequent request for an overlapping subnet which begins on the same ip", func() { 311 var ( 312 firstSubnetPool *net.IPNet 313 secondSubnetPool *net.IPNet 314 ) 315 316 JustBeforeEach(func() { 317 _, firstSubnetPool = networkParms("10.9.3.0/30") 318 _, secondSubnetPool = networkParms("10.9.3.0/29") 319 320 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{firstSubnetPool}, subnets.DynamicIPSelector, logger) 321 Expect(err).ToNot(HaveOccurred()) 322 }) 323 324 It("returns an appropriate error", func() { 325 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{secondSubnetPool}, subnets.DynamicIPSelector, logger) 326 Expect(err).To(MatchError("the requested subnet (10.9.3.0/29) overlaps an existing subnet (10.9.3.0/30)")) 327 }) 328 }) 329 330 Context("after a subnet has been allocated, a subsequent request for an overlapping subnet", func() { 331 var ( 332 firstSubnetPool *net.IPNet 333 firstContainerIP net.IP 334 secondSubnetPool *net.IPNet 335 ) 336 337 JustBeforeEach(func() { 338 var err error 339 firstContainerIP, firstSubnetPool = networkParms("10.9.3.4/30") 340 Expect(err).ToNot(HaveOccurred()) 341 342 _, secondSubnetPool = networkParms("10.9.3.0/29") 343 Expect(err).ToNot(HaveOccurred()) 344 345 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{firstSubnetPool}, subnets.DynamicIPSelector, logger) 346 Expect(err).ToNot(HaveOccurred()) 347 }) 348 349 It("returns an appropriate error", func() { 350 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{secondSubnetPool}, subnets.DynamicIPSelector, logger) 351 Expect(err).To(MatchError("the requested subnet (10.9.3.0/29) overlaps an existing subnet (10.9.3.4/30)")) 352 }) 353 354 Context("but after it is released", func() { 355 It("allows allocation again", func() { 356 err := subnetpool.Release(&linux_backend.Network{firstSubnetPool, firstContainerIP}, logger) 357 Expect(err).ToNot(HaveOccurred()) 358 359 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{secondSubnetPool}, subnets.DynamicIPSelector, logger) 360 Expect(err).ToNot(HaveOccurred()) 361 }) 362 }) 363 }) 364 365 Context("requesting a specific IP address in a static subnet", func() { 366 It("does not return an error", func() { 367 _, static := networkParms("10.9.3.6/29") 368 369 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 370 Expect(err).ToNot(HaveOccurred()) 371 }) 372 }) 373 374 }) 375 }) 376 377 Describe("Dynamic /30 Subnet Allocation", func() { 378 Context("when the pool does not have sufficient IPs to allocate a subnet", func() { 379 BeforeEach(func() { 380 defaultSubnetPool = subnetPool("10.2.3.0/31") 381 }) 382 383 It("the first request returns an error", func() { 384 _, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 385 Expect(err).To(HaveOccurred()) 386 }) 387 }) 388 389 Context("when the pool has sufficient IPs to allocate a single subnet", func() { 390 BeforeEach(func() { 391 defaultSubnetPool = subnetPool("10.2.3.0/30") 392 }) 393 394 Context("the first request", func() { 395 It("succeeds, and returns a /30 network within the subnet", func() { 396 network, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 397 Expect(err).ToNot(HaveOccurred()) 398 399 Expect(network.Subnet).ToNot(BeNil()) 400 Expect(network.Subnet.String()).To(Equal("10.2.3.0/30")) 401 }) 402 }) 403 404 Context("subsequent requests", func() { 405 It("fails, and return an err", func() { 406 _, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 407 Expect(err).ToNot(HaveOccurred()) 408 409 _, err = subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 410 Expect(err).To(HaveOccurred()) 411 }) 412 }) 413 414 Context("when an allocated network is released", func() { 415 It("a subsequent allocation succeeds, and returns the first network again", func() { 416 // first 417 network, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 418 Expect(err).ToNot(HaveOccurred()) 419 420 // second - will fail (sanity check) 421 _, err = subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 422 Expect(err).To(HaveOccurred()) 423 424 // release 425 err = subnetpool.Release(&linux_backend.Network{network.Subnet, network.IP}, logger) 426 Expect(err).ToNot(HaveOccurred()) 427 428 // third - should work now because of release 429 network2, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 430 Expect(err).ToNot(HaveOccurred()) 431 432 Expect(network2.Subnet).ToNot(BeNil()) 433 Expect(network2.Subnet.String()).To(Equal(network.Subnet.String())) 434 }) 435 436 Context("and it is not the last IP in the subnet", func() { 437 It("returns gone=false", func() { 438 _, static := networkParms("10.3.3.0/29") 439 440 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 441 Expect(err).ToNot(HaveOccurred()) 442 443 network, err := subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.DynamicIPSelector, logger) 444 Expect(err).ToNot(HaveOccurred()) 445 446 err = subnetpool.Release(&linux_backend.Network{network.Subnet, network.IP}, logger) 447 Expect(err).ToNot(HaveOccurred()) 448 }) 449 }) 450 }) 451 452 Context("when a network is released twice", func() { 453 It("returns an error", func() { 454 // first 455 network, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 456 Expect(err).ToNot(HaveOccurred()) 457 458 // release 459 err = subnetpool.Release(&linux_backend.Network{network.Subnet, network.IP}, logger) 460 Expect(err).ToNot(HaveOccurred()) 461 462 // release again 463 err = subnetpool.Release(&linux_backend.Network{network.Subnet, network.IP}, logger) 464 Expect(err).To(HaveOccurred()) 465 Expect(err).To(Equal(subnets.ErrReleasedUnallocatedSubnet)) 466 }) 467 }) 468 }) 469 470 Context("when the pool has sufficient IPs to allocate two /30 subnets", func() { 471 BeforeEach(func() { 472 defaultSubnetPool = subnetPool("10.2.3.0/29") 473 }) 474 475 Context("the second request", func() { 476 It("succeeds", func() { 477 _, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 478 Expect(err).ToNot(HaveOccurred()) 479 480 _, err = subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 481 Expect(err).ToNot(HaveOccurred()) 482 }) 483 484 It("returns the second /30 network within the subnet", func() { 485 _, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 486 Expect(err).ToNot(HaveOccurred()) 487 488 network, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 489 Expect(err).ToNot(HaveOccurred()) 490 491 Expect(network.Subnet).ToNot(BeNil()) 492 Expect(network.Subnet.String()).To(Equal("10.2.3.4/30")) 493 }) 494 }) 495 496 It("allocates distinct networks concurrently", func() { 497 prev := runtime.GOMAXPROCS(2) 498 defer runtime.GOMAXPROCS(prev) 499 500 Consistently(func() bool { 501 _, network, err := net.ParseCIDR("10.0.0.0/29") 502 Expect(err).ToNot(HaveOccurred()) 503 504 subnetpool, err := subnets.NewSubnets(network) 505 Expect(err).ToNot(HaveOccurred()) 506 507 out := make(chan *net.IPNet) 508 go func(out chan *net.IPNet) { 509 defer GinkgoRecover() 510 n1, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 511 Expect(err).ToNot(HaveOccurred()) 512 out <- n1.Subnet 513 }(out) 514 515 go func(out chan *net.IPNet) { 516 defer GinkgoRecover() 517 n1, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 518 Expect(err).ToNot(HaveOccurred()) 519 out <- n1.Subnet 520 }(out) 521 522 a := <-out 523 b := <-out 524 return a.IP.Equal(b.IP) 525 }, "100ms", "2ms").ShouldNot(BeTrue()) 526 }) 527 528 It("correctly handles concurrent release of the same network", func() { 529 prev := runtime.GOMAXPROCS(2) 530 defer runtime.GOMAXPROCS(prev) 531 532 Consistently(func() bool { 533 _, network, err := net.ParseCIDR("10.0.0.0/29") 534 Expect(err).ToNot(HaveOccurred()) 535 536 subnetpool, err := subnets.NewSubnets(network) 537 Expect(err).ToNot(HaveOccurred()) 538 539 acquired, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.DynamicIPSelector, logger) 540 Expect(err).ToNot(HaveOccurred()) 541 542 out := make(chan error) 543 go func(out chan error) { 544 defer GinkgoRecover() 545 err := subnetpool.Release(&linux_backend.Network{acquired.Subnet, acquired.IP}, logger) 546 out <- err 547 }(out) 548 549 go func(out chan error) { 550 defer GinkgoRecover() 551 err := subnetpool.Release(&linux_backend.Network{acquired.Subnet, acquired.IP}, logger) 552 out <- err 553 }(out) 554 555 a := <-out 556 b := <-out 557 return (a == nil) != (b == nil) 558 }, "200ms", "2ms").Should(BeTrue()) 559 }) 560 561 It("correctly handles concurrent allocation of the same network", func() { 562 prev := runtime.GOMAXPROCS(2) 563 defer runtime.GOMAXPROCS(prev) 564 565 Consistently(func() bool { 566 network := subnetPool("10.0.0.0/29") 567 568 subnetpool, err := subnets.NewSubnets(network) 569 Expect(err).ToNot(HaveOccurred()) 570 571 ip, n1 := networkParms("10.1.0.0/30") 572 573 out := make(chan error) 574 go func(out chan error) { 575 defer GinkgoRecover() 576 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{n1}, subnets.StaticIPSelector{ip}, logger) 577 out <- err 578 }(out) 579 580 go func(out chan error) { 581 defer GinkgoRecover() 582 _, err := subnetpool.Acquire(subnets.StaticSubnetSelector{n1}, subnets.StaticIPSelector{ip}, logger) 583 out <- err 584 }(out) 585 586 a := <-out 587 b := <-out 588 return (a == nil) != (b == nil) 589 }, "200ms", "2ms").Should(BeTrue()) 590 }) 591 }) 592 }) 593 594 Describe("Removeing", func() { 595 BeforeEach(func() { 596 defaultSubnetPool = subnetPool("10.2.3.0/29") 597 }) 598 599 Context("an allocation outside the dynamic allocation net", func() { 600 It("recovers the first time", func() { 601 _, static := networkParms("10.9.3.4/30") 602 603 err := subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.9.3.5")}, logger) 604 Expect(err).ToNot(HaveOccurred()) 605 }) 606 607 It("does not allow recovering twice", func() { 608 _, static := networkParms("10.9.3.4/30") 609 610 err := subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.9.3.5")}, logger) 611 Expect(err).ToNot(HaveOccurred()) 612 613 err = subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.9.3.5")}, logger) 614 Expect(err).To(HaveOccurred()) 615 }) 616 617 It("does not allow allocating after recovery", func() { 618 _, static := networkParms("10.9.3.4/30") 619 620 ip := net.ParseIP("10.9.3.5") 621 err := subnetpool.Remove(&linux_backend.Network{static, ip}, logger) 622 Expect(err).ToNot(HaveOccurred()) 623 624 _, err = subnetpool.Acquire(subnets.StaticSubnetSelector{static}, subnets.StaticIPSelector{ip}, logger) 625 Expect(err).To(HaveOccurred()) 626 }) 627 628 It("does not allow recovering without an explicit IP", func() { 629 _, static := networkParms("10.9.3.4/30") 630 631 err := subnetpool.Remove(&linux_backend.Network{static, nil}, logger) 632 Expect(err).To(HaveOccurred()) 633 }) 634 }) 635 636 Context("an allocation inside the dynamic allocation net", func() { 637 It("recovers the first time", func() { 638 _, static := networkParms("10.2.3.4/30") 639 640 err := subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.2.3.5")}, logger) 641 Expect(err).ToNot(HaveOccurred()) 642 }) 643 644 It("does not allow recovering twice", func() { 645 _, static := networkParms("10.2.3.4/30") 646 647 err := subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.2.3.5")}, logger) 648 Expect(err).ToNot(HaveOccurred()) 649 650 err = subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.2.3.5")}, logger) 651 Expect(err).To(HaveOccurred()) 652 }) 653 654 It("does not dynamically allocate a recovered network", func() { 655 _, static := networkParms("10.2.3.4/30") 656 657 err := subnetpool.Remove(&linux_backend.Network{static, net.ParseIP("10.2.3.1")}, logger) 658 Expect(err).ToNot(HaveOccurred()) 659 660 network, err := subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.StaticIPSelector{net.ParseIP("10.2.3.2")}, logger) 661 Expect(err).ToNot(HaveOccurred()) 662 Expect(network.Subnet.String()).To(Equal("10.2.3.0/30")) 663 664 _, err = subnetpool.Acquire(subnets.DynamicSubnetSelector, subnets.StaticIPSelector{net.ParseIP("10.2.3.2")}, logger) 665 Expect(err).To(Equal(subnets.ErrInsufficientSubnets)) 666 }) 667 }) 668 669 }) 670 671 }) 672 }) 673 674 func subnetPool(networkString string) *net.IPNet { 675 _, subnetPool := networkParms(networkString) 676 return subnetPool 677 } 678 679 func networkParms(networkString string) (net.IP, *net.IPNet) { 680 containerIP, subnet, err := net.ParseCIDR(networkString) 681 Expect(err).ToNot(HaveOccurred()) 682 gatewayIP := nextIP(subnet.IP) 683 684 if containerIP.Equal(subnet.IP) { 685 containerIP = nextIP(containerIP) 686 } 687 if containerIP.Equal(gatewayIP) { 688 containerIP = nextIP(containerIP) 689 } 690 691 return containerIP, subnet 692 } 693 694 func nextIP(ip net.IP) net.IP { 695 next := net.ParseIP(ip.String()) 696 inc(next) 697 return next 698 } 699 700 func inc(ip net.IP) { 701 for j := len(ip) - 1; j >= 0; j-- { 702 ip[j]++ 703 if ip[j] > 0 { 704 break 705 } 706 } 707 }