Browse code

Merge pull request #3872 from crosbymichael/network-driver

Remove networking out of core and into a driver

Guillaume J. Charmes authored on 2014/02/01 10:22:37
Showing 13 changed files
... ...
@@ -5,6 +5,11 @@ import (
5 5
 	"net"
6 6
 )
7 7
 
8
+const (
9
+	DefaultNetworkMtu    = 1500
10
+	DisableNetworkBridge = "none"
11
+)
12
+
8 13
 // FIXME: separate runtime configuration from http api configuration
9 14
 type DaemonConfig struct {
10 15
 	Pidfile                     string
... ...
@@ -13,12 +18,13 @@ type DaemonConfig struct {
13 13
 	Dns                         []string
14 14
 	EnableIptables              bool
15 15
 	EnableIpForward             bool
16
-	BridgeIface                 string
17
-	BridgeIp                    string
18 16
 	DefaultIp                   net.IP
17
+	BridgeIface                 string
18
+	BridgeIP                    string
19 19
 	InterContainerCommunication bool
20 20
 	GraphDriver                 string
21 21
 	Mtu                         int
22
+	DisableNetwork              bool
22 23
 }
23 24
 
24 25
 // ConfigFromJob creates and returns a new DaemonConfig object
... ...
@@ -30,7 +36,7 @@ func DaemonConfigFromJob(job *engine.Job) *DaemonConfig {
30 30
 		AutoRestart:                 job.GetenvBool("AutoRestart"),
31 31
 		EnableIptables:              job.GetenvBool("EnableIptables"),
32 32
 		EnableIpForward:             job.GetenvBool("EnableIpForward"),
33
-		BridgeIp:                    job.Getenv("BridgeIp"),
33
+		BridgeIP:                    job.Getenv("BridgeIP"),
34 34
 		DefaultIp:                   net.ParseIP(job.Getenv("DefaultIp")),
35 35
 		InterContainerCommunication: job.GetenvBool("InterContainerCommunication"),
36 36
 		GraphDriver:                 job.Getenv("GraphDriver"),
... ...
@@ -38,16 +44,12 @@ func DaemonConfigFromJob(job *engine.Job) *DaemonConfig {
38 38
 	if dns := job.GetenvList("Dns"); dns != nil {
39 39
 		config.Dns = dns
40 40
 	}
41
-	if br := job.Getenv("BridgeIface"); br != "" {
42
-		config.BridgeIface = br
43
-	} else {
44
-		config.BridgeIface = DefaultNetworkBridge
45
-	}
46 41
 	if mtu := job.GetenvInt("Mtu"); mtu != 0 {
47 42
 		config.Mtu = mtu
48 43
 	} else {
49 44
 		config.Mtu = DefaultNetworkMtu
50 45
 	}
46
+	config.DisableNetwork = job.Getenv("BridgeIface") == DisableNetworkBridge
51 47
 
52 48
 	return config
53 49
 }
... ...
@@ -8,7 +8,6 @@ import (
8 8
 	"github.com/dotcloud/docker/engine"
9 9
 	"github.com/dotcloud/docker/execdriver"
10 10
 	"github.com/dotcloud/docker/graphdriver"
11
-	"github.com/dotcloud/docker/networkdriver/ipallocator"
12 11
 	"github.com/dotcloud/docker/pkg/mount"
13 12
 	"github.com/dotcloud/docker/pkg/term"
14 13
 	"github.com/dotcloud/docker/utils"
... ...
@@ -16,7 +15,6 @@ import (
16 16
 	"io"
17 17
 	"io/ioutil"
18 18
 	"log"
19
-	"net"
20 19
 	"os"
21 20
 	"path"
22 21
 	"path/filepath"
... ...
@@ -47,7 +45,6 @@ type Container struct {
47 47
 	State  State
48 48
 	Image  string
49 49
 
50
-	network         *NetworkInterface
51 50
 	NetworkSettings *NetworkSettings
52 51
 
53 52
 	ResolvConfPath string
... ...
@@ -558,6 +555,7 @@ func populateCommand(c *Container) {
558 558
 		en           *execdriver.Network
559 559
 		driverConfig []string
560 560
 	)
561
+
561 562
 	if !c.Config.NetworkDisabled {
562 563
 		network := c.NetworkSettings
563 564
 		en = &execdriver.Network{
... ...
@@ -603,15 +601,18 @@ func (container *Container) Start() (err error) {
603 603
 	if container.State.IsRunning() {
604 604
 		return fmt.Errorf("The container %s is already running.", container.ID)
605 605
 	}
606
+
606 607
 	defer func() {
607 608
 		if err != nil {
608 609
 			container.cleanup()
609 610
 		}
610 611
 	}()
612
+
611 613
 	if err := container.Mount(); err != nil {
612 614
 		return err
613 615
 	}
614
-	if container.runtime.networkManager.disabled {
616
+
617
+	if container.runtime.config.DisableNetwork {
615 618
 		container.Config.NetworkDisabled = true
616 619
 		container.buildHostnameAndHostsFiles("127.0.1.1")
617 620
 	} else {
... ...
@@ -681,7 +682,7 @@ func (container *Container) Start() (err error) {
681 681
 		}
682 682
 
683 683
 		for p, child := range children {
684
-			link, err := NewLink(container, child, p, runtime.networkManager.bridgeIface)
684
+			link, err := NewLink(container, child, p, runtime.eng)
685 685
 			if err != nil {
686 686
 				rollback()
687 687
 				return err
... ...
@@ -1102,34 +1103,40 @@ func (container *Container) allocateNetwork() error {
1102 1102
 	}
1103 1103
 
1104 1104
 	var (
1105
-		iface *NetworkInterface
1106
-		err   error
1105
+		env *engine.Env
1106
+		err error
1107
+		eng = container.runtime.eng
1107 1108
 	)
1109
+
1108 1110
 	if container.State.IsGhost() {
1109
-		if manager := container.runtime.networkManager; manager.disabled {
1110
-			iface = &NetworkInterface{disabled: true}
1111
+		if container.runtime.config.DisableNetwork {
1112
+			env = &engine.Env{}
1111 1113
 		} else {
1112
-			iface = &NetworkInterface{
1113
-				IPNet:   net.IPNet{IP: net.ParseIP(container.NetworkSettings.IPAddress), Mask: manager.bridgeNetwork.Mask},
1114
-				Gateway: manager.bridgeNetwork.IP,
1115
-				manager: manager,
1114
+			currentIP := container.NetworkSettings.IPAddress
1115
+
1116
+			job := eng.Job("allocate_interface", container.ID)
1117
+			if currentIP != "" {
1118
+				job.Setenv("RequestIP", currentIP)
1116 1119
 			}
1117
-			if iface != nil && iface.IPNet.IP != nil {
1118
-				if _, err := ipallocator.RequestIP(manager.bridgeNetwork, &iface.IPNet.IP); err != nil {
1119
-					return err
1120
-				}
1121
-			} else {
1122
-				iface, err = container.runtime.networkManager.Allocate()
1123
-				if err != nil {
1124
-					return err
1125
-				}
1120
+
1121
+			env, err = job.Stdout.AddEnv()
1122
+			if err != nil {
1123
+				return err
1124
+			}
1125
+
1126
+			if err := job.Run(); err != nil {
1127
+				return err
1126 1128
 			}
1127 1129
 		}
1128 1130
 	} else {
1129
-		iface, err = container.runtime.networkManager.Allocate()
1131
+		job := eng.Job("allocate_interface", container.ID)
1132
+		env, err = job.Stdout.AddEnv()
1130 1133
 		if err != nil {
1131 1134
 			return err
1132 1135
 		}
1136
+		if err := job.Run(); err != nil {
1137
+			return err
1138
+		}
1133 1139
 	}
1134 1140
 
1135 1141
 	if container.Config.PortSpecs != nil {
... ...
@@ -1171,37 +1178,50 @@ func (container *Container) allocateNetwork() error {
1171 1171
 		if container.hostConfig.PublishAllPorts && len(binding) == 0 {
1172 1172
 			binding = append(binding, PortBinding{})
1173 1173
 		}
1174
+
1174 1175
 		for i := 0; i < len(binding); i++ {
1175 1176
 			b := binding[i]
1176
-			nat, err := iface.AllocatePort(port, b)
1177
+
1178
+			portJob := eng.Job("allocate_port", container.ID)
1179
+			portJob.Setenv("HostIP", b.HostIp)
1180
+			portJob.Setenv("HostPort", b.HostPort)
1181
+			portJob.Setenv("Proto", port.Proto())
1182
+			portJob.Setenv("ContainerPort", port.Port())
1183
+
1184
+			portEnv, err := portJob.Stdout.AddEnv()
1177 1185
 			if err != nil {
1178
-				iface.Release()
1179 1186
 				return err
1180 1187
 			}
1181
-			utils.Debugf("Allocate port: %s:%s->%s", nat.Binding.HostIp, port, nat.Binding.HostPort)
1182
-			binding[i] = nat.Binding
1188
+			if err := portJob.Run(); err != nil {
1189
+				eng.Job("release_interface", container.ID).Run()
1190
+				return err
1191
+			}
1192
+			b.HostIp = portEnv.Get("HostIP")
1193
+			b.HostPort = portEnv.Get("HostPort")
1194
+
1195
+			binding[i] = b
1183 1196
 		}
1184 1197
 		bindings[port] = binding
1185 1198
 	}
1186 1199
 	container.writeHostConfig()
1187 1200
 
1188 1201
 	container.NetworkSettings.Ports = bindings
1189
-	container.network = iface
1190 1202
 
1191
-	container.NetworkSettings.Bridge = container.runtime.networkManager.bridgeIface
1192
-	container.NetworkSettings.IPAddress = iface.IPNet.IP.String()
1193
-	container.NetworkSettings.IPPrefixLen, _ = iface.IPNet.Mask.Size()
1194
-	container.NetworkSettings.Gateway = iface.Gateway.String()
1203
+	container.NetworkSettings.Bridge = env.Get("Bridge")
1204
+	container.NetworkSettings.IPAddress = env.Get("IP")
1205
+	container.NetworkSettings.IPPrefixLen = env.GetInt("IPPrefixLen")
1206
+	container.NetworkSettings.Gateway = env.Get("Gateway")
1195 1207
 
1196 1208
 	return nil
1197 1209
 }
1198 1210
 
1199 1211
 func (container *Container) releaseNetwork() {
1200
-	if container.Config.NetworkDisabled || container.network == nil {
1212
+	if container.Config.NetworkDisabled {
1201 1213
 		return
1202 1214
 	}
1203
-	container.network.Release()
1204
-	container.network = nil
1215
+	eng := container.runtime.eng
1216
+
1217
+	eng.Job("release_interface", container.ID).Run()
1205 1218
 	container.NetworkSettings = &NetworkSettings{}
1206 1219
 }
1207 1220
 
... ...
@@ -91,7 +91,7 @@ func main() {
91 91
 		job.SetenvBool("EnableIptables", *flEnableIptables)
92 92
 		job.SetenvBool("EnableIpForward", *flEnableIpForward)
93 93
 		job.Setenv("BridgeIface", *bridgeName)
94
-		job.Setenv("BridgeIp", *bridgeIp)
94
+		job.Setenv("BridgeIP", *bridgeIp)
95 95
 		job.Setenv("DefaultIp", *flDefaultIp)
96 96
 		job.SetenvBool("InterContainerCommunication", *flInterContainerComm)
97 97
 		job.Setenv("GraphDriver", *flGraphDriver)
... ...
@@ -34,7 +34,13 @@ func mkRuntime(f utils.Fataler) *docker.Runtime {
34 34
 		AutoRestart: false,
35 35
 		Mtu:         docker.DefaultNetworkMtu,
36 36
 	}
37
-	r, err := docker.NewRuntimeFromDirectory(config)
37
+
38
+	eng, err := engine.New(root)
39
+	if err != nil {
40
+		f.Fatal(err)
41
+	}
42
+
43
+	r, err := docker.NewRuntimeFromDirectory(config, eng)
38 44
 	if err != nil {
39 45
 		f.Fatal(err)
40 46
 	}
... ...
@@ -2,7 +2,7 @@ package docker
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"github.com/dotcloud/docker/pkg/iptables"
5
+	"github.com/dotcloud/docker/engine"
6 6
 	"path"
7 7
 	"strings"
8 8
 )
... ...
@@ -11,13 +11,13 @@ type Link struct {
11 11
 	ParentIP         string
12 12
 	ChildIP          string
13 13
 	Name             string
14
-	BridgeInterface  string
15 14
 	ChildEnvironment []string
16 15
 	Ports            []Port
17 16
 	IsEnabled        bool
17
+	eng              *engine.Engine
18 18
 }
19 19
 
20
-func NewLink(parent, child *Container, name, bridgeInterface string) (*Link, error) {
20
+func NewLink(parent, child *Container, name string, eng *engine.Engine) (*Link, error) {
21 21
 	if parent.ID == child.ID {
22 22
 		return nil, fmt.Errorf("Cannot link to self: %s == %s", parent.ID, child.ID)
23 23
 	}
... ...
@@ -33,12 +33,12 @@ func NewLink(parent, child *Container, name, bridgeInterface string) (*Link, err
33 33
 	}
34 34
 
35 35
 	l := &Link{
36
-		BridgeInterface:  bridgeInterface,
37 36
 		Name:             name,
38 37
 		ChildIP:          child.NetworkSettings.IPAddress,
39 38
 		ParentIP:         parent.NetworkSettings.IPAddress,
40 39
 		ChildEnvironment: child.Config.Env,
41 40
 		Ports:            ports,
41
+		eng:              eng,
42 42
 	}
43 43
 	return l, nil
44 44
 
... ...
@@ -119,18 +119,21 @@ func (l *Link) Disable() {
119 119
 }
120 120
 
121 121
 func (l *Link) toggle(action string, ignoreErrors bool) error {
122
-	for _, p := range l.Ports {
123
-		if output, err := iptables.Raw(action, "FORWARD",
124
-			"-i", l.BridgeInterface, "-o", l.BridgeInterface,
125
-			"-p", p.Proto(),
126
-			"-s", l.ParentIP,
127
-			"--dport", p.Port(),
128
-			"-d", l.ChildIP,
129
-			"-j", "ACCEPT"); !ignoreErrors && err != nil {
130
-			return err
131
-		} else if len(output) != 0 {
132
-			return fmt.Errorf("Error toggle iptables forward: %s", output)
133
-		}
122
+	job := l.eng.Job("link", action)
123
+
124
+	job.Setenv("ParentIP", l.ParentIP)
125
+	job.Setenv("ChildIP", l.ChildIP)
126
+	job.SetenvBool("IgnoreErrors", ignoreErrors)
127
+
128
+	out := make([]string, len(l.Ports))
129
+	for i, p := range l.Ports {
130
+		out[i] = fmt.Sprintf("%s/%s", p.Port(), p.Proto())
131
+	}
132
+	job.SetenvList("Ports", out)
133
+
134
+	if err := job.Run(); err != nil {
135
+		// TODO: get ouput from job
136
+		return err
134 137
 	}
135 138
 	return nil
136 139
 }
... ...
@@ -30,7 +30,7 @@ func TestLinkNew(t *testing.T) {
30 30
 
31 31
 	to := newMockLinkContainer(toID, "172.0.17.3")
32 32
 
33
-	link, err := NewLink(to, from, "/db/docker", "172.0.17.1")
33
+	link, err := NewLink(to, from, "/db/docker", nil)
34 34
 	if err != nil {
35 35
 		t.Fatal(err)
36 36
 	}
... ...
@@ -50,9 +50,6 @@ func TestLinkNew(t *testing.T) {
50 50
 	if link.ChildIP != "172.0.17.2" {
51 51
 		t.Fail()
52 52
 	}
53
-	if link.BridgeInterface != "172.0.17.1" {
54
-		t.Fail()
55
-	}
56 53
 	for _, p := range link.Ports {
57 54
 		if p != Port("6379/tcp") {
58 55
 			t.Fail()
... ...
@@ -75,7 +72,7 @@ func TestLinkEnv(t *testing.T) {
75 75
 
76 76
 	to := newMockLinkContainer(toID, "172.0.17.3")
77 77
 
78
-	link, err := NewLink(to, from, "/db/docker", "172.0.17.1")
78
+	link, err := NewLink(to, from, "/db/docker", nil)
79 79
 	if err != nil {
80 80
 		t.Fatal(err)
81 81
 	}
82 82
deleted file mode 100644
... ...
@@ -1,413 +0,0 @@
1
-package docker
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/networkdriver"
6
-	"github.com/dotcloud/docker/networkdriver/ipallocator"
7
-	"github.com/dotcloud/docker/networkdriver/portallocator"
8
-	"github.com/dotcloud/docker/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
-	"strconv"
16
-	"syscall"
17
-	"unsafe"
18
-)
19
-
20
-const (
21
-	DefaultNetworkBridge = "docker0"
22
-	DisableNetworkBridge = "none"
23
-	DefaultNetworkMtu    = 1500
24
-	siocBRADDBR          = 0x89a0
25
-)
26
-
27
-// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`,
28
-// and attempts to configure it with an address which doesn't conflict with any other interface on the host.
29
-// If it can't find an address which doesn't conflict, it will return an error.
30
-func CreateBridgeIface(config *DaemonConfig) error {
31
-	addrs := []string{
32
-		// Here we don't follow the convention of using the 1st IP of the range for the gateway.
33
-		// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
34
-		// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
35
-		// on the internal addressing or other stupid things like that.
36
-		// The shouldn't, but hey, let's not break them unless we really have to.
37
-		"172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
38
-		"10.0.42.1/16",   // Don't even try using the entire /8, that's too intrusive
39
-		"10.1.42.1/16",
40
-		"10.42.42.1/16",
41
-		"172.16.42.1/24",
42
-		"172.16.43.1/24",
43
-		"172.16.44.1/24",
44
-		"10.0.42.1/24",
45
-		"10.0.43.1/24",
46
-		"192.168.42.1/24",
47
-		"192.168.43.1/24",
48
-		"192.168.44.1/24",
49
-	}
50
-
51
-	nameservers := []string{}
52
-	resolvConf, _ := utils.GetResolvConf()
53
-	// we don't check for an error here, because we don't really care
54
-	// if we can't read /etc/resolv.conf. So instead we skip the append
55
-	// if resolvConf is nil. It either doesn't exist, or we can't read it
56
-	// for some reason.
57
-	if resolvConf != nil {
58
-		nameservers = append(nameservers, utils.GetNameserversAsCIDR(resolvConf)...)
59
-	}
60
-
61
-	var ifaceAddr string
62
-	if len(config.BridgeIp) != 0 {
63
-		_, _, err := net.ParseCIDR(config.BridgeIp)
64
-		if err != nil {
65
-			return err
66
-		}
67
-		ifaceAddr = config.BridgeIp
68
-	} else {
69
-		for _, addr := range addrs {
70
-			_, dockerNetwork, err := net.ParseCIDR(addr)
71
-			if err != nil {
72
-				return err
73
-			}
74
-			if err := networkdriver.CheckNameserverOverlaps(nameservers, dockerNetwork); err == nil {
75
-				if err := networkdriver.CheckRouteOverlaps(dockerNetwork); err == nil {
76
-					ifaceAddr = addr
77
-					break
78
-				} else {
79
-					utils.Debugf("%s %s", addr, err)
80
-				}
81
-			}
82
-		}
83
-	}
84
-
85
-	if ifaceAddr == "" {
86
-		return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", config.BridgeIface, config.BridgeIface)
87
-	}
88
-	utils.Debugf("Creating bridge %s with network %s", config.BridgeIface, ifaceAddr)
89
-
90
-	if err := createBridgeIface(config.BridgeIface); err != nil {
91
-		return err
92
-	}
93
-	iface, err := net.InterfaceByName(config.BridgeIface)
94
-	if err != nil {
95
-		return err
96
-	}
97
-	ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr)
98
-	if err != nil {
99
-		return err
100
-	}
101
-	if netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
102
-		return fmt.Errorf("Unable to add private network: %s", err)
103
-	}
104
-	if err := netlink.NetworkLinkUp(iface); err != nil {
105
-		return fmt.Errorf("Unable to start network bridge: %s", err)
106
-	}
107
-
108
-	return nil
109
-}
110
-
111
-// Create the actual bridge device.  This is more backward-compatible than
112
-// netlink.NetworkLinkAdd and works on RHEL 6.
113
-func createBridgeIface(name string) error {
114
-	s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_IP)
115
-	if err != nil {
116
-		utils.Debugf("Bridge socket creation failed IPv6 probably not enabled: %v", err)
117
-		s, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_IP)
118
-		if err != nil {
119
-			return fmt.Errorf("Error creating bridge creation socket: %s", err)
120
-		}
121
-	}
122
-	defer syscall.Close(s)
123
-
124
-	nameBytePtr, err := syscall.BytePtrFromString(name)
125
-	if err != nil {
126
-		return fmt.Errorf("Error converting bridge name %s to byte array: %s", name, err)
127
-	}
128
-
129
-	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), siocBRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
130
-		return fmt.Errorf("Error creating bridge: %s", err)
131
-	}
132
-	return nil
133
-}
134
-
135
-// Return the IPv4 address of a network interface
136
-func getIfaceAddr(name string) (net.Addr, error) {
137
-	iface, err := net.InterfaceByName(name)
138
-	if err != nil {
139
-		return nil, err
140
-	}
141
-	addrs, err := iface.Addrs()
142
-	if err != nil {
143
-		return nil, err
144
-	}
145
-	var addrs4 []net.Addr
146
-	for _, addr := range addrs {
147
-		ip := (addr.(*net.IPNet)).IP
148
-		if ip4 := ip.To4(); len(ip4) == net.IPv4len {
149
-			addrs4 = append(addrs4, addr)
150
-		}
151
-	}
152
-	switch {
153
-	case len(addrs4) == 0:
154
-		return nil, fmt.Errorf("Interface %v has no IP addresses", name)
155
-	case len(addrs4) > 1:
156
-		fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
157
-			name, (addrs4[0].(*net.IPNet)).IP)
158
-	}
159
-	return addrs4[0], nil
160
-}
161
-
162
-// Network interface represents the networking stack of a container
163
-type NetworkInterface struct {
164
-	IPNet   net.IPNet
165
-	Gateway net.IP
166
-
167
-	manager  *NetworkManager
168
-	extPorts []*Nat
169
-	disabled bool
170
-}
171
-
172
-// Allocate an external port and map it to the interface
173
-func (iface *NetworkInterface) AllocatePort(port Port, binding PortBinding) (*Nat, error) {
174
-
175
-	if iface.disabled {
176
-		return nil, fmt.Errorf("Trying to allocate port for interface %v, which is disabled", iface) // FIXME
177
-	}
178
-
179
-	ip := iface.manager.defaultBindingIP
180
-
181
-	if binding.HostIp != "" {
182
-		ip = net.ParseIP(binding.HostIp)
183
-	} else {
184
-		binding.HostIp = ip.String()
185
-	}
186
-
187
-	nat := &Nat{
188
-		Port:    port,
189
-		Binding: binding,
190
-	}
191
-
192
-	containerPort, err := parsePort(port.Port())
193
-	if err != nil {
194
-		return nil, err
195
-	}
196
-
197
-	hostPort, _ := parsePort(nat.Binding.HostPort)
198
-
199
-	extPort, err := portallocator.RequestPort(ip, nat.Port.Proto(), hostPort)
200
-	if err != nil {
201
-		return nil, err
202
-	}
203
-
204
-	var backend net.Addr
205
-	if nat.Port.Proto() == "tcp" {
206
-		backend = &net.TCPAddr{IP: iface.IPNet.IP, Port: containerPort}
207
-	} else {
208
-		backend = &net.UDPAddr{IP: iface.IPNet.IP, Port: containerPort}
209
-	}
210
-
211
-	if err := portmapper.Map(backend, ip, extPort); err != nil {
212
-		portallocator.ReleasePort(ip, nat.Port.Proto(), extPort)
213
-		return nil, err
214
-	}
215
-
216
-	nat.Binding.HostPort = strconv.Itoa(extPort)
217
-	iface.extPorts = append(iface.extPorts, nat)
218
-
219
-	return nat, nil
220
-}
221
-
222
-type Nat struct {
223
-	Port    Port
224
-	Binding PortBinding
225
-}
226
-
227
-func (n *Nat) String() string {
228
-	return fmt.Sprintf("%s:%s:%s/%s", n.Binding.HostIp, n.Binding.HostPort, n.Port.Port(), n.Port.Proto())
229
-}
230
-
231
-// Release: Network cleanup - release all resources
232
-func (iface *NetworkInterface) Release() {
233
-	if iface.disabled {
234
-		return
235
-	}
236
-
237
-	for _, nat := range iface.extPorts {
238
-		hostPort, err := parsePort(nat.Binding.HostPort)
239
-		if err != nil {
240
-			log.Printf("Unable to get host port: %s", err)
241
-			continue
242
-		}
243
-		ip := net.ParseIP(nat.Binding.HostIp)
244
-		utils.Debugf("Unmaping %s/%s:%s", nat.Port.Proto, ip.String(), nat.Binding.HostPort)
245
-
246
-		var host net.Addr
247
-		if nat.Port.Proto() == "tcp" {
248
-			host = &net.TCPAddr{IP: ip, Port: hostPort}
249
-		} else {
250
-			host = &net.UDPAddr{IP: ip, Port: hostPort}
251
-		}
252
-
253
-		if err := portmapper.Unmap(host); err != nil {
254
-			log.Printf("Unable to unmap port %s: %s", nat, err)
255
-		}
256
-
257
-		if err := portallocator.ReleasePort(ip, nat.Port.Proto(), hostPort); err != nil {
258
-			log.Printf("Unable to release port %s", nat)
259
-		}
260
-	}
261
-
262
-	if err := ipallocator.ReleaseIP(iface.manager.bridgeNetwork, &iface.IPNet.IP); err != nil {
263
-		log.Printf("Unable to release ip %s\n", err)
264
-	}
265
-}
266
-
267
-// Network Manager manages a set of network interfaces
268
-// Only *one* manager per host machine should be used
269
-type NetworkManager struct {
270
-	bridgeIface      string
271
-	bridgeNetwork    *net.IPNet
272
-	defaultBindingIP net.IP
273
-	disabled         bool
274
-}
275
-
276
-// Allocate a network interface
277
-func (manager *NetworkManager) Allocate() (*NetworkInterface, error) {
278
-
279
-	if manager.disabled {
280
-		return &NetworkInterface{disabled: true}, nil
281
-	}
282
-
283
-	var ip *net.IP
284
-	var err error
285
-
286
-	ip, err = ipallocator.RequestIP(manager.bridgeNetwork, nil)
287
-	if err != nil {
288
-		return nil, err
289
-	}
290
-
291
-	iface := &NetworkInterface{
292
-		IPNet:   net.IPNet{IP: *ip, Mask: manager.bridgeNetwork.Mask},
293
-		Gateway: manager.bridgeNetwork.IP,
294
-		manager: manager,
295
-	}
296
-	return iface, nil
297
-}
298
-
299
-func newNetworkManager(config *DaemonConfig) (*NetworkManager, error) {
300
-	if config.BridgeIface == DisableNetworkBridge {
301
-		manager := &NetworkManager{
302
-			disabled: true,
303
-		}
304
-		return manager, nil
305
-	}
306
-
307
-	var network *net.IPNet
308
-	addr, err := getIfaceAddr(config.BridgeIface)
309
-	if err != nil {
310
-		// If the iface is not found, try to create it
311
-		if err := CreateBridgeIface(config); err != nil {
312
-			return nil, err
313
-		}
314
-		addr, err = getIfaceAddr(config.BridgeIface)
315
-		if err != nil {
316
-			return nil, err
317
-		}
318
-		network = addr.(*net.IPNet)
319
-	} else {
320
-		network = addr.(*net.IPNet)
321
-	}
322
-
323
-	// Configure iptables for link support
324
-	if config.EnableIptables {
325
-
326
-		// Enable NAT
327
-		natArgs := []string{"POSTROUTING", "-t", "nat", "-s", addr.String(), "!", "-d", addr.String(), "-j", "MASQUERADE"}
328
-
329
-		if !iptables.Exists(natArgs...) {
330
-			if output, err := iptables.Raw(append([]string{"-I"}, natArgs...)...); err != nil {
331
-				return nil, fmt.Errorf("Unable to enable network bridge NAT: %s", err)
332
-			} else if len(output) != 0 {
333
-				return nil, fmt.Errorf("Error iptables postrouting: %s", output)
334
-			}
335
-		}
336
-
337
-		args := []string{"FORWARD", "-i", config.BridgeIface, "-o", config.BridgeIface, "-j"}
338
-		acceptArgs := append(args, "ACCEPT")
339
-		dropArgs := append(args, "DROP")
340
-
341
-		if !config.InterContainerCommunication {
342
-			iptables.Raw(append([]string{"-D"}, acceptArgs...)...)
343
-			if !iptables.Exists(dropArgs...) {
344
-				utils.Debugf("Disable inter-container communication")
345
-				if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil {
346
-					return nil, fmt.Errorf("Unable to prevent intercontainer communication: %s", err)
347
-				} else if len(output) != 0 {
348
-					return nil, fmt.Errorf("Error disabling intercontainer communication: %s", output)
349
-				}
350
-			}
351
-		} else {
352
-			iptables.Raw(append([]string{"-D"}, dropArgs...)...)
353
-			if !iptables.Exists(acceptArgs...) {
354
-				utils.Debugf("Enable inter-container communication")
355
-				if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil {
356
-					return nil, fmt.Errorf("Unable to allow intercontainer communication: %s", err)
357
-				} else if len(output) != 0 {
358
-					return nil, fmt.Errorf("Error enabling intercontainer communication: %s", output)
359
-				}
360
-			}
361
-		}
362
-
363
-		// Accept all non-intercontainer outgoing packets
364
-		outgoingArgs := []string{"FORWARD", "-i", config.BridgeIface, "!", "-o", config.BridgeIface, "-j", "ACCEPT"}
365
-
366
-		if !iptables.Exists(outgoingArgs...) {
367
-			if output, err := iptables.Raw(append([]string{"-I"}, outgoingArgs...)...); err != nil {
368
-				return nil, fmt.Errorf("Unable to allow outgoing packets: %s", err)
369
-			} else if len(output) != 0 {
370
-				return nil, fmt.Errorf("Error iptables allow outgoing: %s", output)
371
-			}
372
-		}
373
-
374
-		// Accept incoming packets for existing connections
375
-		existingArgs := []string{"FORWARD", "-o", config.BridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}
376
-
377
-		if !iptables.Exists(existingArgs...) {
378
-			if output, err := iptables.Raw(append([]string{"-I"}, existingArgs...)...); err != nil {
379
-				return nil, fmt.Errorf("Unable to allow incoming packets: %s", err)
380
-			} else if len(output) != 0 {
381
-				return nil, fmt.Errorf("Error iptables allow incoming: %s", output)
382
-			}
383
-		}
384
-
385
-	}
386
-
387
-	if config.EnableIpForward {
388
-		// Enable IPv4 forwarding
389
-		if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
390
-			log.Printf("WARNING: unable to enable IPv4 forwarding: %s\n", err)
391
-		}
392
-	}
393
-
394
-	// We can always try removing the iptables
395
-	if err := iptables.RemoveExistingChain("DOCKER"); err != nil {
396
-		return nil, err
397
-	}
398
-
399
-	if config.EnableIptables {
400
-		chain, err := iptables.NewChain("DOCKER", config.BridgeIface)
401
-		if err != nil {
402
-			return nil, err
403
-		}
404
-		portmapper.SetIptablesChain(chain)
405
-	}
406
-
407
-	manager := &NetworkManager{
408
-		bridgeIface:      config.BridgeIface,
409
-		bridgeNetwork:    network,
410
-		defaultBindingIP: config.DefaultIp,
411
-	}
412
-	return manager, nil
413
-}
414 1
new file mode 100644
... ...
@@ -0,0 +1,471 @@
0
+package lxc
1
+
2
+import (
3
+	"fmt"
4
+	"github.com/dotcloud/docker/engine"
5
+	"github.com/dotcloud/docker/networkdriver"
6
+	"github.com/dotcloud/docker/networkdriver/ipallocator"
7
+	"github.com/dotcloud/docker/networkdriver/portallocator"
8
+	"github.com/dotcloud/docker/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 init() {
60
+	if err := engine.Register("init_networkdriver", InitDriver); err != nil {
61
+		panic(err)
62
+	}
63
+}
64
+
65
+func InitDriver(job *engine.Job) engine.Status {
66
+	var (
67
+		network        *net.IPNet
68
+		enableIPTables = job.GetenvBool("EnableIptables")
69
+		icc            = job.GetenvBool("InterContainerCommunication")
70
+		ipForward      = job.GetenvBool("EnableIpForward")
71
+		bridgeIP       = job.Getenv("BridgeIP")
72
+	)
73
+
74
+	if defaultIP := job.Getenv("DefaultBindingIP"); defaultIP != "" {
75
+		defaultBindingIP = net.ParseIP(defaultIP)
76
+	}
77
+
78
+	bridgeIface = job.Getenv("BridgeIface")
79
+	if bridgeIface == "" {
80
+		bridgeIface = DefaultNetworkBridge
81
+	}
82
+
83
+	addr, err := networkdriver.GetIfaceAddr(bridgeIface)
84
+	if err != nil {
85
+		// If the iface is not found, try to create it
86
+		job.Logf("creating new bridge for %s", bridgeIface)
87
+		if err := createBridge(bridgeIP); err != nil {
88
+			job.Error(err)
89
+			return engine.StatusErr
90
+		}
91
+
92
+		job.Logf("getting iface addr")
93
+		addr, err = networkdriver.GetIfaceAddr(bridgeIface)
94
+		if err != nil {
95
+			job.Error(err)
96
+			return engine.StatusErr
97
+		}
98
+		network = addr.(*net.IPNet)
99
+	} else {
100
+		network = addr.(*net.IPNet)
101
+	}
102
+
103
+	// Configure iptables for link support
104
+	if enableIPTables {
105
+		if err := setupIPTables(addr, icc); err != nil {
106
+			job.Error(err)
107
+			return engine.StatusErr
108
+		}
109
+	}
110
+
111
+	if ipForward {
112
+		// Enable IPv4 forwarding
113
+		if err := ioutil.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte{'1', '\n'}, 0644); err != nil {
114
+			job.Logf("WARNING: unable to enable IPv4 forwarding: %s\n", err)
115
+		}
116
+	}
117
+
118
+	// We can always try removing the iptables
119
+	if err := iptables.RemoveExistingChain("DOCKER"); err != nil {
120
+		job.Error(err)
121
+		return engine.StatusErr
122
+	}
123
+
124
+	if enableIPTables {
125
+		chain, err := iptables.NewChain("DOCKER", bridgeIface)
126
+		if err != nil {
127
+			job.Error(err)
128
+			return engine.StatusErr
129
+		}
130
+		portmapper.SetIptablesChain(chain)
131
+	}
132
+
133
+	bridgeNetwork = network
134
+
135
+	// https://github.com/dotcloud/docker/issues/2768
136
+	job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", bridgeNetwork.IP)
137
+
138
+	for name, f := range map[string]engine.Handler{
139
+		"allocate_interface": Allocate,
140
+		"release_interface":  Release,
141
+		"allocate_port":      AllocatePort,
142
+		"link":               LinkContainers,
143
+	} {
144
+		if err := job.Eng.Register(name, f); err != nil {
145
+			job.Error(err)
146
+			return engine.StatusErr
147
+		}
148
+	}
149
+	return engine.StatusOK
150
+}
151
+
152
+func setupIPTables(addr net.Addr, icc bool) error {
153
+	// Enable NAT
154
+	natArgs := []string{"POSTROUTING", "-t", "nat", "-s", addr.String(), "!", "-d", addr.String(), "-j", "MASQUERADE"}
155
+
156
+	if !iptables.Exists(natArgs...) {
157
+		if output, err := iptables.Raw(append([]string{"-I"}, natArgs...)...); err != nil {
158
+			return fmt.Errorf("Unable to enable network bridge NAT: %s", err)
159
+		} else if len(output) != 0 {
160
+			return fmt.Errorf("Error iptables postrouting: %s", output)
161
+		}
162
+	}
163
+
164
+	var (
165
+		args       = []string{"FORWARD", "-i", bridgeIface, "-o", bridgeIface, "-j"}
166
+		acceptArgs = append(args, "ACCEPT")
167
+		dropArgs   = append(args, "DROP")
168
+	)
169
+
170
+	if !icc {
171
+		iptables.Raw(append([]string{"-D"}, acceptArgs...)...)
172
+
173
+		if !iptables.Exists(dropArgs...) {
174
+
175
+			utils.Debugf("Disable inter-container communication")
176
+			if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil {
177
+				return fmt.Errorf("Unable to prevent intercontainer communication: %s", err)
178
+			} else if len(output) != 0 {
179
+				return fmt.Errorf("Error disabling intercontainer communication: %s", output)
180
+			}
181
+		}
182
+	} else {
183
+		iptables.Raw(append([]string{"-D"}, dropArgs...)...)
184
+
185
+		if !iptables.Exists(acceptArgs...) {
186
+			utils.Debugf("Enable inter-container communication")
187
+			if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil {
188
+				return fmt.Errorf("Unable to allow intercontainer communication: %s", err)
189
+			} else if len(output) != 0 {
190
+				return fmt.Errorf("Error enabling intercontainer communication: %s", output)
191
+			}
192
+		}
193
+	}
194
+
195
+	// Accept all non-intercontainer outgoing packets
196
+	outgoingArgs := []string{"FORWARD", "-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}
197
+	if !iptables.Exists(outgoingArgs...) {
198
+		if output, err := iptables.Raw(append([]string{"-I"}, outgoingArgs...)...); err != nil {
199
+			return fmt.Errorf("Unable to allow outgoing packets: %s", err)
200
+		} else if len(output) != 0 {
201
+			return fmt.Errorf("Error iptables allow outgoing: %s", output)
202
+		}
203
+	}
204
+
205
+	// Accept incoming packets for existing connections
206
+	existingArgs := []string{"FORWARD", "-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}
207
+
208
+	if !iptables.Exists(existingArgs...) {
209
+		if output, err := iptables.Raw(append([]string{"-I"}, existingArgs...)...); err != nil {
210
+			return fmt.Errorf("Unable to allow incoming packets: %s", err)
211
+		} else if len(output) != 0 {
212
+			return fmt.Errorf("Error iptables allow incoming: %s", output)
213
+		}
214
+	}
215
+	return nil
216
+}
217
+
218
+// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`,
219
+// and attempts to configure it with an address which doesn't conflict with any other interface on the host.
220
+// If it can't find an address which doesn't conflict, it will return an error.
221
+func createBridge(bridgeIP string) error {
222
+	nameservers := []string{}
223
+	resolvConf, _ := utils.GetResolvConf()
224
+	// we don't check for an error here, because we don't really care
225
+	// if we can't read /etc/resolv.conf. So instead we skip the append
226
+	// if resolvConf is nil. It either doesn't exist, or we can't read it
227
+	// for some reason.
228
+	if resolvConf != nil {
229
+		nameservers = append(nameservers, utils.GetNameserversAsCIDR(resolvConf)...)
230
+	}
231
+
232
+	var ifaceAddr string
233
+	if len(bridgeIP) != 0 {
234
+		_, _, err := net.ParseCIDR(bridgeIP)
235
+		if err != nil {
236
+			return err
237
+		}
238
+		ifaceAddr = bridgeIP
239
+	} else {
240
+		for _, addr := range addrs {
241
+			_, dockerNetwork, err := net.ParseCIDR(addr)
242
+			if err != nil {
243
+				return err
244
+			}
245
+			if err := networkdriver.CheckNameserverOverlaps(nameservers, dockerNetwork); err == nil {
246
+				if err := networkdriver.CheckRouteOverlaps(dockerNetwork); err == nil {
247
+					ifaceAddr = addr
248
+					break
249
+				} else {
250
+					utils.Debugf("%s %s", addr, err)
251
+				}
252
+			}
253
+		}
254
+	}
255
+
256
+	if ifaceAddr == "" {
257
+		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)
258
+	}
259
+	utils.Debugf("Creating bridge %s with network %s", bridgeIface, ifaceAddr)
260
+
261
+	if err := createBridgeIface(bridgeIface); err != nil {
262
+		return err
263
+	}
264
+
265
+	iface, err := net.InterfaceByName(bridgeIface)
266
+	if err != nil {
267
+		return err
268
+	}
269
+
270
+	ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr)
271
+	if err != nil {
272
+		return err
273
+	}
274
+
275
+	if netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
276
+		return fmt.Errorf("Unable to add private network: %s", err)
277
+	}
278
+	if err := netlink.NetworkLinkUp(iface); err != nil {
279
+		return fmt.Errorf("Unable to start network bridge: %s", err)
280
+	}
281
+	return nil
282
+}
283
+
284
+// Create the actual bridge device.  This is more backward-compatible than
285
+// netlink.NetworkLinkAdd and works on RHEL 6.
286
+func createBridgeIface(name string) error {
287
+	s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_IP)
288
+	if err != nil {
289
+		utils.Debugf("Bridge socket creation failed IPv6 probably not enabled: %v", err)
290
+		s, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_IP)
291
+		if err != nil {
292
+			return fmt.Errorf("Error creating bridge creation socket: %s", err)
293
+		}
294
+	}
295
+	defer syscall.Close(s)
296
+
297
+	nameBytePtr, err := syscall.BytePtrFromString(name)
298
+	if err != nil {
299
+		return fmt.Errorf("Error converting bridge name %s to byte array: %s", name, err)
300
+	}
301
+
302
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), siocBRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
303
+		return fmt.Errorf("Error creating bridge: %s", err)
304
+	}
305
+	return nil
306
+}
307
+
308
+// Allocate a network interface
309
+func Allocate(job *engine.Job) engine.Status {
310
+	var (
311
+		ip          *net.IP
312
+		err         error
313
+		id          = job.Args[0]
314
+		requestedIP = net.ParseIP(job.Getenv("RequestedIP"))
315
+	)
316
+
317
+	if requestedIP != nil {
318
+		ip, err = ipallocator.RequestIP(bridgeNetwork, &requestedIP)
319
+	} else {
320
+		ip, err = ipallocator.RequestIP(bridgeNetwork, nil)
321
+	}
322
+	if err != nil {
323
+		job.Error(err)
324
+		return engine.StatusErr
325
+	}
326
+
327
+	out := engine.Env{}
328
+	out.Set("IP", ip.String())
329
+	out.Set("Mask", bridgeNetwork.Mask.String())
330
+	out.Set("Gateway", bridgeNetwork.IP.String())
331
+	out.Set("Bridge", bridgeIface)
332
+
333
+	size, _ := bridgeNetwork.Mask.Size()
334
+	out.SetInt("IPPrefixLen", size)
335
+
336
+	currentInterfaces[id] = &networkInterface{
337
+		IP: *ip,
338
+	}
339
+
340
+	out.WriteTo(job.Stdout)
341
+
342
+	return engine.StatusOK
343
+}
344
+
345
+// release an interface for a select ip
346
+func Release(job *engine.Job) engine.Status {
347
+	var (
348
+		id                 = job.Args[0]
349
+		containerInterface = currentInterfaces[id]
350
+		ip                 net.IP
351
+		port               int
352
+		proto              string
353
+	)
354
+
355
+	for _, nat := range containerInterface.PortMappings {
356
+		if err := portmapper.Unmap(nat); err != nil {
357
+			log.Printf("Unable to unmap port %s: %s", nat, err)
358
+		}
359
+
360
+		// this is host mappings
361
+		switch a := nat.(type) {
362
+		case *net.TCPAddr:
363
+			proto = "tcp"
364
+			ip = a.IP
365
+			port = a.Port
366
+		case *net.UDPAddr:
367
+			proto = "udp"
368
+			ip = a.IP
369
+			port = a.Port
370
+		}
371
+
372
+		if err := portallocator.ReleasePort(ip, proto, port); err != nil {
373
+			log.Printf("Unable to release port %s", nat)
374
+		}
375
+	}
376
+
377
+	if err := ipallocator.ReleaseIP(bridgeNetwork, &containerInterface.IP); err != nil {
378
+		log.Printf("Unable to release ip %s\n", err)
379
+	}
380
+	return engine.StatusOK
381
+}
382
+
383
+// Allocate an external port and map it to the interface
384
+func AllocatePort(job *engine.Job) engine.Status {
385
+	var (
386
+		err error
387
+
388
+		ip            = defaultBindingIP
389
+		id            = job.Args[0]
390
+		hostIP        = job.Getenv("HostIP")
391
+		hostPort      = job.GetenvInt("HostPort")
392
+		containerPort = job.GetenvInt("ContainerPort")
393
+		proto         = job.Getenv("Proto")
394
+		network       = currentInterfaces[id]
395
+	)
396
+
397
+	if hostIP != "" {
398
+		ip = net.ParseIP(hostIP)
399
+	}
400
+
401
+	// host ip, proto, and host port
402
+	hostPort, err = portallocator.RequestPort(ip, proto, hostPort)
403
+	if err != nil {
404
+		job.Error(err)
405
+		return engine.StatusErr
406
+	}
407
+
408
+	var (
409
+		container net.Addr
410
+		host      net.Addr
411
+	)
412
+
413
+	if proto == "tcp" {
414
+		host = &net.TCPAddr{IP: ip, Port: hostPort}
415
+		container = &net.TCPAddr{IP: network.IP, Port: containerPort}
416
+	} else {
417
+		host = &net.UDPAddr{IP: ip, Port: hostPort}
418
+		container = &net.UDPAddr{IP: network.IP, Port: containerPort}
419
+	}
420
+
421
+	if err := portmapper.Map(container, ip, hostPort); err != nil {
422
+		portallocator.ReleasePort(ip, proto, hostPort)
423
+
424
+		job.Error(err)
425
+		return engine.StatusErr
426
+	}
427
+	network.PortMappings = append(network.PortMappings, host)
428
+
429
+	out := engine.Env{}
430
+	out.Set("HostIP", ip.String())
431
+	out.SetInt("HostPort", hostPort)
432
+
433
+	if _, err := out.WriteTo(job.Stdout); err != nil {
434
+		job.Error(err)
435
+		return engine.StatusErr
436
+	}
437
+	return engine.StatusOK
438
+}
439
+
440
+func LinkContainers(job *engine.Job) engine.Status {
441
+	var (
442
+		action       = job.Args[0]
443
+		childIP      = job.Getenv("ChildIP")
444
+		parentIP     = job.Getenv("ParentIP")
445
+		ignoreErrors = job.GetenvBool("IgnoreErrors")
446
+		ports        = job.GetenvList("Ports")
447
+	)
448
+	split := func(p string) (string, string) {
449
+		parts := strings.Split(p, "/")
450
+		return parts[0], parts[1]
451
+	}
452
+
453
+	for _, p := range ports {
454
+		port, proto := split(p)
455
+		if output, err := iptables.Raw(action, "FORWARD",
456
+			"-i", bridgeIface, "-o", bridgeIface,
457
+			"-p", proto,
458
+			"-s", parentIP,
459
+			"--dport", port,
460
+			"-d", childIP,
461
+			"-j", "ACCEPT"); !ignoreErrors && err != nil {
462
+			job.Error(err)
463
+			return engine.StatusErr
464
+		} else if len(output) != 0 {
465
+			job.Errorf("Error toggle iptables forward: %s", output)
466
+			return engine.StatusErr
467
+		}
468
+	}
469
+	return engine.StatusOK
470
+}
... ...
@@ -1,80 +1,10 @@
1 1
 package networkdriver
2 2
 
3 3
 import (
4
-	"encoding/binary"
5 4
 	"errors"
6
-	"github.com/dotcloud/docker/pkg/netlink"
7
-	"net"
8 5
 )
9 6
 
10 7
 var (
11 8
 	ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver")
12 9
 	ErrNetworkOverlaps                = errors.New("requested network overlaps with existing network")
13 10
 )
14
-
15
-var (
16
-	networkGetRoutesFct = netlink.NetworkGetRoutes
17
-)
18
-
19
-func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
20
-	if len(nameservers) > 0 {
21
-		for _, ns := range nameservers {
22
-			_, nsNetwork, err := net.ParseCIDR(ns)
23
-			if err != nil {
24
-				return err
25
-			}
26
-			if NetworkOverlaps(toCheck, nsNetwork) {
27
-				return ErrNetworkOverlapsWithNameservers
28
-			}
29
-		}
30
-	}
31
-	return nil
32
-}
33
-
34
-func CheckRouteOverlaps(toCheck *net.IPNet) error {
35
-	networks, err := networkGetRoutesFct()
36
-	if err != nil {
37
-		return err
38
-	}
39
-
40
-	for _, network := range networks {
41
-		if network.IPNet != nil && NetworkOverlaps(toCheck, network.IPNet) {
42
-			return ErrNetworkOverlaps
43
-		}
44
-	}
45
-	return nil
46
-}
47
-
48
-// Detects overlap between one IPNet and another
49
-func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
50
-	if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) {
51
-		return true
52
-	}
53
-	if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) {
54
-		return true
55
-	}
56
-	return false
57
-}
58
-
59
-// Calculates the first and last IP addresses in an IPNet
60
-func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
61
-	var (
62
-		netIP   = network.IP.To4()
63
-		firstIP = netIP.Mask(network.Mask)
64
-		lastIP  = net.IPv4(0, 0, 0, 0).To4()
65
-	)
66
-
67
-	for i := 0; i < len(lastIP); i++ {
68
-		lastIP[i] = netIP[i] | ^network.Mask[i]
69
-	}
70
-	return firstIP, lastIP
71
-}
72
-
73
-// Given a netmask, calculates the number of available hosts
74
-func NetworkSize(mask net.IPMask) int32 {
75
-	m := net.IPv4Mask(0, 0, 0, 0)
76
-	for i := 0; i < net.IPv4len; i++ {
77
-		m[i] = ^mask[i]
78
-	}
79
-	return int32(binary.BigEndian.Uint32(m)) + 1
80
-}
... ...
@@ -51,7 +51,7 @@ func RequestPort(ip net.IP, proto string, port int) (int, error) {
51 51
 	}
52 52
 
53 53
 	// If the user requested a specific port to be allocated
54
-	if port != 0 {
54
+	if port > 0 {
55 55
 		if err := registerSetPort(ip, proto, port); err != nil {
56 56
 			return 0, err
57 57
 		}
58 58
new file mode 100644
... ...
@@ -0,0 +1,102 @@
0
+package networkdriver
1
+
2
+import (
3
+	"encoding/binary"
4
+	"fmt"
5
+	"github.com/dotcloud/docker/pkg/netlink"
6
+	"net"
7
+)
8
+
9
+var (
10
+	networkGetRoutesFct = netlink.NetworkGetRoutes
11
+)
12
+
13
+func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
14
+	if len(nameservers) > 0 {
15
+		for _, ns := range nameservers {
16
+			_, nsNetwork, err := net.ParseCIDR(ns)
17
+			if err != nil {
18
+				return err
19
+			}
20
+			if NetworkOverlaps(toCheck, nsNetwork) {
21
+				return ErrNetworkOverlapsWithNameservers
22
+			}
23
+		}
24
+	}
25
+	return nil
26
+}
27
+
28
+func CheckRouteOverlaps(toCheck *net.IPNet) error {
29
+	networks, err := networkGetRoutesFct()
30
+	if err != nil {
31
+		return err
32
+	}
33
+
34
+	for _, network := range networks {
35
+		if network.IPNet != nil && NetworkOverlaps(toCheck, network.IPNet) {
36
+			return ErrNetworkOverlaps
37
+		}
38
+	}
39
+	return nil
40
+}
41
+
42
+// Detects overlap between one IPNet and another
43
+func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
44
+	if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) {
45
+		return true
46
+	}
47
+	if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) {
48
+		return true
49
+	}
50
+	return false
51
+}
52
+
53
+// Calculates the first and last IP addresses in an IPNet
54
+func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
55
+	var (
56
+		netIP   = network.IP.To4()
57
+		firstIP = netIP.Mask(network.Mask)
58
+		lastIP  = net.IPv4(0, 0, 0, 0).To4()
59
+	)
60
+
61
+	for i := 0; i < len(lastIP); i++ {
62
+		lastIP[i] = netIP[i] | ^network.Mask[i]
63
+	}
64
+	return firstIP, lastIP
65
+}
66
+
67
+// Given a netmask, calculates the number of available hosts
68
+func NetworkSize(mask net.IPMask) int32 {
69
+	m := net.IPv4Mask(0, 0, 0, 0)
70
+	for i := 0; i < net.IPv4len; i++ {
71
+		m[i] = ^mask[i]
72
+	}
73
+	return int32(binary.BigEndian.Uint32(m)) + 1
74
+}
75
+
76
+// Return the IPv4 address of a network interface
77
+func GetIfaceAddr(name string) (net.Addr, error) {
78
+	iface, err := net.InterfaceByName(name)
79
+	if err != nil {
80
+		return nil, err
81
+	}
82
+	addrs, err := iface.Addrs()
83
+	if err != nil {
84
+		return nil, err
85
+	}
86
+	var addrs4 []net.Addr
87
+	for _, addr := range addrs {
88
+		ip := (addr.(*net.IPNet)).IP
89
+		if ip4 := ip.To4(); len(ip4) == net.IPv4len {
90
+			addrs4 = append(addrs4, addr)
91
+		}
92
+	}
93
+	switch {
94
+	case len(addrs4) == 0:
95
+		return nil, fmt.Errorf("Interface %v has no IP addresses", name)
96
+	case len(addrs4) > 1:
97
+		fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
98
+			name, (addrs4[0].(*net.IPNet)).IP)
99
+	}
100
+	return addrs4[0], nil
101
+}
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"container/list"
5 5
 	"fmt"
