port_allocator.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package userspace
  14. import (
  15. "errors"
  16. "math/big"
  17. "math/rand"
  18. "sync"
  19. "time"
  20. "k8s.io/apimachinery/pkg/util/net"
  21. "k8s.io/apimachinery/pkg/util/wait"
  22. )
  23. var (
  24. errPortRangeNoPortsRemaining = errors.New("port allocation failed; there are no remaining ports left to allocate in the accepted range")
  25. )
  26. type PortAllocator interface {
  27. AllocateNext() (int, error)
  28. Release(int)
  29. }
  30. // randomAllocator is a PortAllocator implementation that allocates random ports, yielding
  31. // a port value of 0 for every call to AllocateNext().
  32. type randomAllocator struct{}
  33. // AllocateNext always returns 0
  34. func (r *randomAllocator) AllocateNext() (int, error) {
  35. return 0, nil
  36. }
  37. // Release is a noop
  38. func (r *randomAllocator) Release(_ int) {
  39. // noop
  40. }
  41. // newPortAllocator builds PortAllocator for a given PortRange. If the PortRange is empty
  42. // then a random port allocator is returned; otherwise, a new range-based allocator
  43. // is returned.
  44. func newPortAllocator(r net.PortRange) PortAllocator {
  45. if r.Base == 0 {
  46. return &randomAllocator{}
  47. }
  48. return newPortRangeAllocator(r, true)
  49. }
  50. const (
  51. portsBufSize = 16
  52. nextFreePortCooldown = 500 * time.Millisecond
  53. allocateNextTimeout = 1 * time.Second
  54. )
  55. type rangeAllocator struct {
  56. net.PortRange
  57. ports chan int
  58. used big.Int
  59. lock sync.Mutex
  60. rand *rand.Rand
  61. }
  62. func newPortRangeAllocator(r net.PortRange, autoFill bool) PortAllocator {
  63. if r.Base == 0 || r.Size == 0 {
  64. panic("illegal argument: may not specify an empty port range")
  65. }
  66. ra := &rangeAllocator{
  67. PortRange: r,
  68. ports: make(chan int, portsBufSize),
  69. rand: rand.New(rand.NewSource(time.Now().UnixNano())),
  70. }
  71. if autoFill {
  72. go wait.Forever(func() { ra.fillPorts() }, nextFreePortCooldown)
  73. }
  74. return ra
  75. }
  76. // fillPorts loops, always searching for the next free port and, if found, fills the ports buffer with it.
  77. // this func blocks unless there are no remaining free ports.
  78. func (r *rangeAllocator) fillPorts() {
  79. for {
  80. if !r.fillPortsOnce() {
  81. return
  82. }
  83. }
  84. }
  85. func (r *rangeAllocator) fillPortsOnce() bool {
  86. port := r.nextFreePort()
  87. if port == -1 {
  88. return false
  89. }
  90. r.ports <- port
  91. return true
  92. }
  93. // nextFreePort finds a free port, first picking a random port. if that port is already in use
  94. // then the port range is scanned sequentially until either a port is found or the scan completes
  95. // unsuccessfully. an unsuccessful scan returns a port of -1.
  96. func (r *rangeAllocator) nextFreePort() int {
  97. r.lock.Lock()
  98. defer r.lock.Unlock()
  99. // choose random port
  100. j := r.rand.Intn(r.Size)
  101. if b := r.used.Bit(j); b == 0 {
  102. r.used.SetBit(&r.used, j, 1)
  103. return j + r.Base
  104. }
  105. // search sequentially
  106. for i := j + 1; i < r.Size; i++ {
  107. if b := r.used.Bit(i); b == 0 {
  108. r.used.SetBit(&r.used, i, 1)
  109. return i + r.Base
  110. }
  111. }
  112. for i := 0; i < j; i++ {
  113. if b := r.used.Bit(i); b == 0 {
  114. r.used.SetBit(&r.used, i, 1)
  115. return i + r.Base
  116. }
  117. }
  118. return -1
  119. }
  120. func (r *rangeAllocator) AllocateNext() (port int, err error) {
  121. select {
  122. case port = <-r.ports:
  123. case <-time.After(allocateNextTimeout):
  124. err = errPortRangeNoPortsRemaining
  125. }
  126. return
  127. }
  128. func (r *rangeAllocator) Release(port int) {
  129. port -= r.Base
  130. if port < 0 || port >= r.Size {
  131. return
  132. }
  133. r.lock.Lock()
  134. defer r.lock.Unlock()
  135. r.used.SetBit(&r.used, port, 0)
  136. }