diff options
Diffstat (limited to 'daemon/networkdriver/portmapper/mapper.go')
-rw-r--r-- | daemon/networkdriver/portmapper/mapper.go | 69 |
1 files changed, 53 insertions, 16 deletions
diff --git a/daemon/networkdriver/portmapper/mapper.go b/daemon/networkdriver/portmapper/mapper.go index e29959a245..1bd332271f 100644 --- a/daemon/networkdriver/portmapper/mapper.go +++ b/daemon/networkdriver/portmapper/mapper.go @@ -3,10 +3,12 @@ package portmapper import ( "errors" "fmt" - "github.com/dotcloud/docker/pkg/iptables" - "github.com/dotcloud/docker/pkg/proxy" "net" "sync" + + "github.com/dotcloud/docker/daemon/networkdriver/portallocator" + "github.com/dotcloud/docker/pkg/iptables" + "github.com/dotcloud/docker/pkg/proxy" ) type mapping struct { @@ -35,43 +37,66 @@ func SetIptablesChain(c *iptables.Chain) { chain = c } -func Map(container net.Addr, hostIP net.IP, hostPort int) error { +func Map(container net.Addr, hostIP net.IP, hostPort int) (net.Addr, error) { lock.Lock() defer lock.Unlock() - var m *mapping + var ( + m *mapping + err error + proto string + allocatedHostPort int + ) + + // release the port on any error during return. + defer func() { + if err != nil { + portallocator.ReleasePort(hostIP, proto, allocatedHostPort) + } + }() + switch container.(type) { case *net.TCPAddr: + proto = "tcp" + if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { + return nil, err + } m = &mapping{ - proto: "tcp", - host: &net.TCPAddr{IP: hostIP, Port: hostPort}, + proto: proto, + host: &net.TCPAddr{IP: hostIP, Port: allocatedHostPort}, container: container, } case *net.UDPAddr: + proto = "udp" + if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { + return nil, err + } m = &mapping{ - proto: "udp", - host: &net.UDPAddr{IP: hostIP, Port: hostPort}, + proto: proto, + host: &net.UDPAddr{IP: hostIP, Port: allocatedHostPort}, container: container, } default: - return ErrUnknownBackendAddressType + err = ErrUnknownBackendAddressType + return nil, err } key := getKey(m.host) if _, exists := currentMappings[key]; exists { - return ErrPortMappedForIP + err = ErrPortMappedForIP + return nil, err } containerIP, containerPort := getIPAndPort(m.container) - if err := forward(iptables.Add, m.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil { - return err + if err := forward(iptables.Add, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil { + return nil, err } p, err := newProxy(m.host, m.container) if err != nil { - // need to undo the iptables rules before we reutrn - forward(iptables.Delete, m.proto, hostIP, hostPort, containerIP.String(), containerPort) - return err + // need to undo the iptables rules before we return + forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) + return nil, err } m.userlandProxy = p @@ -79,7 +104,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) error { go p.Run() - return nil + return m.host, nil } func Unmap(host net.Addr) error { @@ -100,6 +125,18 @@ func Unmap(host net.Addr) error { if err := forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil { return err } + + switch a := host.(type) { + case *net.TCPAddr: + if err := portallocator.ReleasePort(a.IP, "tcp", a.Port); err != nil { + return err + } + case *net.UDPAddr: + if err := portallocator.ReleasePort(a.IP, "udp", a.Port); err != nil { + return err + } + } + return nil } |