summaryrefslogtreecommitdiff
path: root/daemon/networkdriver/portmapper/mapper.go
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/networkdriver/portmapper/mapper.go')
-rw-r--r--daemon/networkdriver/portmapper/mapper.go69
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
}