Browse code

Move networking drivers into runtime top level pkg Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby authored on 2014/03/15 06:03:23
Showing 23 changed files
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"github.com/dotcloud/docker/engine"
5 5
 
6 6
 	"github.com/dotcloud/docker/api"
7
-	"github.com/dotcloud/docker/networkdriver/lxc"
7
+	"github.com/dotcloud/docker/runtime/networkdriver/lxc"
8 8
 	"github.com/dotcloud/docker/server"
9 9
 )
10 10
 
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"net"
5 5
 
6 6
 	"github.com/dotcloud/docker/engine"
7
-	"github.com/dotcloud/docker/networkdriver"
7
+	"github.com/dotcloud/docker/runtime/networkdriver"
8 8
 )
9 9
 
10 10
 const (
11 11
deleted file mode 100644
... ...
@@ -1,159 +0,0 @@
1
-package ipallocator
2
-
3
-import (
4
-	"encoding/binary"
5
-	"errors"
6
-	"github.com/dotcloud/docker/networkdriver"
7
-	"github.com/dotcloud/docker/pkg/collections"
8
-	"net"
9
-	"sync"
10
-)
11
-
12
-type networkSet map[string]*collections.OrderedIntSet
13
-
14
-var (
15
-	ErrNoAvailableIPs     = errors.New("no available ip addresses on network")
16
-	ErrIPAlreadyAllocated = errors.New("ip already allocated")
17
-)
18
-
19
-var (
20
-	lock         = sync.Mutex{}
21
-	allocatedIPs = networkSet{}
22
-	availableIPS = networkSet{}
23
-)
24
-
25
-// RequestIP requests an available ip from the given network.  It
26
-// will return the next available ip if the ip provided is nil.  If the
27
-// ip provided is not nil it will validate that the provided ip is available
28
-// for use or return an error
29
-func RequestIP(address *net.IPNet, ip *net.IP) (*net.IP, error) {
30
-	lock.Lock()
31
-	defer lock.Unlock()
32
-
33
-	checkAddress(address)
34
-
35
-	if ip == nil {
36
-		next, err := getNextIp(address)
37
-		if err != nil {
38
-			return nil, err
39
-		}
40
-		return next, nil
41
-	}
42
-
43
-	if err := registerIP(address, ip); err != nil {
44
-		return nil, err
45
-	}
46
-	return ip, nil
47
-}
48
-
49
-// ReleaseIP adds the provided ip back into the pool of
50
-// available ips to be returned for use.
51
-func ReleaseIP(address *net.IPNet, ip *net.IP) error {
52
-	lock.Lock()
53
-	defer lock.Unlock()
54
-
55
-	checkAddress(address)
56
-
57
-	var (
58
-		existing  = allocatedIPs[address.String()]
59
-		available = availableIPS[address.String()]
60
-		pos       = getPosition(address, ip)
61
-	)
62
-
63
-	existing.Remove(int(pos))
64
-	available.Push(int(pos))
65
-
66
-	return nil
67
-}
68
-
69
-// convert the ip into the position in the subnet.  Only
70
-// position are saved in the set
71
-func getPosition(address *net.IPNet, ip *net.IP) int32 {
72
-	var (
73
-		first, _ = networkdriver.NetworkRange(address)
74
-		base     = ipToInt(&first)
75
-		i        = ipToInt(ip)
76
-	)
77
-	return i - base
78
-}
79
-
80
-// return an available ip if one is currently available.  If not,
81
-// return the next available ip for the nextwork
82
-func getNextIp(address *net.IPNet) (*net.IP, error) {
83
-	var (
84
-		ownIP     = ipToInt(&address.IP)
85
-		available = availableIPS[address.String()]
86
-		allocated = allocatedIPs[address.String()]
87
-		first, _  = networkdriver.NetworkRange(address)
88
-		base      = ipToInt(&first)
89
-		size      = int(networkdriver.NetworkSize(address.Mask))
90
-		max       = int32(size - 2) // size -1 for the broadcast address, -1 for the gateway address
91
-		pos       = int32(available.Pop())
92
-	)
93
-
94
-	// We pop and push the position not the ip
95
-	if pos != 0 {
96
-		ip := intToIP(int32(base + pos))
97
-		allocated.Push(int(pos))
98
-
99
-		return ip, nil
100
-	}
101
-
102
-	var (
103
-		firstNetIP = address.IP.To4().Mask(address.Mask)
104
-		firstAsInt = ipToInt(&firstNetIP) + 1
105
-	)
106
-
107
-	pos = int32(allocated.PullBack())
108
-	for i := int32(0); i < max; i++ {
109
-		pos = pos%max + 1
110
-		next := int32(base + pos)
111
-
112
-		if next == ownIP || next == firstAsInt {
113
-			continue
114
-		}
115
-
116
-		if !allocated.Exists(int(pos)) {
117
-			ip := intToIP(next)
118
-			allocated.Push(int(pos))
119
-			return ip, nil
120
-		}
121
-	}
122
-	return nil, ErrNoAvailableIPs
123
-}
124
-
125
-func registerIP(address *net.IPNet, ip *net.IP) error {
126
-	var (
127
-		existing  = allocatedIPs[address.String()]
128
-		available = availableIPS[address.String()]
129
-		pos       = getPosition(address, ip)
130
-	)
131
-
132
-	if existing.Exists(int(pos)) {
133
-		return ErrIPAlreadyAllocated
134
-	}
135
-	available.Remove(int(pos))
136
-
137
-	return nil
138
-}
139
-
140
-// Converts a 4 bytes IP into a 32 bit integer
141
-func ipToInt(ip *net.IP) int32 {
142
-	return int32(binary.BigEndian.Uint32(ip.To4()))
143
-}
144
-
145
-// Converts 32 bit integer into a 4 bytes IP address
146
-func intToIP(n int32) *net.IP {
147
-	b := make([]byte, 4)
148
-	binary.BigEndian.PutUint32(b, uint32(n))
149
-	ip := net.IP(b)
150
-	return &ip
151
-}
152
-
153
-func checkAddress(address *net.IPNet) {
154
-	key := address.String()
155
-	if _, exists := allocatedIPs[key]; !exists {
156
-		allocatedIPs[key] = collections.NewOrderedIntSet()
157
-		availableIPS[key] = collections.NewOrderedIntSet()
158
-	}
159
-}
160 1
deleted file mode 100644
... ...
@@ -1,241 +0,0 @@
1
-package ipallocator
2
-
3
-import (
4
-	"fmt"
5
-	"net"
6
-	"testing"
7
-)
8
-
9
-func reset() {
10
-	allocatedIPs = networkSet{}
11
-	availableIPS = networkSet{}
12
-}
13
-
14
-func TestRequestNewIps(t *testing.T) {
15
-	defer reset()
16
-	network := &net.IPNet{
17
-		IP:   []byte{192, 168, 0, 1},
18
-		Mask: []byte{255, 255, 255, 0},
19
-	}
20
-
21
-	for i := 2; i < 10; i++ {
22
-		ip, err := RequestIP(network, nil)
23
-		if err != nil {
24
-			t.Fatal(err)
25
-		}
26
-
27
-		if expected := fmt.Sprintf("192.168.0.%d", i); ip.String() != expected {
28
-			t.Fatalf("Expected ip %s got %s", expected, ip.String())
29
-		}
30
-	}
31
-}
32
-
33
-func TestReleaseIp(t *testing.T) {
34
-	defer reset()
35
-	network := &net.IPNet{
36
-		IP:   []byte{192, 168, 0, 1},
37
-		Mask: []byte{255, 255, 255, 0},
38
-	}
39
-
40
-	ip, err := RequestIP(network, nil)
41
-	if err != nil {
42
-		t.Fatal(err)
43
-	}
44
-
45
-	if err := ReleaseIP(network, ip); err != nil {
46
-		t.Fatal(err)
47
-	}
48
-}
49
-
50
-func TestGetReleasedIp(t *testing.T) {
51
-	defer reset()
52
-	network := &net.IPNet{
53
-		IP:   []byte{192, 168, 0, 1},
54
-		Mask: []byte{255, 255, 255, 0},
55
-	}
56
-
57
-	ip, err := RequestIP(network, nil)
58
-	if err != nil {
59
-		t.Fatal(err)
60
-	}
61
-
62
-	value := ip.String()
63
-	if err := ReleaseIP(network, ip); err != nil {
64
-		t.Fatal(err)
65
-	}
66
-
67
-	ip, err = RequestIP(network, nil)
68
-	if err != nil {
69
-		t.Fatal(err)
70
-	}
71
-
72
-	if ip.String() != value {
73
-		t.Fatalf("Expected to receive same ip %s got %s", value, ip.String())
74
-	}
75
-}
76
-
77
-func TestRequesetSpecificIp(t *testing.T) {
78
-	defer reset()
79
-	network := &net.IPNet{
80
-		IP:   []byte{192, 168, 0, 1},
81
-		Mask: []byte{255, 255, 255, 0},
82
-	}
83
-
84
-	ip := net.ParseIP("192.168.1.5")
85
-
86
-	if _, err := RequestIP(network, &ip); err != nil {
87
-		t.Fatal(err)
88
-	}
89
-}
90
-
91
-func TestConversion(t *testing.T) {
92
-	ip := net.ParseIP("127.0.0.1")
93
-	i := ipToInt(&ip)
94
-	if i == 0 {
95
-		t.Fatal("converted to zero")
96
-	}
97
-	conv := intToIP(i)
98
-	if !ip.Equal(*conv) {
99
-		t.Error(conv.String())
100
-	}
101
-}
102
-
103
-func TestIPAllocator(t *testing.T) {
104
-	expectedIPs := []net.IP{
105
-		0: net.IPv4(127, 0, 0, 2),
106
-		1: net.IPv4(127, 0, 0, 3),
107
-		2: net.IPv4(127, 0, 0, 4),
108
-		3: net.IPv4(127, 0, 0, 5),
109
-		4: net.IPv4(127, 0, 0, 6),
110
-	}
111
-
112
-	gwIP, n, _ := net.ParseCIDR("127.0.0.1/29")
113
-	network := &net.IPNet{IP: gwIP, Mask: n.Mask}
114
-	// Pool after initialisation (f = free, u = used)
115
-	// 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
116
-	//  ↑
117
-
118
-	// Check that we get 5 IPs, from 127.0.0.2–127.0.0.6, in that
119
-	// order.
120
-	for i := 0; i < 5; i++ {
121
-		ip, err := RequestIP(network, nil)
122
-		if err != nil {
123
-			t.Fatal(err)
124
-		}
125
-
126
-		assertIPEquals(t, &expectedIPs[i], ip)
127
-	}
128
-	// Before loop begin
129
-	// 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
130
-	//  ↑
131
-
132
-	// After i = 0
133
-	// 2(u) - 3(f) - 4(f) - 5(f) - 6(f)
134
-	//         ↑
135
-
136
-	// After i = 1
137
-	// 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
138
-	//                ↑
139
-
140
-	// After i = 2
141
-	// 2(u) - 3(u) - 4(u) - 5(f) - 6(f)
142
-	//                       ↑
143
-
144
-	// After i = 3
145
-	// 2(u) - 3(u) - 4(u) - 5(u) - 6(f)
146
-	//                              ↑
147
-
148
-	// After i = 4
149
-	// 2(u) - 3(u) - 4(u) - 5(u) - 6(u)
150
-	//  ↑
151
-
152
-	// Check that there are no more IPs
153
-	ip, err := RequestIP(network, nil)
154
-	if err == nil {
155
-		t.Fatalf("There shouldn't be any IP addresses at this point, got %s\n", ip)
156
-	}
157
-
158
-	// Release some IPs in non-sequential order
159
-	if err := ReleaseIP(network, &expectedIPs[3]); err != nil {
160
-		t.Fatal(err)
161
-	}
162
-	// 2(u) - 3(u) - 4(u) - 5(f) - 6(u)
163
-	//                       ↑
164
-
165
-	if err := ReleaseIP(network, &expectedIPs[2]); err != nil {
166
-		t.Fatal(err)
167
-	}
168
-	// 2(u) - 3(u) - 4(f) - 5(f) - 6(u)
169
-	//                       ↑
170
-
171
-	if err := ReleaseIP(network, &expectedIPs[4]); err != nil {
172
-		t.Fatal(err)
173
-	}
174
-	// 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
175
-	//                       ↑
176
-
177
-	// Make sure that IPs are reused in sequential order, starting
178
-	// with the first released IP
179
-	newIPs := make([]*net.IP, 3)
180
-	for i := 0; i < 3; i++ {
181
-		ip, err := RequestIP(network, nil)
182
-		if err != nil {
183
-			t.Fatal(err)
184
-		}
185
-
186
-		newIPs[i] = ip
187
-	}
188
-	// Before loop begin
189
-	// 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
190
-	//                       ↑
191
-
192
-	// After i = 0
193
-	// 2(u) - 3(u) - 4(f) - 5(u) - 6(f)
194
-	//                              ↑
195
-
196
-	// After i = 1
197
-	// 2(u) - 3(u) - 4(f) - 5(u) - 6(u)
198
-	//                ↑
199
-
200
-	// After i = 2
201
-	// 2(u) - 3(u) - 4(u) - 5(u) - 6(u)
202
-	//                       ↑
203
-
204
-	// Reordered these because the new set will always return the
205
-	// lowest ips first and not in the order that they were released
206
-	assertIPEquals(t, &expectedIPs[2], newIPs[0])
207
-	assertIPEquals(t, &expectedIPs[3], newIPs[1])
208
-	assertIPEquals(t, &expectedIPs[4], newIPs[2])
209
-
210
-	_, err = RequestIP(network, nil)
211
-	if err == nil {
212
-		t.Fatal("There shouldn't be any IP addresses at this point")
213
-	}
214
-}
215
-
216
-func TestAllocateFirstIP(t *testing.T) {
217
-	defer reset()
218
-	network := &net.IPNet{
219
-		IP:   []byte{192, 168, 0, 0},
220
-		Mask: []byte{255, 255, 255, 0},
221
-	}
222
-
223
-	firstIP := network.IP.To4().Mask(network.Mask)
224
-	first := ipToInt(&firstIP) + 1
225
-
226
-	ip, err := RequestIP(network, nil)
227
-	if err != nil {
228
-		t.Fatal(err)
229
-	}
230
-	allocated := ipToInt(ip)
231
-
232
-	if allocated == first {
233
-		t.Fatalf("allocated ip should not equal first ip: %d == %d", first, allocated)
234
-	}
235
-}
236
-
237
-func assertIPEquals(t *testing.T, ip1, ip2 *net.IP) {
238
-	if !ip1.Equal(*ip2) {
239
-		t.Fatalf("Expected IP %s, got %s", ip1, ip2)
240
-	}
241
-}
242 1
deleted file mode 100644
... ...
@@ -1,482 +0,0 @@
1
-package lxc
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/engine"
6
-	"github.com/dotcloud/docker/networkdriver"
7
-	"github.com/dotcloud/docker/networkdriver/ipallocator"
8
-	"github.com/dotcloud/docker/networkdriver/portallocator"
9
-	"github.com/dotcloud/docker/networkdriver/portmapper"
10
-	"github.com/dotcloud/docker/pkg/iptables"
11
-	"github.com/dotcloud/docker/pkg/netlink"
12
-	"github.com/dotcloud/docker/utils"
13
-	"io/ioutil"
14
-	"log"
15
-	"net"
16
-	"strings"
17
-	"syscall"
18
-	"unsafe"
19
-)
20
-
21
-const (
22
-	DefaultNetworkBridge = "docker0"
23
-	siocBRADDBR          = 0x89a0
24
-)
25
-
26
-// Network interface represents the networking stack of a container
27
-type networkInterface struct {
28
-	IP           net.IP
29
-	PortMappings []net.Addr // there are mappings to the host interfaces
30
-}
31
-
32
-var (
33
-	addrs = []string{
34
-		// Here we don't follow the convention of using the 1st IP of the range for the gateway.
35
-		// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
36
-		// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
37
-		// on the internal addressing or other stupid things like that.
38
-		// The shouldn't, but hey, let's not break them unless we really have to.
39
-		"172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
40
-		"10.0.42.1/16",   // Don't even try using the entire /8, that's too intrusive
41
-		"10.1.42.1/16",
42
-		"10.42.42.1/16",
43
-		"172.16.42.1/24",
44
-		"172.16.43.1/24",
45
-		"172.16.44.1/24",
46
-		"10.0.42.1/24",
47
-		"10.0.43.1/24",
48
-		"192.168.42.1/24",
49
-		"192.168.43.1/24",
50
-		"192.168.44.1/24",
51
-	}
52
-
53
-	bridgeIface   string
54
-	bridgeNetwork *net.IPNet
55
-
56
-	defaultBindingIP  = net.ParseIP("0.0.0.0")
57
-	currentInterfaces = make(map[string]*networkInterface)
58
-)
59
-
60
-func InitDriver(job *engine.Job) engine.Status {
61
-	var (
62
-		network        *net.IPNet
63
-		enableIPTables = job.GetenvBool("EnableIptables")
64
-		icc            = job.GetenvBool("InterContainerCommunication")
65
-		ipForward      = job.GetenvBool("EnableIpForward")
66
-		bridgeIP       = job.Getenv("BridgeIP")
67
-	)
68
-
69
-	if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
70
-		defaultBindingIP = net.ParseIP(defaultIP)
71
-	}
72
-
73
-	bridgeIface = job.Getenv("BridgeIface")
74
-	if bridgeIface == "" {
75
-		bridgeIface = DefaultNetworkBridge
76
-	}
77
-
78
-	addr, err := networkdriver.GetIfaceAddr(bridgeIface)
79
-	if err != nil {
80
-		// If the iface is not found, try to create it
81
-		job.Logf("creating new bridge for %s", bridgeIface)
82
-		if err := createBridge(bridgeIP); err != nil {
83
-			job.Error(err)
84
-			return engine.StatusErr
85
-		}
86
-
87
-		job.Logf("getting iface addr")
88
-		addr, err = networkdriver.GetIfaceAddr(bridgeIface)
89
-		if err != nil {
90
-			job.Error(err)
91
-			return engine.StatusErr
92
-		}
93
-		network = addr.(*net.IPNet)
94
-	} else {
95
-		network = addr.(*net.IPNet)
96
-	}
97
-
98
-	// Configure iptables for link support
99
-	if enableIPTables {
100
-		if err := setupIPTables(addr, icc); err != nil {
101
-			job.Error(err)
102
-			return engine.StatusErr
103
-		}
104
-	}
105
-
106
-	if ipForward {
107
-		// Enable IPv4 forwarding
108
-		if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
109
-			job.Logf("WARNING: unable to enable IPv4 forwarding: %s\n", err)
110
-		}
111
-	}
112
-
113
-	// We can always try removing the iptables
114
-	if err := iptables.RemoveExistingChain("DOCKER"); err != nil {
115
-		job.Error(err)
116
-		return engine.StatusErr
117
-	}
118
-
119
-	if enableIPTables {
120
-		chain, err := iptables.NewChain("DOCKER", bridgeIface)
121
-		if err != nil {
122
-			job.Error(err)
123
-			return engine.StatusErr
124
-		}
125
-		portmapper.SetIptablesChain(chain)
126
-	}
127
-
128
-	bridgeNetwork = network
129
-
130
-	// https://github.com/dotcloud/docker/issues/2768
131
-	job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeNetwork.IP)
132
-
133
-	for name, f := range map[string]engine.Handler{
134
-		"allocate_interface": Allocate,
135
-		"release_interface":  Release,
136
-		"allocate_port":      AllocatePort,
137
-		"link":               LinkContainers,
138
-	} {
139
-		if err := job.Eng.Register(name, f); err != nil {
140
-			job.Error(err)
141
-			return engine.StatusErr
142
-		}
143
-	}
144
-	return engine.StatusOK
145
-}
146
-
147
-func setupIPTables(addr net.Addr, icc bool) error {
148
-	// Enable NAT
149
-	natArgs := []string{"POSTROUTING", "-t", "nat", "-s", addr.String(), "!", "-d", addr.String(), "-j", "MASQUERADE"}
150
-
151
-	if !iptables.Exists(natArgs...) {
152
-		if output, err := iptables.Raw(append([]string{"-I"}, natArgs...)...); err != nil {
153
-			return fmt.Errorf("Unable to enable network bridge NAT: %s", err)
154
-		} else if len(output) != 0 {
155
-			return fmt.Errorf("Error iptables postrouting: %s", output)
156
-		}
157
-	}
158
-
159
-	var (
160
-		args       = []string{"FORWARD", "-i", bridgeIface, "-o", bridgeIface, "-j"}
161
-		acceptArgs = append(args, "ACCEPT")
162
-		dropArgs   = append(args, "DROP")
163
-	)
164
-
165
-	if !icc {
166
-		iptables.Raw(append([]string{"-D"}, acceptArgs...)...)
167
-
168
-		if !iptables.Exists(dropArgs...) {
169
-			utils.Debugf("Disable inter-container communication")
170
-			if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil {
171
-				return fmt.Errorf("Unable to prevent intercontainer communication: %s", err)
172
-			} else if len(output) != 0 {
173
-				return fmt.Errorf("Error disabling intercontainer communication: %s", output)
174
-			}
175
-		}
176
-	} else {
177
-		iptables.Raw(append([]string{"-D"}, dropArgs...)...)
178
-
179
-		if !iptables.Exists(acceptArgs...) {
180
-			utils.Debugf("Enable inter-container communication")
181
-			if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil {
182
-				return fmt.Errorf("Unable to allow intercontainer communication: %s", err)
183
-			} else if len(output) != 0 {
184
-				return fmt.Errorf("Error enabling intercontainer communication: %s", output)
185
-			}
186
-		}
187
-	}
188
-
189
-	// Accept all non-intercontainer outgoing packets
190
-	outgoingArgs := []string{"FORWARD", "-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}
191
-	if !iptables.Exists(outgoingArgs...) {
192
-		if output, err := iptables.Raw(append([]string{"-I"}, outgoingArgs...)...); err != nil {
193
-			return fmt.Errorf("Unable to allow outgoing packets: %s", err)
194
-		} else if len(output) != 0 {
195
-			return fmt.Errorf("Error iptables allow outgoing: %s", output)
196
-		}
197
-	}
198
-
199
-	// Accept incoming packets for existing connections
200
-	existingArgs := []string{"FORWARD", "-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}
201
-
202
-	if !iptables.Exists(existingArgs...) {
203
-		if output, err := iptables.Raw(append([]string{"-I"}, existingArgs...)...); err != nil {
204
-			return fmt.Errorf("Unable to allow incoming packets: %s", err)
205
-		} else if len(output) != 0 {
206
-			return fmt.Errorf("Error iptables allow incoming: %s", output)
207
-		}
208
-	}
209
-	return nil
210
-}
211
-
212
-// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`,
213
-// and attempts to configure it with an address which doesn't conflict with any other interface on the host.
214
-// If it can't find an address which doesn't conflict, it will return an error.
215
-func createBridge(bridgeIP string) error {
216
-	nameservers := []string{}
217
-	resolvConf, _ := utils.GetResolvConf()
218
-	// we don't check for an error here, because we don't really care
219
-	// if we can't read /etc/resolv.conf. So instead we skip the append
220
-	// if resolvConf is nil. It either doesn't exist, or we can't read it
221
-	// for some reason.
222
-	if resolvConf != nil {
223
-		nameservers = append(nameservers, utils.GetNameserversAsCIDR(resolvConf)...)
224
-	}
225
-
226
-	var ifaceAddr string
227
-	if len(bridgeIP) != 0 {
228
-		_, _, err := net.ParseCIDR(bridgeIP)
229
-		if err != nil {
230
-			return err
231
-		}
232
-		ifaceAddr = bridgeIP
233
-	} else {
234
-		for _, addr := range addrs {
235
-			_, dockerNetwork, err := net.ParseCIDR(addr)
236
-			if err != nil {
237
-				return err
238
-			}
239
-			if err := networkdriver.CheckNameserverOverlaps(nameservers, dockerNetwork); err == nil {
240
-				if err := networkdriver.CheckRouteOverlaps(dockerNetwork); err == nil {
241
-					ifaceAddr = addr
242
-					break
243
-				} else {
244
-					utils.Debugf("%s %s", addr, err)
245
-				}
246
-			}
247
-		}
248
-	}
249
-
250
-	if ifaceAddr == "" {
251
-		return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", bridgeIface, bridgeIface)
252
-	}
253
-	utils.Debugf("Creating bridge %s with network %s", bridgeIface, ifaceAddr)
254
-
255
-	if err := createBridgeIface(bridgeIface); err != nil {
256
-		return err
257
-	}
258
-
259
-	iface, err := net.InterfaceByName(bridgeIface)
260
-	if err != nil {
261
-		return err
262
-	}
263
-
264
-	ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr)
265
-	if err != nil {
266
-		return err
267
-	}
268
-
269
-	if netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
270
-		return fmt.Errorf("Unable to add private network: %s", err)
271
-	}
272
-	if err := netlink.NetworkLinkUp(iface); err != nil {
273
-		return fmt.Errorf("Unable to start network bridge: %s", err)
274
-	}
275
-	return nil
276
-}
277
-
278
-// Create the actual bridge device.  This is more backward-compatible than
279
-// netlink.NetworkLinkAdd and works on RHEL 6.
280
-func createBridgeIface(name string) error {
281
-	s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_IP)
282
-	if err != nil {
283
-		utils.Debugf("Bridge socket creation failed IPv6 probably not enabled: %v", err)
284
-		s, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_IP)
285
-		if err != nil {
286
-			return fmt.Errorf("Error creating bridge creation socket: %s", err)
287
-		}
288
-	}
289
-	defer syscall.Close(s)
290
-
291
-	nameBytePtr, err := syscall.BytePtrFromString(name)
292
-	if err != nil {
293
-		return fmt.Errorf("Error converting bridge name %s to byte array: %s", name, err)
294
-	}
295
-
296
-	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), siocBRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
297
-		return fmt.Errorf("Error creating bridge: %s", err)
298
-	}
299
-	return nil
300
-}
301
-
302
-// Allocate a network interface
303
-func Allocate(job *engine.Job) engine.Status {
304
-	var (
305
-		ip          *net.IP
306
-		err         error
307
-		id          = job.Args[0]
308
-		requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
309
-	)
310
-
311
-	if requestedIP != nil {
312
-		ip, err = ipallocator.RequestIP(bridgeNetwork, &requestedIP)
313
-	} else {
314
-		ip, err = ipallocator.RequestIP(bridgeNetwork, nil)
315
-	}
316
-	if err != nil {
317
-		job.Error(err)
318
-		return engine.StatusErr
319
-	}
320
-
321
-	out := engine.Env{}
322
-	out.Set("IP", ip.String())
323
-	out.Set("Mask", bridgeNetwork.Mask.String())
324
-	out.Set("Gateway", bridgeNetwork.IP.String())
325
-	out.Set("Bridge", bridgeIface)
326
-
327
-	size, _ := bridgeNetwork.Mask.Size()
328
-	out.SetInt("IPPrefixLen", size)
329
-
330
-	currentInterfaces[id] = &networkInterface{
331
-		IP: *ip,
332
-	}
333
-
334
-	out.WriteTo(job.Stdout)
335
-
336
-	return engine.StatusOK
337
-}
338
-
339
-// release an interface for a select ip
340
-func Release(job *engine.Job) engine.Status {
341
-	var (
342
-		id                 = job.Args[0]
343
-		containerInterface = currentInterfaces[id]
344
-		ip                 net.IP
345
-		port               int
346
-		proto              string
347
-	)
348
-
349
-	if containerInterface == nil {
350
-		return job.Errorf("No network information to release for %s", id)
351
-	}
352
-
353
-	for _, nat := range containerInterface.PortMappings {
354
-		if err := portmapper.Unmap(nat); err != nil {
355
-			log.Printf("Unable to unmap port %s: %s", nat, err)
356
-		}
357
-
358
-		// this is host mappings
359
-		switch a := nat.(type) {
360
-		case *net.TCPAddr:
361
-			proto = "tcp"
362
-			ip = a.IP
363
-			port = a.Port
364
-		case *net.UDPAddr:
365
-			proto = "udp"
366
-			ip = a.IP
367
-			port = a.Port
368
-		}
369
-
370
-		if err := portallocator.ReleasePort(ip, proto, port); err != nil {
371
-			log.Printf("Unable to release port %s", nat)
372
-		}
373
-	}
374
-
375
-	if err := ipallocator.ReleaseIP(bridgeNetwork, &containerInterface.IP); err != nil {
376
-		log.Printf("Unable to release ip %s\n", err)
377
-	}
378
-	return engine.StatusOK
379
-}
380
-
381
-// Allocate an external port and map it to the interface
382
-func AllocatePort(job *engine.Job) engine.Status {
383
-	var (
384
-		err error
385
-
386
-		ip            = defaultBindingIP
387
-		id            = job.Args[0]
388
-		hostIP        = job.Getenv("HostIP")
389
-		hostPort      = job.GetenvInt("HostPort")
390
-		containerPort = job.GetenvInt("ContainerPort")
391
-		proto         = job.Getenv("Proto")
392
-		network       = currentInterfaces[id]
393
-	)
394
-
395
-	if hostIP != "" {
396
-		ip = net.ParseIP(hostIP)
397
-	}
398
-
399
-	// host ip, proto, and host port
400
-	hostPort, err = portallocator.RequestPort(ip, proto, hostPort)
401
-	if err != nil {
402
-		job.Error(err)
403
-		return engine.StatusErr
404
-	}
405
-
406
-	var (
407
-		container net.Addr
408
-		host      net.Addr
409
-	)
410
-
411
-	if proto == "tcp" {
412
-		host = &net.TCPAddr{IP: ip, Port: hostPort}
413
-		container = &net.TCPAddr{IP: network.IP, Port: containerPort}
414
-	} else {
415
-		host = &net.UDPAddr{IP: ip, Port: hostPort}
416
-		container = &net.UDPAddr{IP: network.IP, Port: containerPort}
417
-	}
418
-
419
-	if err := portmapper.Map(container, ip, hostPort); err != nil {
420
-		portallocator.ReleasePort(ip, proto, hostPort)
421
-
422
-		job.Error(err)
423
-		return engine.StatusErr
424
-	}
425
-	network.PortMappings = append(network.PortMappings, host)
426
-
427
-	out := engine.Env{}
428
-	out.Set("HostIP", ip.String())
429
-	out.SetInt("HostPort", hostPort)
430
-
431
-	if _, err := out.WriteTo(job.Stdout); err != nil {
432
-		job.Error(err)
433
-		return engine.StatusErr
434
-	}
435
-	return engine.StatusOK
436
-}
437
-
438
-func LinkContainers(job *engine.Job) engine.Status {
439
-	var (
440
-		action       = job.Args[0]
441
-		childIP      = job.Getenv("ChildIP")
442
-		parentIP     = job.Getenv("ParentIP")
443
-		ignoreErrors = job.GetenvBool("IgnoreErrors")
444
-		ports        = job.GetenvList("Ports")
445
-	)
446
-	split := func(p string) (string, string) {
447
-		parts := strings.Split(p, "/")
448
-		return parts[0], parts[1]
449
-	}
450
-
451
-	for _, p := range ports {
452
-		port, proto := split(p)
453
-		if output, err := iptables.Raw(action, "FORWARD",
454
-			"-i", bridgeIface, "-o", bridgeIface,
455
-			"-p", proto,
456
-			"-s", parentIP,
457
-			"--dport", port,
458
-			"-d", childIP,
459
-			"-j", "ACCEPT"); !ignoreErrors && err != nil {
460
-			job.Error(err)
461
-			return engine.StatusErr
462
-		} else if len(output) != 0 {
463
-			job.Errorf("Error toggle iptables forward: %s", output)
464
-			return engine.StatusErr
465
-		}
466
-
467
-		if output, err := iptables.Raw(action, "FORWARD",
468
-			"-i", bridgeIface, "-o", bridgeIface,
469
-			"-p", proto,
470
-			"-s", childIP,
471
-			"--sport", port,
472
-			"-d", parentIP,
473
-			"-j", "ACCEPT"); !ignoreErrors && err != nil {
474
-			job.Error(err)
475
-			return engine.StatusErr
476
-		} else if len(output) != 0 {
477
-			job.Errorf("Error toggle iptables forward: %s", output)
478
-			return engine.StatusErr
479
-		}
480
-	}
481
-	return engine.StatusOK
482
-}
483 1
deleted file mode 100644
... ...
@@ -1,10 +0,0 @@
1
-package networkdriver
2
-
3
-import (
4
-	"errors"
5
-)
6
-
7
-var (
8
-	ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver")
9
-	ErrNetworkOverlaps                = errors.New("requested network overlaps with existing network")
10
-)
11 1
deleted file mode 100644
... ...
@@ -1,190 +0,0 @@
1
-package networkdriver
2
-
3
-import (
4
-	"github.com/dotcloud/docker/pkg/netlink"
5
-	"net"
6
-	"testing"
7
-)
8
-
9
-func TestNonOverlapingNameservers(t *testing.T) {
10
-	network := &net.IPNet{
11
-		IP:   []byte{192, 168, 0, 1},
12
-		Mask: []byte{255, 255, 255, 0},
13
-	}
14
-	nameservers := []string{
15
-		"127.0.0.1/32",
16
-	}
17
-
18
-	if err := CheckNameserverOverlaps(nameservers, network); err != nil {
19
-		t.Fatal(err)
20
-	}
21
-}
22
-
23
-func TestOverlapingNameservers(t *testing.T) {
24
-	network := &net.IPNet{
25
-		IP:   []byte{192, 168, 0, 1},
26
-		Mask: []byte{255, 255, 255, 0},
27
-	}
28
-	nameservers := []string{
29
-		"192.168.0.1/32",
30
-	}
31
-
32
-	if err := CheckNameserverOverlaps(nameservers, network); err == nil {
33
-		t.Fatalf("Expected error %s got %s", ErrNetworkOverlapsWithNameservers, err)
34
-	}
35
-}
36
-
37
-func TestCheckRouteOverlaps(t *testing.T) {
38
-	orig := networkGetRoutesFct
39
-	defer func() {
40
-		networkGetRoutesFct = orig
41
-	}()
42
-	networkGetRoutesFct = func() ([]netlink.Route, error) {
43
-		routesData := []string{"10.0.2.0/32", "10.0.3.0/24", "10.0.42.0/24", "172.16.42.0/24", "192.168.142.0/24"}
44
-
45
-		routes := []netlink.Route{}
46
-		for _, addr := range routesData {
47
-			_, netX, _ := net.ParseCIDR(addr)
48
-			routes = append(routes, netlink.Route{IPNet: netX})
49
-		}
50
-		return routes, nil
51
-	}
52
-
53
-	_, netX, _ := net.ParseCIDR("172.16.0.1/24")
54
-	if err := CheckRouteOverlaps(netX); err != nil {
55
-		t.Fatal(err)
56
-	}
57
-
58
-	_, netX, _ = net.ParseCIDR("10.0.2.0/24")
59
-	if err := CheckRouteOverlaps(netX); err == nil {
60
-		t.Fatalf("10.0.2.0/24 and 10.0.2.0 should overlap but it doesn't")
61
-	}
62
-}
63
-
64
-func TestCheckNameserverOverlaps(t *testing.T) {
65
-	nameservers := []string{"10.0.2.3/32", "192.168.102.1/32"}
66
-
67
-	_, netX, _ := net.ParseCIDR("10.0.2.3/32")
68
-
69
-	if err := CheckNameserverOverlaps(nameservers, netX); err == nil {
70
-		t.Fatalf("%s should overlap 10.0.2.3/32 but doesn't", netX)
71
-	}
72
-
73
-	_, netX, _ = net.ParseCIDR("192.168.102.2/32")
74
-
75
-	if err := CheckNameserverOverlaps(nameservers, netX); err != nil {
76
-		t.Fatalf("%s should not overlap %v but it does", netX, nameservers)
77
-	}
78
-}
79
-
80
-func AssertOverlap(CIDRx string, CIDRy string, t *testing.T) {
81
-	_, netX, _ := net.ParseCIDR(CIDRx)
82
-	_, netY, _ := net.ParseCIDR(CIDRy)
83
-	if !NetworkOverlaps(netX, netY) {
84
-		t.Errorf("%v and %v should overlap", netX, netY)
85
-	}
86
-}
87
-
88
-func AssertNoOverlap(CIDRx string, CIDRy string, t *testing.T) {
89
-	_, netX, _ := net.ParseCIDR(CIDRx)
90
-	_, netY, _ := net.ParseCIDR(CIDRy)
91
-	if NetworkOverlaps(netX, netY) {
92
-		t.Errorf("%v and %v should not overlap", netX, netY)
93
-	}
94
-}
95
-
96
-func TestNetworkOverlaps(t *testing.T) {
97
-	//netY starts at same IP and ends within netX
98
-	AssertOverlap("172.16.0.1/24", "172.16.0.1/25", t)
99
-	//netY starts within netX and ends at same IP
100
-	AssertOverlap("172.16.0.1/24", "172.16.0.128/25", t)
101
-	//netY starts and ends within netX
102
-	AssertOverlap("172.16.0.1/24", "172.16.0.64/25", t)
103
-	//netY starts at same IP and ends outside of netX
104
-	AssertOverlap("172.16.0.1/24", "172.16.0.1/23", t)
105
-	//netY starts before and ends at same IP of netX
106
-	AssertOverlap("172.16.1.1/24", "172.16.0.1/23", t)
107
-	//netY starts before and ends outside of netX
108
-	AssertOverlap("172.16.1.1/24", "172.16.0.1/22", t)
109
-	//netY starts and ends before netX
110
-	AssertNoOverlap("172.16.1.1/25", "172.16.0.1/24", t)
111
-	//netX starts and ends before netY
112
-	AssertNoOverlap("172.16.1.1/25", "172.16.2.1/24", t)
113
-}
114
-
115
-func TestNetworkRange(t *testing.T) {
116
-	// Simple class C test
117
-	_, network, _ := net.ParseCIDR("192.168.0.1/24")
118
-	first, last := NetworkRange(network)
119
-	if !first.Equal(net.ParseIP("192.168.0.0")) {
120
-		t.Error(first.String())
121
-	}
122
-	if !last.Equal(net.ParseIP("192.168.0.255")) {
123
-		t.Error(last.String())
124
-	}
125
-	if size := NetworkSize(network.Mask); size != 256 {
126
-		t.Error(size)
127
-	}
128
-
129
-	// Class A test
130
-	_, network, _ = net.ParseCIDR("10.0.0.1/8")
131
-	first, last = NetworkRange(network)
132
-	if !first.Equal(net.ParseIP("10.0.0.0")) {
133
-		t.Error(first.String())
134
-	}
135
-	if !last.Equal(net.ParseIP("10.255.255.255")) {
136
-		t.Error(last.String())
137
-	}
138
-	if size := NetworkSize(network.Mask); size != 16777216 {
139
-		t.Error(size)
140
-	}
141
-
142
-	// Class A, random IP address
143
-	_, network, _ = net.ParseCIDR("10.1.2.3/8")
144
-	first, last = NetworkRange(network)
145
-	if !first.Equal(net.ParseIP("10.0.0.0")) {
146
-		t.Error(first.String())
147
-	}
148
-	if !last.Equal(net.ParseIP("10.255.255.255")) {
149
-		t.Error(last.String())
150
-	}
151
-
152
-	// 32bit mask
153
-	_, network, _ = net.ParseCIDR("10.1.2.3/32")
154
-	first, last = NetworkRange(network)
155
-	if !first.Equal(net.ParseIP("10.1.2.3")) {
156
-		t.Error(first.String())
157
-	}
158
-	if !last.Equal(net.ParseIP("10.1.2.3")) {
159
-		t.Error(last.String())
160
-	}
161
-	if size := NetworkSize(network.Mask); size != 1 {
162
-		t.Error(size)
163
-	}
164
-
165
-	// 31bit mask
166
-	_, network, _ = net.ParseCIDR("10.1.2.3/31")
167
-	first, last = NetworkRange(network)
168
-	if !first.Equal(net.ParseIP("10.1.2.2")) {
169
-		t.Error(first.String())
170
-	}
171
-	if !last.Equal(net.ParseIP("10.1.2.3")) {
172
-		t.Error(last.String())
173
-	}
174
-	if size := NetworkSize(network.Mask); size != 2 {
175
-		t.Error(size)
176
-	}
177
-
178
-	// 26bit mask
179
-	_, network, _ = net.ParseCIDR("10.1.2.3/26")
180
-	first, last = NetworkRange(network)
181
-	if !first.Equal(net.ParseIP("10.1.2.0")) {
182
-		t.Error(first.String())
183
-	}
184
-	if !last.Equal(net.ParseIP("10.1.2.63")) {
185
-		t.Error(last.String())
186
-	}
187
-	if size := NetworkSize(network.Mask); size != 64 {
188
-		t.Error(size)
189
-	}
190
-}
191 1
deleted file mode 100644
... ...
@@ -1,165 +0,0 @@
1
-package portallocator
2
-
3
-import (
4
-	"errors"
5
-	"github.com/dotcloud/docker/pkg/collections"
6
-	"net"
7
-	"sync"
8
-)
9
-
10
-const (
11
-	BeginPortRange = 49153
12
-	EndPortRange   = 65535
13
-)
14
-
15
-type (
16
-	portMappings map[string]*collections.OrderedIntSet
17
-	ipMapping    map[string]portMappings
18
-)
19
-
20
-var (
21
-	ErrPortAlreadyAllocated = errors.New("port has already been allocated")
22
-	ErrPortExceedsRange     = errors.New("port exceeds upper range")
23
-	ErrUnknownProtocol      = errors.New("unknown protocol")
24
-)
25
-
26
-var (
27
-	currentDynamicPort = map[string]int{
28
-		"tcp": BeginPortRange - 1,
29
-		"udp": BeginPortRange - 1,
30
-	}
31
-	defaultIP             = net.ParseIP("0.0.0.0")
32
-	defaultAllocatedPorts = portMappings{}
33
-	otherAllocatedPorts   = ipMapping{}
34
-	lock                  = sync.Mutex{}
35
-)
36
-
37
-func init() {
38
-	defaultAllocatedPorts["tcp"] = collections.NewOrderedIntSet()
39
-	defaultAllocatedPorts["udp"] = collections.NewOrderedIntSet()
40
-}
41
-
42
-// RequestPort returns an available port if the port is 0
43
-// If the provided port is not 0 then it will be checked if
44
-// it is available for allocation
45
-func RequestPort(ip net.IP, proto string, port int) (int, error) {
46
-	lock.Lock()
47
-	defer lock.Unlock()
48
-
49
-	if err := validateProtocol(proto); err != nil {
50
-		return 0, err
51
-	}
52
-
53
-	// If the user requested a specific port to be allocated
54
-	if port > 0 {
55
-		if err := registerSetPort(ip, proto, port); err != nil {
56
-			return 0, err
57
-		}
58
-		return port, nil
59
-	}
60
-	return registerDynamicPort(ip, proto)
61
-}
62
-
63
-// ReleasePort will return the provided port back into the
64
-// pool for reuse
65
-func ReleasePort(ip net.IP, proto string, port int) error {
66
-	lock.Lock()
67
-	defer lock.Unlock()
68
-
69
-	if err := validateProtocol(proto); err != nil {
70
-		return err
71
-	}
72
-
73
-	allocated := defaultAllocatedPorts[proto]
74
-	allocated.Remove(port)
75
-
76
-	if !equalsDefault(ip) {
77
-		registerIP(ip)
78
-
79
-		// Remove the port for the specific ip address
80
-		allocated = otherAllocatedPorts[ip.String()][proto]
81
-		allocated.Remove(port)
82
-	}
83
-	return nil
84
-}
85
-
86
-func ReleaseAll() error {
87
-	lock.Lock()
88
-	defer lock.Unlock()
89
-
90
-	currentDynamicPort["tcp"] = BeginPortRange - 1
91
-	currentDynamicPort["udp"] = BeginPortRange - 1
92
-
93
-	defaultAllocatedPorts = portMappings{}
94
-	defaultAllocatedPorts["tcp"] = collections.NewOrderedIntSet()
95
-	defaultAllocatedPorts["udp"] = collections.NewOrderedIntSet()
96
-
97
-	otherAllocatedPorts = ipMapping{}
98
-
99
-	return nil
100
-}
101
-
102
-func registerDynamicPort(ip net.IP, proto string) (int, error) {
103
-	allocated := defaultAllocatedPorts[proto]
104
-
105
-	port := nextPort(proto)
106
-	if port > EndPortRange {
107
-		return 0, ErrPortExceedsRange
108
-	}
109
-
110
-	if !equalsDefault(ip) {
111
-		registerIP(ip)
112
-
113
-		ipAllocated := otherAllocatedPorts[ip.String()][proto]
114
-		ipAllocated.Push(port)
115
-	} else {
116
-		allocated.Push(port)
117
-	}
118
-	return port, nil
119
-}
120
-
121
-func registerSetPort(ip net.IP, proto string, port int) error {
122
-	allocated := defaultAllocatedPorts[proto]
123
-	if allocated.Exists(port) {
124
-		return ErrPortAlreadyAllocated
125
-	}
126
-
127
-	if !equalsDefault(ip) {
128
-		registerIP(ip)
129
-
130
-		ipAllocated := otherAllocatedPorts[ip.String()][proto]
131
-		if ipAllocated.Exists(port) {
132
-			return ErrPortAlreadyAllocated
133
-		}
134
-		ipAllocated.Push(port)
135
-	} else {
136
-		allocated.Push(port)
137
-	}
138
-	return nil
139
-}
140
-
141
-func equalsDefault(ip net.IP) bool {
142
-	return ip == nil || ip.Equal(defaultIP)
143
-}
144
-
145
-func nextPort(proto string) int {
146
-	c := currentDynamicPort[proto] + 1
147
-	currentDynamicPort[proto] = c
148
-	return c
149
-}
150
-
151
-func registerIP(ip net.IP) {
152
-	if _, exists := otherAllocatedPorts[ip.String()]; !exists {
153
-		otherAllocatedPorts[ip.String()] = portMappings{
154
-			"tcp": collections.NewOrderedIntSet(),
155
-			"udp": collections.NewOrderedIntSet(),
156
-		}
157
-	}
158
-}
159
-
160
-func validateProtocol(proto string) error {
161
-	if _, exists := defaultAllocatedPorts[proto]; !exists {
162
-		return ErrUnknownProtocol
163
-	}
164
-	return nil
165
-}
166 1
deleted file mode 100644
... ...
@@ -1,184 +0,0 @@
1
-package portallocator
2
-
3
-import (
4
-	"net"
5
-	"testing"
6
-)
7
-
8
-func reset() {
9
-	ReleaseAll()
10
-}
11
-
12
-func TestRequestNewPort(t *testing.T) {
13
-	defer reset()
14
-
15
-	port, err := RequestPort(defaultIP, "tcp", 0)
16
-	if err != nil {
17
-		t.Fatal(err)
18
-	}
19
-
20
-	if expected := BeginPortRange; port != expected {
21
-		t.Fatalf("Expected port %d got %d", expected, port)
22
-	}
23
-}
24
-
25
-func TestRequestSpecificPort(t *testing.T) {
26
-	defer reset()
27
-
28
-	port, err := RequestPort(defaultIP, "tcp", 5000)
29
-	if err != nil {
30
-		t.Fatal(err)
31
-	}
32
-	if port != 5000 {
33
-		t.Fatalf("Expected port 5000 got %d", port)
34
-	}
35
-}
36
-
37
-func TestReleasePort(t *testing.T) {
38
-	defer reset()
39
-
40
-	port, err := RequestPort(defaultIP, "tcp", 5000)
41
-	if err != nil {
42
-		t.Fatal(err)
43
-	}
44
-	if port != 5000 {
45
-		t.Fatalf("Expected port 5000 got %d", port)
46
-	}
47
-
48
-	if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
49
-		t.Fatal(err)
50
-	}
51
-}
52
-
53
-func TestReuseReleasedPort(t *testing.T) {
54
-	defer reset()
55
-
56
-	port, err := RequestPort(defaultIP, "tcp", 5000)
57
-	if err != nil {
58
-		t.Fatal(err)
59
-	}
60
-	if port != 5000 {
61
-		t.Fatalf("Expected port 5000 got %d", port)
62
-	}
63
-
64
-	if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
65
-		t.Fatal(err)
66
-	}
67
-
68
-	port, err = RequestPort(defaultIP, "tcp", 5000)
69
-	if err != nil {
70
-		t.Fatal(err)
71
-	}
72
-}
73
-
74
-func TestReleaseUnreadledPort(t *testing.T) {
75
-	defer reset()
76
-
77
-	port, err := RequestPort(defaultIP, "tcp", 5000)
78
-	if err != nil {
79
-		t.Fatal(err)
80
-	}
81
-	if port != 5000 {
82
-		t.Fatalf("Expected port 5000 got %d", port)
83
-	}
84
-
85
-	port, err = RequestPort(defaultIP, "tcp", 5000)
86
-	if err != ErrPortAlreadyAllocated {
87
-		t.Fatalf("Expected error %s got %s", ErrPortAlreadyAllocated, err)
88
-	}
89
-}
90
-
91
-func TestUnknowProtocol(t *testing.T) {
92
-	defer reset()
93
-
94
-	if _, err := RequestPort(defaultIP, "tcpp", 0); err != ErrUnknownProtocol {
95
-		t.Fatalf("Expected error %s got %s", ErrUnknownProtocol, err)
96
-	}
97
-}
98
-
99
-func TestAllocateAllPorts(t *testing.T) {
100
-	defer reset()
101
-
102
-	for i := 0; i <= EndPortRange-BeginPortRange; i++ {
103
-		port, err := RequestPort(defaultIP, "tcp", 0)
104
-		if err != nil {
105
-			t.Fatal(err)
106
-		}
107
-
108
-		if expected := BeginPortRange + i; port != expected {
109
-			t.Fatalf("Expected port %d got %d", expected, port)
110
-		}
111
-	}
112
-
113
-	if _, err := RequestPort(defaultIP, "tcp", 0); err != ErrPortExceedsRange {
114
-		t.Fatalf("Expected error %s got %s", ErrPortExceedsRange, err)
115
-	}
116
-
117
-	_, err := RequestPort(defaultIP, "udp", 0)
118
-	if err != nil {
119
-		t.Fatal(err)
120
-	}
121
-}
122
-
123
-func BenchmarkAllocatePorts(b *testing.B) {
124
-	defer reset()
125
-
126
-	for i := 0; i < b.N; i++ {
127
-		for i := 0; i <= EndPortRange-BeginPortRange; i++ {
128
-			port, err := RequestPort(defaultIP, "tcp", 0)
129
-			if err != nil {
130
-				b.Fatal(err)
131
-			}
132
-
133
-			if expected := BeginPortRange + i; port != expected {
134
-				b.Fatalf("Expected port %d got %d", expected, port)
135
-			}
136
-		}
137
-		reset()
138
-	}
139
-}
140
-
141
-func TestPortAllocation(t *testing.T) {
142
-	defer reset()
143
-
144
-	ip := net.ParseIP("192.168.0.1")
145
-	ip2 := net.ParseIP("192.168.0.2")
146
-	if port, err := RequestPort(ip, "tcp", 80); err != nil {
147
-		t.Fatal(err)
148
-	} else if port != 80 {
149
-		t.Fatalf("Acquire(80) should return 80, not %d", port)
150
-	}
151
-	port, err := RequestPort(ip, "tcp", 0)
152
-	if err != nil {
153
-		t.Fatal(err)
154
-	}
155
-	if port <= 0 {
156
-		t.Fatalf("Acquire(0) should return a non-zero port")
157
-	}
158
-
159
-	if _, err := RequestPort(ip, "tcp", port); err == nil {
160
-		t.Fatalf("Acquiring a port already in use should return an error")
161
-	}
162
-
163
-	if newPort, err := RequestPort(ip, "tcp", 0); err != nil {
164
-		t.Fatal(err)
165
-	} else if newPort == port {
166
-		t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
167
-	}
168
-
169
-	if _, err := RequestPort(ip, "tcp", 80); err == nil {
170
-		t.Fatalf("Acquiring a port already in use should return an error")
171
-	}
172
-	if _, err := RequestPort(ip2, "tcp", 80); err != nil {
173
-		t.Fatalf("It should be possible to allocate the same port on a different interface")
174
-	}
175
-	if _, err := RequestPort(ip2, "tcp", 80); err == nil {
176
-		t.Fatalf("Acquiring a port already in use should return an error")
177
-	}
178
-	if err := ReleasePort(ip, "tcp", 80); err != nil {
179
-		t.Fatal(err)
180
-	}
181
-	if _, err := RequestPort(ip, "tcp", 80); err != nil {
182
-		t.Fatal(err)
183
-	}
184
-}
185 1
deleted file mode 100644
... ...
@@ -1,131 +0,0 @@
1
-package portmapper
2
-
3
-import (
4
-	"errors"
5
-	"fmt"
6
-	"github.com/dotcloud/docker/pkg/iptables"
7
-	"github.com/dotcloud/docker/pkg/proxy"
8
-	"net"
9
-	"sync"
10
-)
11
-
12
-type mapping struct {
13
-	proto         string
14
-	userlandProxy proxy.Proxy
15
-	host          net.Addr
16
-	container     net.Addr
17
-}
18
-
19
-var (
20
-	chain *iptables.Chain
21
-	lock  sync.Mutex
22
-
23
-	// udp:ip:port
24
-	currentMappings = make(map[string]*mapping)
25
-	newProxy        = proxy.NewProxy
26
-)
27
-
28
-var (
29
-	ErrUnknownBackendAddressType = errors.New("unknown container address type not supported")
30
-	ErrPortMappedForIP           = errors.New("port is already mapped to ip")
31
-	ErrPortNotMapped             = errors.New("port is not mapped")
32
-)
33
-
34
-func SetIptablesChain(c *iptables.Chain) {
35
-	chain = c
36
-}
37
-
38
-func Map(container net.Addr, hostIP net.IP, hostPort int) error {
39
-	lock.Lock()
40
-	defer lock.Unlock()
41
-
42
-	var m *mapping
43
-	switch container.(type) {
44
-	case *net.TCPAddr:
45
-		m = &mapping{
46
-			proto:     "tcp",
47
-			host:      &net.TCPAddr{IP: hostIP, Port: hostPort},
48
-			container: container,
49
-		}
50
-	case *net.UDPAddr:
51
-		m = &mapping{
52
-			proto:     "udp",
53
-			host:      &net.UDPAddr{IP: hostIP, Port: hostPort},
54
-			container: container,
55
-		}
56
-	default:
57
-		return ErrUnknownBackendAddressType
58
-	}
59
-
60
-	key := getKey(m.host)
61
-	if _, exists := currentMappings[key]; exists {
62
-		return ErrPortMappedForIP
63
-	}
64
-
65
-	containerIP, containerPort := getIPAndPort(m.container)
66
-	if err := forward(iptables.Add, m.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
67
-		return err
68
-	}
69
-
70
-	p, err := newProxy(m.host, m.container)
71
-	if err != nil {
72
-		// need to undo the iptables rules before we reutrn
73
-		forward(iptables.Delete, m.proto, hostIP, hostPort, containerIP.String(), containerPort)
74
-		return err
75
-	}
76
-
77
-	m.userlandProxy = p
78
-	currentMappings[key] = m
79
-
80
-	go p.Run()
81
-
82
-	return nil
83
-}
84
-
85
-func Unmap(host net.Addr) error {
86
-	lock.Lock()
87
-	defer lock.Unlock()
88
-
89
-	key := getKey(host)
90
-	data, exists := currentMappings[key]
91
-	if !exists {
92
-		return ErrPortNotMapped
93
-	}
94
-
95
-	data.userlandProxy.Close()
96
-	delete(currentMappings, key)
97
-
98
-	containerIP, containerPort := getIPAndPort(data.container)
99
-	hostIP, hostPort := getIPAndPort(data.host)
100
-	if err := forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
101
-		return err
102
-	}
103
-	return nil
104
-}
105
-
106
-func getKey(a net.Addr) string {
107
-	switch t := a.(type) {
108
-	case *net.TCPAddr:
109
-		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "tcp")
110
-	case *net.UDPAddr:
111
-		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "udp")
112
-	}
113
-	return ""
114
-}
115
-
116
-func getIPAndPort(a net.Addr) (net.IP, int) {
117
-	switch t := a.(type) {
118
-	case *net.TCPAddr:
119
-		return t.IP, t.Port
120
-	case *net.UDPAddr:
121
-		return t.IP, t.Port
122
-	}
123
-	return nil, 0
124
-}
125
-
126
-func forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
127
-	if chain == nil {
128
-		return nil
129
-	}
130
-	return chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort)
131
-}
132 1
deleted file mode 100644
... ...
@@ -1,107 +0,0 @@
1
-package portmapper
2
-
3
-import (
4
-	"github.com/dotcloud/docker/pkg/iptables"
5
-	"github.com/dotcloud/docker/pkg/proxy"
6
-	"net"
7
-	"testing"
8
-)
9
-
10
-func init() {
11
-	// override this func to mock out the proxy server
12
-	newProxy = proxy.NewStubProxy
13
-}
14
-
15
-func reset() {
16
-	chain = nil
17
-	currentMappings = make(map[string]*mapping)
18
-}
19
-
20
-func TestSetIptablesChain(t *testing.T) {
21
-	defer reset()
22
-
23
-	c := &iptables.Chain{
24
-		Name:   "TEST",
25
-		Bridge: "192.168.1.1",
26
-	}
27
-
28
-	if chain != nil {
29
-		t.Fatal("chain should be nil at init")
30
-	}
31
-
32
-	SetIptablesChain(c)
33
-	if chain == nil {
34
-		t.Fatal("chain should not be nil after set")
35
-	}
36
-}
37
-
38
-func TestMapPorts(t *testing.T) {
39
-	dstIp1 := net.ParseIP("192.168.0.1")
40
-	dstIp2 := net.ParseIP("192.168.0.2")
41
-	dstAddr1 := &net.TCPAddr{IP: dstIp1, Port: 80}
42
-	dstAddr2 := &net.TCPAddr{IP: dstIp2, Port: 80}
43
-
44
-	srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
45
-	srcAddr2 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.2")}
46
-
47
-	if err := Map(srcAddr1, dstIp1, 80); err != nil {
48
-		t.Fatalf("Failed to allocate port: %s", err)
49
-	}
50
-
51
-	if Map(srcAddr1, dstIp1, 80) == nil {
52
-		t.Fatalf("Port is in use - mapping should have failed")
53
-	}
54
-
55
-	if Map(srcAddr2, dstIp1, 80) == nil {
56
-		t.Fatalf("Port is in use - mapping should have failed")
57
-	}
58
-
59
-	if err := Map(srcAddr2, dstIp2, 80); err != nil {
60
-		t.Fatalf("Failed to allocate port: %s", err)
61
-	}
62
-
63
-	if Unmap(dstAddr1) != nil {
64
-		t.Fatalf("Failed to release port")
65
-	}
66
-
67
-	if Unmap(dstAddr2) != nil {
68
-		t.Fatalf("Failed to release port")
69
-	}
70
-
71
-	if Unmap(dstAddr2) == nil {
72
-		t.Fatalf("Port already released, but no error reported")
73
-	}
74
-}
75
-
76
-func TestGetUDPKey(t *testing.T) {
77
-	addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}
78
-
79
-	key := getKey(addr)
80
-
81
-	if expected := "192.168.1.5:53/udp"; key != expected {
82
-		t.Fatalf("expected key %s got %s", expected, key)
83
-	}
84
-}
85
-
86
-func TestGetTCPKey(t *testing.T) {
87
-	addr := &net.TCPAddr{IP: net.ParseIP("192.168.1.5"), Port: 80}
88
-
89
-	key := getKey(addr)
90
-
91
-	if expected := "192.168.1.5:80/tcp"; key != expected {
92
-		t.Fatalf("expected key %s got %s", expected, key)
93
-	}
94
-}
95
-
96
-func TestGetUDPIPAndPort(t *testing.T) {
97
-	addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}
98
-
99
-	ip, port := getIPAndPort(addr)
100
-	if expected := "192.168.1.5"; ip.String() != expected {
101
-		t.Fatalf("expected ip %s got %s", expected, ip)
102
-	}
103
-
104
-	if ep := 53; port != ep {
105
-		t.Fatalf("expected port %d got %d", ep, port)
106
-	}
107
-}
108 1
deleted file mode 100644
... ...
@@ -1,118 +0,0 @@
1
-package networkdriver
2
-
3
-import (
4
-	"encoding/binary"
5
-	"errors"
6
-	"fmt"
7
-	"net"
8
-
9
-	"github.com/dotcloud/docker/pkg/netlink"
10
-)
11
-
12
-var (
13
-	networkGetRoutesFct = netlink.NetworkGetRoutes
14
-	ErrNoDefaultRoute   = errors.New("no default route")
15
-)
16
-
17
-func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
18
-	if len(nameservers) > 0 {
19
-		for _, ns := range nameservers {
20
-			_, nsNetwork, err := net.ParseCIDR(ns)
21
-			if err != nil {
22
-				return err
23
-			}
24
-			if NetworkOverlaps(toCheck, nsNetwork) {
25
-				return ErrNetworkOverlapsWithNameservers
26
-			}
27
-		}
28
-	}
29
-	return nil
30
-}
31
-
32
-func CheckRouteOverlaps(toCheck *net.IPNet) error {
33
-	networks, err := networkGetRoutesFct()
34
-	if err != nil {
35
-		return err
36
-	}
37
-
38
-	for _, network := range networks {
39
-		if network.IPNet != nil && NetworkOverlaps(toCheck, network.IPNet) {
40
-			return ErrNetworkOverlaps
41
-		}
42
-	}
43
-	return nil
44
-}
45
-
46
-// Detects overlap between one IPNet and another
47
-func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
48
-	if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) {
49
-		return true
50
-	}
51
-	if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) {
52
-		return true
53
-	}
54
-	return false
55
-}
56
-
57
-// Calculates the first and last IP addresses in an IPNet
58
-func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
59
-	var (
60
-		netIP   = network.IP.To4()
61
-		firstIP = netIP.Mask(network.Mask)
62
-		lastIP  = net.IPv4(0, 0, 0, 0).To4()
63
-	)
64
-
65
-	for i := 0; i < len(lastIP); i++ {
66
-		lastIP[i] = netIP[i] | ^network.Mask[i]
67
-	}
68
-	return firstIP, lastIP
69
-}
70
-
71
-// Given a netmask, calculates the number of available hosts
72
-func NetworkSize(mask net.IPMask) int32 {
73
-	m := net.IPv4Mask(0, 0, 0, 0)
74
-	for i := 0; i < net.IPv4len; i++ {
75
-		m[i] = ^mask[i]
76
-	}
77
-	return int32(binary.BigEndian.Uint32(m)) + 1
78
-}
79
-
80
-// Return the IPv4 address of a network interface
81
-func GetIfaceAddr(name string) (net.Addr, error) {
82
-	iface, err := net.InterfaceByName(name)
83
-	if err != nil {
84
-		return nil, err
85
-	}
86
-	addrs, err := iface.Addrs()
87
-	if err != nil {
88
-		return nil, err
89
-	}
90
-	var addrs4 []net.Addr
91
-	for _, addr := range addrs {
92
-		ip := (addr.(*net.IPNet)).IP
93
-		if ip4 := ip.To4(); len(ip4) == net.IPv4len {
94
-			addrs4 = append(addrs4, addr)
95
-		}
96
-	}
97
-	switch {
98
-	case len(addrs4) == 0:
99
-		return nil, fmt.Errorf("Interface %v has no IP addresses", name)
100
-	case len(addrs4) > 1:
101
-		fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
102
-			name, (addrs4[0].(*net.IPNet)).IP)
103
-	}
104
-	return addrs4[0], nil
105
-}
106
-
107
-func GetDefaultRouteIface() (*net.Interface, error) {
108
-	rs, err := networkGetRoutesFct()
109
-	if err != nil {
110
-		return nil, fmt.Errorf("unable to get routes: %v", err)
111
-	}
112
-	for _, r := range rs {
113
-		if r.Default {
114
-			return r.Iface, nil
115
-		}
116
-	}
117
-	return nil, ErrNoDefaultRoute
118
-}
119 1
new file mode 100644
... ...
@@ -0,0 +1,159 @@
0
+package ipallocator
1
+
2
+import (
3
+	"encoding/binary"
4
+	"errors"
5
+	"github.com/dotcloud/docker/runtime/networkdriver"
6
+	"github.com/dotcloud/docker/pkg/collections"
7
+	"net"
8
+	"sync"
9
+)
10
+
11
+type networkSet map[string]*collections.OrderedIntSet
12
+
13
+var (
14
+	ErrNoAvailableIPs     = errors.New("no available ip addresses on network")
15
+	ErrIPAlreadyAllocated = errors.New("ip already allocated")
16
+)
17
+
18
+var (
19
+	lock         = sync.Mutex{}
20
+	allocatedIPs = networkSet{}
21
+	availableIPS = networkSet{}
22
+)
23
+
24
+// RequestIP requests an available ip from the given network.  It
25
+// will return the next available ip if the ip provided is nil.  If the
26
+// ip provided is not nil it will validate that the provided ip is available
27
+// for use or return an error
28
+func RequestIP(address *net.IPNet, ip *net.IP) (*net.IP, error) {
29
+	lock.Lock()
30
+	defer lock.Unlock()
31
+
32
+	checkAddress(address)
33
+
34
+	if ip == nil {
35
+		next, err := getNextIp(address)
36
+		if err != nil {
37
+			return nil, err
38
+		}
39
+		return next, nil
40
+	}
41
+
42
+	if err := registerIP(address, ip); err != nil {
43
+		return nil, err
44
+	}
45
+	return ip, nil
46
+}
47
+
48
+// ReleaseIP adds the provided ip back into the pool of
49
+// available ips to be returned for use.
50
+func ReleaseIP(address *net.IPNet, ip *net.IP) error {
51
+	lock.Lock()
52
+	defer lock.Unlock()
53
+
54
+	checkAddress(address)
55
+
56
+	var (
57
+		existing  = allocatedIPs[address.String()]
58
+		available = availableIPS[address.String()]
59
+		pos       = getPosition(address, ip)
60
+	)
61
+
62
+	existing.Remove(int(pos))
63
+	available.Push(int(pos))
64
+
65
+	return nil
66
+}
67
+
68
+// convert the ip into the position in the subnet.  Only
69
+// position are saved in the set
70
+func getPosition(address *net.IPNet, ip *net.IP) int32 {
71
+	var (
72
+		first, _ = networkdriver.NetworkRange(address)
73
+		base     = ipToInt(&first)
74
+		i        = ipToInt(ip)
75
+	)
76
+	return i - base
77
+}
78
+
79
+// return an available ip if one is currently available.  If not,
80
+// return the next available ip for the nextwork
81
+func getNextIp(address *net.IPNet) (*net.IP, error) {
82
+	var (
83
+		ownIP     = ipToInt(&address.IP)
84
+		available = availableIPS[address.String()]
85
+		allocated = allocatedIPs[address.String()]
86
+		first, _  = networkdriver.NetworkRange(address)
87
+		base      = ipToInt(&first)
88
+		size      = int(networkdriver.NetworkSize(address.Mask))
89
+		max       = int32(size - 2) // size -1 for the broadcast address, -1 for the gateway address
90
+		pos       = int32(available.Pop())
91
+	)
92
+
93
+	// We pop and push the position not the ip
94
+	if pos != 0 {
95
+		ip := intToIP(int32(base + pos))
96
+		allocated.Push(int(pos))
97
+
98
+		return ip, nil
99
+	}
100
+
101
+	var (
102
+		firstNetIP = address.IP.To4().Mask(address.Mask)
103
+		firstAsInt = ipToInt(&firstNetIP) + 1
104
+	)
105
+
106
+	pos = int32(allocated.PullBack())
107
+	for i := int32(0); i < max; i++ {
108
+		pos = pos%max + 1
109
+		next := int32(base + pos)
110
+
111
+		if next == ownIP || next == firstAsInt {
112
+			continue
113
+		}
114
+
115
+		if !allocated.Exists(int(pos)) {
116
+			ip := intToIP(next)
117
+			allocated.Push(int(pos))
118
+			return ip, nil
119
+		}
120
+	}
121
+	return nil, ErrNoAvailableIPs
122
+}
123
+
124
+func registerIP(address *net.IPNet, ip *net.IP) error {
125
+	var (
126
+		existing  = allocatedIPs[address.String()]
127
+		available = availableIPS[address.String()]
128
+		pos       = getPosition(address, ip)
129
+	)
130
+
131
+	if existing.Exists(int(pos)) {
132
+		return ErrIPAlreadyAllocated
133
+	}
134
+	available.Remove(int(pos))
135
+
136
+	return nil
137
+}
138
+
139
+// Converts a 4 bytes IP into a 32 bit integer
140
+func ipToInt(ip *net.IP) int32 {
141
+	return int32(binary.BigEndian.Uint32(ip.To4()))
142
+}
143
+
144
+// Converts 32 bit integer into a 4 bytes IP address
145
+func intToIP(n int32) *net.IP {
146
+	b := make([]byte, 4)
147
+	binary.BigEndian.PutUint32(b, uint32(n))
148
+	ip := net.IP(b)
149
+	return &ip
150
+}
151
+
152
+func checkAddress(address *net.IPNet) {
153
+	key := address.String()
154
+	if _, exists := allocatedIPs[key]; !exists {
155
+		allocatedIPs[key] = collections.NewOrderedIntSet()
156
+		availableIPS[key] = collections.NewOrderedIntSet()
157
+	}
158
+}
0 159
new file mode 100644
... ...
@@ -0,0 +1,241 @@
0
+package ipallocator
1
+
2
+import (
3
+	"fmt"
4
+	"net"
5
+	"testing"
6
+)
7
+
8
+func reset() {
9
+	allocatedIPs = networkSet{}
10
+	availableIPS = networkSet{}
11
+}
12
+
13
+func TestRequestNewIps(t *testing.T) {
14
+	defer reset()
15
+	network := &net.IPNet{
16
+		IP:   []byte{192, 168, 0, 1},
17
+		Mask: []byte{255, 255, 255, 0},
18
+	}
19
+
20
+	for i := 2; i < 10; i++ {
21
+		ip, err := RequestIP(network, nil)
22
+		if err != nil {
23
+			t.Fatal(err)
24
+		}
25
+
26
+		if expected := fmt.Sprintf("192.168.0.%d", i); ip.String() != expected {
27
+			t.Fatalf("Expected ip %s got %s", expected, ip.String())
28
+		}
29
+	}
30
+}
31
+
32
+func TestReleaseIp(t *testing.T) {
33
+	defer reset()
34
+	network := &net.IPNet{
35
+		IP:   []byte{192, 168, 0, 1},
36
+		Mask: []byte{255, 255, 255, 0},
37
+	}
38
+
39
+	ip, err := RequestIP(network, nil)
40
+	if err != nil {
41
+		t.Fatal(err)
42
+	}
43
+
44
+	if err := ReleaseIP(network, ip); err != nil {
45
+		t.Fatal(err)
46
+	}
47
+}
48
+
49
+func TestGetReleasedIp(t *testing.T) {
50
+	defer reset()
51
+	network := &net.IPNet{
52
+		IP:   []byte{192, 168, 0, 1},
53
+		Mask: []byte{255, 255, 255, 0},
54
+	}
55
+
56
+	ip, err := RequestIP(network, nil)
57
+	if err != nil {
58
+		t.Fatal(err)
59
+	}
60
+
61
+	value := ip.String()
62
+	if err := ReleaseIP(network, ip); err != nil {
63
+		t.Fatal(err)
64
+	}
65
+
66
+	ip, err = RequestIP(network, nil)
67
+	if err != nil {
68
+		t.Fatal(err)
69
+	}
70
+
71
+	if ip.String() != value {
72
+		t.Fatalf("Expected to receive same ip %s got %s", value, ip.String())
73
+	}
74
+}
75
+
76
+func TestRequesetSpecificIp(t *testing.T) {
77
+	defer reset()
78
+	network := &net.IPNet{
79
+		IP:   []byte{192, 168, 0, 1},
80
+		Mask: []byte{255, 255, 255, 0},
81
+	}
82
+
83
+	ip := net.ParseIP("192.168.1.5")
84
+
85
+	if _, err := RequestIP(network, &ip); err != nil {
86
+		t.Fatal(err)
87
+	}
88
+}
89
+
90
+func TestConversion(t *testing.T) {
91
+	ip := net.ParseIP("127.0.0.1")
92
+	i := ipToInt(&ip)
93
+	if i == 0 {
94
+		t.Fatal("converted to zero")
95
+	}
96
+	conv := intToIP(i)
97
+	if !ip.Equal(*conv) {
98
+		t.Error(conv.String())
99
+	}
100
+}
101
+
102
+func TestIPAllocator(t *testing.T) {
103
+	expectedIPs := []net.IP{
104
+		0: net.IPv4(127, 0, 0, 2),
105
+		1: net.IPv4(127, 0, 0, 3),
106
+		2: net.IPv4(127, 0, 0, 4),
107
+		3: net.IPv4(127, 0, 0, 5),
108
+		4: net.IPv4(127, 0, 0, 6),
109
+	}
110
+
111
+	gwIP, n, _ := net.ParseCIDR("127.0.0.1/29")
112
+	network := &net.IPNet{IP: gwIP, Mask: n.Mask}
113
+	// Pool after initialisation (f = free, u = used)
114
+	// 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
115
+	//  ↑
116
+
117
+	// Check that we get 5 IPs, from 127.0.0.2–127.0.0.6, in that
118
+	// order.
119
+	for i := 0; i < 5; i++ {
120
+		ip, err := RequestIP(network, nil)
121
+		if err != nil {
122
+			t.Fatal(err)
123
+		}
124
+
125
+		assertIPEquals(t, &expectedIPs[i], ip)
126
+	}
127
+	// Before loop begin
128
+	// 2(f) - 3(f) - 4(f) - 5(f) - 6(f)
129
+	//  ↑
130
+
131
+	// After i = 0
132
+	// 2(u) - 3(f) - 4(f) - 5(f) - 6(f)
133
+	//         ↑
134
+
135
+	// After i = 1
136
+	// 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
137
+	//                ↑
138
+
139
+	// After i = 2
140
+	// 2(u) - 3(u) - 4(u) - 5(f) - 6(f)
141
+	//                       ↑
142
+
143
+	// After i = 3
144
+	// 2(u) - 3(u) - 4(u) - 5(u) - 6(f)
145
+	//                              ↑
146
+
147
+	// After i = 4
148
+	// 2(u) - 3(u) - 4(u) - 5(u) - 6(u)
149
+	//  ↑
150
+
151
+	// Check that there are no more IPs
152
+	ip, err := RequestIP(network, nil)
153
+	if err == nil {
154
+		t.Fatalf("There shouldn't be any IP addresses at this point, got %s\n", ip)
155
+	}
156
+
157
+	// Release some IPs in non-sequential order
158
+	if err := ReleaseIP(network, &expectedIPs[3]); err != nil {
159
+		t.Fatal(err)
160
+	}
161
+	// 2(u) - 3(u) - 4(u) - 5(f) - 6(u)
162
+	//                       ↑
163
+
164
+	if err := ReleaseIP(network, &expectedIPs[2]); err != nil {
165
+		t.Fatal(err)
166
+	}
167
+	// 2(u) - 3(u) - 4(f) - 5(f) - 6(u)
168
+	//                       ↑
169
+
170
+	if err := ReleaseIP(network, &expectedIPs[4]); err != nil {
171
+		t.Fatal(err)
172
+	}
173
+	// 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
174
+	//                       ↑
175
+
176
+	// Make sure that IPs are reused in sequential order, starting
177
+	// with the first released IP
178
+	newIPs := make([]*net.IP, 3)
179
+	for i := 0; i < 3; i++ {
180
+		ip, err := RequestIP(network, nil)
181
+		if err != nil {
182
+			t.Fatal(err)
183
+		}
184
+
185
+		newIPs[i] = ip
186
+	}
187
+	// Before loop begin
188
+	// 2(u) - 3(u) - 4(f) - 5(f) - 6(f)
189
+	//                       ↑
190
+
191
+	// After i = 0
192
+	// 2(u) - 3(u) - 4(f) - 5(u) - 6(f)
193
+	//                              ↑
194
+
195
+	// After i = 1
196
+	// 2(u) - 3(u) - 4(f) - 5(u) - 6(u)
197
+	//                ↑
198
+
199
+	// After i = 2
200
+	// 2(u) - 3(u) - 4(u) - 5(u) - 6(u)
201
+	//                       ↑
202
+
203
+	// Reordered these because the new set will always return the
204
+	// lowest ips first and not in the order that they were released
205
+	assertIPEquals(t, &expectedIPs[2], newIPs[0])
206
+	assertIPEquals(t, &expectedIPs[3], newIPs[1])
207
+	assertIPEquals(t, &expectedIPs[4], newIPs[2])
208
+
209
+	_, err = RequestIP(network, nil)
210
+	if err == nil {
211
+		t.Fatal("There shouldn't be any IP addresses at this point")
212
+	}
213
+}
214
+
215
+func TestAllocateFirstIP(t *testing.T) {
216
+	defer reset()
217
+	network := &net.IPNet{
218
+		IP:   []byte{192, 168, 0, 0},
219
+		Mask: []byte{255, 255, 255, 0},
220
+	}
221
+
222
+	firstIP := network.IP.To4().Mask(network.Mask)
223
+	first := ipToInt(&firstIP) + 1
224
+
225
+	ip, err := RequestIP(network, nil)
226
+	if err != nil {
227
+		t.Fatal(err)
228
+	}
229
+	allocated := ipToInt(ip)
230
+
231
+	if allocated == first {
232
+		t.Fatalf("allocated ip should not equal first ip: %d == %d", first, allocated)
233
+	}
234
+}
235
+
236
+func assertIPEquals(t *testing.T, ip1, ip2 *net.IP) {
237
+	if !ip1.Equal(*ip2) {
238
+		t.Fatalf("Expected IP %s, got %s", ip1, ip2)
239
+	}
240
+}
0 241
new file mode 100644
... ...
@@ -0,0 +1,482 @@
0
+package lxc
1
+
2
+import (
3
+	"fmt"
4
+	"github.com/dotcloud/docker/engine"
5
+	"github.com/dotcloud/docker/runtime/networkdriver"
6
+	"github.com/dotcloud/docker/runtime/networkdriver/ipallocator"
7
+	"github.com/dotcloud/docker/runtime/networkdriver/portallocator"
8
+	"github.com/dotcloud/docker/runtime/networkdriver/portmapper"
9
+	"github.com/dotcloud/docker/pkg/iptables"
10
+	"github.com/dotcloud/docker/pkg/netlink"
11
+	"github.com/dotcloud/docker/utils"
12
+	"io/ioutil"
13
+	"log"
14
+	"net"
15
+	"strings"
16
+	"syscall"
17
+	"unsafe"
18
+)
19
+
20
+const (
21
+	DefaultNetworkBridge = "docker0"
22
+	siocBRADDBR          = 0x89a0
23
+)
24
+
25
+// Network interface represents the networking stack of a container
26
+type networkInterface struct {
27
+	IP           net.IP
28
+	PortMappings []net.Addr // there are mappings to the host interfaces
29
+}
30
+
31
+var (
32
+	addrs = []string{
33
+		// Here we don't follow the convention of using the 1st IP of the range for the gateway.
34
+		// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
35
+		// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
36
+		// on the internal addressing or other stupid things like that.
37
+		// The shouldn't, but hey, let's not break them unless we really have to.
38
+		"172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
39
+		"10.0.42.1/16",   // Don't even try using the entire /8, that's too intrusive
40
+		"10.1.42.1/16",
41
+		"10.42.42.1/16",
42
+		"172.16.42.1/24",
43
+		"172.16.43.1/24",
44
+		"172.16.44.1/24",
45
+		"10.0.42.1/24",
46
+		"10.0.43.1/24",
47
+		"192.168.42.1/24",
48
+		"192.168.43.1/24",
49
+		"192.168.44.1/24",
50
+	}
51
+
52
+	bridgeIface   string
53
+	bridgeNetwork *net.IPNet
54
+
55
+	defaultBindingIP  = net.ParseIP("0.0.0.0")
56
+	currentInterfaces = make(map[string]*networkInterface)
57
+)
58
+
59
+func InitDriver(job *engine.Job) engine.Status {
60
+	var (
61
+		network        *net.IPNet
62
+		enableIPTables = job.GetenvBool("EnableIptables")
63
+		icc            = job.GetenvBool("InterContainerCommunication")
64
+		ipForward      = job.GetenvBool("EnableIpForward")
65
+		bridgeIP       = job.Getenv("BridgeIP")
66
+	)
67
+
68
+	if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
69
+		defaultBindingIP = net.ParseIP(defaultIP)
70
+	}
71
+
72
+	bridgeIface = job.Getenv("BridgeIface")
73
+	if bridgeIface == "" {
74
+		bridgeIface = DefaultNetworkBridge
75
+	}
76
+
77
+	addr, err := networkdriver.GetIfaceAddr(bridgeIface)
78
+	if err != nil {
79
+		// If the iface is not found, try to create it
80
+		job.Logf("creating new bridge for %s", bridgeIface)
81
+		if err := createBridge(bridgeIP); err != nil {
82
+			job.Error(err)
83
+			return engine.StatusErr
84
+		}
85
+
86
+		job.Logf("getting iface addr")
87
+		addr, err = networkdriver.GetIfaceAddr(bridgeIface)
88
+		if err != nil {
89
+			job.Error(err)
90
+			return engine.StatusErr
91
+		}
92
+		network = addr.(*net.IPNet)
93
+	} else {
94
+		network = addr.(*net.IPNet)
95
+	}
96
+
97
+	// Configure iptables for link support
98
+	if enableIPTables {
99
+		if err := setupIPTables(addr, icc); err != nil {
100
+			job.Error(err)
101
+			return engine.StatusErr
102
+		}
103
+	}
104
+
105
+	if ipForward {
106
+		// Enable IPv4 forwarding
107
+		if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
108
+			job.Logf("WARNING: unable to enable IPv4 forwarding: %s\n", err)
109
+		}
110
+	}
111
+
112
+	// We can always try removing the iptables
113
+	if err := iptables.RemoveExistingChain("DOCKER"); err != nil {
114
+		job.Error(err)
115
+		return engine.StatusErr
116
+	}
117
+
118
+	if enableIPTables {
119
+		chain, err := iptables.NewChain("DOCKER", bridgeIface)
120
+		if err != nil {
121
+			job.Error(err)
122
+			return engine.StatusErr
123
+		}
124
+		portmapper.SetIptablesChain(chain)
125
+	}
126
+
127
+	bridgeNetwork = network
128
+
129
+	// https://github.com/dotcloud/docker/issues/2768
130
+	job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeNetwork.IP)
131
+
132
+	for name, f := range map[string]engine.Handler{
133
+		"allocate_interface": Allocate,
134
+		"release_interface":  Release,
135
+		"allocate_port":      AllocatePort,
136
+		"link":               LinkContainers,
137
+	} {
138
+		if err := job.Eng.Register(name, f); err != nil {
139
+			job.Error(err)
140
+			return engine.StatusErr
141
+		}
142
+	}
143
+	return engine.StatusOK
144
+}
145
+
146
+func setupIPTables(addr net.Addr, icc bool) error {
147
+	// Enable NAT
148
+	natArgs := []string{"POSTROUTING", "-t", "nat", "-s", addr.String(), "!", "-d", addr.String(), "-j", "MASQUERADE"}
149
+
150
+	if !iptables.Exists(natArgs...) {
151
+		if output, err := iptables.Raw(append([]string{"-I"}, natArgs...)...); err != nil {
152
+			return fmt.Errorf("Unable to enable network bridge NAT: %s", err)
153
+		} else if len(output) != 0 {
154
+			return fmt.Errorf("Error iptables postrouting: %s", output)
155
+		}
156
+	}
157
+
158
+	var (
159
+		args       = []string{"FORWARD", "-i", bridgeIface, "-o", bridgeIface, "-j"}
160
+		acceptArgs = append(args, "ACCEPT")
161
+		dropArgs   = append(args, "DROP")
162
+	)
163
+
164
+	if !icc {
165
+		iptables.Raw(append([]string{"-D"}, acceptArgs...)...)
166
+
167
+		if !iptables.Exists(dropArgs...) {
168
+			utils.Debugf("Disable inter-container communication")
169
+			if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil {
170
+				return fmt.Errorf("Unable to prevent intercontainer communication: %s", err)
171
+			} else if len(output) != 0 {
172
+				return fmt.Errorf("Error disabling intercontainer communication: %s", output)
173
+			}
174
+		}
175
+	} else {
176
+		iptables.Raw(append([]string{"-D"}, dropArgs...)...)
177
+
178
+		if !iptables.Exists(acceptArgs...) {
179
+			utils.Debugf("Enable inter-container communication")
180
+			if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil {
181
+				return fmt.Errorf("Unable to allow intercontainer communication: %s", err)
182
+			} else if len(output) != 0 {
183
+				return fmt.Errorf("Error enabling intercontainer communication: %s", output)
184
+			}
185
+		}
186
+	}
187
+
188
+	// Accept all non-intercontainer outgoing packets
189
+	outgoingArgs := []string{"FORWARD", "-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}
190
+	if !iptables.Exists(outgoingArgs...) {
191
+		if output, err := iptables.Raw(append([]string{"-I"}, outgoingArgs...)...); err != nil {
192
+			return fmt.Errorf("Unable to allow outgoing packets: %s", err)
193
+		} else if len(output) != 0 {
194
+			return fmt.Errorf("Error iptables allow outgoing: %s", output)
195
+		}
196
+	}
197
+
198
+	// Accept incoming packets for existing connections
199
+	existingArgs := []string{"FORWARD", "-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}
200
+
201
+	if !iptables.Exists(existingArgs...) {
202
+		if output, err := iptables.Raw(append([]string{"-I"}, existingArgs...)...); err != nil {
203
+			return fmt.Errorf("Unable to allow incoming packets: %s", err)
204
+		} else if len(output) != 0 {
205
+			return fmt.Errorf("Error iptables allow incoming: %s", output)
206
+		}
207
+	}
208
+	return nil
209
+}
210
+
211
+// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`,
212
+// and attempts to configure it with an address which doesn't conflict with any other interface on the host.
213
+// If it can't find an address which doesn't conflict, it will return an error.
214
+func createBridge(bridgeIP string) error {
215
+	nameservers := []string{}
216
+	resolvConf, _ := utils.GetResolvConf()
217
+	// we don't check for an error here, because we don't really care
218
+	// if we can't read /etc/resolv.conf. So instead we skip the append
219
+	// if resolvConf is nil. It either doesn't exist, or we can't read it
220
+	// for some reason.
221
+	if resolvConf != nil {
222
+		nameservers = append(nameservers, utils.GetNameserversAsCIDR(resolvConf)...)
223
+	}
224
+
225
+	var ifaceAddr string
226
+	if len(bridgeIP) != 0 {
227
+		_, _, err := net.ParseCIDR(bridgeIP)
228
+		if err != nil {
229
+			return err
230
+		}
231
+		ifaceAddr = bridgeIP
232
+	} else {
233
+		for _, addr := range addrs {
234
+			_, dockerNetwork, err := net.ParseCIDR(addr)
235
+			if err != nil {
236
+				return err
237
+			}
238
+			if err := networkdriver.CheckNameserverOverlaps(nameservers, dockerNetwork); err == nil {
239
+				if err := networkdriver.CheckRouteOverlaps(dockerNetwork); err == nil {
240
+					ifaceAddr = addr
241
+					break
242
+				} else {
243
+					utils.Debugf("%s %s", addr, err)
244
+				}
245
+			}
246
+		}
247
+	}
248
+
249
+	if ifaceAddr == "" {
250
+		return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", bridgeIface, bridgeIface)
251
+	}
252
+	utils.Debugf("Creating bridge %s with network %s", bridgeIface, ifaceAddr)
253
+
254
+	if err := createBridgeIface(bridgeIface); err != nil {
255
+		return err
256
+	}
257
+
258
+	iface, err := net.InterfaceByName(bridgeIface)
259
+	if err != nil {
260
+		return err
261
+	}
262
+
263
+	ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr)
264
+	if err != nil {
265
+		return err
266
+	}
267
+
268
+	if netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
269
+		return fmt.Errorf("Unable to add private network: %s", err)
270
+	}
271
+	if err := netlink.NetworkLinkUp(iface); err != nil {
272
+		return fmt.Errorf("Unable to start network bridge: %s", err)
273
+	}
274
+	return nil
275
+}
276
+
277
+// Create the actual bridge device.  This is more backward-compatible than
278
+// netlink.NetworkLinkAdd and works on RHEL 6.
279
+func createBridgeIface(name string) error {
280
+	s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_IP)
281
+	if err != nil {
282
+		utils.Debugf("Bridge socket creation failed IPv6 probably not enabled: %v", err)
283
+		s, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_IP)
284
+		if err != nil {
285
+			return fmt.Errorf("Error creating bridge creation socket: %s", err)
286
+		}
287
+	}
288
+	defer syscall.Close(s)
289
+
290
+	nameBytePtr, err := syscall.BytePtrFromString(name)
291
+	if err != nil {
292
+		return fmt.Errorf("Error converting bridge name %s to byte array: %s", name, err)
293
+	}
294
+
295
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), siocBRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
296
+		return fmt.Errorf("Error creating bridge: %s", err)
297
+	}
298
+	return nil
299
+}
300
+
301
+// Allocate a network interface
302
+func Allocate(job *engine.Job) engine.Status {
303
+	var (
304
+		ip          *net.IP
305
+		err         error
306
+		id          = job.Args[0]
307
+		requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
308
+	)
309
+
310
+	if requestedIP != nil {
311
+		ip, err = ipallocator.RequestIP(bridgeNetwork, &requestedIP)
312
+	} else {
313
+		ip, err = ipallocator.RequestIP(bridgeNetwork, nil)
314
+	}
315
+	if err != nil {
316
+		job.Error(err)
317
+		return engine.StatusErr
318
+	}
319
+
320
+	out := engine.Env{}
321
+	out.Set("IP", ip.String())
322
+	out.Set("Mask", bridgeNetwork.Mask.String())
323
+	out.Set("Gateway", bridgeNetwork.IP.String())
324
+	out.Set("Bridge", bridgeIface)
325
+
326
+	size, _ := bridgeNetwork.Mask.Size()
327
+	out.SetInt("IPPrefixLen", size)
328
+
329
+	currentInterfaces[id] = &networkInterface{
330
+		IP: *ip,
331
+	}
332
+
333
+	out.WriteTo(job.Stdout)
334
+
335
+	return engine.StatusOK
336
+}
337
+
338
+// release an interface for a select ip
339
+func Release(job *engine.Job) engine.Status {
340
+	var (
341
+		id                 = job.Args[0]
342
+		containerInterface = currentInterfaces[id]
343
+		ip                 net.IP
344
+		port               int
345
+		proto              string
346
+	)
347
+
348
+	if containerInterface == nil {
349
+		return job.Errorf("No network information to release for %s", id)
350
+	}
351
+
352
+	for _, nat := range containerInterface.PortMappings {
353
+		if err := portmapper.Unmap(nat); err != nil {
354
+			log.Printf("Unable to unmap port %s: %s", nat, err)
355
+		}
356
+
357
+		// this is host mappings
358
+		switch a := nat.(type) {
359
+		case *net.TCPAddr:
360
+			proto = "tcp"
361
+			ip = a.IP
362
+			port = a.Port
363
+		case *net.UDPAddr:
364
+			proto = "udp"
365
+			ip = a.IP
366
+			port = a.Port
367
+		}
368
+
369
+		if err := portallocator.ReleasePort(ip, proto, port); err != nil {
370
+			log.Printf("Unable to release port %s", nat)
371
+		}
372
+	}
373
+
374
+	if err := ipallocator.ReleaseIP(bridgeNetwork, &containerInterface.IP); err != nil {
375
+		log.Printf("Unable to release ip %s\n", err)
376
+	}
377
+	return engine.StatusOK
378
+}
379
+
380
+// Allocate an external port and map it to the interface
381
+func AllocatePort(job *engine.Job) engine.Status {
382
+	var (
383
+		err error
384
+
385
+		ip            = defaultBindingIP
386
+		id            = job.Args[0]
387
+		hostIP        = job.Getenv("HostIP")
388
+		hostPort      = job.GetenvInt("HostPort")
389
+		containerPort = job.GetenvInt("ContainerPort")
390
+		proto         = job.Getenv("Proto")
391
+		network       = currentInterfaces[id]
392
+	)
393
+
394
+	if hostIP != "" {
395
+		ip = net.ParseIP(hostIP)
396
+	}
397
+
398
+	// host ip, proto, and host port
399
+	hostPort, err = portallocator.RequestPort(ip, proto, hostPort)
400
+	if err != nil {
401
+		job.Error(err)
402
+		return engine.StatusErr
403
+	}
404
+
405
+	var (
406
+		container net.Addr
407
+		host      net.Addr
408
+	)
409
+
410
+	if proto == "tcp" {
411
+		host = &net.TCPAddr{IP: ip, Port: hostPort}
412
+		container = &net.TCPAddr{IP: network.IP, Port: containerPort}
413
+	} else {
414
+		host = &net.UDPAddr{IP: ip, Port: hostPort}
415
+		container = &net.UDPAddr{IP: network.IP, Port: containerPort}
416
+	}
417
+
418
+	if err := portmapper.Map(container, ip, hostPort); err != nil {
419
+		portallocator.ReleasePort(ip, proto, hostPort)
420
+
421
+		job.Error(err)
422
+		return engine.StatusErr
423
+	}
424
+	network.PortMappings = append(network.PortMappings, host)
425
+
426
+	out := engine.Env{}
427
+	out.Set("HostIP", ip.String())
428
+	out.SetInt("HostPort", hostPort)
429
+
430
+	if _, err := out.WriteTo(job.Stdout); err != nil {
431
+		job.Error(err)
432
+		return engine.StatusErr
433
+	}
434
+	return engine.StatusOK
435
+}
436
+
437
+func LinkContainers(job *engine.Job) engine.Status {
438
+	var (
439
+		action       = job.Args[0]
440
+		childIP      = job.Getenv("ChildIP")
441
+		parentIP     = job.Getenv("ParentIP")
442
+		ignoreErrors = job.GetenvBool("IgnoreErrors")
443
+		ports        = job.GetenvList("Ports")
444
+	)
445
+	split := func(p string) (string, string) {
446
+		parts := strings.Split(p, "/")
447
+		return parts[0], parts[1]
448
+	}
449
+
450
+	for _, p := range ports {
451
+		port, proto := split(p)
452
+		if output, err := iptables.Raw(action, "FORWARD",
453
+			"-i", bridgeIface, "-o", bridgeIface,
454
+			"-p", proto,
455
+			"-s", parentIP,
456
+			"--dport", port,
457
+			"-d", childIP,
458
+			"-j", "ACCEPT"); !ignoreErrors && err != nil {
459
+			job.Error(err)
460
+			return engine.StatusErr
461
+		} else if len(output) != 0 {
462
+			job.Errorf("Error toggle iptables forward: %s", output)
463
+			return engine.StatusErr
464
+		}
465
+
466
+		if output, err := iptables.Raw(action, "FORWARD",
467
+			"-i", bridgeIface, "-o", bridgeIface,
468
+			"-p", proto,
469
+			"-s", childIP,
470
+			"--sport", port,
471
+			"-d", parentIP,
472
+			"-j", "ACCEPT"); !ignoreErrors && err != nil {
473
+			job.Error(err)
474
+			return engine.StatusErr
475
+		} else if len(output) != 0 {
476
+			job.Errorf("Error toggle iptables forward: %s", output)
477
+			return engine.StatusErr
478
+		}
479
+	}
480
+	return engine.StatusOK
481
+}
0 482
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+package networkdriver
1
+
2
+import (
3
+	"errors"
4
+)
5
+
6
+var (
7
+	ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver")
8
+	ErrNetworkOverlaps                = errors.New("requested network overlaps with existing network")
9
+)
0 10
new file mode 100644
... ...
@@ -0,0 +1,190 @@
0
+package networkdriver
1
+
2
+import (
3
+	"github.com/dotcloud/docker/pkg/netlink"
4
+	"net"
5
+	"testing"
6
+)
7
+
8
+func TestNonOverlapingNameservers(t *testing.T) {
9
+	network := &net.IPNet{
10
+		IP:   []byte{192, 168, 0, 1},
11
+		Mask: []byte{255, 255, 255, 0},
12
+	}
13
+	nameservers := []string{
14
+		"127.0.0.1/32",
15
+	}
16
+
17
+	if err := CheckNameserverOverlaps(nameservers, network); err != nil {
18
+		t.Fatal(err)
19
+	}
20
+}
21
+
22
+func TestOverlapingNameservers(t *testing.T) {
23
+	network := &net.IPNet{
24
+		IP:   []byte{192, 168, 0, 1},
25
+		Mask: []byte{255, 255, 255, 0},
26
+	}
27
+	nameservers := []string{
28
+		"192.168.0.1/32",
29
+	}
30
+
31
+	if err := CheckNameserverOverlaps(nameservers, network); err == nil {
32
+		t.Fatalf("Expected error %s got %s", ErrNetworkOverlapsWithNameservers, err)
33
+	}
34
+}
35
+
36
+func TestCheckRouteOverlaps(t *testing.T) {
37
+	orig := networkGetRoutesFct
38
+	defer func() {
39
+		networkGetRoutesFct = orig
40
+	}()
41
+	networkGetRoutesFct = func() ([]netlink.Route, error) {
42
+		routesData := []string{"10.0.2.0/32", "10.0.3.0/24", "10.0.42.0/24", "172.16.42.0/24", "192.168.142.0/24"}
43
+
44
+		routes := []netlink.Route{}
45
+		for _, addr := range routesData {
46
+			_, netX, _ := net.ParseCIDR(addr)
47
+			routes = append(routes, netlink.Route{IPNet: netX})
48
+		}
49
+		return routes, nil
50
+	}
51
+
52
+	_, netX, _ := net.ParseCIDR("172.16.0.1/24")
53
+	if err := CheckRouteOverlaps(netX); err != nil {
54
+		t.Fatal(err)
55
+	}
56
+
57
+	_, netX, _ = net.ParseCIDR("10.0.2.0/24")
58
+	if err := CheckRouteOverlaps(netX); err == nil {
59
+		t.Fatalf("10.0.2.0/24 and 10.0.2.0 should overlap but it doesn't")
60
+	}
61
+}
62
+
63
+func TestCheckNameserverOverlaps(t *testing.T) {
64
+	nameservers := []string{"10.0.2.3/32", "192.168.102.1/32"}
65
+
66
+	_, netX, _ := net.ParseCIDR("10.0.2.3/32")
67
+
68
+	if err := CheckNameserverOverlaps(nameservers, netX); err == nil {
69
+		t.Fatalf("%s should overlap 10.0.2.3/32 but doesn't", netX)
70
+	}
71
+
72
+	_, netX, _ = net.ParseCIDR("192.168.102.2/32")
73
+
74
+	if err := CheckNameserverOverlaps(nameservers, netX); err != nil {
75
+		t.Fatalf("%s should not overlap %v but it does", netX, nameservers)
76
+	}
77
+}
78
+
79
+func AssertOverlap(CIDRx string, CIDRy string, t *testing.T) {
80
+	_, netX, _ := net.ParseCIDR(CIDRx)
81
+	_, netY, _ := net.ParseCIDR(CIDRy)
82
+	if !NetworkOverlaps(netX, netY) {
83
+		t.Errorf("%v and %v should overlap", netX, netY)
84
+	}
85
+}
86
+
87
+func AssertNoOverlap(CIDRx string, CIDRy string, t *testing.T) {
88
+	_, netX, _ := net.ParseCIDR(CIDRx)
89
+	_, netY, _ := net.ParseCIDR(CIDRy)
90
+	if NetworkOverlaps(netX, netY) {
91
+		t.Errorf("%v and %v should not overlap", netX, netY)
92
+	}
93
+}
94
+
95
+func TestNetworkOverlaps(t *testing.T) {
96
+	//netY starts at same IP and ends within netX
97
+	AssertOverlap("172.16.0.1/24", "172.16.0.1/25", t)
98
+	//netY starts within netX and ends at same IP
99
+	AssertOverlap("172.16.0.1/24", "172.16.0.128/25", t)
100
+	//netY starts and ends within netX
101
+	AssertOverlap("172.16.0.1/24", "172.16.0.64/25", t)
102
+	//netY starts at same IP and ends outside of netX
103
+	AssertOverlap("172.16.0.1/24", "172.16.0.1/23", t)
104
+	//netY starts before and ends at same IP of netX
105
+	AssertOverlap("172.16.1.1/24", "172.16.0.1/23", t)
106
+	//netY starts before and ends outside of netX
107
+	AssertOverlap("172.16.1.1/24", "172.16.0.1/22", t)
108
+	//netY starts and ends before netX
109
+	AssertNoOverlap("172.16.1.1/25", "172.16.0.1/24", t)
110
+	//netX starts and ends before netY
111
+	AssertNoOverlap("172.16.1.1/25", "172.16.2.1/24", t)
112
+}
113
+
114
+func TestNetworkRange(t *testing.T) {
115
+	// Simple class C test
116
+	_, network, _ := net.ParseCIDR("192.168.0.1/24")
117
+	first, last := NetworkRange(network)
118
+	if !first.Equal(net.ParseIP("192.168.0.0")) {
119
+		t.Error(first.String())
120
+	}
121
+	if !last.Equal(net.ParseIP("192.168.0.255")) {
122
+		t.Error(last.String())
123
+	}
124
+	if size := NetworkSize(network.Mask); size != 256 {
125
+		t.Error(size)
126
+	}
127
+
128
+	// Class A test
129
+	_, network, _ = net.ParseCIDR("10.0.0.1/8")
130
+	first, last = NetworkRange(network)
131
+	if !first.Equal(net.ParseIP("10.0.0.0")) {
132
+		t.Error(first.String())
133
+	}
134
+	if !last.Equal(net.ParseIP("10.255.255.255")) {
135
+		t.Error(last.String())
136
+	}
137
+	if size := NetworkSize(network.Mask); size != 16777216 {
138
+		t.Error(size)
139
+	}
140
+
141
+	// Class A, random IP address
142
+	_, network, _ = net.ParseCIDR("10.1.2.3/8")
143
+	first, last = NetworkRange(network)
144
+	if !first.Equal(net.ParseIP("10.0.0.0")) {
145
+		t.Error(first.String())
146
+	}
147
+	if !last.Equal(net.ParseIP("10.255.255.255")) {
148
+		t.Error(last.String())
149
+	}
150
+
151
+	// 32bit mask
152
+	_, network, _ = net.ParseCIDR("10.1.2.3/32")
153
+	first, last = NetworkRange(network)
154
+	if !first.Equal(net.ParseIP("10.1.2.3")) {
155
+		t.Error(first.String())
156
+	}
157
+	if !last.Equal(net.ParseIP("10.1.2.3")) {
158
+		t.Error(last.String())
159
+	}
160
+	if size := NetworkSize(network.Mask); size != 1 {
161
+		t.Error(size)
162
+	}
163
+
164
+	// 31bit mask
165
+	_, network, _ = net.ParseCIDR("10.1.2.3/31")
166
+	first, last = NetworkRange(network)
167
+	if !first.Equal(net.ParseIP("10.1.2.2")) {
168
+		t.Error(first.String())
169
+	}
170
+	if !last.Equal(net.ParseIP("10.1.2.3")) {
171
+		t.Error(last.String())
172
+	}
173
+	if size := NetworkSize(network.Mask); size != 2 {
174
+		t.Error(size)
175
+	}
176
+
177
+	// 26bit mask
178
+	_, network, _ = net.ParseCIDR("10.1.2.3/26")
179
+	first, last = NetworkRange(network)
180
+	if !first.Equal(net.ParseIP("10.1.2.0")) {
181
+		t.Error(first.String())
182
+	}
183
+	if !last.Equal(net.ParseIP("10.1.2.63")) {
184
+		t.Error(last.String())
185
+	}
186
+	if size := NetworkSize(network.Mask); size != 64 {
187
+		t.Error(size)
188
+	}
189
+}
0 190
new file mode 100644
... ...
@@ -0,0 +1,165 @@
0
+package portallocator
1
+
2
+import (
3
+	"errors"
4
+	"github.com/dotcloud/docker/pkg/collections"
5
+	"net"
6
+	"sync"
7
+)
8
+
9
+const (
10
+	BeginPortRange = 49153
11
+	EndPortRange   = 65535
12
+)
13
+
14
+type (
15
+	portMappings map[string]*collections.OrderedIntSet
16
+	ipMapping    map[string]portMappings
17
+)
18
+
19
+var (
20
+	ErrPortAlreadyAllocated = errors.New("port has already been allocated")
21
+	ErrPortExceedsRange     = errors.New("port exceeds upper range")
22
+	ErrUnknownProtocol      = errors.New("unknown protocol")
23
+)
24
+
25
+var (
26
+	currentDynamicPort = map[string]int{
27
+		"tcp": BeginPortRange - 1,
28
+		"udp": BeginPortRange - 1,
29
+	}
30
+	defaultIP             = net.ParseIP("0.0.0.0")
31
+	defaultAllocatedPorts = portMappings{}
32
+	otherAllocatedPorts   = ipMapping{}
33
+	lock                  = sync.Mutex{}
34
+)
35
+
36
+func init() {
37
+	defaultAllocatedPorts["tcp"] = collections.NewOrderedIntSet()
38
+	defaultAllocatedPorts["udp"] = collections.NewOrderedIntSet()
39
+}
40
+
41
+// RequestPort returns an available port if the port is 0
42
+// If the provided port is not 0 then it will be checked if
43
+// it is available for allocation
44
+func RequestPort(ip net.IP, proto string, port int) (int, error) {
45
+	lock.Lock()
46
+	defer lock.Unlock()
47
+
48
+	if err := validateProtocol(proto); err != nil {
49
+		return 0, err
50
+	}
51
+
52
+	// If the user requested a specific port to be allocated
53
+	if port > 0 {
54
+		if err := registerSetPort(ip, proto, port); err != nil {
55
+			return 0, err
56
+		}
57
+		return port, nil
58
+	}
59
+	return registerDynamicPort(ip, proto)
60
+}
61
+
62
+// ReleasePort will return the provided port back into the
63
+// pool for reuse
64
+func ReleasePort(ip net.IP, proto string, port int) error {
65
+	lock.Lock()
66
+	defer lock.Unlock()
67
+
68
+	if err := validateProtocol(proto); err != nil {
69
+		return err
70
+	}
71
+
72
+	allocated := defaultAllocatedPorts[proto]
73
+	allocated.Remove(port)
74
+
75
+	if !equalsDefault(ip) {
76
+		registerIP(ip)
77
+
78
+		// Remove the port for the specific ip address
79
+		allocated = otherAllocatedPorts[ip.String()][proto]
80
+		allocated.Remove(port)
81
+	}
82
+	return nil
83
+}
84
+
85
+func ReleaseAll() error {
86
+	lock.Lock()
87
+	defer lock.Unlock()
88
+
89
+	currentDynamicPort["tcp"] = BeginPortRange - 1
90
+	currentDynamicPort["udp"] = BeginPortRange - 1
91
+
92
+	defaultAllocatedPorts = portMappings{}
93
+	defaultAllocatedPorts["tcp"] = collections.NewOrderedIntSet()
94
+	defaultAllocatedPorts["udp"] = collections.NewOrderedIntSet()
95
+
96
+	otherAllocatedPorts = ipMapping{}
97
+
98
+	return nil
99
+}
100
+
101
+func registerDynamicPort(ip net.IP, proto string) (int, error) {
102
+	allocated := defaultAllocatedPorts[proto]
103
+
104
+	port := nextPort(proto)
105
+	if port > EndPortRange {
106
+		return 0, ErrPortExceedsRange
107
+	}
108
+
109
+	if !equalsDefault(ip) {
110
+		registerIP(ip)
111
+
112
+		ipAllocated := otherAllocatedPorts[ip.String()][proto]
113
+		ipAllocated.Push(port)
114
+	} else {
115
+		allocated.Push(port)
116
+	}
117
+	return port, nil
118
+}
119
+
120
+func registerSetPort(ip net.IP, proto string, port int) error {
121
+	allocated := defaultAllocatedPorts[proto]
122
+	if allocated.Exists(port) {
123
+		return ErrPortAlreadyAllocated
124
+	}
125
+
126
+	if !equalsDefault(ip) {
127
+		registerIP(ip)
128
+
129
+		ipAllocated := otherAllocatedPorts[ip.String()][proto]
130
+		if ipAllocated.Exists(port) {
131
+			return ErrPortAlreadyAllocated
132
+		}
133
+		ipAllocated.Push(port)
134
+	} else {
135
+		allocated.Push(port)
136
+	}
137
+	return nil
138
+}
139
+
140
+func equalsDefault(ip net.IP) bool {
141
+	return ip == nil || ip.Equal(defaultIP)
142
+}
143
+
144
+func nextPort(proto string) int {
145
+	c := currentDynamicPort[proto] + 1
146
+	currentDynamicPort[proto] = c
147
+	return c
148
+}
149
+
150
+func registerIP(ip net.IP) {
151
+	if _, exists := otherAllocatedPorts[ip.String()]; !exists {
152
+		otherAllocatedPorts[ip.String()] = portMappings{
153
+			"tcp": collections.NewOrderedIntSet(),
154
+			"udp": collections.NewOrderedIntSet(),
155
+		}
156
+	}
157
+}
158
+
159
+func validateProtocol(proto string) error {
160
+	if _, exists := defaultAllocatedPorts[proto]; !exists {
161
+		return ErrUnknownProtocol
162
+	}
163
+	return nil
164
+}
0 165
new file mode 100644
... ...
@@ -0,0 +1,184 @@
0
+package portallocator
1
+
2
+import (
3
+	"net"
4
+	"testing"
5
+)
6
+
7
+func reset() {
8
+	ReleaseAll()
9
+}
10
+
11
+func TestRequestNewPort(t *testing.T) {
12
+	defer reset()
13
+
14
+	port, err := RequestPort(defaultIP, "tcp", 0)
15
+	if err != nil {
16
+		t.Fatal(err)
17
+	}
18
+
19
+	if expected := BeginPortRange; port != expected {
20
+		t.Fatalf("Expected port %d got %d", expected, port)
21
+	}
22
+}
23
+
24
+func TestRequestSpecificPort(t *testing.T) {
25
+	defer reset()
26
+
27
+	port, err := RequestPort(defaultIP, "tcp", 5000)
28
+	if err != nil {
29
+		t.Fatal(err)
30
+	}
31
+	if port != 5000 {
32
+		t.Fatalf("Expected port 5000 got %d", port)
33
+	}
34
+}
35
+
36
+func TestReleasePort(t *testing.T) {
37
+	defer reset()
38
+
39
+	port, err := RequestPort(defaultIP, "tcp", 5000)
40
+	if err != nil {
41
+		t.Fatal(err)
42
+	}
43
+	if port != 5000 {
44
+		t.Fatalf("Expected port 5000 got %d", port)
45
+	}
46
+
47
+	if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
48
+		t.Fatal(err)
49
+	}
50
+}
51
+
52
+func TestReuseReleasedPort(t *testing.T) {
53
+	defer reset()
54
+
55
+	port, err := RequestPort(defaultIP, "tcp", 5000)
56
+	if err != nil {
57
+		t.Fatal(err)
58
+	}
59
+	if port != 5000 {
60
+		t.Fatalf("Expected port 5000 got %d", port)
61
+	}
62
+
63
+	if err := ReleasePort(defaultIP, "tcp", 5000); err != nil {
64
+		t.Fatal(err)
65
+	}
66
+
67
+	port, err = RequestPort(defaultIP, "tcp", 5000)
68
+	if err != nil {
69
+		t.Fatal(err)
70
+	}
71
+}
72
+
73
+func TestReleaseUnreadledPort(t *testing.T) {
74
+	defer reset()
75
+
76
+	port, err := RequestPort(defaultIP, "tcp", 5000)
77
+	if err != nil {
78
+		t.Fatal(err)
79
+	}
80
+	if port != 5000 {
81
+		t.Fatalf("Expected port 5000 got %d", port)
82
+	}
83
+
84
+	port, err = RequestPort(defaultIP, "tcp", 5000)
85
+	if err != ErrPortAlreadyAllocated {
86
+		t.Fatalf("Expected error %s got %s", ErrPortAlreadyAllocated, err)
87
+	}
88
+}
89
+
90
+func TestUnknowProtocol(t *testing.T) {
91
+	defer reset()
92
+
93
+	if _, err := RequestPort(defaultIP, "tcpp", 0); err != ErrUnknownProtocol {
94
+		t.Fatalf("Expected error %s got %s", ErrUnknownProtocol, err)
95
+	}
96
+}
97
+
98
+func TestAllocateAllPorts(t *testing.T) {
99
+	defer reset()
100
+
101
+	for i := 0; i <= EndPortRange-BeginPortRange; i++ {
102
+		port, err := RequestPort(defaultIP, "tcp", 0)
103
+		if err != nil {
104
+			t.Fatal(err)
105
+		}
106
+
107
+		if expected := BeginPortRange + i; port != expected {
108
+			t.Fatalf("Expected port %d got %d", expected, port)
109
+		}
110
+	}
111
+
112
+	if _, err := RequestPort(defaultIP, "tcp", 0); err != ErrPortExceedsRange {
113
+		t.Fatalf("Expected error %s got %s", ErrPortExceedsRange, err)
114
+	}
115
+
116
+	_, err := RequestPort(defaultIP, "udp", 0)
117
+	if err != nil {
118
+		t.Fatal(err)
119
+	}
120
+}
121
+
122
+func BenchmarkAllocatePorts(b *testing.B) {
123
+	defer reset()
124
+
125
+	for i := 0; i < b.N; i++ {
126
+		for i := 0; i <= EndPortRange-BeginPortRange; i++ {
127
+			port, err := RequestPort(defaultIP, "tcp", 0)
128
+			if err != nil {
129
+				b.Fatal(err)
130
+			}
131
+
132
+			if expected := BeginPortRange + i; port != expected {
133
+				b.Fatalf("Expected port %d got %d", expected, port)
134
+			}
135
+		}
136
+		reset()
137
+	}
138
+}
139
+
140
+func TestPortAllocation(t *testing.T) {
141
+	defer reset()
142
+
143
+	ip := net.ParseIP("192.168.0.1")
144
+	ip2 := net.ParseIP("192.168.0.2")
145
+	if port, err := RequestPort(ip, "tcp", 80); err != nil {
146
+		t.Fatal(err)
147
+	} else if port != 80 {
148
+		t.Fatalf("Acquire(80) should return 80, not %d", port)
149
+	}
150
+	port, err := RequestPort(ip, "tcp", 0)
151
+	if err != nil {
152
+		t.Fatal(err)
153
+	}
154
+	if port <= 0 {
155
+		t.Fatalf("Acquire(0) should return a non-zero port")
156
+	}
157
+
158
+	if _, err := RequestPort(ip, "tcp", port); err == nil {
159
+		t.Fatalf("Acquiring a port already in use should return an error")
160
+	}
161
+
162
+	if newPort, err := RequestPort(ip, "tcp", 0); err != nil {
163
+		t.Fatal(err)
164
+	} else if newPort == port {
165
+		t.Fatalf("Acquire(0) allocated the same port twice: %d", port)
166
+	}
167
+
168
+	if _, err := RequestPort(ip, "tcp", 80); err == nil {
169
+		t.Fatalf("Acquiring a port already in use should return an error")
170
+	}
171
+	if _, err := RequestPort(ip2, "tcp", 80); err != nil {
172
+		t.Fatalf("It should be possible to allocate the same port on a different interface")
173
+	}
174
+	if _, err := RequestPort(ip2, "tcp", 80); err == nil {
175
+		t.Fatalf("Acquiring a port already in use should return an error")
176
+	}
177
+	if err := ReleasePort(ip, "tcp", 80); err != nil {
178
+		t.Fatal(err)
179
+	}
180
+	if _, err := RequestPort(ip, "tcp", 80); err != nil {
181
+		t.Fatal(err)
182
+	}
183
+}
0 184
new file mode 100644
... ...
@@ -0,0 +1,131 @@
0
+package portmapper
1
+
2
+import (
3
+	"errors"
4
+	"fmt"
5
+	"github.com/dotcloud/docker/pkg/iptables"
6
+	"github.com/dotcloud/docker/pkg/proxy"
7
+	"net"
8
+	"sync"
9
+)
10
+
11
+type mapping struct {
12
+	proto         string
13
+	userlandProxy proxy.Proxy
14
+	host          net.Addr
15
+	container     net.Addr
16
+}
17
+
18
+var (
19
+	chain *iptables.Chain
20
+	lock  sync.Mutex
21
+
22
+	// udp:ip:port
23
+	currentMappings = make(map[string]*mapping)
24
+	newProxy        = proxy.NewProxy
25
+)
26
+
27
+var (
28
+	ErrUnknownBackendAddressType = errors.New("unknown container address type not supported")
29
+	ErrPortMappedForIP           = errors.New("port is already mapped to ip")
30
+	ErrPortNotMapped             = errors.New("port is not mapped")
31
+)
32
+
33
+func SetIptablesChain(c *iptables.Chain) {
34
+	chain = c
35
+}
36
+
37
+func Map(container net.Addr, hostIP net.IP, hostPort int) error {
38
+	lock.Lock()
39
+	defer lock.Unlock()
40
+
41
+	var m *mapping
42
+	switch container.(type) {
43
+	case *net.TCPAddr:
44
+		m = &mapping{
45
+			proto:     "tcp",
46
+			host:      &net.TCPAddr{IP: hostIP, Port: hostPort},
47
+			container: container,
48
+		}
49
+	case *net.UDPAddr:
50
+		m = &mapping{
51
+			proto:     "udp",
52
+			host:      &net.UDPAddr{IP: hostIP, Port: hostPort},
53
+			container: container,
54
+		}
55
+	default:
56
+		return ErrUnknownBackendAddressType
57
+	}
58
+
59
+	key := getKey(m.host)
60
+	if _, exists := currentMappings[key]; exists {
61
+		return ErrPortMappedForIP
62
+	}
63
+
64
+	containerIP, containerPort := getIPAndPort(m.container)
65
+	if err := forward(iptables.Add, m.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
66
+		return err
67
+	}
68
+
69
+	p, err := newProxy(m.host, m.container)
70
+	if err != nil {
71
+		// need to undo the iptables rules before we reutrn
72
+		forward(iptables.Delete, m.proto, hostIP, hostPort, containerIP.String(), containerPort)
73
+		return err
74
+	}
75
+
76
+	m.userlandProxy = p
77
+	currentMappings[key] = m
78
+
79
+	go p.Run()
80
+
81
+	return nil
82
+}
83
+
84
+func Unmap(host net.Addr) error {
85
+	lock.Lock()
86
+	defer lock.Unlock()
87
+
88
+	key := getKey(host)
89
+	data, exists := currentMappings[key]
90
+	if !exists {
91
+		return ErrPortNotMapped
92
+	}
93
+
94
+	data.userlandProxy.Close()
95
+	delete(currentMappings, key)
96
+
97
+	containerIP, containerPort := getIPAndPort(data.container)
98
+	hostIP, hostPort := getIPAndPort(data.host)
99
+	if err := forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
100
+		return err
101
+	}
102
+	return nil
103
+}
104
+
105
+func getKey(a net.Addr) string {
106
+	switch t := a.(type) {
107
+	case *net.TCPAddr:
108
+		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "tcp")
109
+	case *net.UDPAddr:
110
+		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "udp")
111
+	}
112
+	return ""
113
+}
114
+
115
+func getIPAndPort(a net.Addr) (net.IP, int) {
116
+	switch t := a.(type) {
117
+	case *net.TCPAddr:
118
+		return t.IP, t.Port
119
+	case *net.UDPAddr:
120
+		return t.IP, t.Port
121
+	}
122
+	return nil, 0
123
+}
124
+
125
+func forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
126
+	if chain == nil {
127
+		return nil
128
+	}
129
+	return chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort)
130
+}
0 131
new file mode 100644
... ...
@@ -0,0 +1,107 @@
0
+package portmapper
1
+
2
+import (
3
+	"github.com/dotcloud/docker/pkg/iptables"
4
+	"github.com/dotcloud/docker/pkg/proxy"
5
+	"net"
6
+	"testing"
7
+)
8
+
9
+func init() {
10
+	// override this func to mock out the proxy server
11
+	newProxy = proxy.NewStubProxy
12
+}
13
+
14
+func reset() {
15
+	chain = nil
16
+	currentMappings = make(map[string]*mapping)
17
+}
18
+
19
+func TestSetIptablesChain(t *testing.T) {
20
+	defer reset()
21
+
22
+	c := &iptables.Chain{
23
+		Name:   "TEST",
24
+		Bridge: "192.168.1.1",
25
+	}
26
+
27
+	if chain != nil {
28
+		t.Fatal("chain should be nil at init")
29
+	}
30
+
31
+	SetIptablesChain(c)
32
+	if chain == nil {
33
+		t.Fatal("chain should not be nil after set")
34
+	}
35
+}
36
+
37
+func TestMapPorts(t *testing.T) {
38
+	dstIp1 := net.ParseIP("192.168.0.1")
39
+	dstIp2 := net.ParseIP("192.168.0.2")
40
+	dstAddr1 := &net.TCPAddr{IP: dstIp1, Port: 80}
41
+	dstAddr2 := &net.TCPAddr{IP: dstIp2, Port: 80}
42
+
43
+	srcAddr1 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
44
+	srcAddr2 := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.2")}
45
+
46
+	if err := Map(srcAddr1, dstIp1, 80); err != nil {
47
+		t.Fatalf("Failed to allocate port: %s", err)
48
+	}
49
+
50
+	if Map(srcAddr1, dstIp1, 80) == nil {
51
+		t.Fatalf("Port is in use - mapping should have failed")
52
+	}
53
+
54
+	if Map(srcAddr2, dstIp1, 80) == nil {
55
+		t.Fatalf("Port is in use - mapping should have failed")
56
+	}
57
+
58
+	if err := Map(srcAddr2, dstIp2, 80); err != nil {
59
+		t.Fatalf("Failed to allocate port: %s", err)
60
+	}
61
+
62
+	if Unmap(dstAddr1) != nil {
63
+		t.Fatalf("Failed to release port")
64
+	}
65
+
66
+	if Unmap(dstAddr2) != nil {
67
+		t.Fatalf("Failed to release port")
68
+	}
69
+
70
+	if Unmap(dstAddr2) == nil {
71
+		t.Fatalf("Port already released, but no error reported")
72
+	}
73
+}
74
+
75
+func TestGetUDPKey(t *testing.T) {
76
+	addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}
77
+
78
+	key := getKey(addr)
79
+
80
+	if expected := "192.168.1.5:53/udp"; key != expected {
81
+		t.Fatalf("expected key %s got %s", expected, key)
82
+	}
83
+}
84
+
85
+func TestGetTCPKey(t *testing.T) {
86
+	addr := &net.TCPAddr{IP: net.ParseIP("192.168.1.5"), Port: 80}
87
+
88
+	key := getKey(addr)
89
+
90
+	if expected := "192.168.1.5:80/tcp"; key != expected {
91
+		t.Fatalf("expected key %s got %s", expected, key)
92
+	}
93
+}
94
+
95
+func TestGetUDPIPAndPort(t *testing.T) {
96
+	addr := &net.UDPAddr{IP: net.ParseIP("192.168.1.5"), Port: 53}
97
+
98
+	ip, port := getIPAndPort(addr)
99
+	if expected := "192.168.1.5"; ip.String() != expected {
100
+		t.Fatalf("expected ip %s got %s", expected, ip)
101
+	}
102
+
103
+	if ep := 53; port != ep {
104
+		t.Fatalf("expected port %d got %d", ep, port)
105
+	}
106
+}
0 107
new file mode 100644
... ...
@@ -0,0 +1,118 @@
0
+package networkdriver
1
+
2
+import (
3
+	"encoding/binary"
4
+	"errors"
5
+	"fmt"
6
+	"net"
7
+
8
+	"github.com/dotcloud/docker/pkg/netlink"
9
+)
10
+
11
+var (
12
+	networkGetRoutesFct = netlink.NetworkGetRoutes
13
+	ErrNoDefaultRoute   = errors.New("no default route")
14
+)
15
+
16
+func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
17
+	if len(nameservers) > 0 {
18
+		for _, ns := range nameservers {
19
+			_, nsNetwork, err := net.ParseCIDR(ns)
20
+			if err != nil {
21
+				return err
22
+			}
23
+			if NetworkOverlaps(toCheck, nsNetwork) {
24
+				return ErrNetworkOverlapsWithNameservers
25
+			}
26
+		}
27
+	}
28
+	return nil
29
+}
30
+
31
+func CheckRouteOverlaps(toCheck *net.IPNet) error {
32
+	networks, err := networkGetRoutesFct()
33
+	if err != nil {
34
+		return err
35
+	}
36
+
37
+	for _, network := range networks {
38
+		if network.IPNet != nil && NetworkOverlaps(toCheck, network.IPNet) {
39
+			return ErrNetworkOverlaps
40
+		}
41
+	}
42
+	return nil
43
+}
44
+
45
+// Detects overlap between one IPNet and another
46
+func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
47
+	if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) {
48
+		return true
49
+	}
50
+	if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) {
51
+		return true
52
+	}
53
+	return false
54
+}
55
+
56
+// Calculates the first and last IP addresses in an IPNet
57
+func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
58
+	var (
59
+		netIP   = network.IP.To4()
60
+		firstIP = netIP.Mask(network.Mask)
61
+		lastIP  = net.IPv4(0, 0, 0, 0).To4()
62
+	)
63
+
64
+	for i := 0; i < len(lastIP); i++ {
65
+		lastIP[i] = netIP[i] | ^network.Mask[i]
66
+	}
67
+	return firstIP, lastIP
68
+}
69
+
70
+// Given a netmask, calculates the number of available hosts
71
+func NetworkSize(mask net.IPMask) int32 {
72
+	m := net.IPv4Mask(0, 0, 0, 0)
73
+	for i := 0; i < net.IPv4len; i++ {
74
+		m[i] = ^mask[i]
75
+	}
76
+	return int32(binary.BigEndian.Uint32(m)) + 1
77
+}
78
+
79
+// Return the IPv4 address of a network interface
80
+func GetIfaceAddr(name string) (net.Addr, error) {
81
+	iface, err := net.InterfaceByName(name)
82
+	if err != nil {
83
+		return nil, err
84
+	}
85
+	addrs, err := iface.Addrs()
86
+	if err != nil {
87
+		return nil, err
88
+	}
89
+	var addrs4 []net.Addr
90
+	for _, addr := range addrs {
91
+		ip := (addr.(*net.IPNet)).IP
92
+		if ip4 := ip.To4(); len(ip4) == net.IPv4len {
93
+			addrs4 = append(addrs4, addr)
94
+		}
95
+	}
96
+	switch {
97
+	case len(addrs4) == 0:
98
+		return nil, fmt.Errorf("Interface %v has no IP addresses", name)
99
+	case len(addrs4) > 1:
100
+		fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
101
+			name, (addrs4[0].(*net.IPNet)).IP)
102
+	}
103
+	return addrs4[0], nil
104
+}
105
+
106
+func GetDefaultRouteIface() (*net.Interface, error) {
107
+	rs, err := networkGetRoutesFct()
108
+	if err != nil {
109
+		return nil, fmt.Errorf("unable to get routes: %v", err)
110
+	}
111
+	for _, r := range rs {
112
+		if r.Default {
113
+			return r.Iface, nil
114
+		}
115
+	}
116
+	return nil, ErrNoDefaultRoute
117
+}
... ...
@@ -17,8 +17,8 @@ import (
17 17
 	_ "github.com/dotcloud/docker/graphdriver/devmapper"
18 18
 	_ "github.com/dotcloud/docker/graphdriver/vfs"
19 19
 	"github.com/dotcloud/docker/image"
20
-	_ "github.com/dotcloud/docker/networkdriver/lxc"
21
-	"github.com/dotcloud/docker/networkdriver/portallocator"
20
+	_ "github.com/dotcloud/docker/runtime/networkdriver/lxc"
21
+	"github.com/dotcloud/docker/runtime/networkdriver/portallocator"
22 22
 	"github.com/dotcloud/docker/pkg/graphdb"
23 23
 	"github.com/dotcloud/docker/pkg/sysinfo"
24 24
 	"github.com/dotcloud/docker/runconfig"