mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
f5c1c78179
Currently sandbox code exposes bare structs externally to the package. It is untenable to continue this way and it becomes too inflexible to use it to store internal state. Changed all of them to use interfaces. Also cleaned up a lot of boiler plate code which needs to set into namespace. Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
123 lines
3.4 KiB
Go
123 lines
3.4 KiB
Go
package bridge
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/libnetwork/types"
|
|
)
|
|
|
|
var (
|
|
defaultBindingIP = net.IPv4(0, 0, 0, 0)
|
|
)
|
|
|
|
func (n *bridgeNetwork) allocatePorts(epConfig *endpointConfiguration, ep *bridgeEndpoint, 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 n.allocatePortsInternal(epConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
|
|
}
|
|
|
|
func (n *bridgeNetwork) 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 := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
|
|
// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
|
|
if cuErr := n.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 (n *bridgeNetwork) 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 = n.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 (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
|
|
return n.releasePortsInternal(ep.portMapping)
|
|
}
|
|
|
|
func (n *bridgeNetwork) 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 := n.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 (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
|
|
// Construct the host side transport address
|
|
host, err := bnd.HostAddr()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return n.portMapper.Unmap(host)
|
|
}
|