port_mapping.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. // Construct the container side transport address
  50. container, err := bnd.ContainerAddr()
  51. if err != nil {
  52. return err
  53. }
  54. // Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
  55. for i := 0; i < maxAllocatePortAttempts; i++ {
  56. if host, err = n.portMapper.Map(container, bnd.HostIP, int(bnd.HostPort), ulPxyEnabled); err == nil {
  57. break
  58. }
  59. // There is no point in immediately retrying to map an explicitly chosen port.
  60. if bnd.HostPort != 0 {
  61. logrus.Warnf("Failed to allocate and map port %d: %s", bnd.HostPort, err)
  62. break
  63. }
  64. logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
  65. }
  66. if err != nil {
  67. return err
  68. }
  69. // Save the host port (regardless it was or not specified in the binding)
  70. switch netAddr := host.(type) {
  71. case *net.TCPAddr:
  72. bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
  73. return nil
  74. case *net.UDPAddr:
  75. bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
  76. return nil
  77. default:
  78. // For completeness
  79. return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
  80. }
  81. }
  82. func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
  83. return n.releasePortsInternal(ep.portMapping)
  84. }
  85. func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
  86. var errorBuf bytes.Buffer
  87. // Attempt to release all port bindings, do not stop on failure
  88. for _, m := range bindings {
  89. if err := n.releasePort(m); err != nil {
  90. errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
  91. }
  92. }
  93. if errorBuf.Len() != 0 {
  94. return errors.New(errorBuf.String())
  95. }
  96. return nil
  97. }
  98. func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
  99. // Construct the host side transport address
  100. host, err := bnd.HostAddr()
  101. if err != nil {
  102. return err
  103. }
  104. return n.portMapper.Unmap(host)
  105. }