Browse code

Docker integration with libnetwork

- Updated Dockerfile to satisfy libnetwork GOPATH requirements.
- Reworked daemon to allocate network resources using libnetwork.
- Reworked remove link code to also update network resources in libnetwork.
- Adjusted the exec driver command population to reflect libnetwork design.
- Adjusted the exec driver create command steps.
- Updated a few test cases to reflect the change in design.
- Removed the dns setup code from docker as resolv.conf is entirely managed
in libnetwork.
- Integrated with lxc exec driver.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>

Jana Radhakrishnan authored on 2015/05/07 07:39:29
Showing 20 changed files
... ...
@@ -9,6 +9,7 @@ DOCKER_ENVS := \
9 9
 	-e DOCKER_EXECDRIVER \
10 10
 	-e DOCKER_GRAPHDRIVER \
11 11
 	-e DOCKER_STORAGE_OPTS \
12
+	-e DOCKER_USERLANDPROXY \
12 13
 	-e TESTDIRS \
13 14
 	-e TESTFLAGS \
14 15
 	-e TIMEOUT
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"github.com/docker/docker/pkg/resolvconf/dns"
13 13
 	"github.com/docker/docker/pkg/signal"
14 14
 	"github.com/docker/docker/runconfig"
15
+	"github.com/docker/libnetwork/resolvconf/dns"
15 16
 )
16 17
 
