mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
a9fa764cbb
This is need to decouple types from netutils which has linux dependencies. This way the client code which needs network types can just pull in types package which makes client code platform agnostic. Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
124 lines
3.3 KiB
Go
124 lines
3.3 KiB
Go
package bridge
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/libnetwork/sandbox"
|
|
"github.com/docker/libnetwork/types"
|
|
)
|
|
|
|
var (
|
|
defaultBindingIP = net.IPv4(0, 0, 0, 0)
|
|
)
|
|
|
|
func allocatePorts(epConfig *EndpointConfiguration, intf *sandbox.Interface, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
|
if epConfig == nil || epConfig.PortBindings == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
defHostIP := defaultBindingIP
|
|
if reqDefBindIP != nil {
|
|
defHostIP = reqDefBindIP
|
|
}
|
|
|
|
return allocatePortsInternal(epConfig.PortBindings, intf.Address.IP, defHostIP, ulPxyEnabled)
|
|
}
|
|
|
|
func allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
|
|
bs := make([]types.PortBinding, 0, len(bindings))
|
|
for _, c := range bindings {
|
|
b := c.GetCopy()
|
|
if err := allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
|
|
// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
|
|
if cuErr := releasePortsInternal(bs); cuErr != nil {
|
|
logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
|
|
}
|
|
return nil, err
|
|
}
|
|
bs = append(bs, b)
|
|
}
|
|
return bs, nil
|
|
}
|
|
|
|
func allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
|
|
var (
|
|
host net.Addr
|
|
err error
|
|
)
|
|
|
|
// Store the container interface address in the operational binding
|
|
bnd.IP = containerIP
|
|
|
|
// Adjust the host address in the operational binding
|
|
if len(bnd.HostIP) == 0 {
|
|
bnd.HostIP = defHostIP
|
|
}
|
|
|
|
// Construct the container side transport address
|
|
container, err := bnd.ContainerAddr()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
|
|
for i := 0; i < maxAllocatePortAttempts; i++ {
|
|
if host, err = portMapper.Map(container, bnd.HostIP, int(bnd.HostPort), ulPxyEnabled); err == nil {
|
|
break
|
|
}
|
|
// There is no point in immediately retrying to map an explicitly chosen port.
|
|
if bnd.HostPort != 0 {
|
|
logrus.Warnf("Failed to allocate and map port %d: %s", bnd.HostPort, err)
|
|
break
|
|
}
|
|
logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Save the host port (regardless it was or not specified in the binding)
|
|
switch netAddr := host.(type) {
|
|
case *net.TCPAddr:
|
|
bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
|
|
return nil
|
|
case *net.UDPAddr:
|
|
bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
|
|
return nil
|
|
default:
|
|
// For completeness
|
|
return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
|
|
}
|
|
}
|
|
|
|
func releasePorts(ep *bridgeEndpoint) error {
|
|
return releasePortsInternal(ep.portMapping)
|
|
}
|
|
|
|
func releasePortsInternal(bindings []types.PortBinding) error {
|
|
var errorBuf bytes.Buffer
|
|
|
|
// Attempt to release all port bindings, do not stop on failure
|
|
for _, m := range bindings {
|
|
if err := releasePort(m); err != nil {
|
|
errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
|
|
}
|
|
}
|
|
|
|
if errorBuf.Len() != 0 {
|
|
return errors.New(errorBuf.String())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func releasePort(bnd types.PortBinding) error {
|
|
// Construct the host side transport address
|
|
host, err := bnd.HostAddr()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return portMapper.Unmap(host)
|
|
}
|