6 6
 	"github.com/dotcloud/docker/archive"
7
+	"github.com/dotcloud/docker/engine"
7 8
 	"github.com/dotcloud/docker/execdriver"
8 9
 	"github.com/dotcloud/docker/execdriver/chroot"
9 10
 	"github.com/dotcloud/docker/execdriver/lxc"
... ...
@@ -12,6 +13,7 @@ import (
12 12
 	_ "github.com/dotcloud/docker/graphdriver/btrfs"
13 13
 	_ "github.com/dotcloud/docker/graphdriver/devmapper"
14 14
 	_ "github.com/dotcloud/docker/graphdriver/vfs"
15
+	_ "github.com/dotcloud/docker/networkdriver/lxc"
15 16
 	"github.com/dotcloud/docker/networkdriver/portallocator"
16 17
 	"github.com/dotcloud/docker/pkg/graphdb"
17 18
 	"github.com/dotcloud/docker/pkg/sysinfo"
... ...
@@ -42,13 +44,13 @@ type Runtime struct {
42 42
 	repository     string
43 43
 	sysInitPath    string
44 44
 	containers     *list.List
45
-	networkManager *NetworkManager
46 45
 	graph          *Graph
47 46
 	repositories   *TagStore
48 47
 	idIndex        *utils.TruncIndex
49 48
 	sysInfo        *sysinfo.SysInfo
50 49
 	volumes        *Graph
51 50
 	srv            *Server
51
+	eng            *engine.Engine
52 52
 	config         *DaemonConfig
53 53
 	containerGraph *graphdb.Database
54 54
 	driver         graphdriver.Driver
... ...
@@ -609,15 +611,15 @@ func (runtime *Runtime) RegisterLink(parent, child *Container, alias string) err
609 609
 }
610 610
 
611 611
 // FIXME: harmonize with NewGraph()
612
-func NewRuntime(config *DaemonConfig) (*Runtime, error) {
613
-	runtime, err := NewRuntimeFromDirectory(config)
612
+func NewRuntime(config *DaemonConfig, eng *engine.Engine) (*Runtime, error) {
613
+	runtime, err := NewRuntimeFromDirectory(config, eng)
614 614
 	if err != nil {
615 615
 		return nil, err
616 616
 	}
617 617
 	return runtime, nil
618 618
 }
619 619
 
620
-func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) {
620
+func NewRuntimeFromDirectory(config *DaemonConfig, eng *engine.Engine) (*Runtime, error) {
621 621
 
622 622
 	// Set the default driver
623 623
 	graphdriver.DefaultDriver = config.GraphDriver
... ...
@@ -664,12 +666,20 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) {
664 664
 	if err != nil {
665 665
 		return nil, fmt.Errorf("Couldn't create Tag store: %s", err)
666 666
 	}
667
-	if config.BridgeIface == "" {
668
-		config.BridgeIface = DefaultNetworkBridge
669
-	}
670
-	netManager, err := newNetworkManager(config)
671
-	if err != nil {
672
-		return nil, err
667
+
668
+	if !config.DisableNetwork {
669
+		job := eng.Job("init_networkdriver")
670
+
671
+		job.SetenvBool("EnableIptables", config.EnableIptables)
672
+		job.SetenvBool("InterContainerCommunication", config.InterContainerCommunication)
673
+		job.SetenvBool("EnableIpForward", config.EnableIpForward)
674
+		job.Setenv("BridgeIface", config.BridgeIface)
675
+		job.Setenv("BridgeIP", config.BridgeIP)
676
+		job.Setenv("DefaultBindingIP", config.DefaultIp.String())
677
+
678
+		if err := job.Run(); err != nil {
679
+			return nil, err
680
+		}
673 681
 	}
674 682
 
675 683
 	graphdbPath := path.Join(config.Root, "linkgraph.db")
... ...
@@ -721,7 +731,6 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) {
721 721
 	runtime := &Runtime{
722 722
 		repository:     runtimeRepo,
723 723
 		containers:     list.New(),
724
-		networkManager: netManager,
725 724
 		graph:          g,
726 725
 		repositories:   repositories,
727 726
 		idIndex:        utils.NewTruncIndex(),
... ...
@@ -732,6 +741,7 @@ func NewRuntimeFromDirectory(config *DaemonConfig) (*Runtime, error) {
732 732
 		driver:         driver,
733 733
 		sysInitPath:    sysInitPath,
734 734
 		execDriver:     ed,
735
+		eng:            eng,
735 736
 	}
736 737
 
737 738
 	if err := runtime.restore(); err != nil {
... ...
@@ -64,10 +64,7 @@ func jobInitServer(job *engine.Job) engine.Status {
64 64
 	}()
65 65
 	job.Eng.Hack_SetGlobalVar("httpapi.server", srv)
66 66
 	job.Eng.Hack_SetGlobalVar("httpapi.runtime", srv.runtime)
67
-	// https://github.com/dotcloud/docker/issues/2768
68
-	if srv.runtime.networkManager.bridgeNetwork != nil {
69
-		job.Eng.Hack_SetGlobalVar("httpapi.bridgeIP", srv.runtime.networkManager.bridgeNetwork.IP)
70
-	}
67
+
71 68
 	for name, handler := range map[string]engine.Handler{
72 69
 		"export":           srv.ContainerExport,
73 70
 		"create":           srv.ContainerCreate,
... ...
@@ -2325,7 +2322,7 @@ func (srv *Server) ContainerCopy(job *engine.Job) engine.Status {
2325 2325
 }
2326 2326
 
2327 2327
 func NewServer(eng *engine.Engine, config *DaemonConfig) (*Server, error) {
2328
-	runtime, err := NewRuntime(config)
2328
+	runtime, err := NewRuntime(config, eng)
2329 2329
 	if err != nil {
2330 2330
 		return nil, err
2331 2331
 	}