port_mapping.go 3.5 KB

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