port_mapping.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package bridge
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "net"
  7. "github.com/docker/libnetwork/types"
  8. "github.com/ishidawataru/sctp"
  9. "github.com/sirupsen/logrus"
  10. )
  11. var (
  12. defaultBindingIP = net.IPv4(0, 0, 0, 0)
  13. defaultBindingIPV6 = net.ParseIP("::")
  14. )
  15. func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
  16. if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
  17. return nil, nil
  18. }
  19. defHostIP := defaultBindingIP
  20. if reqDefBindIP != nil {
  21. defHostIP = reqDefBindIP
  22. }
  23. // IPv4 port binding including user land proxy
  24. pb, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
  25. if err != nil {
  26. return nil, err
  27. }
  28. // IPv6 port binding excluding user land proxy
  29. if n.driver.config.EnableIP6Tables && ep.addrv6 != nil {
  30. // TODO IPv6 custom default binding IP
  31. pbv6, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addrv6.IP, defaultBindingIPV6, false)
  32. if err != nil {
  33. // ensure we clear the previous allocated IPv4 ports
  34. n.releasePortsInternal(pb)
  35. return nil, err
  36. }
  37. pb = append(pb, pbv6...)
  38. }
  39. return pb, nil
  40. }
  41. func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
  42. bs := make([]types.PortBinding, 0, len(bindings))
  43. for _, c := range bindings {
  44. b := c.GetCopy()
  45. if err := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
  46. // On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
  47. if cuErr := n.releasePortsInternal(bs); cuErr != nil {
  48. logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
  49. }
  50. return nil, err
  51. }
  52. bs = append(bs, b)
  53. }
  54. return bs, nil
  55. }
  56. func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
  57. var (
  58. host net.Addr
  59. err error
  60. )
  61. // Store the container interface address in the operational binding
  62. bnd.IP = containerIP
  63. // Adjust the host address in the operational binding
  64. if len(bnd.HostIP) == 0 {
  65. bnd.HostIP = defHostIP
  66. }
  67. // Adjust HostPortEnd if this is not a range.
  68. if bnd.HostPortEnd == 0 {
  69. bnd.HostPortEnd = bnd.HostPort
  70. }
  71. // Construct the container side transport address
  72. container, err := bnd.ContainerAddr()
  73. if err != nil {
  74. return err
  75. }
  76. portmapper := n.portMapper
  77. if containerIP.To4() == nil {
  78. portmapper = n.portMapperV6
  79. }
  80. // Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
  81. for i := 0; i < maxAllocatePortAttempts; i++ {
  82. if host, err = portmapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
  83. break
  84. }
  85. // There is no point in immediately retrying to map an explicitly chosen port.
  86. if bnd.HostPort != 0 {
  87. logrus.Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
  88. break
  89. }
  90. logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
  91. }
  92. if err != nil {
  93. return err
  94. }
  95. // Save the host port (regardless it was or not specified in the binding)
  96. switch netAddr := host.(type) {
  97. case *net.TCPAddr:
  98. bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
  99. return nil
  100. case *net.UDPAddr:
  101. bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
  102. return nil
  103. case *sctp.SCTPAddr:
  104. bnd.HostPort = uint16(host.(*sctp.SCTPAddr).Port)
  105. return nil
  106. default:
  107. // For completeness
  108. return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
  109. }
  110. }
  111. func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
  112. return n.releasePortsInternal(ep.portMapping)
  113. }
  114. func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
  115. var errorBuf bytes.Buffer
  116. // Attempt to release all port bindings, do not stop on failure
  117. for _, m := range bindings {
  118. if err := n.releasePort(m); err != nil {
  119. errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
  120. }
  121. }
  122. if errorBuf.Len() != 0 {
  123. return errors.New(errorBuf.String())
  124. }
  125. return nil
  126. }
  127. func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
  128. // Construct the host side transport address
  129. host, err := bnd.HostAddr()
  130. if err != nil {
  131. return err
  132. }
  133. portmapper := n.portMapper
  134. if bnd.HostIP.To4() == nil {
  135. portmapper = n.portMapperV6
  136. }
  137. return portmapper.Unmap(host)
  138. }