port_mapping.go 3.2 KB

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