17 18
 func (cid *cidFile) Close() error {
... ...
@@ -23,7 +23,6 @@ import (
23 23
 	"github.com/docker/docker/builder"
24 24
 	"github.com/docker/docker/cliconfig"
25 25
 	"github.com/docker/docker/daemon"
26
-	"github.com/docker/docker/daemon/networkdriver/bridge"
27 26
 	"github.com/docker/docker/graph"
28 27
 	"github.com/docker/docker/pkg/ioutils"
29 28
 	"github.com/docker/docker/pkg/jsonmessage"
... ...
@@ -36,6 +35,7 @@ import (
36 36
 	"github.com/docker/docker/pkg/version"
37 37
 	"github.com/docker/docker/runconfig"
38 38
 	"github.com/docker/docker/utils"
39
+	"github.com/docker/libnetwork/portallocator"
39 40
 )
40 41
 
41 42
 type ServerConfig struct {
... ...
@@ -1548,8 +1548,9 @@ func allocateDaemonPort(addr string) error {
1548 1548
 		return fmt.Errorf("failed to lookup %s address in host specification", host)
1549 1549
 	}
1550 1550
 
1551
+	pa := portallocator.Get()
1551 1552
 	for _, hostIP := range hostIPs {
1552
-		if _, err := bridge.RequestPort(hostIP, "tcp", intPort); err != nil {
1553
+		if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil {
1553 1554
 			return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err)
1554 1555
 		}
1555 1556
 	}
... ...
@@ -1,8 +1,8 @@
1 1
 package daemon
2 2
 
3 3
 import (
4
-	"github.com/docker/docker/daemon/networkdriver"
5
-	"github.com/docker/docker/daemon/networkdriver/bridge"
4
+	"net"
5
+
6 6
 	"github.com/docker/docker/opts"
7 7
 	flag "github.com/docker/docker/pkg/mflag"
8 8
 	"github.com/docker/docker/runconfig"
... ...
@@ -16,8 +16,9 @@ const (
16 16
 // CommonConfig defines the configuration of a docker daemon which are
17 17
 // common across platforms.
18 18
 type CommonConfig struct {
19
-	AutoRestart    bool
20
-	Bridge         bridge.Config
19
+	AutoRestart bool
20
+	// Bridge holds bridge network specific configuration.
21
+	Bridge         bridgeConfig
21 22
 	Context        map[string][]string
22 23
 	CorsHeaders    string
23 24
 	DisableNetwork bool
... ...
@@ -35,6 +36,24 @@ type CommonConfig struct {
35 35
 	TrustKeyPath   string
36 36
 }
37 37
 
38
+// bridgeConfig stores all the bridge driver specific
39
+// configuration.
40
+type bridgeConfig struct {
41
+	EnableIPv6                  bool
42
+	EnableIPTables              bool
43
+	EnableIPForward             bool
44
+	EnableIPMasq                bool
45
+	EnableUserlandProxy         bool
46
+	DefaultIP                   net.IP
47
+	Iface                       string
48
+	IP                          string
49
+	FixedCIDR                   string
50
+	FixedCIDRv6                 string
51
+	DefaultGatewayIPv4          string
52
+	DefaultGatewayIPv6          string
53
+	InterContainerCommunication bool
54
+}
55
+
38 56
 // InstallCommonFlags adds command-line options to the top-level flag parser for
39 57
 // the current process.
40 58
 // Subsequent calls to `flag.Parse` will populate config with values parsed
... ...
@@ -45,9 +64,9 @@ func (config *Config) InstallCommonFlags() {
45 45
 	flag.StringVar(&config.Root, []string{"g", "-graph"}, defaultGraph, "Root of the Docker runtime")
46 46
 	flag.StringVar(&config.ExecRoot, []string{"-exec-root"}, "/var/run/docker", "Root of the Docker execdriver")
47 47
 	flag.BoolVar(&config.AutoRestart, []string{"#r", "#-restart"}, true, "--restart on the daemon has been deprecated in favor of --restart policies on docker run")
48
-	flag.BoolVar(&config.Bridge.EnableIptables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
49
-	flag.BoolVar(&config.Bridge.EnableIpForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
50
-	flag.BoolVar(&config.Bridge.EnableIpMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
48
+	flag.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, "Enable addition of iptables rules")
49
+	flag.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
50
+	flag.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, "Enable IP masquerading")
51 51
 	flag.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, "Enable IPv6 networking")
52 52
 	flag.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", "Specify network bridge IP")
53 53
 	flag.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", "Attach containers to a network bridge")
... ...
@@ -61,7 +80,7 @@ func (config *Config) InstallCommonFlags() {
61 61
 	flag.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, "Set the containers network MTU")
62 62
 	flag.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header")
63 63
 	flag.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", "Set CORS headers in the remote API")
64
-	opts.IPVar(&config.Bridge.DefaultIp, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
64
+	opts.IPVar(&config.Bridge.DefaultIP, []string{"#ip", "-ip"}, "0.0.0.0", "Default IP when binding container ports")
65 65
 	// FIXME: why the inconsistency between "hosts" and "sockets"?
66 66
 	opts.IPListVar(&config.Dns, []string{"#dns", "-dns"}, "DNS server to use")
67 67
 	opts.DnsSearchListVar(&config.DnsSearch, []string{"-dns-search"}, "DNS search domains to use")
... ...
@@ -71,10 +90,3 @@ func (config *Config) InstallCommonFlags() {
71 71
 	flag.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, "Use userland proxy for loopback traffic")
72 72
 
73 73
 }
74
-
75
-func getDefaultNetworkMtu() int {
76
-	if iface, err := networkdriver.GetDefaultRouteIface(); err == nil {
77
-		return iface.MTU
78
-	}
79
-	return defaultNetworkMtu
80
-}
... ...
@@ -252,18 +252,12 @@ func (container *Container) Start() (err error) {
252 252
 		}
253 253
 	}()
254 254
 
255
-	if err := container.setupContainerDns(); err != nil {
256
-		return err
257
-	}
258 255
 	if err := container.Mount(); err != nil {
259 256
 		return err
260 257
 	}
261 258
 	if err := container.initializeNetworking(); err != nil {
262 259
 		return err
263 260
 	}
264
-	if err := container.updateParentsHosts(); err != nil {
265
-		return err
266
-	}
267 261
 	container.verifyDaemonSettings()
268 262
 	if err := container.prepareVolumes(); err != nil {
269 263
 		return err
... ...
@@ -3,11 +3,13 @@
3 3
 package daemon
4 4
 
5 5
 import (
6
-	"bytes"
7 6
 	"fmt"
8 7
 	"io/ioutil"
8
+	"net"
9 9
 	"os"
10
+	"path"
10 11
 	"path/filepath"
12
+	"strconv"
11 13
 	"strings"
12 14
 	"syscall"
13 15
 	"time"
... ...
@@ -15,20 +17,21 @@ import (
15 15
 	"github.com/Sirupsen/logrus"
16 16
 	"github.com/docker/docker/daemon/execdriver"
17 17
 	"github.com/docker/docker/daemon/network"
18
-	"github.com/docker/docker/daemon/networkdriver/bridge"
19 18
 	"github.com/docker/docker/links"
20 19
 	"github.com/docker/docker/nat"
21 20
 	"github.com/docker/docker/pkg/archive"
22 21
 	"github.com/docker/docker/pkg/directory"
23
-	"github.com/docker/docker/pkg/etchosts"
24 22
 	"github.com/docker/docker/pkg/ioutils"
25
-	"github.com/docker/docker/pkg/resolvconf"
26 23
 	"github.com/docker/docker/pkg/stringid"
27 24
 	"github.com/docker/docker/pkg/ulimit"
28 25
 	"github.com/docker/docker/runconfig"
29 26
 	"github.com/docker/docker/utils"
30 27
 	"github.com/docker/libcontainer/configs"
31 28
 	"github.com/docker/libcontainer/devices"
29
+	"github.com/docker/libnetwork"
30
+	"github.com/docker/libnetwork/netlabel"
31
+	"github.com/docker/libnetwork/netutils"
32
+	"github.com/docker/libnetwork/options"
32 33
 )
33 34
 
34 35
 const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
... ...
@@ -65,179 +68,6 @@ func killProcessDirectly(container *Container) error {
65 65
 	return nil
66 66
 }
67 67
 
68
-func (container *Container) setupContainerDns() error {
69
-	if container.ResolvConfPath != "" {
70
-		// check if this is an existing container that needs DNS update:
71
-		if container.UpdateDns {
72
-			// read the host's resolv.conf, get the hash and call updateResolvConf
73
-			logrus.Debugf("Check container (%s) for update to resolv.conf - UpdateDns flag was set", container.ID)
74
-			latestResolvConf, latestHash := resolvconf.GetLastModified()
75
-
76
-			// clean container resolv.conf re: localhost nameservers and IPv6 NS (if IPv6 disabled)
77
-			updatedResolvConf, modified := resolvconf.FilterResolvDns(latestResolvConf, container.daemon.config.Bridge.EnableIPv6)
78
-			if modified {
79
-				// changes have occurred during resolv.conf localhost cleanup: generate an updated hash
80
-				newHash, err := ioutils.HashData(bytes.NewReader(updatedResolvConf))
81
-				if err != nil {
82
-					return err
83
-				}
84
-				latestHash = newHash
85
-			}
86
-
87
-			if err := container.updateResolvConf(updatedResolvConf, latestHash); err != nil {
88
-				return err
89
-			}
90
-			// successful update of the restarting container; set the flag off
91
-			container.UpdateDns = false
92
-		}
93
-		return nil
94
-	}
95
-
96
-	var (
97
-		config = container.hostConfig
98
-		daemon = container.daemon
99
-	)
100
-
101
-	resolvConf, err := resolvconf.Get()
102
-	if err != nil {
103
-		return err
104
-	}
105
-	container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
106
-	if err != nil {
107
-		return err
108
-	}
109
-
110
-	if config.NetworkMode.IsBridge() || config.NetworkMode.IsNone() {
111
-		// check configurations for any container/daemon dns settings
112
-		if len(config.Dns) > 0 || len(daemon.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(daemon.config.DnsSearch) > 0 {
113
-			var (
114
-				dns       = resolvconf.GetNameservers(resolvConf)
115
-				dnsSearch = resolvconf.GetSearchDomains(resolvConf)
116
-			)
117
-			if len(config.Dns) > 0 {
118
-				dns = config.Dns
119
-			} else if len(daemon.config.Dns) > 0 {
120
-				dns = daemon.config.Dns
121
-			}
122
-			if len(config.DnsSearch) > 0 {
123
-				dnsSearch = config.DnsSearch
124
-			} else if len(daemon.config.DnsSearch) > 0 {
125
-				dnsSearch = daemon.config.DnsSearch
126
-			}
127
-			return resolvconf.Build(container.ResolvConfPath, dns, dnsSearch)
128
-		}
129
-
130
-		// replace any localhost/127.*, and remove IPv6 nameservers if IPv6 disabled in daemon
131
-		resolvConf, _ = resolvconf.FilterResolvDns(resolvConf, daemon.config.Bridge.EnableIPv6)
132
-	}
133
-	//get a sha256 hash of the resolv conf at this point so we can check
134
-	//for changes when the host resolv.conf changes (e.g. network update)
135
-	resolvHash, err := ioutils.HashData(bytes.NewReader(resolvConf))
136
-	if err != nil {
137
-		return err
138
-	}
139
-	resolvHashFile := container.ResolvConfPath + ".hash"
140
-	if err = ioutil.WriteFile(resolvHashFile, []byte(resolvHash), 0644); err != nil {
141
-		return err
142
-	}
143
-	return ioutil.WriteFile(container.ResolvConfPath, resolvConf, 0644)
144
-}
145
-
146
-// called when the host's resolv.conf changes to check whether container's resolv.conf
147
-// is unchanged by the container "user" since container start: if unchanged, the
148
-// container's resolv.conf will be updated to match the host's new resolv.conf
149
-func (container *Container) updateResolvConf(updatedResolvConf []byte, newResolvHash string) error {
150
-
151
-	if container.ResolvConfPath == "" {
152
-		return nil
153
-	}
154
-	if container.Running {
155
-		//set a marker in the hostConfig to update on next start/restart
156
-		container.UpdateDns = true
157
-		return nil
158
-	}
159
-
160
-	resolvHashFile := container.ResolvConfPath + ".hash"
161
-
162
-	//read the container's current resolv.conf and compute the hash
163
-	resolvBytes, err := ioutil.ReadFile(container.ResolvConfPath)
164
-	if err != nil {
165
-		return err
166
-	}
167
-	curHash, err := ioutils.HashData(bytes.NewReader(resolvBytes))
168
-	if err != nil {
169
-		return err
170
-	}
171
-
172
-	//read the hash from the last time we wrote resolv.conf in the container
173
-	hashBytes, err := ioutil.ReadFile(resolvHashFile)
174
-	if err != nil {
175
-		if !os.IsNotExist(err) {
176
-			return err
177
-		}
178
-		// backwards compat: if no hash file exists, this container pre-existed from
179
-		// a Docker daemon that didn't contain this update feature. Given we can't know
180
-		// if the user has modified the resolv.conf since container start time, safer
181
-		// to just never update the container's resolv.conf during it's lifetime which
182
-		// we can control by setting hashBytes to an empty string
183
-		hashBytes = []byte("")
184
-	}
185
-
186
-	//if the user has not modified the resolv.conf of the container since we wrote it last
187
-	//we will replace it with the updated resolv.conf from the host
188
-	if string(hashBytes) == curHash {
189
-		logrus.Debugf("replacing %q with updated host resolv.conf", container.ResolvConfPath)
190
-
191
-		// for atomic updates to these files, use temporary files with os.Rename:
192
-		dir := filepath.Dir(container.ResolvConfPath)
193
-		tmpHashFile, err := ioutil.TempFile(dir, "hash")
194
-		if err != nil {
195
-			return err
196
-		}
197
-		tmpResolvFile, err := ioutil.TempFile(dir, "resolv")
198
-		if err != nil {
199
-			return err
200
-		}
201
-
202
-		// write the updates to the temp files
203
-		if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newResolvHash), 0644); err != nil {
204
-			return err
205
-		}
206
-		if err = ioutil.WriteFile(tmpResolvFile.Name(), updatedResolvConf, 0644); err != nil {
207
-			return err
208
-		}
209
-
210
-		// rename the temp files for atomic replace
211
-		if err = os.Rename(tmpHashFile.Name(), resolvHashFile); err != nil {
212
-			return err
213
-		}
214
-		return os.Rename(tmpResolvFile.Name(), container.ResolvConfPath)
215
-	}
216
-	return nil
217
-}
218
-
219
-func (container *Container) updateParentsHosts() error {
220
-	refs := container.daemon.ContainerGraph().RefPaths(container.ID)
221
-	for _, ref := range refs {
222
-		if ref.ParentID == "0" {
223
-			continue
224
-		}
225
-
226
-		c, err := container.daemon.Get(ref.ParentID)
227
-		if err != nil {
228
-			logrus.Error(err)
229
-		}
230
-
231
-		if c != nil && !container.daemon.config.DisableNetwork && container.hostConfig.NetworkMode.IsPrivate() {
232
-			logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
233
-			if err := etchosts.Update(c.HostsPath, container.NetworkSettings.IPAddress, ref.Name); err != nil {
234
-				logrus.Errorf("Failed to update /etc/hosts in parent container %s for alias %s: %v", c.ID, ref.Name, err)
235
-			}
236
-		}
237
-	}
238
-	return nil
239
-}
240
-
241 68
 func (container *Container) setupLinkedContainers() ([]string, error) {
242 69
 	var (
243 70
 		env    []string
... ...
@@ -360,39 +190,16 @@ func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.
360 360
 
361 361
 func populateCommand(c *Container, env []string) error {
362 362
 	en := &execdriver.Network{
363
-		Mtu:       c.daemon.config.Mtu,
364
-		Interface: nil,
363
+		NamespacePath: c.NetworkSettings.SandboxKey,
365 364
 	}
366 365
 
367 366
 	parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2)
368
-	switch parts[0] {
369
-	case "none":
370
-	case "host":
371
-		en.HostNetworking = true
372
-	case "bridge", "": // empty string to support existing containers
373
-		if !c.Config.NetworkDisabled {
374
-			network := c.NetworkSettings
375
-			en.Interface = &execdriver.NetworkInterface{
376
-				Gateway:              network.Gateway,
377
-				Bridge:               network.Bridge,
378
-				IPAddress:            network.IPAddress,
379
-				IPPrefixLen:          network.IPPrefixLen,
380
-				MacAddress:           network.MacAddress,
381
-				LinkLocalIPv6Address: network.LinkLocalIPv6Address,
382
-				GlobalIPv6Address:    network.GlobalIPv6Address,
383
-				GlobalIPv6PrefixLen:  network.GlobalIPv6PrefixLen,
384
-				IPv6Gateway:          network.IPv6Gateway,
385
-				HairpinMode:          network.HairpinMode,
386
-			}
387
-		}
388
-	case "container":
367
+	if parts[0] == "container" {
389 368
 		nc, err := c.getNetworkedContainer()
390 369
 		if err != nil {
391 370
 			return err
392 371
 		}
393 372
 		en.ContainerID = nc.ID
394
-	default:
395
-		return fmt.Errorf("invalid network mode: %s", c.hostConfig.NetworkMode)
396 373
 	}
397 374
 
398 375
 	ipc := &execdriver.Ipc{}
... ...
@@ -537,40 +344,318 @@ func (container *Container) GetSize() (int64, int64) {
537 537
 	return sizeRw, sizeRootfs
538 538
 }
539 539
 
540
-func (container *Container) AllocateNetwork() error {
541
-	mode := container.hostConfig.NetworkMode
542
-	if container.Config.NetworkDisabled || !mode.IsPrivate() {
540
+func (container *Container) buildHostnameFile() error {
541
+	hostnamePath, err := container.GetRootResourcePath("hostname")
542
+	if err != nil {
543
+		return err
544
+	}
545
+	container.HostnamePath = hostnamePath
546
+
547
+	if container.Config.Domainname != "" {
548
+		return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
549
+	}
550
+	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
551
+}
552
+
553
+func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, error) {
554
+	var (
555
+		joinOptions []libnetwork.EndpointOption
556
+		err         error
557
+		dns         []string
558
+		dnsSearch   []string
559
+	)
560
+
561
+	joinOptions = append(joinOptions, libnetwork.JoinOptionHostname(container.Config.Hostname),
562
+		libnetwork.JoinOptionDomainname(container.Config.Domainname))
563
+
564
+	if container.hostConfig.NetworkMode.IsHost() {
565
+		joinOptions = append(joinOptions, libnetwork.JoinOptionUseDefaultSandbox())
566
+	}
567
+
568
+	container.HostsPath, err = container.GetRootResourcePath("hosts")
569
+	if err != nil {
570
+		return nil, err
571
+	}
572
+	joinOptions = append(joinOptions, libnetwork.JoinOptionHostsPath(container.HostsPath))
573
+
574
+	container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
575
+	if err != nil {
576
+		return nil, err
577
+	}
578
+	joinOptions = append(joinOptions, libnetwork.JoinOptionResolvConfPath(container.ResolvConfPath))
579
+
580
+	if len(container.hostConfig.Dns) > 0 {
581
+		dns = container.hostConfig.Dns
582
+	} else if len(container.daemon.config.Dns) > 0 {
583
+		dns = container.daemon.config.Dns
584
+	}
585
+
586
+	for _, d := range dns {
587
+		joinOptions = append(joinOptions, libnetwork.JoinOptionDNS(d))
588
+	}
589
+
590
+	if len(container.hostConfig.DnsSearch) > 0 {
591
+		dnsSearch = container.hostConfig.DnsSearch
592
+	} else if len(container.daemon.config.DnsSearch) > 0 {
593
+		dnsSearch = container.daemon.config.DnsSearch
594
+	}
595
+
596
+	for _, ds := range dnsSearch {
597
+		joinOptions = append(joinOptions, libnetwork.JoinOptionDNSSearch(ds))
598
+	}
599
+
600
+	if container.NetworkSettings.SecondaryIPAddresses != nil {
601
+		name := container.Config.Hostname
602
+		if container.Config.Domainname != "" {
603
+			name = name + "." + container.Config.Domainname
604
+		}
605
+
606
+		for _, a := range container.NetworkSettings.SecondaryIPAddresses {
607
+			joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(name, a.Addr))
608
+		}
609
+	}
610
+
611
+	var childEndpoints, parentEndpoints []string
612
+
613
+	children, err := container.daemon.Children(container.Name)
614
+	if err != nil {
615
+		return nil, err
616
+	}
617
+
618
+	for linkAlias, child := range children {
619
+		_, alias := path.Split(linkAlias)
620
+		// allow access to the linked container via the alias, real name, and container hostname
621
+		aliasList := alias + " " + child.Config.Hostname
622
+		// only add the name if alias isn't equal to the name
623
+		if alias != child.Name[1:] {
624
+			aliasList = aliasList + " " + child.Name[1:]
625
+		}
626
+		joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(aliasList, child.NetworkSettings.IPAddress))
627
+		if child.NetworkSettings.EndpointID != "" {
628
+			childEndpoints = append(childEndpoints, child.NetworkSettings.EndpointID)
629
+		}
630
+	}
631
+
632
+	for _, extraHost := range container.hostConfig.ExtraHosts {
633
+		// allow IPv6 addresses in extra hosts; only split on first ":"
634
+		parts := strings.SplitN(extraHost, ":", 2)
635
+		joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(parts[0], parts[1]))
636
+	}
637
+
638
+	refs := container.daemon.ContainerGraph().RefPaths(container.ID)
639
+	for _, ref := range refs {
640
+		if ref.ParentID == "0" {
641
+			continue
642
+		}
643
+
644
+		c, err := container.daemon.Get(ref.ParentID)
645
+		if err != nil {
646
+			logrus.Error(err)
647
+		}
648
+
649
+		if c != nil && !container.daemon.config.DisableNetwork && container.hostConfig.NetworkMode.IsPrivate() {
650
+			logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
651
+			joinOptions = append(joinOptions, libnetwork.JoinOptionParentUpdate(c.NetworkSettings.EndpointID, ref.Name, container.NetworkSettings.IPAddress))
652
+			if c.NetworkSettings.EndpointID != "" {
653
+				parentEndpoints = append(parentEndpoints, c.NetworkSettings.EndpointID)
654
+			}
655
+		}
656
+	}
657
+
658
+	linkOptions := options.Generic{
659
+		netlabel.GenericData: options.Generic{
660
+			"ParentEndpoints": parentEndpoints,
661
+			"ChildEndpoints":  childEndpoints,
662
+		},
663
+	}
664
+
665
+	joinOptions = append(joinOptions, libnetwork.JoinOptionGeneric(linkOptions))
666
+
667
+	return joinOptions, nil
668
+}
669
+
670
+func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
671
+	if ep == nil {
672
+		return nil, fmt.Errorf("invalid endpoint while building port map info")
673
+	}
674
+
675
+	if networkSettings == nil {
676
+		return nil, fmt.Errorf("invalid networksettings while building port map info")
677
+	}
678
+
679
+	driverInfo, err := ep.DriverInfo()
680
+	if err != nil {
681
+		return nil, err
682
+	}
683
+
684
+	if driverInfo == nil {
685
+		// It is not an error for epInfo to be nil
686
+		return networkSettings, nil
687
+	}
688
+
689
+	if mac, ok := driverInfo[netlabel.MacAddress]; ok {
690
+		networkSettings.MacAddress = mac.(net.HardwareAddr).String()
691
+	}
692
+
693
+	mapData, ok := driverInfo[netlabel.PortMap]
694
+	if !ok {
695
+		return networkSettings, nil
696
+	}
697
+
698
+	if portMapping, ok := mapData.([]netutils.PortBinding); ok {
699
+		networkSettings.Ports = nat.PortMap{}
700
+		for _, pp := range portMapping {
701
+			natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
702
+			natBndg := nat.PortBinding{HostIp: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
703
+			networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg)
704
+		}
705
+	}
706
+
707
+	return networkSettings, nil
708
+}
709
+
710
+func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
711
+	if ep == nil {
712
+		return nil, fmt.Errorf("invalid endpoint while building port map info")
713
+	}
714
+
715
+	if networkSettings == nil {
716
+		return nil, fmt.Errorf("invalid networksettings while building port map info")
717
+	}
718
+
719
+	epInfo := ep.Info()
720
+	if epInfo == nil {
721
+		// It is not an error to get an empty endpoint info
722
+		return networkSettings, nil
723
+	}
724
+
725
+	ifaceList := epInfo.InterfaceList()
726
+	if len(ifaceList) == 0 {
727
+		return networkSettings, nil
728
+	}
729
+
730
+	iface := ifaceList[0]
731
+
732
+	ones, _ := iface.Address().Mask.Size()
733
+	networkSettings.IPAddress = iface.Address().IP.String()
734
+	networkSettings.IPPrefixLen = ones
735
+
736
+	if iface.AddressIPv6().IP.To16() != nil {
737
+		onesv6, _ := iface.AddressIPv6().Mask.Size()
738
+		networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String()
739
+		networkSettings.GlobalIPv6PrefixLen = onesv6
740
+	}
741
+
742
+	if len(ifaceList) == 1 {
743
+		return networkSettings, nil
744
+	}
745
+
746
+	networkSettings.SecondaryIPAddresses = make([]network.Address, 0, len(ifaceList)-1)
747
+	networkSettings.SecondaryIPv6Addresses = make([]network.Address, 0, len(ifaceList)-1)
748
+	for _, iface := range ifaceList[1:] {
749
+		ones, _ := iface.Address().Mask.Size()
750
+		addr := network.Address{Addr: iface.Address().IP.String(), PrefixLen: ones}
751
+		networkSettings.SecondaryIPAddresses = append(networkSettings.SecondaryIPAddresses, addr)
752
+
753
+		if iface.AddressIPv6().IP.To16() != nil {
754
+			onesv6, _ := iface.AddressIPv6().Mask.Size()
755
+			addrv6 := network.Address{Addr: iface.AddressIPv6().IP.String(), PrefixLen: onesv6}
756
+			networkSettings.SecondaryIPv6Addresses = append(networkSettings.SecondaryIPv6Addresses, addrv6)
757
+		}
758
+	}
759
+
760
+	return networkSettings, nil
761
+}
762
+
763
+func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error {
764
+	epInfo := ep.Info()
765
+	if epInfo == nil {
766
+		// It is not an error to get an empty endpoint info
543 767
 		return nil
544 768
 	}
545 769
 
546
-	var err error
770
+	container.NetworkSettings.Gateway = epInfo.Gateway().String()
771
+	if epInfo.GatewayIPv6().To16() != nil {
772
+		container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String()
773
+	}
774
+
775
+	container.NetworkSettings.SandboxKey = epInfo.SandboxKey()
547 776
 
548
-	networkSettings, err := bridge.Allocate(container.ID, container.Config.MacAddress, "", "")
777
+	return nil
778
+}
779
+
780
+func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
781
+	networkSettings := &network.Settings{NetworkID: n.ID(), EndpointID: ep.ID()}
782
+
783
+	networkSettings, err := container.buildPortMapInfo(n, ep, networkSettings)
549 784
 	if err != nil {
550 785
 		return err
551 786
 	}
552 787
 
553
-	// Error handling: At this point, the interface is allocated so we have to
554
-	// make sure that it is always released in case of error, otherwise we
555
-	// might leak resources.
788
+	networkSettings, err = container.buildEndpointInfo(n, ep, networkSettings)
789
+	if err != nil {
790
+		return err
791
+	}
792
+
793
+	if container.hostConfig.NetworkMode == runconfig.NetworkMode("bridge") {
794
+		networkSettings.Bridge = container.daemon.config.Bridge.Iface
795
+	}
796
+
797
+	container.NetworkSettings = networkSettings
798
+	return nil
799
+}
800
+
801
+func (container *Container) UpdateNetwork() error {
802
+	n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID)
803
+	if err != nil {
804
+		return fmt.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err)
805
+	}
806
+
807
+	ep, err := n.EndpointByID(container.NetworkSettings.EndpointID)
808
+	if err != nil {
809
+		return fmt.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err)
810
+	}
811
+
812
+	if err := ep.Leave(container.ID); err != nil {
813
+		return fmt.Errorf("endpoint leave failed: %v", err)
814
+
815
+	}
816
+
817
+	joinOptions, err := container.buildJoinOptions()
818
+	if err != nil {
819
+		return fmt.Errorf("Update network failed: %v", err)
820
+	}
821
+
822
+	if _, err := ep.Join(container.ID, joinOptions...); err != nil {
823
+		return fmt.Errorf("endpoint join failed: %v", err)
824
+	}
825
+
826
+	if err := container.updateJoinInfo(ep); err != nil {
827
+		return fmt.Errorf("Updating join info failed: %v", err)
828
+	}
829
+
830
+	return nil
831
+}
832
+
833
+func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointOption, error) {
834
+	var (
835
+		portSpecs     = make(nat.PortSet)
836
+		bindings      = make(nat.PortMap)
837
+		pbList        []netutils.PortBinding
838
+		exposeList    []netutils.TransportPort
839
+		createOptions []libnetwork.EndpointOption
840
+	)
556 841
 
557 842
 	if container.Config.PortSpecs != nil {
558
-		if err = migratePortMappings(container.Config, container.hostConfig); err != nil {
559
-			bridge.Release(container.ID)
560
-			return err
843
+		if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
844
+			return nil, err
561 845
 		}
562 846
 		container.Config.PortSpecs = nil
563
-		if err = container.WriteHostConfig(); err != nil {
564
-			bridge.Release(container.ID)
565
-			return err
847
+		if err := container.WriteHostConfig(); err != nil {
848
+			return nil, err
566 849
 		}
567 850
 	}
568 851
 
569
-	var (
570
-		portSpecs = make(nat.PortSet)
571
-		bindings  = make(nat.PortMap)
572
-	)
573
-
574 852
 	if container.Config.ExposedPorts != nil {
575 853
 		portSpecs = container.Config.ExposedPorts
576 854
 	}
... ...
@@ -597,52 +682,99 @@ func (container *Container) AllocateNetwork() error {
597 597
 	}
598 598
 	nat.SortPortMap(ports, bindings)
599 599
 	for _, port := range ports {
600
-		if err = container.allocatePort(port, bindings); err != nil {
601
-			bridge.Release(container.ID)
602
-			return err
600
+		expose := netutils.TransportPort{}
601
+		expose.Proto = netutils.ParseProtocol(port.Proto())
602
+		expose.Port = uint16(port.Int())
603
+		exposeList = append(exposeList, expose)
604
+
605
+		pb := netutils.PortBinding{Port: expose.Port, Proto: expose.Proto}
606
+		binding := bindings[port]
607
+		for i := 0; i < len(binding); i++ {
608
+			pbCopy := pb.GetCopy()
609
+			pbCopy.HostPort = uint16(nat.Port(binding[i].HostPort).Int())
610
+			pbCopy.HostIP = net.ParseIP(binding[i].HostIp)
611
+			pbList = append(pbList, pbCopy)
603 612
 		}
604
-	}
605
-	container.WriteHostConfig()
606 613
 
607
-	networkSettings.Ports = bindings
608
-	container.NetworkSettings = networkSettings
614
+		if container.hostConfig.PublishAllPorts && len(binding) == 0 {
615
+			pbList = append(pbList, pb)
616
+		}
617
+	}
609 618
 
610
-	return nil
611
-}
619
+	createOptions = append(createOptions,
620
+		libnetwork.CreateOptionPortMapping(pbList),
621
+		libnetwork.CreateOptionExposedPorts(exposeList))
612 622
 
613
-func (container *Container) initializeNetworking() error {
614
-	var err error
615
-	if container.hostConfig.NetworkMode.IsHost() {
616
-		container.Config.Hostname, err = os.Hostname()
623
+	if container.Config.MacAddress != "" {
624
+		mac, err := net.ParseMAC(container.Config.MacAddress)
617 625
 		if err != nil {
618
-			return err
626
+			return nil, err
619 627
 		}
620 628
 
621
-		parts := strings.SplitN(container.Config.Hostname, ".", 2)
622
-		if len(parts) > 1 {
623
-			container.Config.Hostname = parts[0]
624
-			container.Config.Domainname = parts[1]
629
+		genericOption := options.Generic{
630
+			netlabel.MacAddress: mac,
625 631
 		}
626 632
 
627
-		content, err := ioutil.ReadFile("/etc/hosts")
628
-		if os.IsNotExist(err) {
629
-			return container.buildHostnameAndHostsFiles("")
630
-		} else if err != nil {
631
-			return err
632
-		}
633
+		createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
634
+	}
633 635
 
634
-		if err := container.buildHostnameFile(); err != nil {
635
-			return err
636
-		}
636
+	return createOptions, nil
637
+}
637 638
 
638
-		hostsPath, err := container.GetRootResourcePath("hosts")
639
-		if err != nil {
640
-			return err
641
-		}
642
-		container.HostsPath = hostsPath
639
+func (container *Container) AllocateNetwork() error {
640
+	mode := container.hostConfig.NetworkMode
641
+	if container.Config.NetworkDisabled || mode.IsContainer() {
642
+		return nil
643
+	}
644
+
645
+	var err error
646
+
647
+	n, err := container.daemon.netController.NetworkByName(string(mode))
648
+	if err != nil {
649
+		return fmt.Errorf("error locating network with name %s: %v", string(mode), err)
650
+	}
643 651
 
644
-		return ioutil.WriteFile(container.HostsPath, content, 0644)
652
+	createOptions, err := container.buildCreateEndpointOptions()
653
+	if err != nil {
654
+		return err
655
+	}
656
+
657
+	ep, err := n.CreateEndpoint(container.Name, createOptions...)
658
+	if err != nil {
659
+		return err
660
+	}
661
+
662
+	if err := container.updateNetworkSettings(n, ep); err != nil {
663
+		return err
664
+	}
665
+
666
+	joinOptions, err := container.buildJoinOptions()
667
+	if err != nil {
668
+		return err
645 669
 	}
670
+
671
+	if _, err := ep.Join(container.ID, joinOptions...); err != nil {
672
+		return err
673
+	}
674
+
675
+	if err := container.updateJoinInfo(ep); err != nil {
676
+		return fmt.Errorf("Updating join info failed: %v", err)
677
+	}
678
+
679
+	container.WriteHostConfig()
680
+
681
+	return nil
682
+}
683
+
684
+func (container *Container) initializeNetworking() error {
685
+	var err error
686
+
687
+	// Make sure NetworkMode has an acceptable value before
688
+	// initializing networking.
689
+	if container.hostConfig.NetworkMode == runconfig.NetworkMode("") {
690
+		container.hostConfig.NetworkMode = runconfig.NetworkMode("bridge")
691
+	}
692
+
646 693
 	if container.hostConfig.NetworkMode.IsContainer() {
647 694
 		// we need to get the hosts files from the container to join
648 695
 		nc, err := container.getNetworkedContainer()
... ...
@@ -656,14 +788,30 @@ func (container *Container) initializeNetworking() error {
656 656
 		container.Config.Domainname = nc.Config.Domainname
657 657
 		return nil
658 658
 	}
659
+
659 660
 	if container.daemon.config.DisableNetwork {
660 661
 		container.Config.NetworkDisabled = true
661
-		return container.buildHostnameAndHostsFiles("127.0.1.1")
662 662
 	}
663
+
664
+	if container.hostConfig.NetworkMode.IsHost() {
665
+		container.Config.Hostname, err = os.Hostname()
666
+		if err != nil {
667
+			return err
668
+		}
669
+
670
+		parts := strings.SplitN(container.Config.Hostname, ".", 2)
671
+		if len(parts) > 1 {
672
+			container.Config.Hostname = parts[0]
673
+			container.Config.Domainname = parts[1]
674
+		}
675
+
676
+	}
677
+
663 678
 	if err := container.AllocateNetwork(); err != nil {
664 679
 		return err
665 680
 	}
666
-	return container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress)
681
+
682
+	return container.buildHostnameFile()
667 683
 }
668 684
 
669 685
 // Make sure the config is compatible with the current kernel
... ...
@@ -701,62 +849,6 @@ func (container *Container) ExportRw() (archive.Archive, error) {
701 701
 		nil
702 702
 }
703 703
 
704
-func (container *Container) buildHostnameFile() error {
705
-	hostnamePath, err := container.GetRootResourcePath("hostname")
706
-	if err != nil {
707
-		return err
708
-	}
709
-	container.HostnamePath = hostnamePath
710
-
711
-	if container.Config.Domainname != "" {
712
-		return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
713
-	}
714
-	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
715
-}
716
-
717
-func (container *Container) buildHostsFiles(IP string) error {
718
-
719
-	hostsPath, err := container.GetRootResourcePath("hosts")
720
-	if err != nil {
721
-		return err
722
-	}
723
-	container.HostsPath = hostsPath
724
-
725
-	var extraContent []etchosts.Record
726
-
727
-	children, err := container.daemon.Children(container.Name)
728
-	if err != nil {
729
-		return err
730
-	}
731
-
732
-	for linkAlias, child := range children {
733
-		_, alias := filepath.Split(linkAlias)
734
-		// allow access to the linked container via the alias, real name, and container hostname
735
-		aliasList := alias + " " + child.Config.Hostname
736
-		// only add the name if alias isn't equal to the name
737
-		if alias != child.Name[1:] {
738
-			aliasList = aliasList + " " + child.Name[1:]
739
-		}
740
-		extraContent = append(extraContent, etchosts.Record{Hosts: aliasList, IP: child.NetworkSettings.IPAddress})
741
-	}
742
-
743
-	for _, extraHost := range container.hostConfig.ExtraHosts {
744
-		// allow IPv6 addresses in extra hosts; only split on first ":"
745
-		parts := strings.SplitN(extraHost, ":", 2)
746
-		extraContent = append(extraContent, etchosts.Record{Hosts: parts[0], IP: parts[1]})
747
-	}
748
-
749
-	return etchosts.Build(container.HostsPath, IP, container.Config.Hostname, container.Config.Domainname, extraContent)
750
-}
751
-
752
-func (container *Container) buildHostnameAndHostsFiles(IP string) error {
753
-	if err := container.buildHostnameFile(); err != nil {
754
-		return err
755
-	}
756
-
757
-	return container.buildHostsFiles(IP)
758
-}
759
-
760 704
 func (container *Container) getIpcContainer() (*Container, error) {
761 705
 	containerID := container.hostConfig.IpcMode.Container()
762 706
 	c, err := container.daemon.Get(containerID)
... ...
@@ -795,23 +887,6 @@ func (container *Container) setupWorkingDirectory() error {
795 795
 	return nil
796 796
 }
797 797
 
798
-func (container *Container) allocatePort(port nat.Port, bindings nat.PortMap) error {
799
-	binding := bindings[port]
800
-	if container.hostConfig.PublishAllPorts && len(binding) == 0 {
801
-		binding = append(binding, nat.PortBinding{})
802
-	}
803
-
804
-	for i := 0; i < len(binding); i++ {
805
-		b, err := bridge.AllocatePort(container.ID, port, binding[i])
806
-		if err != nil {
807
-			return err
808
-		}
809
-		binding[i] = b
810
-	}
811
-	bindings[port] = binding
812
-	return nil
813
-}
814
-
815 798
 func (container *Container) getNetworkedContainer() (*Container, error) {
816 799
 	parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2)
817 800
 	switch parts[0] {
... ...
@@ -836,34 +911,31 @@ func (container *Container) getNetworkedContainer() (*Container, error) {
836 836
 }
837 837
 
838 838
 func (container *Container) ReleaseNetwork() {
839
-	if container.Config.NetworkDisabled || !container.hostConfig.NetworkMode.IsPrivate() {
839
+	if container.hostConfig.NetworkMode.IsContainer() {
840 840
 		return
841 841
 	}
842
-	bridge.Release(container.ID)
843
-	container.NetworkSettings = &network.Settings{}
844
-}
845 842
 
846
-func (container *Container) RestoreNetwork() error {
847
-	mode := container.hostConfig.NetworkMode
848
-	// Don't attempt a restore if we previously didn't allocate networking.
849
-	// This might be a legacy container with no network allocated, in which case the
850
-	// allocation will happen once and for all at start.
851
-	if !container.isNetworkAllocated() || container.Config.NetworkDisabled || !mode.IsPrivate() {
852
-		return nil
843
+	n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID)
844
+	if err != nil {
845
+		logrus.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err)
846
+		return
853 847
 	}
854 848
 
855
-	// Re-allocate the interface with the same IP and MAC address.
856
-	if _, err := bridge.Allocate(container.ID, container.NetworkSettings.MacAddress, container.NetworkSettings.IPAddress, ""); err != nil {
857
-		return err
849
+	ep, err := n.EndpointByID(container.NetworkSettings.EndpointID)
850
+	if err != nil {
851
+		logrus.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err)
852
+		return
858 853
 	}
859 854
 
860
-	// Re-allocate any previously allocated ports.
861
-	for port := range container.NetworkSettings.Ports {
862
-		if err := container.allocatePort(port, container.NetworkSettings.Ports); err != nil {
863
-			return err
864
-		}
855
+	if err := ep.Leave(container.ID); err != nil {
856
+		logrus.Errorf("leaving endpoint failed: %v", err)
865 857
 	}
866
-	return nil
858
+
859
+	if err := ep.Delete(); err != nil {
860
+		logrus.Errorf("deleting endpoint failed: %v", err)
861
+	}
862
+
863
+	container.NetworkSettings = &network.Settings{}
867 864
 }
868 865
 
869 866
 func disableAllActiveLinks(container *Container) {
... ...
@@ -878,6 +950,10 @@ func (container *Container) DisableLink(name string) {
878 878
 	if container.activeLinks != nil {
879 879
 		if link, exists := container.activeLinks[name]; exists {
880 880
 			link.Disable()
881
+			delete(container.activeLinks, name)
882
+			if err := container.UpdateNetwork(); err != nil {
883
+				logrus.Debugf("Could not update network to remove link: %v", err)
884
+			}
881 885
 		} else {
882 886
 			logrus.Debugf("Could not find active link for %s", name)
883 887
 		}
... ...
@@ -1,10 +1,10 @@
1 1
 package daemon
2 2
 
3 3
 import (
4
-	"bytes"
5 4
 	"fmt"
6 5
 	"io"
7 6
 	"io/ioutil"
7
+	"net"
8 8
 	"os"
9 9
 	"path"
10 10
 	"path/filepath"
... ...
@@ -15,6 +15,9 @@ import (
15 15
 	"time"
16 16
 
17 17
 	"github.com/docker/libcontainer/label"
18
+	"github.com/docker/libnetwork"
19
+	"github.com/docker/libnetwork/netlabel"
20
+	"github.com/docker/libnetwork/options"
18 21
 
19 22
 	"github.com/Sirupsen/logrus"
20 23
 	"github.com/docker/docker/api"
... ...
@@ -26,7 +29,6 @@ import (
26 26
 	_ "github.com/docker/docker/daemon/graphdriver/vfs"
27 27
 	"github.com/docker/docker/daemon/logger"
28 28
 	"github.com/docker/docker/daemon/network"
29
-	"github.com/docker/docker/daemon/networkdriver/bridge"
30 29
 	"github.com/docker/docker/graph"
31 30
 	"github.com/docker/docker/image"
32 31
 	"github.com/docker/docker/pkg/archive"
... ...
@@ -37,7 +39,6 @@ import (
37 37
 	"github.com/docker/docker/pkg/namesgenerator"
38 38
 	"github.com/docker/docker/pkg/parsers"
39 39
 	"github.com/docker/docker/pkg/parsers/kernel"
40
-	"github.com/docker/docker/pkg/resolvconf"
41 40
 	"github.com/docker/docker/pkg/stringid"
42 41
 	"github.com/docker/docker/pkg/sysinfo"
43 42
 	"github.com/docker/docker/pkg/truncindex"
... ...
@@ -46,8 +47,6 @@ import (
46 46
 	"github.com/docker/docker/trust"
47 47
 	"github.com/docker/docker/utils"
48 48
 	"github.com/docker/docker/volumes"
49
-
50
-	"github.com/go-fsnotify/fsnotify"
51 49
 )
52 50
 
53 51
 var (
... ...
@@ -109,6 +108,7 @@ type Daemon struct {
109 109
 	defaultLogConfig runconfig.LogConfig
110 110
 	RegistryService  *registry.Service
111 111
 	EventsService    *events.Events
112
+	netController    libnetwork.NetworkController
112 113
 }
113 114
 
114 115
 // Get looks for a container using the provided information, which could be
... ...
@@ -349,61 +349,6 @@ func (daemon *Daemon) restore() error {
349 349
 	return nil
350 350
 }
351 351
 
352
-// set up the watch on the host's /etc/resolv.conf so that we can update container's
353
-// live resolv.conf when the network changes on the host
354
-func (daemon *Daemon) setupResolvconfWatcher() error {
355
-
356
-	watcher, err := fsnotify.NewWatcher()
357
-	if err != nil {
358
-		return err
359
-	}
360
-
361
-	//this goroutine listens for the events on the watch we add
362
-	//on the resolv.conf file on the host
363
-	go func() {
364
-		for {
365
-			select {
366
-			case event := <-watcher.Events:
367
-				if event.Name == "/etc/resolv.conf" &&
368
-					(event.Op&(fsnotify.Write|fsnotify.Create) != 0) {
369
-					// verify a real change happened before we go further--a file write may have happened
370
-					// without an actual change to the file
371
-					updatedResolvConf, newResolvConfHash, err := resolvconf.GetIfChanged()
372
-					if err != nil {
373
-						logrus.Debugf("Error retrieving updated host resolv.conf: %v", err)
374
-					} else if updatedResolvConf != nil {
375
-						// because the new host resolv.conf might have localhost nameservers..
376
-						updatedResolvConf, modified := resolvconf.FilterResolvDns(updatedResolvConf, daemon.config.Bridge.EnableIPv6)
377
-						if modified {
378
-							// changes have occurred during localhost cleanup: generate an updated hash
379
-							newHash, err := ioutils.HashData(bytes.NewReader(updatedResolvConf))
380
-							if err != nil {
381
-								logrus.Debugf("Error generating hash of new resolv.conf: %v", err)
382
-							} else {
383
-								newResolvConfHash = newHash
384
-							}
385
-						}
386
-						logrus.Debug("host network resolv.conf changed--walking container list for updates")
387
-						contList := daemon.containers.List()
388
-						for _, container := range contList {
389
-							if err := container.updateResolvConf(updatedResolvConf, newResolvConfHash); err != nil {
390
-								logrus.Debugf("Error on resolv.conf update check for container ID: %s: %v", container.ID, err)
391
-							}
392
-						}
393
-					}
394
-				}
395
-			case err := <-watcher.Errors:
396
-				logrus.Debugf("host resolv.conf notify error: %v", err)
397
-			}
398
-		}
399
-	}()
400
-
401
-	if err := watcher.Add("/etc"); err != nil {
402
-		return err
403
-	}
404
-	return nil
405
-}
406
-
407 352
 func (daemon *Daemon) checkDeprecatedExpose(config *runconfig.Config) bool {
408 353
 	if config != nil {
409 354
 		if config.PortSpecs != nil {
... ...
@@ -727,18 +672,15 @@ func (daemon *Daemon) RegisterLinks(container *Container, hostConfig *runconfig.
727 727
 }
728 728
 
729 729
 func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemon, err error) {
730
-	if config.Mtu == 0 {
731
-		config.Mtu = getDefaultNetworkMtu()
732
-	}
733 730
 	// Check for mutually incompatible config options
734 731
 	if config.Bridge.Iface != "" && config.Bridge.IP != "" {
735 732
 		return nil, fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.")
736 733
 	}
737
-	if !config.Bridge.EnableIptables && !config.Bridge.InterContainerCommunication {
734
+	if !config.Bridge.EnableIPTables && !config.Bridge.InterContainerCommunication {
738 735
 		return nil, fmt.Errorf("You specified --iptables=false with --icc=false. ICC uses iptables to function. Please set --icc or --iptables to true.")
739 736
 	}
740
-	if !config.Bridge.EnableIptables && config.Bridge.EnableIpMasq {
741
-		config.Bridge.EnableIpMasq = false
737
+	if !config.Bridge.EnableIPTables && config.Bridge.EnableIPMasq {
738
+		config.Bridge.EnableIPMasq = false
742 739
 	}
743 740
 	config.DisableNetwork = config.Bridge.Iface == disableNetworkBridge
744 741
 
... ...
@@ -882,8 +824,9 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
882 882
 	}
883 883
 
884 884
 	if !config.DisableNetwork {
885
-		if err := bridge.InitDriver(&config.Bridge); err != nil {
886
-			return nil, fmt.Errorf("Error initializing Bridge: %v", err)
885
+		d.netController, err = initNetworkController(config)
886
+		if err != nil {
887
+			return nil, fmt.Errorf("Error initializing network controller: %v", err)
887 888
 		}
888 889
 	}
889 890
 
... ...
@@ -942,12 +885,97 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
942 942
 		return nil, err
943 943
 	}
944 944
 
945
-	// set up filesystem watch on resolv.conf for network changes
946
-	if err := d.setupResolvconfWatcher(); err != nil {
947
-		return nil, err
945
+	return d, nil
946
+}
947
+
948
+func initNetworkController(config *Config) (libnetwork.NetworkController, error) {
949
+	controller, err := libnetwork.New()
950
+	if err != nil {
951
+		return nil, fmt.Errorf("error obtaining controller instance: %v", err)
948 952
 	}
949 953
 
950
-	return d, nil
954
+	// Initialize default driver "null"
955
+
956
+	if err := controller.ConfigureNetworkDriver("null", options.Generic{}); err != nil {
957
+		return nil, fmt.Errorf("Error initializing null driver: %v", err)
958
+	}
959
+
960
+	// Initialize default network on "null"
961
+	if _, err := controller.NewNetwork("null", "none"); err != nil {
962
+		return nil, fmt.Errorf("Error creating default \"null\" network: %v", err)
963
+	}
964
+
965
+	// Initialize default driver "host"
966
+	if err := controller.ConfigureNetworkDriver("host", options.Generic{}); err != nil {
967
+		return nil, fmt.Errorf("Error initializing host driver: %v", err)
968
+	}
969
+
970
+	// Initialize default network on "host"
971
+	if _, err := controller.NewNetwork("host", "host"); err != nil {
972
+		return nil, fmt.Errorf("Error creating default \"host\" network: %v", err)
973
+	}
974
+
975
+	// Initialize default driver "bridge"
976
+	option := options.Generic{
977
+		"EnableIPForwarding": config.Bridge.EnableIPForward}
978
+
979
+	if err := controller.ConfigureNetworkDriver("bridge", options.Generic{netlabel.GenericData: option}); err != nil {
980
+		return nil, fmt.Errorf("Error initializing bridge driver: %v", err)
981
+	}
982
+
983
+	netOption := options.Generic{
984
+		"BridgeName":          config.Bridge.Iface,
985
+		"Mtu":                 config.Mtu,
986
+		"EnableIPTables":      config.Bridge.EnableIPTables,
987
+		"EnableIPMasquerade":  config.Bridge.EnableIPMasq,
988
+		"EnableICC":           config.Bridge.InterContainerCommunication,
989
+		"EnableUserlandProxy": config.Bridge.EnableUserlandProxy,
990
+	}
991
+
992
+	if config.Bridge.IP != "" {
993
+		ip, bipNet, err := net.ParseCIDR(config.Bridge.IP)
994
+		if err != nil {
995
+			return nil, err
996
+		}
997
+
998
+		bipNet.IP = ip
999
+		netOption["AddressIPv4"] = bipNet
1000
+	}
1001
+
1002
+	if config.Bridge.FixedCIDR != "" {
1003
+		_, fCIDR, err := net.ParseCIDR(config.Bridge.FixedCIDR)
1004
+		if err != nil {
1005
+			return nil, err
1006
+		}
1007
+
1008
+		netOption["FixedCIDR"] = fCIDR
1009
+	}
1010
+
1011
+	if config.Bridge.FixedCIDRv6 != "" {
1012
+		_, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6)
1013
+		if err != nil {
1014
+			return nil, err
1015
+		}
1016
+
1017
+		netOption["FixedCIDRv6"] = fCIDRv6
1018
+	}
1019
+
1020
+	// --ip processing
1021
+	if config.Bridge.DefaultIP != nil {
1022
+		netOption["DefaultBindingIP"] = config.Bridge.DefaultIP
1023
+	}
1024
+
1025
+	// Initialize default network on "bridge" with the same name
1026
+	_, err = controller.NewNetwork("bridge", "bridge",
1027
+		libnetwork.NetworkOptionGeneric(options.Generic{
1028
+			netlabel.GenericData: netOption,
1029
+			netlabel.EnableIPv6:  config.Bridge.EnableIPv6,
1030
+		}))
1031
+	if err != nil {
1032
+		return nil, fmt.Errorf("Error creating default \"bridge\" network: %v", err)
1033
+	}
1034
+
1035
+	return controller, nil
951 1036
 }
952 1037
 
953 1038
 func (daemon *Daemon) Shutdown() error {
... ...
@@ -35,13 +35,14 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error
35 35
 		}
36 36
 		parentContainer, _ := daemon.Get(pe.ID())
37 37
 
38
+		if err := daemon.ContainerGraph().Delete(name); err != nil {
39
+			return err
40
+		}
41
+
38 42
 		if parentContainer != nil {
39 43
 			parentContainer.DisableLink(n)
40 44
 		}
41 45
 
42
-		if err := daemon.ContainerGraph().Delete(name); err != nil {
43
-			return err
44
-		}
45 46
 		return nil
46 47
 	}
47 48
 
... ...
@@ -72,6 +72,7 @@ type Network struct {
72 72
 	Interface      *NetworkInterface `json:"interface"` // if interface is nil then networking is disabled
73 73
 	Mtu            int               `json:"mtu"`
74 74
 	ContainerID    string            `json:"container_id"` // id of the container to join network.
75
+	NamespacePath  string            `json:"namespace_path"`
75 76
 	HostNetworking bool              `json:"host_networking"`
76 77
 }
77 78
 
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"os/exec"
13 13
 	"path"
14 14
 	"path/filepath"
15
+	"runtime"
15 16
 	"strconv"
16 17
 	"strings"
17 18
 	"sync"
... ...
@@ -30,6 +31,7 @@ import (
30 30
 	"github.com/docker/libcontainer/system"
31 31
 	"github.com/docker/libcontainer/user"
32 32
 	"github.com/kr/pty"
33
+	"github.com/vishvananda/netns"
33 34
 )
34 35
 
35 36
 const DriverName = "lxc"
... ...
@@ -80,6 +82,41 @@ func (d *driver) Name() string {
80 80
 	return fmt.Sprintf("%s-%s", DriverName, version)
81 81
 }
82 82
 
83
+func setupNetNs(nsPath string) (*os.Process, error) {
84
+	runtime.LockOSThread()
85
+	defer runtime.UnlockOSThread()
86
+
87
+	origns, err := netns.Get()
88
+	if err != nil {
89
+		return nil, err
90
+	}
91
+	defer origns.Close()
92
+
93
+	f, err := os.OpenFile(nsPath, os.O_RDONLY, 0)
94
+	if err != nil {
95
+		return nil, fmt.Errorf("failed to get network namespace %q: %v", nsPath, err)
96
+	}
97
+	defer f.Close()
98
+
99
+	nsFD := f.Fd()
100
+	if err := netns.Set(netns.NsHandle(nsFD)); err != nil {
101
+		return nil, fmt.Errorf("failed to set network namespace %q: %v", nsPath, err)
102
+	}
103
+	defer netns.Set(origns)
104
+
105
+	cmd := exec.Command("/bin/sh", "-c", "while true; do sleep 1; done")
106
+	if err := cmd.Start(); err != nil {
107
+		return nil, fmt.Errorf("failed to start netns process: %v", err)
108
+	}
109
+
110
+	return cmd.Process, nil
111
+}
112
+
113
+func killNetNsProc(proc *os.Process) {
114
+	proc.Kill()
115
+	proc.Wait()
116
+}
117
+
83 118
 func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) {
84 119
 	var (
85 120
 		term     execdriver.Terminal
... ...
@@ -87,6 +124,10 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
87 87
 		dataPath = d.containerDir(c.ID)
88 88
 	)
89 89
 
90
+	if c.Network.NamespacePath == "" && c.Network.ContainerID == "" {
91
+		return execdriver.ExitStatus{ExitCode: -1}, fmt.Errorf("empty namespace path for non-container network")
92
+	}
93
+
90 94
 	container, err := d.createContainer(c)
91 95
 	if err != nil {
92 96
 		return execdriver.ExitStatus{ExitCode: -1}, err
... ...
@@ -136,10 +177,20 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
136 136
 		params = append(params, "-F")
137 137
 	}
138 138
 
139
+	proc := &os.Process{}
139 140
 	if c.Network.ContainerID != "" {
140 141
 		params = append(params,
141 142
 			"--share-net", c.Network.ContainerID,
142 143
 		)
144
+	} else {
145
+		proc, err = setupNetNs(c.Network.NamespacePath)
146
+		if err != nil {
147
+			return execdriver.ExitStatus{ExitCode: -1}, err
148
+		}
149
+
150
+		pidStr := fmt.Sprintf("%d", proc.Pid)
151
+		params = append(params,
152
+			"--share-net", pidStr)
143 153
 	}
144 154
 	if c.Ipc != nil {
145 155
 		if c.Ipc.ContainerID != "" {
... ...
@@ -157,15 +208,6 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
157 157
 		"--",
158 158
 		c.InitPath,
159 159
 	)
160
-	if c.Network.Interface != nil {
161
-		params = append(params,
162
-			"-g", c.Network.Interface.Gateway,
163
-			"-i", fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
164
-		)
165
-	}
166
-	params = append(params,
167
-		"-mtu", strconv.Itoa(c.Network.Mtu),
168
-	)
169 160
 
170 161
 	if c.ProcessConfig.User != "" {
171 162
 		params = append(params, "-u", c.ProcessConfig.User)
... ...
@@ -214,10 +256,12 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
214 214
 	c.ProcessConfig.Args = append([]string{name}, arg...)
215 215
 
216 216
 	if err := createDeviceNodes(c.Rootfs, c.AutoCreatedDevices); err != nil {
217
+		killNetNsProc(proc)
217 218
 		return execdriver.ExitStatus{ExitCode: -1}, err
218 219
 	}
219 220
 
220 221
 	if err := c.ProcessConfig.Start(); err != nil {
222
+		killNetNsProc(proc)
221 223
 		return execdriver.ExitStatus{ExitCode: -1}, err
222 224
 	}
223 225
 
... ...
@@ -245,8 +289,10 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
245 245
 	// Poll lxc for RUNNING status
246 246
 	pid, err := d.waitForStart(c, waitLock)
247 247
 	if err != nil {
248
+		killNetNsProc(proc)
248 249
 		return terminate(err)
249 250
 	}
251
+	killNetNsProc(proc)
250 252
 
251 253
 	cgroupPaths, err := cgroupPaths(c.ID)
252 254
 	if err != nil {
... ...
@@ -15,8 +15,7 @@ import (
15 15
 	"github.com/docker/libcontainer/label"
16 16
 )
17 17
 
18
-const LxcTemplate = `
19
-{{if .Network.Interface}}
18
+/* {{if .Network.Interface}}
20 19
 # network configuration
21 20
 lxc.network.type = veth
22 21
 lxc.network.link = {{.Network.Interface.Bridge}}
... ...
@@ -30,8 +29,10 @@ lxc.network.type = none
30 30
 lxc.network.type = empty
31 31
 lxc.network.flags = up
32 32
 lxc.network.mtu = {{.Network.Mtu}}
33
-{{end}}
33
+{{end}} */
34 34
 
35
+const LxcTemplate = `
36
+lxc.network.type = none
35 37
 # root filesystem
36 38
 {{$ROOTFS := .Rootfs}}
37 39
 lxc.rootfs = {{$ROOTFS}}
... ...
@@ -145,6 +146,7 @@ lxc.network.ipv4.gateway = {{.Network.Interface.Gateway}}
145 145
 {{if .Network.Interface.MacAddress}}
146 146
 lxc.network.hwaddr = {{.Network.Interface.MacAddress}}
147 147
 {{end}}
148
+{{end}}
148 149
 {{if .ProcessConfig.Env}}
149 150
 lxc.utsname = {{getHostname .ProcessConfig.Env}}
150 151
 {{end}}
... ...
@@ -164,7 +166,6 @@ lxc.cap.drop = {{.}}
164 164
 		{{end}}
165 165
 	{{end}}
166 166
 {{end}}
167
-{{end}}
168 167
 `
169 168
 
170 169
 var LxcTemplateCompiled *template.Template
... ...
@@ -264,13 +264,8 @@ func TestCustomLxcConfigMisc(t *testing.T) {
264 264
 			"lxc.cgroup.cpuset.cpus = 0,1",
265 265
 		},
266 266
 		Network: &execdriver.Network{
267
-			Mtu: 1500,
268
-			Interface: &execdriver.NetworkInterface{
269
-				Gateway:     "10.10.10.1",
270
-				IPAddress:   "10.10.10.10",
271
-				IPPrefixLen: 24,
272
-				Bridge:      "docker0",
273
-			},
267
+			Mtu:       1500,
268
+			Interface: nil,
274 269
 		},
275 270
 		ProcessConfig:   processConfig,
276 271
 		CapAdd:          []string{"net_admin", "syslog"},
... ...
@@ -282,13 +277,6 @@ func TestCustomLxcConfigMisc(t *testing.T) {
282 282
 	if err != nil {
283 283
 		t.Fatal(err)
284 284
 	}
285
-	// network
286
-	grepFile(t, p, "lxc.network.type = veth")
287
-	grepFile(t, p, "lxc.network.link = docker0")
288
-	grepFile(t, p, "lxc.network.name = eth0")
289
-	grepFile(t, p, "lxc.network.ipv4 = 10.10.10.10/24")
290
-	grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1")
291
-	grepFile(t, p, "lxc.network.flags = up")
292 285
 	grepFile(t, p, "lxc.aa_profile = lxc-container-default-with-nesting")
293 286
 	// hostname
294 287
 	grepFile(t, p, "lxc.utsname = testhost")
... ...
@@ -329,13 +317,8 @@ func TestCustomLxcConfigMiscOverride(t *testing.T) {
329 329
 			"lxc.network.ipv4 = 172.0.0.1",
330 330
 		},
331 331
 		Network: &execdriver.Network{
332
-			Mtu: 1500,
333
-			Interface: &execdriver.NetworkInterface{
334
-				Gateway:     "10.10.10.1",
335
-				IPAddress:   "10.10.10.10",
336
-				IPPrefixLen: 24,
337
-				Bridge:      "docker0",
338
-			},
332
+			Mtu:       1500,
333
+			Interface: nil,
339 334
 		},
340 335
 		ProcessConfig: processConfig,
341 336
 		CapAdd:        []string{"NET_ADMIN", "SYSLOG"},
... ...
@@ -346,13 +329,6 @@ func TestCustomLxcConfigMiscOverride(t *testing.T) {
346 346
 	if err != nil {
347 347
 		t.Fatal(err)
348 348
 	}
349
-	// network
350
-	grepFile(t, p, "lxc.network.type = veth")
351
-	grepFile(t, p, "lxc.network.link = docker0")
352
-	grepFile(t, p, "lxc.network.name = eth0")
353
-	grepFile(t, p, "lxc.network.ipv4 = 172.0.0.1")
354
-	grepFile(t, p, "lxc.network.ipv4.gateway = 10.10.10.1")
355
-	grepFile(t, p, "lxc.network.flags = up")
356 349
 
357 350
 	// hostname
358 351
 	grepFile(t, p, "lxc.utsname = testhost")
... ...
@@ -89,40 +89,6 @@ func generateIfaceName() (string, error) {
89 89
 }
90 90
 
91 91
 func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command) error {
92
-	if c.Network.HostNetworking {
93
-		container.Namespaces.Remove(configs.NEWNET)
94
-		return nil
95
-	}
96
-
97
-	container.Networks = []*configs.Network{
98
-		{
99
-			Type: "loopback",
100
-		},
101
-	}
102
-
103
-	iName, err := generateIfaceName()
104
-	if err != nil {
105
-		return err
106
-	}
107
-	if c.Network.Interface != nil {
108
-		vethNetwork := configs.Network{
109
-			Name:              "eth0",
110
-			HostInterfaceName: iName,
111
-			Mtu:               c.Network.Mtu,
112
-			Address:           fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
113
-			MacAddress:        c.Network.Interface.MacAddress,
114
-			Gateway:           c.Network.Interface.Gateway,
115
-			Type:              "veth",
116
-			Bridge:            c.Network.Interface.Bridge,
117
-			HairpinMode:       c.Network.Interface.HairpinMode,
118
-		}
119
-		if c.Network.Interface.GlobalIPv6Address != "" {
120
-			vethNetwork.IPv6Address = fmt.Sprintf("%s/%d", c.Network.Interface.GlobalIPv6Address, c.Network.Interface.GlobalIPv6PrefixLen)
121
-			vethNetwork.IPv6Gateway = c.Network.Interface.IPv6Gateway
122
-		}
123
-		container.Networks = append(container.Networks, &vethNetwork)
124
-	}
125
-
126 92
 	if c.Network.ContainerID != "" {
127 93
 		d.Lock()
128 94
 		active := d.activeContainers[c.Network.ContainerID]
... ...
@@ -138,8 +104,14 @@ func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command)
138 138
 		}
139 139
 
140 140
 		container.Namespaces.Add(configs.NEWNET, state.NamespacePaths[configs.NEWNET])
141
+		return nil
142
+	}
143
+
144
+	if c.Network.NamespacePath == "" {
145
+		return fmt.Errorf("network namespace path is empty")
141 146
 	}
142 147
 
148
+	container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath)
143 149
 	return nil
144 150
 }
145 151
 
... ...
@@ -2,18 +2,28 @@ package network
2 2
 
3 3
 import "github.com/docker/docker/nat"
4 4
 
5
+type Address struct {
6
+	Addr      string
7
+	PrefixLen int
8
+}
9
+
5 10
 type Settings struct {
11
+	Bridge                 string
12
+	EndpointID             string
13
+	Gateway                string
14
+	GlobalIPv6Address      string
15
+	GlobalIPv6PrefixLen    int
16
+	HairpinMode            bool
6 17
 	IPAddress              string
7 18
 	IPPrefixLen            int
8
-	MacAddress             string
19
+	IPv6Gateway            string
9 20
 	LinkLocalIPv6Address   string
10 21
 	LinkLocalIPv6PrefixLen int
11
-	GlobalIPv6Address      string
12
-	GlobalIPv6PrefixLen    int
13
-	Gateway                string
14
-	IPv6Gateway            string
15
-	Bridge                 string
22
+	MacAddress             string
23
+	NetworkID              string
16 24
 	PortMapping            map[string]map[string]string // Deprecated
17 25
 	Ports                  nat.PortMap
18
-	HairpinMode            bool
26
+	SandboxKey             string
27
+	SecondaryIPAddresses   []Address
28
+	SecondaryIPv6Addresses []Address
19 29
 }
... ...
@@ -17,7 +17,7 @@ import (
17 17
 	"github.com/docker/docker/pkg/reexec"
18 18
 )
19 19
 
20
-const userlandProxyCommandName = "docker-proxy"
20
+const userlandProxyCommandName = "docker-proxy-deprecated"
21 21
 
22 22
 func init() {
23 23
 	reexec.Register(userlandProxyCommandName, execProxy)
... ...
@@ -15,6 +15,7 @@ import (
15 15
 	"strings"
16 16
 	"time"
17 17
 
18
+	"github.com/docker/libnetwork/iptables"
18 19
 	"github.com/docker/libtrust"
19 20
 	"github.com/go-check/check"
20 21
 )
... ...
@@ -721,13 +722,49 @@ func (s *DockerDaemonSuite) TestDaemonICCLinkExpose(c *check.C) {
721 721
 	c.Assert(matched, check.Equals, true,
722 722
 		check.Commentf("iptables output should have contained %q, but was %q", regex, out))
723 723
 
724
-	_, err = d.Cmd("run", "-d", "--expose", "4567", "--name", "icc1", "busybox", "nc", "-l", "-p", "4567")
725
-	c.Assert(err, check.IsNil)
724
+	out, err = d.Cmd("run", "-d", "--expose", "4567", "--name", "icc1", "busybox", "nc", "-l", "-p", "4567")
725
+	c.Assert(err, check.IsNil, check.Commentf(out))
726 726
 
727 727
 	out, err = d.Cmd("run", "--link", "icc1:icc1", "busybox", "nc", "icc1", "4567")
728 728
 	c.Assert(err, check.IsNil, check.Commentf(out))
729 729
 }
730 730
 
731
+func (s *DockerDaemonSuite) TestDaemonLinksIpTablesRulesWhenLinkAndUnlink(c *check.C) {
732
+	bridgeName := "external-bridge"
733
+	bridgeIp := "192.169.1.1/24"
734
+
735
+	out, err := createInterface(c, "bridge", bridgeName, bridgeIp)
736
+	c.Assert(err, check.IsNil, check.Commentf(out))
737
+	defer deleteInterface(c, bridgeName)
738
+
739
+	args := []string{"--bridge", bridgeName, "--icc=false"}
740
+	err = s.d.StartWithBusybox(args...)
741
+	c.Assert(err, check.IsNil)
742
+	defer s.d.Restart()
743
+
744
+	_, err = s.d.Cmd("run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "top")
745
+	c.Assert(err, check.IsNil)
746
+	_, err = s.d.Cmd("run", "-d", "--name", "parent", "--link", "child:http", "busybox", "top")
747
+	c.Assert(err, check.IsNil)
748
+
749
+	childIP := s.d.findContainerIP("child")
750
+	parentIP := s.d.findContainerIP("parent")
751
+
752
+	sourceRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"}
753
+	destinationRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"}
754
+	if !iptables.Exists("filter", "DOCKER", sourceRule...) || !iptables.Exists("filter", "DOCKER", destinationRule...) {
755
+		c.Fatal("Iptables rules not found")
756
+	}
757
+
758
+	s.d.Cmd("rm", "--link", "parent/http")
759
+	if iptables.Exists("filter", "DOCKER", sourceRule...) || iptables.Exists("filter", "DOCKER", destinationRule...) {
760
+		c.Fatal("Iptables rules should be removed when unlink")
761
+	}
762
+
763
+	s.d.Cmd("kill", "child")
764
+	s.d.Cmd("kill", "parent")
765
+}
766
+
731 767
 func (s *DockerDaemonSuite) TestDaemonUlimitDefaults(c *check.C) {
732 768
 	testRequires(c, NativeExecDriver)
733 769
 
... ...
@@ -10,7 +10,6 @@ import (
10 10
 	"strings"
11 11
 	"time"
12 12
 
13
-	"github.com/docker/docker/pkg/iptables"
14 13
 	"github.com/go-check/check"
15 14
 )
16 15
 
... ...
@@ -110,31 +109,6 @@ func (s *DockerSuite) TestLinksPingLinkedContainersAfterRename(c *check.C) {
110 110
 
111 111
 }
112 112
 
113
-func (s *DockerSuite) TestLinksIpTablesRulesWhenLinkAndUnlink(c *check.C) {
114
-	testRequires(c, SameHostDaemon)
115
-
116
-	dockerCmd(c, "run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "top")
117
-	dockerCmd(c, "run", "-d", "--name", "parent", "--link", "child:http", "busybox", "top")
118
-
119
-	childIP := findContainerIP(c, "child")
120
-	parentIP := findContainerIP(c, "parent")
121
-
122
-	sourceRule := []string{"-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"}
123
-	destinationRule := []string{"-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"}
124
-	if !iptables.Exists("filter", "DOCKER", sourceRule...) || !iptables.Exists("filter", "DOCKER", destinationRule...) {
125
-		c.Fatal("Iptables rules not found")
126
-	}
127
-
128
-	dockerCmd(c, "rm", "--link", "parent/http")
129
-	if iptables.Exists("filter", "DOCKER", sourceRule...) || iptables.Exists("filter", "DOCKER", destinationRule...) {
130
-		c.Fatal("Iptables rules should be removed when unlink")
131
-	}
132
-
133
-	dockerCmd(c, "kill", "child")
134
-	dockerCmd(c, "kill", "parent")
135
-
136
-}
137
-
138 113
 func (s *DockerSuite) TestLinksInspectLinksStarted(c *check.C) {
139 114
 	var (
140 115
 		expected = map[string]struct{}{"/container1:/testinspectlink/alias1": {}, "/container2:/testinspectlink/alias2": {}}
... ...
@@ -19,7 +19,7 @@ import (
19 19
 	"time"
20 20
 
21 21
 	"github.com/docker/docker/nat"
22
-	"github.com/docker/docker/pkg/resolvconf"
22
+	"github.com/docker/libnetwork/resolvconf"
23 23
 	"github.com/go-check/check"
24 24
 )
25 25
 
... ...
@@ -1459,14 +1459,11 @@ func (s *DockerSuite) TestRunDnsOptionsBasedOnHostResolvConf(c *check.C) {
1459 1459
 	}
1460 1460
 }
1461 1461
 
1462
-// Test the file watch notifier on docker host's /etc/resolv.conf
1463
-// A go-routine is responsible for auto-updating containers which are
1464
-// stopped and have an unmodified copy of resolv.conf, as well as
1465
-// marking running containers as requiring an update on next restart
1466
-func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
1467
-	// Because overlay doesn't support inotify properly, we need to skip
1468
-	// this test if the docker daemon has Storage Driver == overlay
1469
-	testRequires(c, SameHostDaemon, NotOverlay)
1462
+// Test if container resolv.conf gets updated the next time it restarts
1463
+// if host /etc/resolv.conf has changed. This only applies if the container
1464
+// uses the host's /etc/resolv.conf and does not have any dns options provided.
1465
+func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) {
1466
+	testRequires(c, SameHostDaemon)
1470 1467
 
1471 1468
 	tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78")
1472 1469
 	tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1")
... ...
@@ -1492,7 +1489,7 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
1492 1492
 		}
1493 1493
 	}()
1494 1494
 
1495
-	//1. test that a non-running container gets an updated resolv.conf
1495
+	//1. test that a restarting container gets an updated resolv.conf
1496 1496
 	cmd = exec.Command(dockerBinary, "run", "--name='first'", "busybox", "true")
1497 1497
 	if _, err := runCommand(cmd); err != nil {
1498 1498
 		c.Fatal(err)
... ...
@@ -1508,17 +1505,26 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
1508 1508
 		c.Fatal(err)
1509 1509
 	}
1510 1510
 
1511
-	time.Sleep(time.Second / 2)
1511
+	// start the container again to pickup changes
1512
+	cmd = exec.Command(dockerBinary, "start", "first")
1513
+	if out, err := runCommand(cmd); err != nil {
1514
+		c.Fatalf("Errored out %s, \nerror: %v", string(out), err)
1515
+	}
1516
+
1512 1517
 	// check for update in container
1513 1518
 	containerResolv, err := readContainerFile(containerID1, "resolv.conf")
1514 1519
 	if err != nil {
1515 1520
 		c.Fatal(err)
1516 1521
 	}
1517 1522
 	if !bytes.Equal(containerResolv, bytesResolvConf) {
1518
-		c.Fatalf("Stopped container does not have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
1523
+		c.Fatalf("Restarted container does not have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
1519 1524
 	}
1520 1525
 
1521
-	//2. test that a non-running container does not receive resolv.conf updates
1526
+	/* 	//make a change to resolv.conf (in this case replacing our tmp copy with orig copy)
1527
+	   	if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
1528
+	   		c.Fatal(err)
1529
+	   	} */
1530
+	//2. test that a restarting container does not receive resolv.conf updates
1522 1531
 	//   if it modified the container copy of the starting point resolv.conf
1523 1532
 	cmd = exec.Command(dockerBinary, "run", "--name='second'", "busybox", "sh", "-c", "echo 'search mylittlepony.com' >>/etc/resolv.conf")
1524 1533
 	if _, err = runCommand(cmd); err != nil {
... ...
@@ -1528,24 +1534,26 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
1528 1528
 	if err != nil {
1529 1529
 		c.Fatal(err)
1530 1530
 	}
1531
-	containerResolvHashBefore, err := readContainerFile(containerID2, "resolv.conf.hash")
1532
-	if err != nil {
1533
-		c.Fatal(err)
1534
-	}
1535 1531
 
1536 1532
 	//make a change to resolv.conf (in this case replacing our tmp copy with orig copy)
1537 1533
 	if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
1538 1534
 		c.Fatal(err)
1539 1535
 	}
1540 1536
 
1541
-	time.Sleep(time.Second / 2)
1542
-	containerResolvHashAfter, err := readContainerFile(containerID2, "resolv.conf.hash")
1537
+	// start the container again
1538
+	cmd = exec.Command(dockerBinary, "start", "second")
1539
+	if out, err := runCommand(cmd); err != nil {
1540
+		c.Fatalf("Errored out %s, \nerror: %v", string(out), err)
1541
+	}
1542
+
1543
+	// check for update in container
1544
+	containerResolv, err = readContainerFile(containerID2, "resolv.conf")
1543 1545
 	if err != nil {
1544 1546
 		c.Fatal(err)
1545 1547
 	}
1546 1548
 
1547
-	if !bytes.Equal(containerResolvHashBefore, containerResolvHashAfter) {
1548
-		c.Fatalf("Stopped container with modified resolv.conf should not have been updated; expected hash: %v, new hash: %v", containerResolvHashBefore, containerResolvHashAfter)
1549
+	if bytes.Equal(containerResolv, resolvConfSystem) {
1550
+		c.Fatalf("Restarting  a container after container updated resolv.conf should not pick up host changes; expected %q, got %q", string(containerResolv), string(resolvConfSystem))
1549 1551
 	}
1550 1552
 
1551 1553
 	//3. test that a running container's resolv.conf is not modified while running
... ...
@@ -1556,26 +1564,19 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
1556 1556
 	}
1557 1557
 	runningContainerID := strings.TrimSpace(out)
1558 1558
 
1559
-	containerResolvHashBefore, err = readContainerFile(runningContainerID, "resolv.conf.hash")
1560
-	if err != nil {
1561
-		c.Fatal(err)
1562
-	}
1563
-
1564 1559
 	// replace resolv.conf
1565 1560
 	if err := ioutil.WriteFile("/etc/resolv.conf", bytesResolvConf, 0644); err != nil {
1566 1561
 		c.Fatal(err)
1567 1562
 	}
1568 1563
 
1569
-	// make sure the updater has time to run to validate we really aren't
1570
-	// getting updated
1571
-	time.Sleep(time.Second / 2)
1572
-	containerResolvHashAfter, err = readContainerFile(runningContainerID, "resolv.conf.hash")
1564
+	// check for update in container
1565
+	containerResolv, err = readContainerFile(runningContainerID, "resolv.conf")
1573 1566
 	if err != nil {
1574 1567
 		c.Fatal(err)
1575 1568
 	}
1576 1569
 
1577
-	if !bytes.Equal(containerResolvHashBefore, containerResolvHashAfter) {
1578
-		c.Fatalf("Running container's resolv.conf should not be updated; expected hash: %v, new hash: %v", containerResolvHashBefore, containerResolvHashAfter)
1570
+	if bytes.Equal(containerResolv, bytesResolvConf) {
1571
+		c.Fatalf("Running container should not have updated resolv.conf; expected %q, got %q", string(resolvConfSystem), string(containerResolv))
1579 1572
 	}
1580 1573
 
1581 1574
 	//4. test that a running container's resolv.conf is updated upon restart
... ...
@@ -1591,7 +1592,7 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
1591 1591
 		c.Fatal(err)
1592 1592
 	}
1593 1593
 	if !bytes.Equal(containerResolv, bytesResolvConf) {
1594
-		c.Fatalf("Restarted container should have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv))
1594
+		c.Fatalf("Restarted container should have updated resolv.conf; expected %q, got %q", string(bytesResolvConf), string(containerResolv))
1595 1595
 	}
1596 1596
 
1597 1597
 	//5. test that additions of a localhost resolver are cleaned from
... ...
@@ -1603,7 +1604,12 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
1603 1603
 		c.Fatal(err)
1604 1604
 	}
1605 1605
 
1606
-	time.Sleep(time.Second / 2)
1606
+	// start the container again to pickup changes
1607
+	cmd = exec.Command(dockerBinary, "start", "first")
1608
+	if out, err := runCommand(cmd); err != nil {
1609
+		c.Fatalf("Errored out %s, \nerror: %v", string(out), err)
1610
+	}
1611
+
1607 1612
 	// our first exited container ID should have been updated, but with default DNS
1608 1613
 	// after the cleanup of resolv.conf found only a localhost nameserver:
1609 1614
 	containerResolv, err = readContainerFile(containerID1, "resolv.conf")
... ...
@@ -1645,7 +1651,12 @@ func (s *DockerSuite) TestRunResolvconfUpdater(c *check.C) {
1645 1645
 		c.Fatal(err)
1646 1646
 	}
1647 1647
 
1648
-	time.Sleep(time.Second / 2)
1648
+	// start the container again to pickup changes
1649
+	cmd = exec.Command(dockerBinary, "start", "third")
1650
+	if out, err := runCommand(cmd); err != nil {
1651
+		c.Fatalf("Errored out %s, \nerror: %v", string(out), err)
1652
+	}
1653
+
1649 1654
 	// check for update in container
1650 1655
 	containerResolv, err = readContainerFile(containerID3, "resolv.conf")
1651 1656
 	if err != nil {
... ...
@@ -5,9 +5,7 @@ import (
5 5
 	"path"
6 6
 	"strings"
7 7
 
8
-	"github.com/docker/docker/daemon/networkdriver/bridge"
9 8
 	"github.com/docker/docker/nat"
10
-	"github.com/docker/docker/pkg/iptables"
11 9
 )
12 10
 
13 11
 type Link struct {
... ...
@@ -140,26 +138,10 @@ func (l *Link) getDefaultPort() *nat.Port {
140 140
 }
141 141
 
142 142
 func (l *Link) Enable() error {
143
-	// -A == iptables append flag
144
-	if err := l.toggle("-A", false); err != nil {
145
-		return err
146
-	}
147
-	// call this on Firewalld reload
148
-	iptables.OnReloaded(func() { l.toggle("-A", false) })
149 143
 	l.IsEnabled = true
150 144
 	return nil
151 145
 }
152 146
 
153 147
 func (l *Link) Disable() {
154
-	// We do not care about errors here because the link may not
155
-	// exist in iptables
156
-	// -D == iptables delete flag
157
-	l.toggle("-D", true)
158
-	// call this on Firewalld reload
159
-	iptables.OnReloaded(func() { l.toggle("-D", true) })
160 148
 	l.IsEnabled = false
161 149
 }
162
-
163
-func (l *Link) toggle(action string, ignoreErrors bool) error {
164
-	return bridge.LinkContainers(action, l.ParentIP, l.ChildIP, l.Ports, ignoreErrors)
165
-}
... ...
@@ -18,7 +18,7 @@ type NetworkMode string
18 18
 
19 19
 // IsPrivate indicates whether container use it's private network stack
20 20
 func (n NetworkMode) IsPrivate() bool {
21
-	return !(n.IsHost() || n.IsContainer() || n.IsNone())
21
+	return !(n.IsHost() || n.IsContainer())
22 22
 }
23 23
 
24 24
 func (n NetworkMode) IsBridge() bool {