Browse Source

Merge pull request #16038 from aboch/sbx

Vendor libnetwork dc52820147f40fe424c8959987af3b396f842639
Michael Crosby 9 years ago
parent
commit
288275ab60
59 changed files with 2011 additions and 1603 deletions
  1. 64 53
      daemon/container_unix.go
  2. 1 0
      daemon/network/settings.go
  3. 4 8
      daemon/stats.go
  4. 1 1
      hack/vendor.sh
  5. 11 8
      integration-cli/docker_cli_daemon_test.go
  6. 4 4
      integration-cli/docker_cli_run_test.go
  7. 9 9
      vendor/src/github.com/docker/libnetwork/Makefile
  8. 10 8
      vendor/src/github.com/docker/libnetwork/README.md
  9. 204 51
      vendor/src/github.com/docker/libnetwork/api/api.go
  10. 20 22
      vendor/src/github.com/docker/libnetwork/api/types.go
  11. 243 156
      vendor/src/github.com/docker/libnetwork/bitseq/sequence.go
  12. 1 1
      vendor/src/github.com/docker/libnetwork/bitseq/store.go
  13. 26 2
      vendor/src/github.com/docker/libnetwork/client/service.go
  14. 26 21
      vendor/src/github.com/docker/libnetwork/client/types.go
  15. 132 12
      vendor/src/github.com/docker/libnetwork/controller.go
  16. 8 18
      vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go
  17. 36 23
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
  18. 1 1
      vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_armppc64.go
  19. 1 1
      vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_notarm.go
  20. 9 13
      vendor/src/github.com/docker/libnetwork/drivers/host/host.go
  21. 8 8
      vendor/src/github.com/docker/libnetwork/drivers/null/null.go
  22. 2 3
      vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go
  23. 8 9
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go
  24. 14 15
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go
  25. 6 7
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go
  26. 8 2
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go
  27. 1 2
      vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go
  28. 9 11
      vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go
  29. 0 2
      vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go
  30. 19 25
      vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go
  31. 8 11
      vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go
  32. 101 573
      vendor/src/github.com/docker/libnetwork/endpoint.go
  33. 10 53
      vendor/src/github.com/docker/libnetwork/endpoint_info.go
  34. 6 40
      vendor/src/github.com/docker/libnetwork/idm/idm.go
  35. 1 32
      vendor/src/github.com/docker/libnetwork/netutils/test_utils.go
  36. 1 61
      vendor/src/github.com/docker/libnetwork/netutils/utils.go
  37. 22 19
      vendor/src/github.com/docker/libnetwork/network.go
  38. 15 0
      vendor/src/github.com/docker/libnetwork/options/options.go
  39. 1 1
      vendor/src/github.com/docker/libnetwork/osl/interface_freebsd.go
  40. 1 1
      vendor/src/github.com/docker/libnetwork/osl/interface_linux.go
  41. 1 1
      vendor/src/github.com/docker/libnetwork/osl/interface_windows.go
  42. 33 9
      vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go
  43. 1 1
      vendor/src/github.com/docker/libnetwork/osl/namespace_unsupported.go
  44. 13 1
      vendor/src/github.com/docker/libnetwork/osl/namespace_windows.go
  45. 1 1
      vendor/src/github.com/docker/libnetwork/osl/neigh_freebsd.go
  46. 1 1
      vendor/src/github.com/docker/libnetwork/osl/neigh_linux.go
  47. 1 1
      vendor/src/github.com/docker/libnetwork/osl/neigh_windows.go
  48. 1 1
      vendor/src/github.com/docker/libnetwork/osl/options_linux.go
  49. 1 1
      vendor/src/github.com/docker/libnetwork/osl/route_linux.go
  50. 2 1
      vendor/src/github.com/docker/libnetwork/osl/sandbox.go
  51. 13 1
      vendor/src/github.com/docker/libnetwork/osl/sandbox_freebsd.go
  52. 1 1
      vendor/src/github.com/docker/libnetwork/osl/sandbox_unsupported.go
  53. 2 0
      vendor/src/github.com/docker/libnetwork/portmapper/mapper.go
  54. 75 25
      vendor/src/github.com/docker/libnetwork/resolvconf/resolvconf.go
  55. 744 0
      vendor/src/github.com/docker/libnetwork/sandbox.go
  56. 0 259
      vendor/src/github.com/docker/libnetwork/sandboxdata.go
  57. 5 12
      vendor/src/github.com/docker/libnetwork/store.go
  58. 53 0
      vendor/src/github.com/docker/libnetwork/types/types.go
  59. 11 0
      vendor/src/github.com/docker/libnetwork/wrapmake.sh

+ 64 - 53
daemon/container_unix.go

@@ -390,32 +390,34 @@ func (container *Container) buildHostnameFile() error {
 	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
 }
 
-func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, error) {
+func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, error) {
 	var (
-		joinOptions []libnetwork.EndpointOption
+		sboxOptions []libnetwork.SandboxOption
 		err         error
 		dns         []string
 		dnsSearch   []string
 	)
 
-	joinOptions = append(joinOptions, libnetwork.JoinOptionHostname(container.Config.Hostname),
-		libnetwork.JoinOptionDomainname(container.Config.Domainname))
+	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
+		libnetwork.OptionDomainname(container.Config.Domainname))
 
 	if container.hostConfig.NetworkMode.IsHost() {
-		joinOptions = append(joinOptions, libnetwork.JoinOptionUseDefaultSandbox())
+		sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
+		sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
+		sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
 	}
 
 	container.HostsPath, err = container.getRootResourcePath("hosts")
 	if err != nil {
 		return nil, err
 	}
-	joinOptions = append(joinOptions, libnetwork.JoinOptionHostsPath(container.HostsPath))
+	sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath))
 
 	container.ResolvConfPath, err = container.getRootResourcePath("resolv.conf")
 	if err != nil {
 		return nil, err
 	}
-	joinOptions = append(joinOptions, libnetwork.JoinOptionResolvConfPath(container.ResolvConfPath))
+	sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
 
 	if len(container.hostConfig.DNS) > 0 {
 		dns = container.hostConfig.DNS
@@ -424,7 +426,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
 	}
 
 	for _, d := range dns {
-		joinOptions = append(joinOptions, libnetwork.JoinOptionDNS(d))
+		sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d))
 	}
 
 	if len(container.hostConfig.DNSSearch) > 0 {
@@ -434,7 +436,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
 	}
 
 	for _, ds := range dnsSearch {
-		joinOptions = append(joinOptions, libnetwork.JoinOptionDNSSearch(ds))
+		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds))
 	}
 
 	if container.NetworkSettings.SecondaryIPAddresses != nil {
@@ -444,7 +446,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
 		}
 
 		for _, a := range container.NetworkSettings.SecondaryIPAddresses {
-			joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(name, a.Addr))
+			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr))
 		}
 	}
 
@@ -463,7 +465,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
 		if alias != child.Name[1:] {
 			aliasList = aliasList + " " + child.Name[1:]
 		}
-		joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(aliasList, child.NetworkSettings.IPAddress))
+		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.IPAddress))
 		if child.NetworkSettings.EndpointID != "" {
 			childEndpoints = append(childEndpoints, child.NetworkSettings.EndpointID)
 		}
@@ -472,7 +474,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
 	for _, extraHost := range container.hostConfig.ExtraHosts {
 		// allow IPv6 addresses in extra hosts; only split on first ":"
 		parts := strings.SplitN(extraHost, ":", 2)
-		joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(parts[0], parts[1]))
+		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
 	}
 
 	refs := container.daemon.containerGraph().RefPaths(container.ID)
@@ -488,7 +490,7 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
 
 		if c != nil && !container.daemon.configStore.DisableBridge && container.hostConfig.NetworkMode.IsPrivate() {
 			logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
-			joinOptions = append(joinOptions, libnetwork.JoinOptionParentUpdate(c.NetworkSettings.EndpointID, ref.Name, container.NetworkSettings.IPAddress))
+			sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(c.ID, ref.Name, container.NetworkSettings.IPAddress))
 			if c.NetworkSettings.EndpointID != "" {
 				parentEndpoints = append(parentEndpoints, c.NetworkSettings.EndpointID)
 			}
@@ -502,9 +504,9 @@ func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, err
 		},
 	}
 
-	joinOptions = append(joinOptions, libnetwork.JoinOptionGeneric(linkOptions))
+	sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions))
 
-	return joinOptions, nil
+	return sboxOptions, nil
 }
 
 func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
@@ -628,12 +630,10 @@ func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error {
 		container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String()
 	}
 
-	container.NetworkSettings.SandboxKey = epInfo.SandboxKey()
-
 	return nil
 }
 
-func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
+func (container *Container) updateEndpointNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
 	networkSettings := &network.Settings{NetworkID: n.ID(), EndpointID: ep.ID()}
 
 	networkSettings, err := container.buildPortMapInfo(n, ep, networkSettings)
@@ -654,35 +654,30 @@ func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libne
 	return nil
 }
 
+func (container *Container) updateSandboxNetworkSettings(sb libnetwork.Sandbox) error {
+	container.NetworkSettings.SandboxID = sb.ID()
+	container.NetworkSettings.SandboxKey = sb.Key()
+	return nil
+}
+
 // UpdateNetwork is used to update the container's network (e.g. when linked containers
 // get removed/unlinked).
 func (container *Container) updateNetwork() error {
-	n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID)
-	if err != nil {
-		return fmt.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err)
-	}
+	ctrl := container.daemon.netController
+	sid := container.NetworkSettings.SandboxID
 
-	ep, err := n.EndpointByID(container.NetworkSettings.EndpointID)
+	sb, err := ctrl.SandboxByID(sid)
 	if err != nil {
-		return fmt.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err)
-	}
-
-	if err := ep.Leave(container.ID); err != nil {
-		return fmt.Errorf("endpoint leave failed: %v", err)
-
+		return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
 	}
 
-	joinOptions, err := container.buildJoinOptions()
+	options, err := container.buildSandboxOptions()
 	if err != nil {
 		return fmt.Errorf("Update network failed: %v", err)
 	}
 
-	if err := ep.Join(container.ID, joinOptions...); err != nil {
-		return fmt.Errorf("endpoint join failed: %v", err)
-	}
-
-	if err := container.updateJoinInfo(ep); err != nil {
-		return fmt.Errorf("Updating join info failed: %v", err)
+	if err := sb.Refresh(options...); err != nil {
+		return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
 	}
 
 	return nil
@@ -869,6 +864,7 @@ func (container *Container) allocateNetwork() error {
 
 func (container *Container) configureNetwork(networkName, service, networkDriver string, canCreateNetwork bool) error {
 	controller := container.daemon.netController
+
 	n, err := controller.NetworkByName(networkName)
 	if err != nil {
 		if _, ok := err.(libnetwork.ErrNoSuchNetwork); !ok || !canCreateNetwork {
@@ -897,16 +893,32 @@ func (container *Container) configureNetwork(networkName, service, networkDriver
 		}
 	}
 
-	if err := container.updateNetworkSettings(n, ep); err != nil {
+	if err := container.updateEndpointNetworkSettings(n, ep); err != nil {
 		return err
 	}
 
-	joinOptions, err := container.buildJoinOptions()
-	if err != nil {
-		return err
+	var sb libnetwork.Sandbox
+	controller.WalkSandboxes(func(s libnetwork.Sandbox) bool {
+		if s.ContainerID() == container.ID {
+			sb = s
+			return true
+		}
+		return false
+	})
+	if sb == nil {
+		options, err := container.buildSandboxOptions()
+		if err != nil {
+			return err
+		}
+		sb, err = controller.NewSandbox(container.ID, options...)
+		if err != nil {
+			return err
+		}
 	}
 
-	if err := ep.Join(container.ID, joinOptions...); err != nil {
+	container.updateSandboxNetworkSettings(sb)
+
+	if err := ep.Join(sb); err != nil {
 		return err
 	}
 
@@ -1021,12 +1033,19 @@ func (container *Container) releaseNetwork() {
 		return
 	}
 
+	sid := container.NetworkSettings.SandboxID
 	eid := container.NetworkSettings.EndpointID
 	nid := container.NetworkSettings.NetworkID
 
 	container.NetworkSettings = &network.Settings{}
 
-	if nid == "" || eid == "" {
+	if sid == "" || nid == "" || eid == "" {
+		return
+	}
+
+	sb, err := container.daemon.netController.SandboxByID(sid)
+	if err != nil {
+		logrus.Errorf("error locating sandbox id %s: %v", sid, err)
 		return
 	}
 
@@ -1042,17 +1061,9 @@ func (container *Container) releaseNetwork() {
 		return
 	}
 
-	switch {
-	case container.hostConfig.NetworkMode.IsHost():
-		if err := ep.Leave(container.ID); err != nil {
-			logrus.Errorf("Error leaving endpoint id %s for container %s: %v", eid, container.ID, err)
-			return
-		}
-	default:
-		if err := container.daemon.netController.LeaveAll(container.ID); err != nil {
-			logrus.Errorf("Leave all failed for  %s: %v", container.ID, err)
-			return
-		}
+	if err := sb.Delete(); err != nil {
+		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
+		return
 	}
 
 	// In addition to leaving all endpoints, delete implicitly created endpoint

+ 1 - 0
daemon/network/settings.go

@@ -13,6 +13,7 @@ type Address struct {
 type Settings struct {
 	Bridge                 string
 	EndpointID             string
+	SandboxID              string
 	Gateway                string
 	GlobalIPv6Address      string
 	GlobalIPv6PrefixLen    int

+ 4 - 8
daemon/stats.go

@@ -6,7 +6,7 @@ import (
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/daemon/execdriver"
-	"github.com/docker/libnetwork/sandbox"
+	"github.com/docker/libnetwork/osl"
 	"github.com/opencontainers/runc/libcontainer"
 )
 
@@ -86,16 +86,12 @@ func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInter
 		return list, err
 	}
 
-	nw, err := daemon.netController.NetworkByID(c.NetworkSettings.NetworkID)
-	if err != nil {
-		return list, err
-	}
-	ep, err := nw.EndpointByID(c.NetworkSettings.EndpointID)
+	sb, err := daemon.netController.SandboxByID(c.NetworkSettings.SandboxID)
 	if err != nil {
 		return list, err
 	}
 
-	stats, err := ep.Statistics()
+	stats, err := sb.Statistics()
 	if err != nil {
 		return list, err
 	}
@@ -108,7 +104,7 @@ func (daemon *Daemon) getNetworkStats(name string) ([]*libcontainer.NetworkInter
 	return list, nil
 }
 
-func convertLnNetworkStats(name string, stats *sandbox.InterfaceStatistics) *libcontainer.NetworkInterface {
+func convertLnNetworkStats(name string, stats *osl.InterfaceStatistics) *libcontainer.NetworkInterface {
 	n := &libcontainer.NetworkInterface{Name: name}
 	n.RxBytes = stats.RxBytes
 	n.RxPackets = stats.RxPackets

+ 1 - 1
hack/vendor.sh

@@ -21,7 +21,7 @@ clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://gith
 clone hg code.google.com/p/gosqlite 74691fb6f837
 
 #get libnetwork packages
-clone git github.com/docker/libnetwork 22dc04d06067b40a9e7ef575aee6d1bb69d4dcc3
+clone git github.com/docker/libnetwork dc52820147f40fe424c8959987af3b396f842639
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4

+ 11 - 8
integration-cli/docker_cli_daemon_test.go

@@ -1524,19 +1524,23 @@ func (s *DockerDaemonSuite) TestDaemonRestartCleanupNetns(c *check.C) {
 	if err != nil {
 		c.Fatal(out, err)
 	}
+
+	// Get sandbox key via inspect
+	out, err = s.d.Cmd("inspect", "--format", "'{{.NetworkSettings.SandboxKey}}'", "netns")
+	if err != nil {
+		c.Fatalf("Error inspecting container: %s, %v", out, err)
+	}
+	fileName := strings.Trim(out, " \r\n'")
+
 	if out, err := s.d.Cmd("stop", "netns"); err != nil {
 		c.Fatal(out, err)
 	}
 
-	// Construct netns file name from container id
-	out = strings.TrimSpace(out)
-	nsFile := out[:12]
-
 	// Test if the file still exists
-	out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", "/var/run/docker/netns/"+nsFile))
+	out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", fileName))
 	out = strings.TrimSpace(out)
 	c.Assert(err, check.IsNil, check.Commentf("Output: %s", out))
-	c.Assert(out, check.Equals, "/var/run/docker/netns/"+nsFile, check.Commentf("Output: %s", out))
+	c.Assert(out, check.Equals, fileName, check.Commentf("Output: %s", out))
 
 	// Remove the container and restart the daemon
 	if out, err := s.d.Cmd("rm", "netns"); err != nil {
@@ -1548,10 +1552,9 @@ func (s *DockerDaemonSuite) TestDaemonRestartCleanupNetns(c *check.C) {
 	}
 
 	// Test again and see now the netns file does not exist
-	out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", "/var/run/docker/netns/"+nsFile))
+	out, _, err = runCommandWithOutput(exec.Command("stat", "-c", "%n", fileName))
 	out = strings.TrimSpace(out)
 	c.Assert(err, check.Not(check.IsNil), check.Commentf("Output: %s", out))
-	// c.Assert(out, check.Equals, "", check.Commentf("Output: %s", out))
 }
 
 // tests regression detailed in #13964 where DOCKER_TLS_VERIFY env is ignored

+ 4 - 4
integration-cli/docker_cli_run_test.go

@@ -865,7 +865,7 @@ func (s *DockerSuite) TestRunDnsDefaultOptions(c *check.C) {
 	// check that the actual defaults are appended to the commented out
 	// localhost resolver (which should be preserved)
 	// NOTE: if we ever change the defaults from google dns, this will break
-	expected := "#nameserver 127.0.2.1\n\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
+	expected := "#nameserver 127.0.2.1\n\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n"
 	if actual != expected {
 		c.Fatalf("expected resolv.conf be: %q, but was: %q", expected, actual)
 	}
@@ -880,7 +880,7 @@ func (s *DockerSuite) TestRunDnsOptions(c *check.C) {
 	}
 
 	actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1)
-	if actual != "nameserver 127.0.0.1 search mydomain" {
+	if actual != "search mydomain nameserver 127.0.0.1" {
 		c.Fatalf("expected 'nameserver 127.0.0.1 search mydomain', but says: %q", actual)
 	}
 
@@ -1001,7 +1001,7 @@ func (s *DockerSuite) TestRunNonRootUserResolvName(c *check.C) {
 func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) {
 	testRequires(c, SameHostDaemon)
 
-	tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78")
+	tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\n")
 	tmpLocalhostResolvConf := []byte("nameserver 127.0.0.1")
 
 	//take a copy of resolv.conf for restoring after test completes
@@ -1131,7 +1131,7 @@ func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) {
 		c.Fatal(err)
 	}
 
-	expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
+	expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4\n"
 	if !bytes.Equal(containerResolv, []byte(expected)) {
 		c.Fatalf("Container does not have cleaned/replaced DNS in resolv.conf; expected %q, got %q", expected, string(containerResolv))
 	}

+ 9 - 9
vendor/src/github.com/docker/libnetwork/Makefile

@@ -3,12 +3,12 @@ SHELL=/bin/bash
 build_image=libnetwork-build
 dockerargs = --privileged -v $(shell pwd):/go/src/github.com/docker/libnetwork -w /go/src/github.com/docker/libnetwork
 container_env = -e "INSIDECONTAINER=-incontainer=true"
-docker = docker run --rm ${dockerargs} ${container_env} ${build_image}
+docker = docker run --rm -it ${dockerargs} ${container_env} ${build_image}
 ciargs = -e "COVERALLS_TOKEN=$$COVERALLS_TOKEN" -e "INSIDECONTAINER=-incontainer=true"
 cidocker = docker run ${ciargs} ${dockerargs} golang:1.4
 
 all: ${build_image}.created
-	${docker} make all-local
+	${docker} ./wrapmake.sh all-local
 
 all-local: check-local build-local
 
@@ -19,13 +19,13 @@ ${build_image}.created:
 	touch ${build_image}.created
 
 build: ${build_image}.created
-	${docker} make build-local
+	${docker} ./wrapmake.sh build-local
 
 build-local:
 	$(shell which godep) go build -tags libnetwork_discovery ./...
 
 check: ${build_image}.created
-	${docker} make check-local
+	${docker} ./wrapmake.sh check-local
 
 check-code:
 	@echo "Checking code... "
@@ -49,15 +49,15 @@ run-tests:
 		ret=$$? ;\
 		if [ $$ret -ne 0 ]; then exit $$ret; fi ;\
 		popd &> /dev/null; \
-	        if [ -f $$dir/profile.tmp ]; then \
-		        cat $$dir/profile.tmp | tail -n +2 >> coverage.coverprofile ; \
+		if [ -f $$dir/profile.tmp ]; then \
+			cat $$dir/profile.tmp | tail -n +2 >> coverage.coverprofile ; \
 				rm $$dir/profile.tmp ; \
-            fi ; \
-        fi ; \
+	    fi ; \
+	fi ; \
 	done
 	@echo "Done running tests"
 
-check-local: 	check-format check-code run-tests 
+check-local:	check-format check-code run-tests
 
 install-deps:
 	apt-get update && apt-get -y install iptables

+ 10 - 8
vendor/src/github.com/docker/libnetwork/README.md

@@ -29,13 +29,13 @@ There are many networking solutions available to suit a broad range of use-cases
         driverOptions := options.Generic{}
         genericOption := make(map[string]interface{})
         genericOption[netlabel.GenericData] = driverOptions
-        err := controller.ConfigureNetworkDriver(networkType, genericOption)
+        err = controller.ConfigureNetworkDriver(networkType, genericOption)
         if err != nil {
                 return
         }
 
         // Create a network for containers to join.
-        // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of
+        // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can use.
         network, err := controller.NewNetwork(networkType, "network1")
         if err != nil {
                 return
@@ -50,12 +50,14 @@ There are many networking solutions available to suit a broad range of use-cases
                 return
         }
 
-        // A container can join the endpoint by providing the container ID to the join
-        // api.
-        // Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
-        err = ep.Join("container1",
-                libnetwork.JoinOptionHostname("test"),
-                libnetwork.JoinOptionDomainname("docker.io"))
+        // Create the sandbox for the containr.
+        sbx, err := controller.NewSandbox("container1",
+        libnetwork.OptionHostname("test"),
+        libnetwork.OptionDomainname("docker.io"))
+		
+        // A sandbox can join the endpoint via the join api.
+        // Join accepts Variadic arguments which libnetwork and Drivers can use.
+        err = ep.Join(sbx)
         if err != nil {
                 return
         }

+ 204 - 51
vendor/src/github.com/docker/libnetwork/api/api.go

@@ -35,7 +35,10 @@ const (
 	epNameQr = "{" + urlEpName + ":" + qregx + "}"
 	epID     = "{" + urlEpID + ":" + regex + "}"
 	epPIDQr  = "{" + urlEpPID + ":" + qregx + "}"
-	cnID     = "{" + urlCnID + ":" + regex + "}"
+	sbID     = "{" + urlSbID + ":" + regex + "}"
+	sbPIDQr  = "{" + urlSbPID + ":" + qregx + "}"
+	cnIDQr   = "{" + urlCnID + ":" + qregx + "}"
+	cnPIDQr  = "{" + urlCnPID + ":" + qregx + "}"
 
 	// Internal URL variable name.They can be anything as
 	// long as they do not collide with query fields.
@@ -45,7 +48,10 @@ const (
 	urlEpName = "endpoint-name"
 	urlEpID   = "endpoint-id"
 	urlEpPID  = "endpoint-partial-id"
+	urlSbID   = "sandbox-id"
+	urlSbPID  = "sandbox-partial-id"
 	urlCnID   = "container-id"
+	urlCnPID  = "container-partial-id"
 
 	// BridgeNetworkDriver is the built-in default for Network Driver
 	BridgeNetworkDriver = "bridge"
@@ -106,21 +112,28 @@ func (h *httpHandler) initRouter() {
 			{"/services", []string{"partial-id", epPIDQr}, procGetServices},
 			{"/services", nil, procGetServices},
 			{"/services/" + epID, nil, procGetService},
-			{"/services/" + epID + "/backend", nil, procGetContainers},
+			{"/services/" + epID + "/backend", nil, procGetSandbox},
+			{"/sandboxes", []string{"partial-container-id", cnPIDQr}, procGetSandboxes},
+			{"/sandboxes", []string{"container-id", cnIDQr}, procGetSandboxes},
+			{"/sandboxes", []string{"partial-id", sbPIDQr}, procGetSandboxes},
+			{"/sandboxes", nil, procGetSandboxes},
+			{"/sandboxes/" + sbID, nil, procGetSandbox},
 		},
 		"POST": {
 			{"/networks", nil, procCreateNetwork},
 			{"/networks/" + nwID + "/endpoints", nil, procCreateEndpoint},
-			{"/networks/" + nwID + "/endpoints/" + epID + "/containers", nil, procJoinEndpoint},
+			{"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes", nil, procJoinEndpoint},
 			{"/services", nil, procPublishService},
 			{"/services/" + epID + "/backend", nil, procAttachBackend},
+			{"/sandboxes", nil, procCreateSandbox},
 		},
 		"DELETE": {
 			{"/networks/" + nwID, nil, procDeleteNetwork},
 			{"/networks/" + nwID + "/endpoints/" + epID, nil, procDeleteEndpoint},
-			{"/networks/" + nwID + "/endpoints/" + epID + "/containers/" + cnID, nil, procLeaveEndpoint},
+			{"/networks/" + nwID + "/endpoints/" + epID + "/sandboxes/" + sbID, nil, procLeaveEndpoint},
 			{"/services/" + epID, nil, procUnpublishService},
-			{"/services/" + epID + "/backend/" + cnID, nil, procDetachBackend},
+			{"/services/" + epID + "/backend/" + sbID, nil, procDetachBackend},
+			{"/sandboxes/" + sbID, nil, procDeleteSandbox},
 		},
 	}
 
@@ -155,6 +168,10 @@ func makeHandler(ctrl libnetwork.NetworkController, fct processor) http.HandlerF
 		}
 
 		res, rsp := fct(ctrl, mux.Vars(req), body)
+		if !rsp.isOK() {
+			http.Error(w, rsp.Status, rsp.StatusCode)
+			return
+		}
 		if res != nil {
 			writeJSON(w, rsp.StatusCode, res)
 		}
@@ -191,10 +208,12 @@ func buildEndpointResource(ep libnetwork.Endpoint) *endpointResource {
 	return r
 }
 
-func buildContainerResource(ci libnetwork.ContainerInfo) *containerResource {
-	r := &containerResource{}
-	if ci != nil {
-		r.ID = ci.ID()
+func buildSandboxResource(sb libnetwork.Sandbox) *sandboxResource {
+	r := &sandboxResource{}
+	if sb != nil {
+		r.ID = sb.ID()
+		r.Key = sb.Key()
+		r.ContainerID = sb.ContainerID()
 	}
 	return r
 }
@@ -213,41 +232,41 @@ func (nc *networkCreate) parseOptions() []libnetwork.NetworkOption {
 	return setFctList
 }
 
-func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption {
-	var setFctList []libnetwork.EndpointOption
-	if ej.HostName != "" {
-		setFctList = append(setFctList, libnetwork.JoinOptionHostname(ej.HostName))
+func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption {
+	var setFctList []libnetwork.SandboxOption
+	if sc.HostName != "" {
+		setFctList = append(setFctList, libnetwork.OptionHostname(sc.HostName))
 	}
-	if ej.DomainName != "" {
-		setFctList = append(setFctList, libnetwork.JoinOptionDomainname(ej.DomainName))
+	if sc.DomainName != "" {
+		setFctList = append(setFctList, libnetwork.OptionDomainname(sc.DomainName))
 	}
-	if ej.HostsPath != "" {
-		setFctList = append(setFctList, libnetwork.JoinOptionHostsPath(ej.HostsPath))
+	if sc.HostsPath != "" {
+		setFctList = append(setFctList, libnetwork.OptionHostsPath(sc.HostsPath))
 	}
-	if ej.ResolvConfPath != "" {
-		setFctList = append(setFctList, libnetwork.JoinOptionResolvConfPath(ej.ResolvConfPath))
+	if sc.ResolvConfPath != "" {
+		setFctList = append(setFctList, libnetwork.OptionResolvConfPath(sc.ResolvConfPath))
 	}
-	if ej.UseDefaultSandbox {
-		setFctList = append(setFctList, libnetwork.JoinOptionUseDefaultSandbox())
+	if sc.UseDefaultSandbox {
+		setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox())
 	}
-	if ej.DNS != nil {
-		for _, d := range ej.DNS {
-			setFctList = append(setFctList, libnetwork.JoinOptionDNS(d))
+	if sc.DNS != nil {
+		for _, d := range sc.DNS {
+			setFctList = append(setFctList, libnetwork.OptionDNS(d))
 		}
 	}
-	if ej.ExtraHosts != nil {
-		for _, e := range ej.ExtraHosts {
-			setFctList = append(setFctList, libnetwork.JoinOptionExtraHost(e.Name, e.Address))
-		}
-	}
-	if ej.ParentUpdates != nil {
-		for _, p := range ej.ParentUpdates {
-			setFctList = append(setFctList, libnetwork.JoinOptionParentUpdate(p.EndpointID, p.Name, p.Address))
+	if sc.ExtraHosts != nil {
+		for _, e := range sc.ExtraHosts {
+			setFctList = append(setFctList, libnetwork.OptionExtraHost(e.Name, e.Address))
 		}
 	}
 	return setFctList
 }
 
+func (ej *endpointJoin) parseOptions() []libnetwork.EndpointOption {
+	// priority will go here
+	return []libnetwork.EndpointOption{}
+}
+
 /******************
  Process functions
 *******************/
@@ -337,6 +356,22 @@ func procGetNetworks(c libnetwork.NetworkController, vars map[string]string, bod
 	return list, &successResponse
 }
 
+func procCreateSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
+	var create sandboxCreate
+
+	err := json.Unmarshal(body, &create)
+	if err != nil {
+		return "", &responseStatus{Status: "Invalid body: " + err.Error(), StatusCode: http.StatusBadRequest}
+	}
+
+	sb, err := c.NewSandbox(create.ContainerID, create.parseOptions()...)
+	if err != nil {
+		return "", convertNetworkError(err)
+	}
+
+	return sb.ID(), &createdResponse
+}
+
 /******************
  Network interface
 *******************/
@@ -456,11 +491,16 @@ func procJoinEndpoint(c libnetwork.NetworkController, vars map[string]string, bo
 		return nil, errRsp
 	}
 
-	err = ep.Join(ej.ContainerID, ej.parseOptions()...)
+	sb, errRsp := findSandbox(c, ej.SandboxID, byID)
+	if !errRsp.isOK() {
+		return nil, errRsp
+	}
+
+	err = ep.Join(sb)
 	if err != nil {
 		return nil, convertNetworkError(err)
 	}
-	return ep.Info().SandboxKey(), &successResponse
+	return sb.Key(), &successResponse
 }
 
 func procLeaveEndpoint(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
@@ -472,7 +512,12 @@ func procLeaveEndpoint(c libnetwork.NetworkController, vars map[string]string, b
 		return nil, errRsp
 	}
 
-	err := ep.Leave(vars[urlCnID])
+	sb, errRsp := findSandbox(c, vars[urlSbID], byID)
+	if !errRsp.isOK() {
+		return nil, errRsp
+	}
+
+	err := ep.Leave(sb)
 	if err != nil {
 		return nil, convertNetworkError(err)
 	}
@@ -567,19 +612,6 @@ func procGetService(c libnetwork.NetworkController, vars map[string]string, body
 	return buildEndpointResource(sv), &successResponse
 }
 
-func procGetContainers(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
-	epT, epBy := detectEndpointTarget(vars)
-	sv, errRsp := findService(c, epT, epBy)
-	if !errRsp.isOK() {
-		return nil, endpointToService(errRsp)
-	}
-	var list []*containerResource
-	if sv.ContainerInfo() != nil {
-		list = append(list, buildContainerResource(sv.ContainerInfo()))
-	}
-	return list, &successResponse
-}
-
 func procPublishService(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
 	var sp servicePublish
 
@@ -635,11 +667,16 @@ func procAttachBackend(c libnetwork.NetworkController, vars map[string]string, b
 		return nil, errRsp
 	}
 
-	err = sv.Join(bk.ContainerID, bk.parseOptions()...)
+	sb, errRsp := findSandbox(c, bk.SandboxID, byID)
+	if !errRsp.isOK() {
+		return nil, errRsp
+	}
+
+	err = sv.Join(sb)
 	if err != nil {
 		return nil, convertNetworkError(err)
 	}
-	return sv.Info().SandboxKey(), &successResponse
+	return sb.Key(), &successResponse
 }
 
 func procDetachBackend(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
@@ -649,7 +686,94 @@ func procDetachBackend(c libnetwork.NetworkController, vars map[string]string, b
 		return nil, errRsp
 	}
 
-	err := sv.Leave(vars[urlCnID])
+	sb, errRsp := findSandbox(c, vars[urlSbID], byID)
+	if !errRsp.isOK() {
+		return nil, errRsp
+	}
+
+	err := sv.Leave(sb)
+	if err != nil {
+		return nil, convertNetworkError(err)
+	}
+
+	return nil, &successResponse
+}
+
+/******************
+ Sandbox interface
+*******************/
+func procGetSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
+	if epT, ok := vars[urlEpID]; ok {
+		sv, errRsp := findService(c, epT, byID)
+		if !errRsp.isOK() {
+			return nil, endpointToService(errRsp)
+		}
+		return buildSandboxResource(sv.Info().Sandbox()), &successResponse
+	}
+
+	sbT, by := detectSandboxTarget(vars)
+	sb, errRsp := findSandbox(c, sbT, by)
+	if !errRsp.isOK() {
+		return nil, errRsp
+	}
+	return buildSandboxResource(sb), &successResponse
+}
+
+type cndFnMkr func(string) cndFn
+type cndFn func(libnetwork.Sandbox) bool
+
+// list of (query type, condition function makers) couples
+var cndMkrList = []struct {
+	identifier string
+	maker      cndFnMkr
+}{
+	{urlSbPID, func(id string) cndFn {
+		return func(sb libnetwork.Sandbox) bool { return strings.HasPrefix(sb.ID(), id) }
+	}},
+	{urlCnID, func(id string) cndFn {
+		return func(sb libnetwork.Sandbox) bool { return sb.ContainerID() == id }
+	}},
+	{urlCnPID, func(id string) cndFn {
+		return func(sb libnetwork.Sandbox) bool { return strings.HasPrefix(sb.ContainerID(), id) }
+	}},
+}
+
+func getQueryCondition(vars map[string]string) func(libnetwork.Sandbox) bool {
+	for _, im := range cndMkrList {
+		if val, ok := vars[im.identifier]; ok {
+			return im.maker(val)
+		}
+	}
+	return func(sb libnetwork.Sandbox) bool { return true }
+}
+
+func sandboxWalker(condition cndFn, list *[]*sandboxResource) libnetwork.SandboxWalker {
+	return func(sb libnetwork.Sandbox) bool {
+		if condition(sb) {
+			*list = append(*list, buildSandboxResource(sb))
+		}
+		return false
+	}
+}
+
+func procGetSandboxes(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
+	var list []*sandboxResource
+
+	cnd := getQueryCondition(vars)
+	c.WalkSandboxes(sandboxWalker(cnd, &list))
+
+	return list, &successResponse
+}
+
+func procDeleteSandbox(c libnetwork.NetworkController, vars map[string]string, body []byte) (interface{}, *responseStatus) {
+	sbT, by := detectSandboxTarget(vars)
+
+	sb, errRsp := findSandbox(c, sbT, by)
+	if !errRsp.isOK() {
+		return nil, errRsp
+	}
+
+	err := sb.Delete()
 	if err != nil {
 		return nil, convertNetworkError(err)
 	}
@@ -676,6 +800,14 @@ func detectNetworkTarget(vars map[string]string) (string, int) {
 	panic("Missing URL variable parameter for network")
 }
 
+func detectSandboxTarget(vars map[string]string) (string, int) {
+	if target, ok := vars[urlSbID]; ok {
+		return target, byID
+	}
+	// vars are populated from the URL, following cannot happen
+	panic("Missing URL variable parameter for sandbox")
+}
+
 func detectEndpointTarget(vars map[string]string) (string, int) {
 	if target, ok := vars[urlEpName]; ok {
 		return target, byName
@@ -712,6 +844,27 @@ func findNetwork(c libnetwork.NetworkController, s string, by int) (libnetwork.N
 	return nw, &successResponse
 }
 
+func findSandbox(c libnetwork.NetworkController, s string, by int) (libnetwork.Sandbox, *responseStatus) {
+	var (
+		sb  libnetwork.Sandbox
+		err error
+	)
+
+	switch by {
+	case byID:
+		sb, err = c.SandboxByID(s)
+	default:
+		panic(fmt.Sprintf("unexpected selector for sandbox search: %d", by))
+	}
+	if err != nil {
+		if _, ok := err.(types.NotFoundError); ok {
+			return nil, &responseStatus{Status: "Resource not found: Sandbox", StatusCode: http.StatusNotFound}
+		}
+		return nil, &responseStatus{Status: err.Error(), StatusCode: http.StatusBadRequest}
+	}
+	return sb, &successResponse
+}
+
 func findEndpoint(c libnetwork.NetworkController, ns, es string, nwBy, epBy int) (libnetwork.Endpoint, *responseStatus) {
 	nw, errRsp := findNetwork(c, ns, nwBy)
 	if !errRsp.isOK() {

+ 20 - 22
vendor/src/github.com/docker/libnetwork/api/types.go

@@ -21,9 +21,11 @@ type endpointResource struct {
 	Network string `json:"network"`
 }
 
-// containerResource is the body of "get service backend" response message
-type containerResource struct {
-	ID string `json:"id"`
+// sandboxResource is the body of "get service backend" response message
+type sandboxResource struct {
+	ID          string `json:"id"`
+	Key         string `json:"key"`
+	ContainerID string `json:"container_id"`
 	// will add more fields once labels change is in
 }
 
@@ -45,17 +47,21 @@ type endpointCreate struct {
 	PortMapping  []types.PortBinding   `json:"port_mapping"`
 }
 
+// sandboxCreate is the expected body of the "create sandbox" http request message
+type sandboxCreate struct {
+	ContainerID       string      `json:"container_id"`
+	HostName          string      `json:"host_name"`
+	DomainName        string      `json:"domain_name"`
+	HostsPath         string      `json:"hosts_path"`
+	ResolvConfPath    string      `json:"resolv_conf_path"`
+	DNS               []string    `json:"dns"`
+	ExtraHosts        []extraHost `json:"extra_hosts"`
+	UseDefaultSandbox bool        `json:"use_default_sandbox"`
+}
+
 // endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages
 type endpointJoin struct {
-	ContainerID       string                 `json:"container_id"`
-	HostName          string                 `json:"host_name"`
-	DomainName        string                 `json:"domain_name"`
-	HostsPath         string                 `json:"hosts_path"`
-	ResolvConfPath    string                 `json:"resolv_conf_path"`
-	DNS               []string               `json:"dns"`
-	ExtraHosts        []endpointExtraHost    `json:"extra_hosts"`
-	ParentUpdates     []endpointParentUpdate `json:"parent_updates"`
-	UseDefaultSandbox bool                   `json:"use_default_sandbox"`
+	SandboxID string `json:"sandbox_id"`
 }
 
 // servicePublish represents the body of the "publish service" http request message
@@ -66,16 +72,8 @@ type servicePublish struct {
 	PortMapping  []types.PortBinding   `json:"port_mapping"`
 }
 
-// EndpointExtraHost represents the extra host object
-type endpointExtraHost struct {
+// extraHost represents the extra host object
+type extraHost struct {
 	Name    string `json:"name"`
 	Address string `json:"address"`
 }
-
-// EndpointParentUpdate is the object carrying the information about the
-// endpoint parent that needs to be updated
-type endpointParentUpdate struct {
-	EndpointID string `json:"endpoint_id"`
-	Name       string `json:"name"`
-	Address    string `json:"address"`
-}

+ 243 - 156
vendor/src/github.com/docker/libnetwork/bitseq/sequence.go

@@ -4,27 +4,33 @@
 package bitseq
 
 import (
+	"encoding/binary"
 	"fmt"
 	"sync"
 
 	"github.com/docker/libnetwork/datastore"
-	"github.com/docker/libnetwork/netutils"
+	"github.com/docker/libnetwork/types"
 )
 
-// Block Sequence constants
+// block sequence constants
 // If needed we can think of making these configurable
 const (
-	blockLen      = 32
+	blockLen      = uint32(32)
 	blockBytes    = blockLen / 8
-	blockMAX      = 1<<blockLen - 1
-	blockFirstBit = 1 << (blockLen - 1)
+	blockMAX      = uint32(1<<blockLen - 1)
+	blockFirstBit = uint32(1) << (blockLen - 1)
+	invalidPos    = blockMAX
+)
+
+var (
+	errNoBitAvailable = fmt.Errorf("no bit available")
 )
 
 // Handle contains the sequece representing the bitmask and its identifier
 type Handle struct {
 	bits       uint32
 	unselected uint32
-	head       *Sequence
+	head       *sequence
 	app        string
 	id         string
 	dbIndex    uint64
@@ -41,9 +47,9 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32
 		store:      ds,
 		bits:       numElements,
 		unselected: numElements,
-		head: &Sequence{
-			Block: 0x0,
-			Count: getNumBlocks(numElements),
+		head: &sequence{
+			block: 0x0,
+			count: getNumBlocks(numElements),
 		},
 	}
 
@@ -62,69 +68,64 @@ func NewHandle(app string, ds datastore.DataStore, id string, numElements uint32
 	return h, nil
 }
 
-// Sequence reresents a recurring sequence of 32 bits long bitmasks
-type Sequence struct {
-	Block uint32    // block representing 4 byte long allocation bitmask
-	Count uint32    // number of consecutive blocks
-	Next  *Sequence // next sequence
-}
-
-// NewSequence returns a sequence initialized to represent a bitmaks of numElements bits
-func NewSequence(numElements uint32) *Sequence {
-	return &Sequence{Block: 0x0, Count: getNumBlocks(numElements), Next: nil}
+// sequence represents a recurring sequence of 32 bits long bitmasks
+type sequence struct {
+	block uint32    // block is a symbol representing 4 byte long allocation bitmask
+	count uint32    // number of consecutive blocks (symbols)
+	next  *sequence // next sequence
 }
 
 // String returns a string representation of the block sequence starting from this block
-func (s *Sequence) String() string {
+func (s *sequence) toString() string {
 	var nextBlock string
-	if s.Next == nil {
+	if s.next == nil {
 		nextBlock = "end"
 	} else {
-		nextBlock = s.Next.String()
+		nextBlock = s.next.toString()
 	}
-	return fmt.Sprintf("(0x%x, %d)->%s", s.Block, s.Count, nextBlock)
+	return fmt.Sprintf("(0x%x, %d)->%s", s.block, s.count, nextBlock)
 }
 
 // GetAvailableBit returns the position of the first unset bit in the bitmask represented by this sequence
-func (s *Sequence) GetAvailableBit() (bytePos, bitPos int) {
-	if s.Block == blockMAX || s.Count == 0 {
-		return -1, -1
+func (s *sequence) getAvailableBit() (uint32, uint32, error) {
+	if s.block == blockMAX || s.count == 0 {
+		return invalidPos, invalidPos, fmt.Errorf("no available bit")
 	}
-	bits := 0
-	bitSel := uint32(blockFirstBit)
-	for bitSel > 0 && s.Block&bitSel != 0 {
+	bits := uint32(0)
+	bitSel := blockFirstBit
+	for bitSel > 0 && s.block&bitSel != 0 {
 		bitSel >>= 1
 		bits++
 	}
-	return bits / 8, bits % 8
+	return bits / 8, bits % 8, nil
 }
 
 // GetCopy returns a copy of the linked list rooted at this node
-func (s *Sequence) GetCopy() *Sequence {
-	n := &Sequence{Block: s.Block, Count: s.Count}
+func (s *sequence) getCopy() *sequence {
+	n := &sequence{block: s.block, count: s.count}
 	pn := n
-	ps := s.Next
+	ps := s.next
 	for ps != nil {
-		pn.Next = &Sequence{Block: ps.Block, Count: ps.Count}
-		pn = pn.Next
-		ps = ps.Next
+		pn.next = &sequence{block: ps.block, count: ps.count}
+		pn = pn.next
+		ps = ps.next
 	}
 	return n
 }
 
 // Equal checks if this sequence is equal to the passed one
-func (s *Sequence) Equal(o *Sequence) bool {
+func (s *sequence) equal(o *sequence) bool {
 	this := s
 	other := o
 	for this != nil {
 		if other == nil {
 			return false
 		}
-		if this.Block != other.Block || this.Count != other.Count {
+		if this.block != other.block || this.count != other.count {
 			return false
 		}
-		this = this.Next
-		other = other.Next
+		this = this.next
+		other = other.next
 	}
 	// Check if other is longer than this
 	if other != nil {
@@ -134,23 +135,23 @@ func (s *Sequence) Equal(o *Sequence) bool {
 }
 
 // ToByteArray converts the sequence into a byte array
-// TODO (aboch): manage network/host order stuff
-func (s *Sequence) ToByteArray() ([]byte, error) {
+func (s *sequence) toByteArray() ([]byte, error) {
 	var bb []byte
 
 	p := s
 	for p != nil {
-		bb = append(bb, netutils.U32ToA(p.Block)...)
-		bb = append(bb, netutils.U32ToA(p.Count)...)
-		p = p.Next
+		b := make([]byte, 8)
+		binary.BigEndian.PutUint32(b[0:], p.block)
+		binary.BigEndian.PutUint32(b[4:], p.count)
+		bb = append(bb, b...)
+		p = p.next
 	}
 
 	return bb, nil
 }
 
-// FromByteArray construct the sequence from the byte array
-// TODO (aboch): manage network/host order stuff
-func (s *Sequence) FromByteArray(data []byte) error {
+// fromByteArray construct the sequence from the byte array
+func (s *sequence) fromByteArray(data []byte) error {
 	l := len(data)
 	if l%8 != 0 {
 		return fmt.Errorf("cannot deserialize byte sequence of lenght %d (%v)", l, data)
@@ -159,67 +160,139 @@ func (s *Sequence) FromByteArray(data []byte) error {
 	p := s
 	i := 0
 	for {
-		p.Block = netutils.ATo32(data[i : i+4])
-		p.Count = netutils.ATo32(data[i+4 : i+8])
+		p.block = binary.BigEndian.Uint32(data[i : i+4])
+		p.count = binary.BigEndian.Uint32(data[i+4 : i+8])
 		i += 8
 		if i == l {
 			break
 		}
-		p.Next = &Sequence{}
-		p = p.Next
+		p.next = &sequence{}
+		p = p.next
 	}
 
 	return nil
 }
 
-// GetFirstAvailable returns the byte and bit position of the first unset bit
-func (h *Handle) GetFirstAvailable() (int, int, error) {
-	h.Lock()
-	defer h.Unlock()
-	return GetFirstAvailable(h.head)
+func (h *Handle) getCopy() *Handle {
+	return &Handle{
+		bits:       h.bits,
+		unselected: h.unselected,
+		head:       h.head.getCopy(),
+		app:        h.app,
+		id:         h.id,
+		dbIndex:    h.dbIndex,
+		dbExists:   h.dbExists,
+		store:      h.store,
+	}
 }
 
-// CheckIfAvailable checks if the bit correspondent to the specified ordinal is unset
-// If the ordinal is beyond the Sequence limits, a negative response is returned
-func (h *Handle) CheckIfAvailable(ordinal int) (int, int, error) {
-	h.Lock()
-	defer h.Unlock()
-	return CheckIfAvailable(h.head, ordinal)
+// SetAny atomically sets the first unset bit in the sequence and returns the corresponding ordinal
+func (h *Handle) SetAny() (uint32, error) {
+	if h.Unselected() == 0 {
+		return invalidPos, errNoBitAvailable
+	}
+	return h.set(0, true, false)
 }
 
-// PushReservation pushes the bit reservation inside the bitmask.
-func (h *Handle) PushReservation(bytePos, bitPos int, release bool) error {
-	// Create a copy of the current handler
-	h.Lock()
-	nh := &Handle{
-		app:      h.app,
-		id:       h.id,
-		store:    h.store,
-		dbIndex:  h.dbIndex,
-		head:     h.head.GetCopy(),
-		dbExists: h.dbExists,
+// Set atomically sets the corresponding bit in the sequence
+func (h *Handle) Set(ordinal uint32) error {
+	if err := h.validateOrdinal(ordinal); err != nil {
+		return err
+	}
+	_, err := h.set(ordinal, false, false)
+	return err
+}
+
+// Unset atomically unsets the corresponding bit in the sequence
+func (h *Handle) Unset(ordinal uint32) error {
+	if err := h.validateOrdinal(ordinal); err != nil {
+		return err
 	}
+	_, err := h.set(ordinal, false, true)
+	return err
+}
+
+// IsSet atomically checks if the ordinal bit is set. In case ordinal
+// is outside of the bit sequence limits, false is returned.
+func (h *Handle) IsSet(ordinal uint32) bool {
+	if err := h.validateOrdinal(ordinal); err != nil {
+		return false
+	}
+	h.Lock()
+	_, _, err := checkIfAvailable(h.head, ordinal)
 	h.Unlock()
+	return err != nil
+}
 
-	nh.head = PushReservation(bytePos, bitPos, nh.head, release)
+// set/reset the bit
+func (h *Handle) set(ordinal uint32, any bool, release bool) (uint32, error) {
+	var (
+		bitPos  uint32
+		bytePos uint32
+		ret     uint32
+		err     error
+	)
 
-	err := nh.writeToStore()
-	if err == nil {
-		// Commit went through, save locally
+	for {
 		h.Lock()
-		h.head = nh.head
+		// Get position if available
 		if release {
-			h.unselected++
+			bytePos, bitPos = ordinalToPos(ordinal)
 		} else {
-			h.unselected--
+			if any {
+				bytePos, bitPos, err = getFirstAvailable(h.head)
+				ret = posToOrdinal(bytePos, bitPos)
+			} else {
+				bytePos, bitPos, err = checkIfAvailable(h.head, ordinal)
+				ret = ordinal
+			}
+		}
+		if err != nil {
+			h.Unlock()
+			return ret, err
 		}
-		// Can't use SetIndex() since we're locked.
-		h.dbIndex = nh.Index()
-		h.dbExists = true
+
+		// Create a private copy of h and work on it, also copy the current db index
+		nh := h.getCopy()
+		ci := h.dbIndex
 		h.Unlock()
+
+		nh.head = pushReservation(bytePos, bitPos, nh.head, release)
+		if release {
+			nh.unselected++
+		} else {
+			nh.unselected--
+		}
+
+		// Attempt to write private copy to store
+		if err := nh.writeToStore(); err != nil {
+			if _, ok := err.(types.RetryError); !ok {
+				return ret, fmt.Errorf("internal failure while setting the bit: %v", err)
+			}
+			// Retry
+			continue
+		}
+
+		// Unless unexpected error, save private copy to local copy
+		h.Lock()
+		defer h.Unlock()
+		if h.dbIndex != ci {
+			return ret, fmt.Errorf("unexected database index change")
+		}
+		h.unselected = nh.unselected
+		h.head = nh.head
+		h.dbExists = nh.dbExists
+		h.dbIndex = nh.dbIndex
+		return ret, nil
 	}
+}
 
-	return err
+// checks is needed because to cover the case where the number of bits is not a multiple of blockLen
+func (h *Handle) validateOrdinal(ordinal uint32) error {
+	if ordinal > h.bits {
+		return fmt.Errorf("bit does not belong to the sequence")
+	}
+	return nil
 }
 
 // Destroy removes from the datastore the data belonging to this handle
@@ -229,13 +302,13 @@ func (h *Handle) Destroy() {
 
 // ToByteArray converts this handle's data into a byte array
 func (h *Handle) ToByteArray() ([]byte, error) {
-	ba := make([]byte, 8)
 
 	h.Lock()
 	defer h.Unlock()
-	copy(ba[0:4], netutils.U32ToA(h.bits))
-	copy(ba[4:8], netutils.U32ToA(h.unselected))
-	bm, err := h.head.ToByteArray()
+	ba := make([]byte, 8)
+	binary.BigEndian.PutUint32(ba[0:], h.bits)
+	binary.BigEndian.PutUint32(ba[4:], h.unselected)
+	bm, err := h.head.toByteArray()
 	if err != nil {
 		return nil, fmt.Errorf("failed to serialize head: %s", err.Error())
 	}
@@ -250,16 +323,16 @@ func (h *Handle) FromByteArray(ba []byte) error {
 		return fmt.Errorf("nil byte array")
 	}
 
-	nh := &Sequence{}
-	err := nh.FromByteArray(ba[8:])
+	nh := &sequence{}
+	err := nh.fromByteArray(ba[8:])
 	if err != nil {
 		return fmt.Errorf("failed to deserialize head: %s", err.Error())
 	}
 
 	h.Lock()
 	h.head = nh
-	h.bits = netutils.ATo32(ba[0:4])
-	h.unselected = netutils.ATo32(ba[4:8])
+	h.bits = binary.BigEndian.Uint32(ba[0:4])
+	h.unselected = binary.BigEndian.Uint32(ba[4:8])
 	h.Unlock()
 
 	return nil
@@ -277,64 +350,70 @@ func (h *Handle) Unselected() uint32 {
 	return h.unselected
 }
 
-// GetFirstAvailable looks for the first unset bit in passed mask
-func GetFirstAvailable(head *Sequence) (int, int, error) {
-	byteIndex := 0
+func (h *Handle) String() string {
+	h.Lock()
+	defer h.Unlock()
+	return fmt.Sprintf("App: %s, ID: %s, DBIndex: 0x%x, bits: %d, unselected: %d, sequence: %s",
+		h.app, h.id, h.dbIndex, h.bits, h.unselected, h.head.toString())
+}
+
+// getFirstAvailable looks for the first unset bit in passed mask
+func getFirstAvailable(head *sequence) (uint32, uint32, error) {
+	byteIndex := uint32(0)
 	current := head
 	for current != nil {
-		if current.Block != blockMAX {
-			bytePos, bitPos := current.GetAvailableBit()
-			return byteIndex + bytePos, bitPos, nil
+		if current.block != blockMAX {
+			bytePos, bitPos, err := current.getAvailableBit()
+			return byteIndex + bytePos, bitPos, err
 		}
-		byteIndex += int(current.Count * blockBytes)
-		current = current.Next
+		byteIndex += current.count * blockBytes
+		current = current.next
 	}
-	return -1, -1, fmt.Errorf("no bit available")
+	return invalidPos, invalidPos, errNoBitAvailable
 }
 
-// CheckIfAvailable checks if the bit correspondent to the specified ordinal is unset
-// If the ordinal is beyond the Sequence limits, a negative response is returned
-func CheckIfAvailable(head *Sequence, ordinal int) (int, int, error) {
+// checkIfAvailable checks if the bit correspondent to the specified ordinal is unset
+// If the ordinal is beyond the sequence limits, a negative response is returned
+func checkIfAvailable(head *sequence, ordinal uint32) (uint32, uint32, error) {
 	bytePos := ordinal / 8
 	bitPos := ordinal % 8
 
-	// Find the Sequence containing this byte
+	// Find the sequence containing this byte
 	current, _, _, inBlockBytePos := findSequence(head, bytePos)
-
 	if current != nil {
 		// Check whether the bit corresponding to the ordinal address is unset
-		bitSel := uint32(blockFirstBit >> uint(inBlockBytePos*8+bitPos))
-		if current.Block&bitSel == 0 {
+		bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos)
+		if current.block&bitSel == 0 {
 			return bytePos, bitPos, nil
 		}
 	}
 
-	return -1, -1, fmt.Errorf("requested bit is not available")
+	return invalidPos, invalidPos, fmt.Errorf("requested bit is not available")
 }
 
 // Given the byte position and the sequences list head, return the pointer to the
 // sequence containing the byte (current), the pointer to the previous sequence,
 // the number of blocks preceding the block containing the byte inside the current sequence.
-// If bytePos is outside of the list, function will return (nil, nil, 0, -1)
-func findSequence(head *Sequence, bytePos int) (*Sequence, *Sequence, uint32, int) {
-	// Find the Sequence containing this byte
+// If bytePos is outside of the list, function will return (nil, nil, 0, invalidPos)
+func findSequence(head *sequence, bytePos uint32) (*sequence, *sequence, uint32, uint32) {
+	// Find the sequence containing this byte
 	previous := head
 	current := head
 	n := bytePos
-	for current.Next != nil && n >= int(current.Count*blockBytes) { // Nil check for less than 32 addresses masks
-		n -= int(current.Count * blockBytes)
+	for current.next != nil && n >= (current.count*blockBytes) { // Nil check for less than 32 addresses masks
+		n -= (current.count * blockBytes)
 		previous = current
-		current = current.Next
+		current = current.next
 	}
 
 	// If byte is outside of the list, let caller know
-	if n >= int(current.Count*blockBytes) {
-		return nil, nil, 0, -1
+	if n >= (current.count * blockBytes) {
+		return nil, nil, 0, invalidPos
 	}
 
 	// Find the byte position inside the block and the number of blocks
 	// preceding the block containing the byte inside this sequence
-	precBlocks := uint32(n / blockBytes)
+	precBlocks := n / blockBytes
 	inBlockBytePos := bytePos % blockBytes
 
 	return current, previous, precBlocks, inBlockBytePos
@@ -343,33 +422,33 @@ func findSequence(head *Sequence, bytePos int) (*Sequence, *Sequence, uint32, in
 // PushReservation pushes the bit reservation inside the bitmask.
 // Given byte and bit positions, identify the sequence (current) which holds the block containing the affected bit.
 // Create a new block with the modified bit according to the operation (allocate/release).
-// Create a new Sequence containing the new Block and insert it in the proper position.
+// Create a new sequence containing the new block and insert it in the proper position.
 // Remove current sequence if empty.
-// Check if new Sequence can be merged with neighbour (previous/Next) sequences.
+// Check if new sequence can be merged with neighbour (previous/next) sequences.
 //
 //
-// Identify "current" Sequence containing block:
-//                                      [prev seq] [current seq] [Next seq]
+// Identify "current" sequence containing block:
+//                                      [prev seq] [current seq] [next seq]
 //
 // Based on block position, resulting list of sequences can be any of three forms:
 //
-//        Block position                        Resulting list of sequences
-// A) Block is first in current:         [prev seq] [new] [modified current seq] [Next seq]
-// B) Block is last in current:          [prev seq] [modified current seq] [new] [Next seq]
-// C) Block is in the middle of current: [prev seq] [curr pre] [new] [curr post] [Next seq]
-func PushReservation(bytePos, bitPos int, head *Sequence, release bool) *Sequence {
+//        block position                        Resulting list of sequences
+// A) block is first in current:         [prev seq] [new] [modified current seq] [next seq]
+// B) block is last in current:          [prev seq] [modified current seq] [new] [next seq]
+// C) block is in the middle of current: [prev seq] [curr pre] [new] [curr post] [next seq]
+func pushReservation(bytePos, bitPos uint32, head *sequence, release bool) *sequence {
 	// Store list's head
 	newHead := head
 
-	// Find the Sequence containing this byte
+	// Find the sequence containing this byte
 	current, previous, precBlocks, inBlockBytePos := findSequence(head, bytePos)
 	if current == nil {
 		return newHead
 	}
 
 	// Construct updated block
-	bitSel := uint32(blockFirstBit >> uint(inBlockBytePos*8+bitPos))
-	newBlock := current.Block
+	bitSel := blockFirstBit >> (inBlockBytePos*8 + bitPos)
+	newBlock := current.block
 	if release {
 		newBlock &^= bitSel
 	} else {
@@ -377,40 +456,40 @@ func PushReservation(bytePos, bitPos int, head *Sequence, release bool) *Sequenc
 	}
 
 	// Quit if it was a redundant request
-	if current.Block == newBlock {
+	if current.block == newBlock {
 		return newHead
 	}
 
-	// Current Sequence inevitably looses one block, upadate Count
-	current.Count--
+	// Current sequence inevitably looses one block, upadate count
+	current.count--
 
 	// Create new sequence
-	newSequence := &Sequence{Block: newBlock, Count: 1}
+	newSequence := &sequence{block: newBlock, count: 1}
 
 	// Insert the new sequence in the list based on block position
 	if precBlocks == 0 { // First in sequence (A)
-		newSequence.Next = current
+		newSequence.next = current
 		if current == head {
 			newHead = newSequence
 			previous = newHead
 		} else {
-			previous.Next = newSequence
+			previous.next = newSequence
 		}
 		removeCurrentIfEmpty(&newHead, newSequence, current)
 		mergeSequences(previous)
-	} else if precBlocks == current.Count-2 { // Last in sequence (B)
-		newSequence.Next = current.Next
-		current.Next = newSequence
+	} else if precBlocks == current.count-2 { // Last in sequence (B)
+		newSequence.next = current.next
+		current.next = newSequence
 		mergeSequences(current)
 	} else { // In between the sequence (C)
-		currPre := &Sequence{Block: current.Block, Count: precBlocks, Next: newSequence}
+		currPre := &sequence{block: current.block, count: precBlocks, next: newSequence}
 		currPost := current
-		currPost.Count -= precBlocks
-		newSequence.Next = currPost
+		currPost.count -= precBlocks
+		newSequence.next = currPost
 		if currPost == head {
 			newHead = currPre
 		} else {
-			previous.Next = currPre
+			previous.next = currPre
 		}
 		// No merging or empty current possible here
 	}
@@ -419,29 +498,29 @@ func PushReservation(bytePos, bitPos int, head *Sequence, release bool) *Sequenc
 }
 
 // Removes the current sequence from the list if empty, adjusting the head pointer if needed
-func removeCurrentIfEmpty(head **Sequence, previous, current *Sequence) {
-	if current.Count == 0 {
+func removeCurrentIfEmpty(head **sequence, previous, current *sequence) {
+	if current.count == 0 {
 		if current == *head {
-			*head = current.Next
+			*head = current.next
 		} else {
-			previous.Next = current.Next
-			current = current.Next
+			previous.next = current.next
+			current = current.next
 		}
 	}
 }
 
-// Given a pointer to a Sequence, it checks if it can be merged with any following sequences
+// Given a pointer to a sequence, it checks if it can be merged with any following sequences
 // It stops when no more merging is possible.
 // TODO: Optimization: only attempt merge from start to end sequence, no need to scan till the end of the list
-func mergeSequences(seq *Sequence) {
+func mergeSequences(seq *sequence) {
 	if seq != nil {
 		// Merge all what possible from seq
-		for seq.Next != nil && seq.Block == seq.Next.Block {
-			seq.Count += seq.Next.Count
-			seq.Next = seq.Next.Next
+		for seq.next != nil && seq.block == seq.next.block {
+			seq.count += seq.next.count
+			seq.next = seq.next.next
 		}
-		// Move to Next
-		mergeSequences(seq.Next)
+		// Move to next
+		mergeSequences(seq.next)
 	}
 }
 
@@ -452,3 +531,11 @@ func getNumBlocks(numBits uint32) uint32 {
 	}
 	return numBlocks
 }
+
+func ordinalToPos(ordinal uint32) (uint32, uint32) {
+	return ordinal / 8, ordinal % 8
+}
+
+func posToOrdinal(bytePos, bitPos uint32) uint32 {
+	return bytePos*8 + bitPos
+}

+ 1 - 1
vendor/src/github.com/docker/libnetwork/bitseq/store.go

@@ -122,7 +122,7 @@ func (h *Handle) writeToStore() error {
 	}
 	err := store.PutObjectAtomic(h)
 	if err == datastore.ErrKeyModified {
-		return types.RetryErrorf("failed to perform atomic write (%v). retry might fix the error", err)
+		return types.RetryErrorf("failed to perform atomic write (%v). Retry might fix the error", err)
 	}
 	return err
 }

+ 26 - 2
vendor/src/github.com/docker/libnetwork/client/service.go

@@ -114,6 +114,25 @@ func lookupContainerID(cli *NetworkCli, cnNameID string) (string, error) {
 	return "", fmt.Errorf("Cannot find container ID in json response")
 }
 
+func lookupSandboxID(cli *NetworkCli, containerID string) (string, error) {
+	obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/sandboxes?container-id=%s", containerID), nil, nil))
+	if err != nil {
+		return "", err
+	}
+
+	var sandboxList []sandboxResource
+	err = json.Unmarshal(obj, &sandboxList)
+	if err != nil {
+		return "", err
+	}
+
+	if len(sandboxList) == 0 {
+		return "", fmt.Errorf("cannot find sandbox for container: %s", containerID)
+	}
+
+	return sandboxList[0].ID, nil
+}
+
 // CmdService handles the service UI
 func (cli *NetworkCli) CmdService(chain string, args ...string) error {
 	cmd := cli.Subcmd(chain, "service", "COMMAND [OPTIONS] [arg...]", serviceUsage(chain), false)
@@ -249,7 +268,7 @@ func getBackendID(cli *NetworkCli, servID string) (string, error) {
 	)
 
 	if obj, _, err = readBody(cli.call("GET", "/services/"+servID+"/backend", nil, nil)); err == nil {
-		var bkl []backendResource
+		var bkl []sandboxResource
 		if err := json.NewDecoder(bytes.NewReader(obj)).Decode(&bkl); err == nil {
 			if len(bkl) > 0 {
 				bk = bkl[0].ID
@@ -310,13 +329,18 @@ func (cli *NetworkCli) CmdServiceAttach(chain string, args ...string) error {
 		return err
 	}
 
+	sandboxID, err := lookupSandboxID(cli, containerID)
+	if err != nil {
+		return err
+	}
+
 	sn, nn := parseServiceName(cmd.Arg(1))
 	serviceID, err := lookupServiceID(cli, nn, sn)
 	if err != nil {
 		return err
 	}
 
-	nc := serviceAttach{ContainerID: containerID}
+	nc := serviceAttach{SandboxID: sandboxID}
 
 	_, _, err = readBody(cli.call("POST", "/services/"+serviceID+"/backend", nc, nil))
 

+ 26 - 21
vendor/src/github.com/docker/libnetwork/client/types.go

@@ -21,9 +21,11 @@ type serviceResource struct {
 	Network string `json:"network"`
 }
 
-// backendResource is the body of "get service backend" response message
-type backendResource struct {
-	ID string `json:"id"`
+// sandboxResource is the body of "get service backend" response message
+type sandboxResource struct {
+	ID          string `json:"id"`
+	Key         string `json:"key"`
+	ContainerID string `json:"container_id"`
 }
 
 /***********
@@ -45,29 +47,32 @@ type serviceCreate struct {
 	PortMapping  []types.PortBinding   `json:"port_mapping"`
 }
 
-// serviceAttach represents the expected body of the "attach/detach backend to/from service" http request messages
+// serviceAttach represents the expected body of the "attach/detach sandbox to/from service" http request messages
 type serviceAttach struct {
-	ContainerID       string                `json:"container_id"`
-	HostName          string                `json:"host_name"`
-	DomainName        string                `json:"domain_name"`
-	HostsPath         string                `json:"hosts_path"`
-	ResolvConfPath    string                `json:"resolv_conf_path"`
-	DNS               []string              `json:"dns"`
-	ExtraHosts        []serviceExtraHost    `json:"extra_hosts"`
-	ParentUpdates     []serviceParentUpdate `json:"parent_updates"`
-	UseDefaultSandbox bool                  `json:"use_default_sandbox"`
+	SandboxID string `json:"sandbox_id"`
 }
 
-// serviceExtraHost represents the extra host object
-type serviceExtraHost struct {
+type sandboxCreate struct {
+	ContainerID       string      `json:"container_id"`
+	HostName          string      `json:"host_name"`
+	DomainName        string      `json:"domain_name"`
+	HostsPath         string      `json:"hosts_path"`
+	ResolvConfPath    string      `json:"resolv_conf_path"`
+	DNS               []string    `json:"dns"`
+	ExtraHosts        []extraHost `json:"extra_hosts"`
+	UseDefaultSandbox bool        `json:"use_default_sandbox"`
+}
+
+// extraHost represents the extra host object
+type extraHost struct {
 	Name    string `json:"name"`
 	Address string `json:"address"`
 }
 
-// EndpointParentUpdate is the object carrying the information about the
-// endpoint parent that needs to be updated
-type serviceParentUpdate struct {
-	EndpointID string `json:"service_id"`
-	Name       string `json:"name"`
-	Address    string `json:"address"`
+// sandboxParentUpdate is the object carrying the information about the
+// sanbox parent that needs to be updated
+type sandboxParentUpdate struct {
+	ContainerID string `json:"container_id"`
+	Name        string `json:"name"`
+	Address     string `json:"address"`
 }

+ 132 - 12
vendor/src/github.com/docker/libnetwork/controller.go

@@ -17,7 +17,7 @@ create network namespaces and allocate interfaces for containers to use.
 	}
 
 	// Create a network for containers to join.
-	// NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make of
+	// NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can make use of
 	network, err := controller.NewNetwork(networkType, "network1")
 	if err != nil {
 		return
@@ -32,8 +32,7 @@ create network namespaces and allocate interfaces for containers to use.
 		return
 	}
 
-	// A container can join the endpoint by providing the container ID to the join
-	// api.
+	// A container can join the endpoint by providing the container ID to the join api.
 	// Join accepts Variadic arguments which will be made use of by libnetwork and Drivers
 	err = ep.Join("container1",
 		libnetwork.JoinOptionHostname("test"),
@@ -45,6 +44,7 @@ create network namespaces and allocate interfaces for containers to use.
 package libnetwork
 
 import (
+	"container/heap"
 	"fmt"
 	"net"
 	"strings"
@@ -58,7 +58,7 @@ import (
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/hostdiscovery"
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/sandbox"
+	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -87,8 +87,17 @@ type NetworkController interface {
 	// NetworkByID returns the Network which has the passed id. If not found, the error ErrNoSuchNetwork is returned.
 	NetworkByID(id string) (Network, error)
 
-	// LeaveAll accepts a container id and attempts to leave all endpoints that the container has joined
-	LeaveAll(id string) error
+	// NewSandbox cretes a new network sandbox for the passed container id
+	NewSandbox(containerID string, options ...SandboxOption) (Sandbox, error)
+
+	// Sandboxes returns the list of Sandbox(s) managed by this controller.
+	Sandboxes() []Sandbox
+
+	// WlakSandboxes uses the provided function to walk the Sandbox(s) managed by this controller.
+	WalkSandboxes(walker SandboxWalker)
+
+	// SandboxByID returns the Sandbox which has the passed id. If not found, a types.NotFoundError is returned.
+	SandboxByID(id string) (Sandbox, error)
 
 	// GC triggers immediate garbage collection of resources which are garbage collected.
 	GC()
@@ -98,15 +107,19 @@ type NetworkController interface {
 // When the function returns true, the walk will stop.
 type NetworkWalker func(nw Network) bool
 
+// SandboxWalker is a client provided function which will be used to walk the Sandboxes.
+// When the function returns true, the walk will stop.
+type SandboxWalker func(sb Sandbox) bool
+
 type driverData struct {
 	driver     driverapi.Driver
 	capability driverapi.Capability
 }
 
 type driverTable map[string]*driverData
-type networkTable map[types.UUID]*network
-type endpointTable map[types.UUID]*endpoint
-type sandboxTable map[string]*sandboxData
+type networkTable map[string]*network
+type endpointTable map[string]*endpoint
+type sandboxTable map[string]*sandbox
 
 type controller struct {
 	networks  networkTable
@@ -250,7 +263,7 @@ func (c *controller) NewNetwork(networkType, name string, options ...NetworkOpti
 	network := &network{
 		name:        name,
 		networkType: networkType,
-		id:          types.UUID(stringid.GenerateRandomID()),
+		id:          stringid.GenerateRandomID(),
 		ctrlr:       c,
 		endpoints:   endpointTable{},
 	}
@@ -356,12 +369,119 @@ func (c *controller) NetworkByID(id string) (Network, error) {
 	}
 	c.Lock()
 	defer c.Unlock()
-	if n, ok := c.networks[types.UUID(id)]; ok {
+	if n, ok := c.networks[id]; ok {
 		return n, nil
 	}
 	return nil, ErrNoSuchNetwork(id)
 }
 
+// NewSandbox creates a new sandbox for the passed container id
+func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (Sandbox, error) {
+	var err error
+
+	if containerID == "" {
+		return nil, types.BadRequestErrorf("invalid container ID")
+	}
+
+	var existing Sandbox
+	look := SandboxContainerWalker(&existing, containerID)
+	c.WalkSandboxes(look)
+	if existing != nil {
+		return nil, types.BadRequestErrorf("container %s is already present: %v", containerID, existing)
+	}
+
+	// Create sandbox and process options first. Key generation depends on an option
+	sb := &sandbox{
+		id:          stringid.GenerateRandomID(),
+		containerID: containerID,
+		endpoints:   epHeap{},
+		epPriority:  map[string]int{},
+		config:      containerConfig{},
+		controller:  c,
+	}
+	// This sandbox may be using an existing osl sandbox, sharing it with another sandbox
+	var peerSb Sandbox
+	c.WalkSandboxes(SandboxKeyWalker(&peerSb, sb.Key()))
+	if peerSb != nil {
+		sb.osSbox = peerSb.(*sandbox).osSbox
+	}
+
+	heap.Init(&sb.endpoints)
+
+	sb.processOptions(options...)
+
+	if err = sb.setupResolutionFiles(); err != nil {
+		return nil, err
+	}
+
+	if sb.osSbox == nil {
+		if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox); err != nil {
+			return nil, fmt.Errorf("failed to create new osl sandbox: %v", err)
+		}
+	}
+
+	c.Lock()
+	c.sandboxes[sb.id] = sb
+	c.Unlock()
+
+	return sb, nil
+}
+
+func (c *controller) Sandboxes() []Sandbox {
+	c.Lock()
+	defer c.Unlock()
+
+	list := make([]Sandbox, 0, len(c.sandboxes))
+	for _, s := range c.sandboxes {
+		list = append(list, s)
+	}
+
+	return list
+}
+
+func (c *controller) WalkSandboxes(walker SandboxWalker) {
+	for _, sb := range c.Sandboxes() {
+		if walker(sb) {
+			return
+		}
+	}
+}
+
+func (c *controller) SandboxByID(id string) (Sandbox, error) {
+	if id == "" {
+		return nil, ErrInvalidID(id)
+	}
+	c.Lock()
+	s, ok := c.sandboxes[id]
+	c.Unlock()
+	if !ok {
+		return nil, types.NotFoundErrorf("sandbox %s not found", id)
+	}
+	return s, nil
+}
+
+// SandboxContainerWalker returns a Sandbox Walker function which looks for an existing Sandbox with the passed containerID
+func SandboxContainerWalker(out *Sandbox, containerID string) SandboxWalker {
+	return func(sb Sandbox) bool {
+		if sb.ContainerID() == containerID {
+			*out = sb
+			return true
+		}
+		return false
+	}
+}
+
+// SandboxKeyWalker returns a Sandbox Walker function which looks for an existing Sandbox with the passed key
+func SandboxKeyWalker(out *Sandbox, key string) SandboxWalker {
+	return func(sb Sandbox) bool {
+		if sb.Key() == key {
+			*out = sb
+			return true
+		}
+		return false
+	}
+}
+
 func (c *controller) loadDriver(networkType string) (*driverData, error) {
 	// Plugins pkg performs lazy loading of plugins that acts as remote drivers.
 	// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
@@ -395,5 +515,5 @@ func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) {
 }
 
 func (c *controller) GC() {
-	sandbox.GC()
+	osl.GC()
 }

+ 8 - 18
vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go

@@ -1,10 +1,6 @@
 package driverapi
 
-import (
-	"net"
-
-	"github.com/docker/libnetwork/types"
-)
+import "net"
 
 // NetworkPluginEndpointType represents the Endpoint Type used by Plugin system
 const NetworkPluginEndpointType = "NetworkDriver"
@@ -17,31 +13,31 @@ type Driver interface {
 	// CreateNetwork invokes the driver method to create a network passing
 	// the network id and network specific config. The config mechanism will
 	// eventually be replaced with labels which are yet to be introduced.
-	CreateNetwork(nid types.UUID, options map[string]interface{}) error
+	CreateNetwork(nid string, options map[string]interface{}) error
 
 	// DeleteNetwork invokes the driver method to delete network passing
 	// the network id.
-	DeleteNetwork(nid types.UUID) error
+	DeleteNetwork(nid string) error
 
 	// CreateEndpoint invokes the driver method to create an endpoint
 	// passing the network id, endpoint id endpoint information and driver
 	// specific config. The endpoint information can be either consumed by
 	// the driver or populated by the driver. The config mechanism will
 	// eventually be replaced with labels which are yet to be introduced.
-	CreateEndpoint(nid, eid types.UUID, epInfo EndpointInfo, options map[string]interface{}) error
+	CreateEndpoint(nid, eid string, epInfo EndpointInfo, options map[string]interface{}) error
 
 	// DeleteEndpoint invokes the driver method to delete an endpoint
 	// passing the network id and endpoint id.
-	DeleteEndpoint(nid, eid types.UUID) error
+	DeleteEndpoint(nid, eid string) error
 
 	// EndpointOperInfo retrieves from the driver the operational data related to the specified endpoint
-	EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error)
+	EndpointOperInfo(nid, eid string) (map[string]interface{}, error)
 
 	// Join method is invoked when a Sandbox is attached to an endpoint.
-	Join(nid, eid types.UUID, sboxKey string, jinfo JoinInfo, options map[string]interface{}) error
+	Join(nid, eid string, sboxKey string, jinfo JoinInfo, options map[string]interface{}) error
 
 	// Leave method is invoked when a Sandbox detaches from an endpoint.
-	Leave(nid, eid types.UUID) error
+	Leave(nid, eid string) error
 
 	// Type returns the the type of this driver, the network type this driver manages
 	Type() string
@@ -107,12 +103,6 @@ type JoinInfo interface {
 	// AddStaticRoute adds a routes to the sandbox.
 	// It may be used in addtion to or instead of a default gateway (as above).
 	AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP, interfaceID int) error
-
-	// SetHostsPath sets the overriding /etc/hosts path to use for the container.
-	SetHostsPath(string) error
-
-	// SetResolvConfPath sets the overriding /etc/resolv.conf path to use for the container.
-	SetResolvConfPath(string) error
 }
 
 // DriverCallback provides a Callback interface for Drivers into LibNetwork

+ 36 - 23
vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go

@@ -20,6 +20,7 @@ import (
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/portmapper"
 	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
@@ -75,7 +76,7 @@ type containerConfiguration struct {
 }
 
 type bridgeEndpoint struct {
-	id              types.UUID
+	id              string
 	srcName         string
 	addr            *net.IPNet
 	addrv6          *net.IPNet
@@ -86,10 +87,10 @@ type bridgeEndpoint struct {
 }
 
 type bridgeNetwork struct {
-	id         types.UUID
+	id         string
 	bridge     *bridgeInterface // The bridge's L3 interface
 	config     *networkConfiguration
-	endpoints  map[types.UUID]*bridgeEndpoint // key: endpoint id
+	endpoints  map[string]*bridgeEndpoint // key: endpoint id
 	portMapper *portmapper.PortMapper
 	driver     *driver // The network's driver
 	sync.Mutex
@@ -100,7 +101,7 @@ type driver struct {
 	network     *bridgeNetwork
 	natChain    *iptables.ChainInfo
 	filterChain *iptables.ChainInfo
-	networks    map[types.UUID]*bridgeNetwork
+	networks    map[string]*bridgeNetwork
 	sync.Mutex
 }
 
@@ -110,7 +111,7 @@ func init() {
 
 // New constructs a new bridge driver
 func newDriver() driverapi.Driver {
-	return &driver{networks: map[types.UUID]*bridgeNetwork{}}
+	return &driver{networks: map[string]*bridgeNetwork{}}
 }
 
 // Init registers a new instance of bridge driver
@@ -346,7 +347,7 @@ func (n *bridgeNetwork) getNetworkBridgeName() string {
 	return config.BridgeName
 }
 
-func (n *bridgeNetwork) getEndpoint(eid types.UUID) (*bridgeEndpoint, error) {
+func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
 	n.Lock()
 	defer n.Unlock()
 
@@ -394,7 +395,7 @@ func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) err
 }
 
 // Checks whether this network's configuration for the network with this id conflicts with any of the passed networks
-func (c *networkConfiguration) conflictsWithNetworks(id types.UUID, others []*bridgeNetwork) error {
+func (c *networkConfiguration) conflictsWithNetworks(id string, others []*bridgeNetwork) error {
 	for _, nw := range others {
 
 		nw.Lock()
@@ -475,7 +476,7 @@ func (d *driver) Config(option map[string]interface{}) error {
 	return nil
 }
 
-func (d *driver) getNetwork(id types.UUID) (*bridgeNetwork, error) {
+func (d *driver) getNetwork(id string) (*bridgeNetwork, error) {
 	d.Lock()
 	defer d.Unlock()
 
@@ -567,9 +568,11 @@ func (d *driver) getNetworks() []*bridgeNetwork {
 }
 
 // Create a new network using bridge plugin
-func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 	var err error
 
+	defer osl.InitOSContext()()
+
 	// Sanity checks
 	d.Lock()
 	if _, ok := d.networks[id]; ok {
@@ -596,7 +599,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
 	// Create and set network handler in driver
 	network := &bridgeNetwork{
 		id:         id,
-		endpoints:  make(map[types.UUID]*bridgeEndpoint),
+		endpoints:  make(map[string]*bridgeEndpoint),
 		config:     config,
 		portMapper: portmapper.New(),
 		driver:     d,
@@ -719,9 +722,11 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
 	return nil
 }
 
-func (d *driver) DeleteNetwork(nid types.UUID) error {
+func (d *driver) DeleteNetwork(nid string) error {
 	var err error
 
+	defer osl.InitOSContext()()
+
 	// Get network handler and remove it from driver
 	d.Lock()
 	n, ok := d.networks[nid]
@@ -843,12 +848,14 @@ func setHairpinMode(link netlink.Link, enable bool) error {
 	return nil
 }
 
-func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
+func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
 	var (
 		ipv6Addr *net.IPNet
 		err      error
 	)
 
+	defer osl.InitOSContext()()
+
 	if epInfo == nil {
 		return errors.New("invalid endpoint info passed")
 	}
@@ -927,13 +934,13 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 		LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
 		PeerName:  containerIfName}
 	if err = netlink.LinkAdd(veth); err != nil {
-		return err
+		return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err)
 	}
 
 	// Get the host side pipe interface handler
 	host, err := netlink.LinkByName(hostIfName)
 	if err != nil {
-		return err
+		return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err)
 	}
 	defer func() {
 		if err != nil {
@@ -944,7 +951,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	// Get the sandbox side pipe interface handler
 	sbox, err := netlink.LinkByName(containerIfName)
 	if err != nil {
-		return err
+		return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err)
 	}
 	defer func() {
 		if err != nil {
@@ -960,11 +967,11 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	if config.Mtu != 0 {
 		err = netlink.LinkSetMTU(host, config.Mtu)
 		if err != nil {
-			return err
+			return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err)
 		}
 		err = netlink.LinkSetMTU(sbox, config.Mtu)
 		if err != nil {
-			return err
+			return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err)
 		}
 	}
 
@@ -1054,9 +1061,11 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	return nil
 }
 
-func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
+func (d *driver) DeleteEndpoint(nid, eid string) error {
 	var err error
 
+	defer osl.InitOSContext()()
+
 	// Get the network handler and make sure it exists
 	d.Lock()
 	n, ok := d.networks[nid]
@@ -1138,7 +1147,7 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
 	return nil
 }
 
-func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
+func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
 	// Get the network handler and make sure it exists
 	d.Lock()
 	n, ok := d.networks[nid]
@@ -1195,7 +1204,9 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
 }
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
-func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
+func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
+	defer osl.InitOSContext()()
+
 	network, err := d.getNetwork(nid)
 	if err != nil {
 		return err
@@ -1238,7 +1249,9 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI
 }
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.
-func (d *driver) Leave(nid, eid types.UUID) error {
+func (d *driver) Leave(nid, eid string) error {
+	defer osl.InitOSContext()()
+
 	network, err := d.getNetwork(nid)
 	if err != nil {
 		return err
@@ -1282,7 +1295,7 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
 	if endpoint.config != nil && endpoint.config.ExposedPorts != nil {
 		for _, p := range cc.ParentEndpoints {
 			var parentEndpoint *bridgeEndpoint
-			parentEndpoint, err = network.getEndpoint(types.UUID(p))
+			parentEndpoint, err = network.getEndpoint(p)
 			if err != nil {
 				return err
 			}
@@ -1312,7 +1325,7 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
 
 	for _, c := range cc.ChildEndpoints {
 		var childEndpoint *bridgeEndpoint
-		childEndpoint, err = network.getEndpoint(types.UUID(c))
+		childEndpoint, err = network.getEndpoint(c)
 		if err != nil {
 			return err
 		}

+ 1 - 1
vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_armppc64.go

@@ -1,4 +1,4 @@
-// +build arm ppc64
+// +build arm ppc64 ppc64le
 
 package bridge
 

+ 1 - 1
vendor/src/github.com/docker/libnetwork/drivers/bridge/netlink_deprecated_linux_notarm.go

@@ -1,4 +1,4 @@
-// +build !arm,!ppc64
+// +build !arm,!ppc64,!ppc64le
 
 package bridge
 

+ 9 - 13
vendor/src/github.com/docker/libnetwork/drivers/host/host.go

@@ -10,7 +10,7 @@ import (
 const networkType = "host"
 
 type driver struct {
-	network types.UUID
+	network string
 	sync.Mutex
 }
 
@@ -26,7 +26,7 @@ func (d *driver) Config(option map[string]interface{}) error {
 	return nil
 }
 
-func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 	d.Lock()
 	defer d.Unlock()
 
@@ -39,33 +39,29 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
 	return nil
 }
 
-func (d *driver) DeleteNetwork(nid types.UUID) error {
+func (d *driver) DeleteNetwork(nid string) error {
 	return types.ForbiddenErrorf("network of type \"%s\" cannot be deleted", networkType)
 }
 
-func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
+func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
 	return nil
 }
 
-func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
+func (d *driver) DeleteEndpoint(nid, eid string) error {
 	return nil
 }
 
-func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
+func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
 	return make(map[string]interface{}, 0), nil
 }
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
-func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
-	if err := jinfo.SetHostsPath("/etc/hosts"); err != nil {
-		return err
-	}
-
-	return jinfo.SetResolvConfPath("/etc/resolv.conf")
+func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
+	return nil
 }
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.
-func (d *driver) Leave(nid, eid types.UUID) error {
+func (d *driver) Leave(nid, eid string) error {
 	return nil
 }
 

+ 8 - 8
vendor/src/github.com/docker/libnetwork/drivers/null/null.go

@@ -10,7 +10,7 @@ import (
 const networkType = "null"
 
 type driver struct {
-	network types.UUID
+	network string
 	sync.Mutex
 }
 
@@ -26,7 +26,7 @@ func (d *driver) Config(option map[string]interface{}) error {
 	return nil
 }
 
-func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 	d.Lock()
 	defer d.Unlock()
 
@@ -39,29 +39,29 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
 	return nil
 }
 
-func (d *driver) DeleteNetwork(nid types.UUID) error {
+func (d *driver) DeleteNetwork(nid string) error {
 	return types.ForbiddenErrorf("network of type \"%s\" cannot be deleted", networkType)
 }
 
-func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
+func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
 	return nil
 }
 
-func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
+func (d *driver) DeleteEndpoint(nid, eid string) error {
 	return nil
 }
 
-func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
+func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
 	return make(map[string]interface{}, 0), nil
 }
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
-func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
+func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
 	return nil
 }
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.
-func (d *driver) Leave(nid, eid types.UUID) error {
+func (d *driver) Leave(nid, eid string) error {
 	return nil
 }
 

+ 2 - 3
vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go

@@ -4,12 +4,11 @@ import (
 	"fmt"
 
 	"github.com/docker/libnetwork/driverapi"
-	"github.com/docker/libnetwork/types"
 	"github.com/vishvananda/netlink"
 )
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
-func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
+func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
 	if err := validateID(nid, eid); err != nil {
 		return err
 	}
@@ -77,7 +76,7 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI
 }
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.
-func (d *driver) Leave(nid, eid types.UUID) error {
+func (d *driver) Leave(nid, eid string) error {
 	if err := validateID(nid, eid); err != nil {
 		return err
 	}

+ 8 - 9
vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go

@@ -7,18 +7,17 @@ import (
 
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/netutils"
-	"github.com/docker/libnetwork/types"
 )
 
-type endpointTable map[types.UUID]*endpoint
+type endpointTable map[string]*endpoint
 
 type endpoint struct {
-	id   types.UUID
+	id   string
 	mac  net.HardwareAddr
 	addr *net.IPNet
 }
 
-func (n *network) endpoint(eid types.UUID) *endpoint {
+func (n *network) endpoint(eid string) *endpoint {
 	n.Lock()
 	defer n.Unlock()
 
@@ -31,13 +30,13 @@ func (n *network) addEndpoint(ep *endpoint) {
 	n.Unlock()
 }
 
-func (n *network) deleteEndpoint(eid types.UUID) {
+func (n *network) deleteEndpoint(eid string) {
 	n.Lock()
 	delete(n.endpoints, eid)
 	n.Unlock()
 }
 
-func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo,
+func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 	epOptions map[string]interface{}) error {
 	if err := validateID(nid, eid); err != nil {
 		return err
@@ -73,7 +72,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 
 	binary.BigEndian.PutUint32(ep.addr.IP, bridgeSubnetInt+ipID)
 
-	ep.mac = netutils.GenerateRandomMAC()
+	ep.mac = netutils.GenerateMACFromIP(ep.addr.IP)
 
 	err = epInfo.AddInterface(1, ep.mac, *ep.addr, net.IPNet{})
 	if err != nil {
@@ -85,7 +84,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	return nil
 }
 
-func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
+func (d *driver) DeleteEndpoint(nid, eid string) error {
 	if err := validateID(nid, eid); err != nil {
 		return err
 	}
@@ -105,6 +104,6 @@ func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
 	return nil
 }
 
-func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
+func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
 	return make(map[string]interface{}, 0), nil
 }

+ 14 - 15
vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go

@@ -10,20 +10,19 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/ipallocator"
-	"github.com/docker/libnetwork/sandbox"
-	"github.com/docker/libnetwork/types"
+	"github.com/docker/libnetwork/osl"
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink/nl"
 )
 
-type networkTable map[types.UUID]*network
+type networkTable map[string]*network
 
 type network struct {
-	id          types.UUID
+	id          string
 	vni         uint32
 	dbIndex     uint64
 	dbExists    bool
-	sbox        sandbox.Sandbox
+	sbox        osl.Sandbox
 	endpoints   endpointTable
 	ipAllocator *ipallocator.IPAllocator
 	gw          net.IP
@@ -36,7 +35,7 @@ type network struct {
 	sync.Mutex
 }
 
-func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 	if id == "" {
 		return fmt.Errorf("invalid network id")
 	}
@@ -59,7 +58,7 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
 	return nil
 }
 
-func (d *driver) DeleteNetwork(nid types.UUID) error {
+func (d *driver) DeleteNetwork(nid string) error {
 	if nid == "" {
 		return fmt.Errorf("invalid network id")
 	}
@@ -140,8 +139,8 @@ func (n *network) initSandbox() error {
 	n.initEpoch++
 	n.Unlock()
 
-	sbox, err := sandbox.NewSandbox(
-		sandbox.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+string(n.id)), true)
+	sbox, err := osl.NewSandbox(
+		osl.GenerateKey(fmt.Sprintf("%d-", n.initEpoch)+n.id), true)
 	if err != nil {
 		return fmt.Errorf("could not create network sandbox: %v", err)
 	}
@@ -216,7 +215,7 @@ func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
 				continue
 			}
 
-			if err := n.driver.peerAdd(n.id, types.UUID("dummy"), neigh.IP, mac, vtep, true); err != nil {
+			if err := n.driver.peerAdd(n.id, "dummy", neigh.IP, mac, vtep, true); err != nil {
 				logrus.Errorf("could not add neighbor entry for missed peer: %v", err)
 			}
 		}
@@ -229,27 +228,27 @@ func (d *driver) addNetwork(n *network) {
 	d.Unlock()
 }
 
-func (d *driver) deleteNetwork(nid types.UUID) {
+func (d *driver) deleteNetwork(nid string) {
 	d.Lock()
 	delete(d.networks, nid)
 	d.Unlock()
 }
 
-func (d *driver) network(nid types.UUID) *network {
+func (d *driver) network(nid string) *network {
 	d.Lock()
 	defer d.Unlock()
 
 	return d.networks[nid]
 }
 
-func (n *network) sandbox() sandbox.Sandbox {
+func (n *network) sandbox() osl.Sandbox {
 	n.Lock()
 	defer n.Unlock()
 
 	return n.sbox
 }
 
-func (n *network) setSandbox(sbox sandbox.Sandbox) {
+func (n *network) setSandbox(sbox osl.Sandbox) {
 	n.Lock()
 	n.sbox = sbox
 	n.Unlock()
@@ -269,7 +268,7 @@ func (n *network) setVxlanID(vni uint32) {
 }
 
 func (n *network) Key() []string {
-	return []string{"overlay", "network", string(n.id)}
+	return []string{"overlay", "network", n.id}
 }
 
 func (n *network) KeyPrefix() []string {

+ 6 - 7
vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go

@@ -7,14 +7,13 @@ import (
 	"time"
 
 	"github.com/Sirupsen/logrus"
-	"github.com/docker/libnetwork/types"
 	"github.com/hashicorp/serf/serf"
 )
 
 type ovNotify struct {
 	action string
-	eid    types.UUID
-	nid    types.UUID
+	eid    string
+	nid    string
 }
 
 type logWriter struct{}
@@ -150,12 +149,12 @@ func (d *driver) processEvent(u serf.UserEvent) {
 
 	switch action {
 	case "join":
-		if err := d.peerAdd(types.UUID(nid), types.UUID(eid), net.ParseIP(ipStr), mac,
+		if err := d.peerAdd(nid, eid, net.ParseIP(ipStr), mac,
 			net.ParseIP(vtepStr), true); err != nil {
 			fmt.Printf("Peer add failed in the driver: %v\n", err)
 		}
 	case "leave":
-		if err := d.peerDelete(types.UUID(nid), types.UUID(eid), net.ParseIP(ipStr), mac,
+		if err := d.peerDelete(nid, eid, net.ParseIP(ipStr), mac,
 			net.ParseIP(vtepStr), true); err != nil {
 			fmt.Printf("Peer delete failed in the driver: %v\n", err)
 		}
@@ -171,7 +170,7 @@ func (d *driver) processQuery(q *serf.Query) {
 		fmt.Printf("Failed to scan query payload string: %v\n", err)
 	}
 
-	peerMac, vtep, err := d.peerDbSearch(types.UUID(nid), net.ParseIP(ipStr))
+	peerMac, vtep, err := d.peerDbSearch(nid, net.ParseIP(ipStr))
 	if err != nil {
 		return
 	}
@@ -179,7 +178,7 @@ func (d *driver) processQuery(q *serf.Query) {
 	q.Respond([]byte(fmt.Sprintf("%s %s", peerMac.String(), vtep.String())))
 }
 
-func (d *driver) resolvePeer(nid types.UUID, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
+func (d *driver) resolvePeer(nid string, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
 	qPayload := fmt.Sprintf("%s %s", string(nid), peerIP.String())
 	resp, err := d.serfInstance.Query("peerlookup", []byte(qPayload), nil)
 	if err != nil {

+ 8 - 2
vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_utils.go

@@ -4,12 +4,12 @@ import (
 	"fmt"
 
 	"github.com/docker/libnetwork/netutils"
-	"github.com/docker/libnetwork/types"
+	"github.com/docker/libnetwork/osl"
 	"github.com/vishvananda/netlink"
 	"github.com/vishvananda/netlink/nl"
 )
 
-func validateID(nid, eid types.UUID) error {
+func validateID(nid, eid string) error {
 	if nid == "" {
 		return fmt.Errorf("invalid network id")
 	}
@@ -22,6 +22,8 @@ func validateID(nid, eid types.UUID) error {
 }
 
 func createVethPair() (string, string, error) {
+	defer osl.InitOSContext()()
+
 	// Generate a name for what will be the host side pipe interface
 	name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
 	if err != nil {
@@ -46,6 +48,8 @@ func createVethPair() (string, string, error) {
 }
 
 func createVxlan(vni uint32) (string, error) {
+	defer osl.InitOSContext()()
+
 	name, err := netutils.GenerateIfaceName("vxlan", 7)
 	if err != nil {
 		return "", fmt.Errorf("error generating vxlan name: %v", err)
@@ -69,6 +73,8 @@ func createVxlan(vni uint32) (string, error) {
 }
 
 func deleteVxlan(name string) error {
+	defer osl.InitOSContext()()
+
 	link, err := netlink.LinkByName(name)
 	if err != nil {
 		return fmt.Errorf("failed to find vxlan interface with name %s: %v", name, err)

+ 1 - 2
vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go

@@ -11,7 +11,6 @@ import (
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/idm"
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/types"
 	"github.com/hashicorp/serf/serf"
 )
 
@@ -77,7 +76,7 @@ func Init(dc driverapi.DriverCallback) error {
 	return dc.RegisterDriver(networkType, &driver{
 		networks: networkTable{},
 		peerDb: peerNetworkMap{
-			mp: map[types.UUID]peerMap{},
+			mp: map[string]peerMap{},
 		},
 	}, c)
 }

+ 9 - 11
vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go

@@ -5,8 +5,6 @@ import (
 	"net"
 	"sync"
 	"syscall"
-
-	"github.com/docker/libnetwork/types"
 )
 
 type peerKey struct {
@@ -15,7 +13,7 @@ type peerKey struct {
 }
 
 type peerEntry struct {
-	eid       types.UUID
+	eid       string
 	vtep      net.IP
 	inSandbox bool
 	isLocal   bool
@@ -27,7 +25,7 @@ type peerMap struct {
 }
 
 type peerNetworkMap struct {
-	mp map[types.UUID]peerMap
+	mp map[string]peerMap
 	sync.Mutex
 }
 
@@ -58,7 +56,7 @@ func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error {
 
 var peerDbWg sync.WaitGroup
 
-func (d *driver) peerDbWalk(nid types.UUID, f func(*peerKey, *peerEntry) bool) error {
+func (d *driver) peerDbWalk(nid string, f func(*peerKey, *peerEntry) bool) error {
 	d.peerDb.Lock()
 	pMap, ok := d.peerDb.mp[nid]
 	if !ok {
@@ -84,7 +82,7 @@ func (d *driver) peerDbWalk(nid types.UUID, f func(*peerKey, *peerEntry) bool) e
 	return nil
 }
 
-func (d *driver) peerDbSearch(nid types.UUID, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
+func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.IP, error) {
 	var (
 		peerMac net.HardwareAddr
 		vtep    net.IP
@@ -113,7 +111,7 @@ func (d *driver) peerDbSearch(nid types.UUID, peerIP net.IP) (net.HardwareAddr,
 	return peerMac, vtep, nil
 }
 
-func (d *driver) peerDbAdd(nid, eid types.UUID, peerIP net.IP,
+func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP,
 	peerMac net.HardwareAddr, vtep net.IP, isLocal bool) {
 
 	peerDbWg.Wait()
@@ -145,7 +143,7 @@ func (d *driver) peerDbAdd(nid, eid types.UUID, peerIP net.IP,
 	pMap.Unlock()
 }
 
-func (d *driver) peerDbDelete(nid, eid types.UUID, peerIP net.IP,
+func (d *driver) peerDbDelete(nid, eid string, peerIP net.IP,
 	peerMac net.HardwareAddr, vtep net.IP) {
 	peerDbWg.Wait()
 
@@ -167,7 +165,7 @@ func (d *driver) peerDbDelete(nid, eid types.UUID, peerIP net.IP,
 	pMap.Unlock()
 }
 
-func (d *driver) peerDbUpdateSandbox(nid types.UUID) {
+func (d *driver) peerDbUpdateSandbox(nid string) {
 	d.peerDb.Lock()
 	pMap, ok := d.peerDb.mp[nid]
 	if !ok {
@@ -214,7 +212,7 @@ func (d *driver) peerDbUpdateSandbox(nid types.UUID) {
 	peerDbWg.Done()
 }
 
-func (d *driver) peerAdd(nid, eid types.UUID, peerIP net.IP,
+func (d *driver) peerAdd(nid, eid string, peerIP net.IP,
 	peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
 
 	if err := validateID(nid, eid); err != nil {
@@ -249,7 +247,7 @@ func (d *driver) peerAdd(nid, eid types.UUID, peerIP net.IP,
 	return nil
 }
 
-func (d *driver) peerDelete(nid, eid types.UUID, peerIP net.IP,
+func (d *driver) peerDelete(nid, eid string, peerIP net.IP,
 	peerMac net.HardwareAddr, vtep net.IP, updateDb bool) error {
 
 	if err := validateID(nid, eid); err != nil {

+ 0 - 2
vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go

@@ -127,8 +127,6 @@ type JoinResponse struct {
 	InterfaceNames []*InterfaceName
 	Gateway        string
 	GatewayIPv6    string
-	HostsPath      string
-	ResolvConfPath string
 	StaticRoutes   []StaticRoute
 }
 

+ 19 - 25
vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go

@@ -57,20 +57,20 @@ func (d *driver) call(methodName string, arg interface{}, retVal maybeError) err
 	return nil
 }
 
-func (d *driver) CreateNetwork(id types.UUID, options map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, options map[string]interface{}) error {
 	create := &api.CreateNetworkRequest{
-		NetworkID: string(id),
+		NetworkID: id,
 		Options:   options,
 	}
 	return d.call("CreateNetwork", create, &api.CreateNetworkResponse{})
 }
 
-func (d *driver) DeleteNetwork(nid types.UUID) error {
-	delete := &api.DeleteNetworkRequest{NetworkID: string(nid)}
+func (d *driver) DeleteNetwork(nid string) error {
+	delete := &api.DeleteNetworkRequest{NetworkID: nid}
 	return d.call("DeleteNetwork", delete, &api.DeleteNetworkResponse{})
 }
 
-func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
+func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
 	if epInfo == nil {
 		return fmt.Errorf("must not be called with nil EndpointInfo")
 	}
@@ -87,8 +87,8 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 		}
 	}
 	create := &api.CreateEndpointRequest{
-		NetworkID:  string(nid),
-		EndpointID: string(eid),
+		NetworkID:  nid,
+		EndpointID: eid,
 		Interfaces: reqIfaces,
 		Options:    epOptions,
 	}
@@ -129,18 +129,18 @@ func errorWithRollback(msg string, err error) error {
 	return fmt.Errorf("%s; %s", msg, rollback)
 }
 
-func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
+func (d *driver) DeleteEndpoint(nid, eid string) error {
 	delete := &api.DeleteEndpointRequest{
-		NetworkID:  string(nid),
-		EndpointID: string(eid),
+		NetworkID:  nid,
+		EndpointID: eid,
 	}
 	return d.call("DeleteEndpoint", delete, &api.DeleteEndpointResponse{})
 }
 
-func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
+func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
 	info := &api.EndpointInfoRequest{
-		NetworkID:  string(nid),
-		EndpointID: string(eid),
+		NetworkID:  nid,
+		EndpointID: eid,
 	}
 	var res api.EndpointInfoResponse
 	if err := d.call("EndpointOperInfo", info, &res); err != nil {
@@ -150,10 +150,10 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
 }
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
-func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
+func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
 	join := &api.JoinRequest{
-		NetworkID:  string(nid),
-		EndpointID: string(eid),
+		NetworkID:  nid,
+		EndpointID: eid,
 		SandboxKey: sboxKey,
 		Options:    options,
 	}
@@ -209,20 +209,14 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI
 			}
 		}
 	}
-	if jinfo.SetHostsPath(res.HostsPath) != nil {
-		return errorWithRollback(fmt.Sprintf("failed to set hosts path: %s", res.HostsPath), d.Leave(nid, eid))
-	}
-	if jinfo.SetResolvConfPath(res.ResolvConfPath) != nil {
-		return errorWithRollback(fmt.Sprintf("failed to set resolv.conf path: %s", res.ResolvConfPath), d.Leave(nid, eid))
-	}
 	return nil
 }
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.
-func (d *driver) Leave(nid, eid types.UUID) error {
+func (d *driver) Leave(nid, eid string) error {
 	leave := &api.LeaveRequest{
-		NetworkID:  string(nid),
-		EndpointID: string(eid),
+		NetworkID:  nid,
+		EndpointID: eid,
 	}
 	return d.call("Leave", leave, &api.LeaveResponse{})
 }

+ 8 - 11
vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go

@@ -1,9 +1,6 @@
 package windows
 
-import (
-	"github.com/docker/libnetwork/driverapi"
-	"github.com/docker/libnetwork/types"
-)
+import "github.com/docker/libnetwork/driverapi"
 
 const networkType = "windows"
 
@@ -23,33 +20,33 @@ func (d *driver) Config(option map[string]interface{}) error {
 	return nil
 }
 
-func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
+func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
 	return nil
 }
 
-func (d *driver) DeleteNetwork(nid types.UUID) error {
+func (d *driver) DeleteNetwork(nid string) error {
 	return nil
 }
 
-func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
+func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
 	return nil
 }
 
-func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
+func (d *driver) DeleteEndpoint(nid, eid string) error {
 	return nil
 }
 
-func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{}, error) {
+func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
 	return make(map[string]interface{}, 0), nil
 }
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
-func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
+func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
 	return nil
 }
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.
-func (d *driver) Leave(nid, eid types.UUID) error {
+func (d *driver) Leave(nid, eid string) error {
 	return nil
 }
 

+ 101 - 573
vendor/src/github.com/docker/libnetwork/endpoint.go

@@ -1,22 +1,14 @@
 package libnetwork
 
 import (
-	"bytes"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
-	"os"
-	"path"
-	"path/filepath"
+	"net"
 	"sync"
 
 	log "github.com/Sirupsen/logrus"
-	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/libnetwork/datastore"
-	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/netlabel"
-	"github.com/docker/libnetwork/resolvconf"
-	"github.com/docker/libnetwork/sandbox"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -31,14 +23,12 @@ type Endpoint interface {
 	// Network returns the name of the network to which this endpoint is attached.
 	Network() string
 
-	// Join creates a new sandbox for the given container ID and populates the
-	// network resources allocated for the endpoint and joins the sandbox to
-	// the endpoint.
-	Join(containerID string, options ...EndpointOption) error
+	// Join joins the sandbox to the endpoint and populates into the sandbox
+	// the network resources allocated for the endpoint.
+	Join(sandbox Sandbox, options ...EndpointOption) error
 
-	// Leave removes the sandbox associated with  container ID and detaches
-	// the network resources populated in the sandbox
-	Leave(containerID string, options ...EndpointOption) error
+	// Leave detaches the network resources populated in the sandbox.
+	Leave(sandbox Sandbox, options ...EndpointOption) error
 
 	// Return certain operational data belonging to this endpoint
 	Info() EndpointInfo
@@ -46,14 +36,8 @@ type Endpoint interface {
 	// DriverInfo returns a collection of driver operational data related to this endpoint retrieved from the driver
 	DriverInfo() (map[string]interface{}, error)
 
-	// ContainerInfo returns the info available at the endpoint about the attached container
-	ContainerInfo() ContainerInfo
-
 	// Delete and detaches this endpoint from the network.
 	Delete() error
-
-	// Retrieve the interfaces' statistics from the sandbox
-	Statistics() (map[string]*sandbox.InterfaceStatistics, error)
 }
 
 // EndpointOption is a option setter function type used to pass varios options to Network
@@ -61,68 +45,13 @@ type Endpoint interface {
 // provided by libnetwork, they look like <Create|Join|Leave>Option[...](...)
 type EndpointOption func(ep *endpoint)
 
-// ContainerData is a set of data returned when a container joins an endpoint.
-type ContainerData struct {
-	SandboxKey string
-}
-
-// These are the container configs used to customize container /etc/hosts file.
-type hostsPathConfig struct {
-	hostName      string
-	domainName    string
-	hostsPath     string
-	extraHosts    []extraHost
-	parentUpdates []parentUpdate
-}
-
-// These are the container configs used to customize container /etc/resolv.conf file.
-type resolvConfPathConfig struct {
-	resolvConfPath string
-	dnsList        []string
-	dnsSearchList  []string
-}
-
-type containerConfig struct {
-	hostsPathConfig
-	resolvConfPathConfig
-	generic           map[string]interface{}
-	useDefaultSandBox bool
-	prio              int // higher the value, more the priority
-}
-
-type extraHost struct {
-	name string
-	IP   string
-}
-
-type parentUpdate struct {
-	eid  string
-	name string
-	ip   string
-}
-
-type containerInfo struct {
-	id     string
-	config containerConfig
-	data   ContainerData
-	sync.Mutex
-}
-
-func (ci *containerInfo) ID() string {
-	return ci.id
-}
-
-func (ci *containerInfo) Labels() map[string]interface{} {
-	return ci.config.generic
-}
-
 type endpoint struct {
 	name          string
-	id            types.UUID
+	id            string
 	network       *network
 	iFaces        []*endpointInterface
 	joinInfo      *endpointJoinInfo
-	container     *containerInfo
+	sandboxID     string
 	exposedPorts  []types.TransportPort
 	generic       map[string]interface{}
 	joinLeaveDone chan struct{}
@@ -131,39 +60,17 @@ type endpoint struct {
 	sync.Mutex
 }
 
-func (ci *containerInfo) MarshalJSON() ([]byte, error) {
-	ci.Lock()
-	defer ci.Unlock()
-
-	// We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need
-	return json.Marshal(ci.id)
-}
-
-func (ci *containerInfo) UnmarshalJSON(b []byte) (err error) {
-	ci.Lock()
-	defer ci.Unlock()
-
-	var id string
-	if err := json.Unmarshal(b, &id); err != nil {
-		return err
-	}
-	ci.id = id
-	return nil
-}
-
 func (ep *endpoint) MarshalJSON() ([]byte, error) {
 	ep.Lock()
 	defer ep.Unlock()
 
 	epMap := make(map[string]interface{})
 	epMap["name"] = ep.name
-	epMap["id"] = string(ep.id)
+	epMap["id"] = ep.id
 	epMap["ep_iface"] = ep.iFaces
 	epMap["exposed_ports"] = ep.exposedPorts
 	epMap["generic"] = ep.generic
-	if ep.container != nil {
-		epMap["container"] = ep.container
-	}
+	epMap["sandbox"] = ep.sandboxID
 	return json.Marshal(epMap)
 }
 
@@ -176,7 +83,7 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
 		return err
 	}
 	ep.name = epMap["name"].(string)
-	ep.id = types.UUID(epMap["id"].(string))
+	ep.id = epMap["id"].(string)
 
 	ib, _ := json.Marshal(epMap["ep_iface"])
 	var ifaces []endpointInterface
@@ -191,13 +98,8 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
 	json.Unmarshal(tb, &tPorts)
 	ep.exposedPorts = tPorts
 
-	epc, ok := epMap["container"]
-	if ok {
-		cb, _ := json.Marshal(epc)
-		var cInfo containerInfo
-		json.Unmarshal(cb, &cInfo)
-		ep.container = &cInfo
-	}
+	cb, _ := json.Marshal(epMap["sandbox"])
+	json.Unmarshal(cb, &ep.sandboxID)
 
 	if epMap["generic"] != nil {
 		ep.generic = epMap["generic"].(map[string]interface{})
@@ -205,13 +107,11 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
 	return nil
 }
 
-const defaultPrefix = "/var/lib/docker/network/files"
-
 func (ep *endpoint) ID() string {
 	ep.Lock()
 	defer ep.Unlock()
 
-	return string(ep.id)
+	return ep.id
 }
 
 func (ep *endpoint) Name() string {
@@ -222,36 +122,27 @@ func (ep *endpoint) Name() string {
 }
 
 func (ep *endpoint) Network() string {
-	ep.Lock()
-	defer ep.Unlock()
-
-	return ep.network.name
+	return ep.getNetwork().name
 }
 
 // endpoint Key structure : endpoint/network-id/endpoint-id
 func (ep *endpoint) Key() []string {
-	ep.Lock()
-	n := ep.network
-	defer ep.Unlock()
-	return []string{datastore.EndpointKeyPrefix, string(n.id), string(ep.id)}
+	return []string{datastore.EndpointKeyPrefix, ep.getNetwork().id, ep.id}
 }
 
 func (ep *endpoint) KeyPrefix() []string {
-	ep.Lock()
-	n := ep.network
-	defer ep.Unlock()
-	return []string{datastore.EndpointKeyPrefix, string(n.id)}
+	return []string{datastore.EndpointKeyPrefix, ep.getNetwork().id}
 }
 
-func (ep *endpoint) networkIDFromKey(key []string) (types.UUID, error) {
+func (ep *endpoint) networkIDFromKey(key []string) (string, error) {
 	// endpoint Key structure : endpoint/network-id/endpoint-id
 	// it's an invalid key if the key doesn't have all the 3 key elements above
 	if key == nil || len(key) < 3 || key[0] != datastore.EndpointKeyPrefix {
-		return types.UUID(""), fmt.Errorf("invalid endpoint key : %v", key)
+		return "", fmt.Errorf("invalid endpoint key : %v", key)
 	}
 
 	// network-id is placed at index=1. pls refer to endpoint.Key() method
-	return types.UUID(key[1]), nil
+	return key[1], nil
 }
 
 func (ep *endpoint) Value() []byte {
@@ -296,27 +187,6 @@ func (ep *endpoint) processOptions(options ...EndpointOption) {
 	}
 }
 
-func createBasePath(dir string) error {
-	return os.MkdirAll(dir, 0644)
-}
-
-func createFile(path string) error {
-	var f *os.File
-
-	dir, _ := filepath.Split(path)
-	err := createBasePath(dir)
-	if err != nil {
-		return err
-	}
-
-	f, err = os.Create(path)
-	if err == nil {
-		f.Close()
-	}
-
-	return err
-}
-
 // joinLeaveStart waits to ensure there are no joins or leaves in progress and
 // marks this join/leave in progress without race
 func (ep *endpoint) joinLeaveStart() {
@@ -349,44 +219,36 @@ func (ep *endpoint) joinLeaveEnd() {
 	}
 }
 
-func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
+func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
 	var err error
 
-	if containerID == "" {
-		return InvalidContainerIDError(containerID)
+	if sbox == nil {
+		return types.BadRequestErrorf("endpoint cannot be joined by nil container")
+	}
+
+	sb, ok := sbox.(*sandbox)
+	if !ok {
+		return types.BadRequestErrorf("not a valid Sandbox interface")
 	}
 
 	ep.joinLeaveStart()
-	defer func() {
-		ep.joinLeaveEnd()
-	}()
+	defer ep.joinLeaveEnd()
 
 	ep.Lock()
-	if ep.container != nil {
+	if ep.sandboxID != "" {
 		ep.Unlock()
-		return ErrInvalidJoin{}
+		return types.ForbiddenErrorf("a sandbox has already joined the endpoint")
 	}
 
-	ep.container = &containerInfo{
-		id: containerID,
-		config: containerConfig{
-			hostsPathConfig: hostsPathConfig{
-				extraHosts:    []extraHost{},
-				parentUpdates: []parentUpdate{},
-			},
-		}}
-
+	ep.sandboxID = sbox.ID()
 	ep.joinInfo = &endpointJoinInfo{}
-
-	container := ep.container
 	network := ep.network
 	epid := ep.id
-
 	ep.Unlock()
 	defer func() {
 		if err != nil {
 			ep.Lock()
-			ep.container = nil
+			ep.sandboxID = ""
 			ep.Unlock()
 		}
 	}()
@@ -394,17 +256,11 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
 	network.Lock()
 	driver := network.driver
 	nid := network.id
-	ctrlr := network.ctrlr
 	network.Unlock()
 
 	ep.processOptions(options...)
 
-	sboxKey := sandbox.GenerateKey(containerID)
-	if container.config.useDefaultSandBox {
-		sboxKey = sandbox.GenerateKey("default")
-	}
-
-	err = driver.Join(nid, epid, sboxKey, ep, container.config.generic)
+	err = driver.Join(nid, epid, sbox.Key(), ep, sbox.Labels())
 	if err != nil {
 		return err
 	}
@@ -417,36 +273,26 @@ func (ep *endpoint) Join(containerID string, options ...EndpointOption) error {
 		}
 	}()
 
-	err = ep.buildHostsFiles()
-	if err != nil {
+	address := ""
+	if ip := ep.getFirstInterfaceAddress(); ip != nil {
+		address = ip.String()
+	}
+	if err = sb.updateHostsFile(address, network.getSvcRecords()); err != nil {
 		return err
 	}
 
-	err = ep.updateParentHosts()
-	if err != nil {
+	if err = sb.updateDNS(ep.getNetwork().enableIPv6); err != nil {
 		return err
 	}
 
-	err = ep.setupDNS()
-	if err != nil {
+	if err = network.ctrlr.updateEndpointToStore(ep); err != nil {
 		return err
 	}
 
-	sb, err := ctrlr.sandboxAdd(sboxKey, !container.config.useDefaultSandBox, ep)
-	if err != nil {
-		return fmt.Errorf("failed sandbox add: %v", err)
-	}
-	defer func() {
-		if err != nil {
-			ctrlr.sandboxRm(sboxKey, ep)
-		}
-	}()
-
-	if err := network.ctrlr.updateEndpointToStore(ep); err != nil {
+	if err = sb.populateNetworkResources(ep); err != nil {
 		return err
 	}
 
-	container.data.SandboxKey = sb.Key()
 	return nil
 }
 
@@ -463,49 +309,54 @@ func (ep *endpoint) hasInterface(iName string) bool {
 	return false
 }
 
-func (ep *endpoint) Leave(containerID string, options ...EndpointOption) error {
-	var err error
-
+func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error {
 	ep.joinLeaveStart()
 	defer ep.joinLeaveEnd()
 
-	ep.processOptions(options...)
+	if sbox == nil || sbox.ID() == "" || sbox.Key() == "" {
+		return types.BadRequestErrorf("invalid Sandbox passed to enpoint leave: %v", sbox)
+	}
 
-	ep.Lock()
-	container := ep.container
-	n := ep.network
+	sb, ok := sbox.(*sandbox)
+	if !ok {
+		return types.BadRequestErrorf("not a valid Sandbox interface")
+	}
 
-	if container == nil || container.id == "" || container.data.SandboxKey == "" ||
-		containerID == "" || container.id != containerID {
-		if container == nil {
-			err = ErrNoContainer{}
-		} else {
-			err = InvalidContainerIDError(containerID)
-		}
+	ep.Lock()
+	sid := ep.sandboxID
+	ep.Unlock()
 
-		ep.Unlock()
-		return err
+	if sid == "" {
+		return types.ForbiddenErrorf("cannot leave endpoint with no attached sandbox")
 	}
-	ep.container = nil
+	if sid != sbox.ID() {
+		return types.ForbiddenErrorf("unexpected sandbox ID in leave request. Expected %s. Got %s", ep.sandboxID, sbox.ID())
+	}
+
+	ep.processOptions(options...)
+
+	ep.Lock()
+	ep.sandboxID = ""
+	n := ep.network
 	ep.Unlock()
 
 	n.Lock()
-	driver := n.driver
-	ctrlr := n.ctrlr
+	c := n.ctrlr
+	d := n.driver
 	n.Unlock()
 
-	if err := ctrlr.updateEndpointToStore(ep); err != nil {
+	if err := c.updateEndpointToStore(ep); err != nil {
 		ep.Lock()
-		ep.container = container
+		ep.sandboxID = sid
 		ep.Unlock()
 		return err
 	}
 
-	err = driver.Leave(n.id, ep.id)
-
-	ctrlr.sandboxRm(container.data.SandboxKey, ep)
+	if err := d.Leave(n.id, ep.id); err != nil {
+		return err
+	}
 
-	return err
+	return sb.clearNetworkResources(ep)
 }
 
 func (ep *endpoint) Delete() error {
@@ -514,9 +365,9 @@ func (ep *endpoint) Delete() error {
 	epid := ep.id
 	name := ep.name
 	n := ep.network
-	if ep.container != nil {
+	if ep.sandboxID != "" {
 		ep.Unlock()
-		return &ActiveContainerError{name: name, id: string(epid)}
+		return &ActiveContainerError{name: name, id: epid}
 	}
 	n.Lock()
 	ctrlr := n.ctrlr
@@ -556,33 +407,6 @@ func (ep *endpoint) Delete() error {
 	return nil
 }
 
-func (ep *endpoint) Statistics() (map[string]*sandbox.InterfaceStatistics, error) {
-	m := make(map[string]*sandbox.InterfaceStatistics)
-
-	ep.Lock()
-	n := ep.network
-	skey := ep.container.data.SandboxKey
-	ep.Unlock()
-
-	n.Lock()
-	c := n.ctrlr
-	n.Unlock()
-
-	sbox := c.sandboxGet(skey)
-	if sbox == nil {
-		return m, nil
-	}
-
-	var err error
-	for _, i := range sbox.Info().Interfaces() {
-		if m[i.DstName()], err = i.Statistics(); err != nil {
-			return m, err
-		}
-	}
-
-	return m, nil
-}
-
 func (ep *endpoint) deleteEndpoint() error {
 	ep.Lock()
 	n := ep.network
@@ -616,260 +440,36 @@ func (ep *endpoint) deleteEndpoint() error {
 	return nil
 }
 
-func (ep *endpoint) addHostEntries(recs []etchosts.Record) {
-	ep.Lock()
-	container := ep.container
-	ep.Unlock()
-
-	if container == nil {
-		return
-	}
-
-	if err := etchosts.Add(container.config.hostsPath, recs); err != nil {
-		log.Warnf("Failed adding service host entries to the running container: %v", err)
-	}
-}
-
-func (ep *endpoint) deleteHostEntries(recs []etchosts.Record) {
+func (ep *endpoint) getNetwork() *network {
 	ep.Lock()
-	container := ep.container
-	ep.Unlock()
-
-	if container == nil {
-		return
-	}
-
-	if err := etchosts.Delete(container.config.hostsPath, recs); err != nil {
-		log.Warnf("Failed deleting service host entries to the running container: %v", err)
-	}
+	defer ep.Unlock()
+	return ep.network
 }
 
-func (ep *endpoint) buildHostsFiles() error {
-	var extraContent []etchosts.Record
-
+func (ep *endpoint) getSandbox() (*sandbox, bool) {
 	ep.Lock()
-	container := ep.container
-	joinInfo := ep.joinInfo
-	ifaces := ep.iFaces
-	n := ep.network
+	c := ep.network.getController()
+	sid := ep.sandboxID
 	ep.Unlock()
 
-	if container == nil {
-		return ErrNoContainer{}
-	}
-
-	if container.config.hostsPath == "" {
-		container.config.hostsPath = defaultPrefix + "/" + container.id + "/hosts"
-	}
-
-	dir, _ := filepath.Split(container.config.hostsPath)
-	err := createBasePath(dir)
-	if err != nil {
-		return err
-	}
-
-	if joinInfo != nil && joinInfo.hostsPath != "" {
-		content, err := ioutil.ReadFile(joinInfo.hostsPath)
-		if err != nil && !os.IsNotExist(err) {
-			return err
-		}
-
-		if err == nil {
-			return ioutil.WriteFile(container.config.hostsPath, content, 0644)
-		}
-	}
-
-	for _, extraHost := range container.config.extraHosts {
-		extraContent = append(extraContent,
-			etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
-	}
-
-	extraContent = append(extraContent, n.getSvcRecords()...)
-
-	IP := ""
-	if len(ifaces) != 0 && ifaces[0] != nil {
-		IP = ifaces[0].addr.IP.String()
-	}
+	c.Lock()
+	ps, ok := c.sandboxes[sid]
+	c.Unlock()
 
-	return etchosts.Build(container.config.hostsPath, IP, container.config.hostName,
-		container.config.domainName, extraContent)
+	return ps, ok
 }
 
-func (ep *endpoint) updateParentHosts() error {
+func (ep *endpoint) getFirstInterfaceAddress() net.IP {
 	ep.Lock()
-	container := ep.container
-	network := ep.network
-	ep.Unlock()
-
-	if container == nil {
-		return ErrNoContainer{}
-	}
-
-	for _, update := range container.config.parentUpdates {
-		network.Lock()
-		pep, ok := network.endpoints[types.UUID(update.eid)]
-		if !ok {
-			network.Unlock()
-			continue
-		}
-		network.Unlock()
-
-		pep.Lock()
-		pContainer := pep.container
-		pep.Unlock()
+	defer ep.Unlock()
 
-		if pContainer != nil {
-			if err := etchosts.Update(pContainer.config.hostsPath, update.ip, update.name); err != nil {
-				return err
-			}
-		}
+	if len(ep.iFaces) != 0 && ep.iFaces[0] != nil {
+		return ep.iFaces[0].addr.IP
 	}
 
 	return nil
 }
 
-func (ep *endpoint) updateDNS(resolvConf []byte) error {
-	ep.Lock()
-	container := ep.container
-	network := ep.network
-	ep.Unlock()
-
-	if container == nil {
-		return ErrNoContainer{}
-	}
-
-	oldHash := []byte{}
-	hashFile := container.config.resolvConfPath + ".hash"
-
-	resolvBytes, err := ioutil.ReadFile(container.config.resolvConfPath)
-	if err != nil {
-		if !os.IsNotExist(err) {
-			return err
-		}
-	} else {
-		oldHash, err = ioutil.ReadFile(hashFile)
-		if err != nil {
-			if !os.IsNotExist(err) {
-				return err
-			}
-
-			oldHash = []byte{}
-		}
-	}
-
-	curHash, err := ioutils.HashData(bytes.NewReader(resolvBytes))
-	if err != nil {
-		return err
-	}
-
-	if string(oldHash) != "" && curHash != string(oldHash) {
-		// Seems the user has changed the container resolv.conf since the last time
-		// we checked so return without doing anything.
-		return nil
-	}
-
-	// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
-	resolvConf, _ = resolvconf.FilterResolvDNS(resolvConf, network.enableIPv6)
-
-	newHash, err := ioutils.HashData(bytes.NewReader(resolvConf))
-	if err != nil {
-		return err
-	}
-
-	// for atomic updates to these files, use temporary files with os.Rename:
-	dir := path.Dir(container.config.resolvConfPath)
-	tmpHashFile, err := ioutil.TempFile(dir, "hash")
-	if err != nil {
-		return err
-	}
-	tmpResolvFile, err := ioutil.TempFile(dir, "resolv")
-	if err != nil {
-		return err
-	}
-
-	// Change the perms to 0644 since ioutil.TempFile creates it by default as 0600
-	if err := os.Chmod(tmpResolvFile.Name(), 0644); err != nil {
-		return err
-	}
-
-	// write the updates to the temp files
-	if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newHash), 0644); err != nil {
-		return err
-	}
-	if err = ioutil.WriteFile(tmpResolvFile.Name(), resolvConf, 0644); err != nil {
-		return err
-	}
-
-	// rename the temp files for atomic replace
-	if err = os.Rename(tmpHashFile.Name(), hashFile); err != nil {
-		return err
-	}
-	return os.Rename(tmpResolvFile.Name(), container.config.resolvConfPath)
-}
-
-func copyFile(src, dst string) error {
-	sBytes, err := ioutil.ReadFile(src)
-	if err != nil {
-		return err
-	}
-
-	return ioutil.WriteFile(dst, sBytes, 0644)
-}
-
-func (ep *endpoint) setupDNS() error {
-	ep.Lock()
-	container := ep.container
-	joinInfo := ep.joinInfo
-	ep.Unlock()
-
-	if container == nil {
-		return ErrNoContainer{}
-	}
-
-	if container.config.resolvConfPath == "" {
-		container.config.resolvConfPath = defaultPrefix + "/" + container.id + "/resolv.conf"
-	}
-
-	dir, _ := filepath.Split(container.config.resolvConfPath)
-	err := createBasePath(dir)
-	if err != nil {
-		return err
-	}
-
-	if joinInfo.resolvConfPath != "" {
-		if err := copyFile(joinInfo.resolvConfPath, container.config.resolvConfPath); err != nil {
-			return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", joinInfo.resolvConfPath, container.config.resolvConfPath, err)
-		}
-
-		return nil
-	}
-
-	resolvConf, err := resolvconf.Get()
-	if err != nil {
-		return err
-	}
-
-	if len(container.config.dnsList) > 0 ||
-		len(container.config.dnsSearchList) > 0 {
-		var (
-			dnsList       = resolvconf.GetNameservers(resolvConf)
-			dnsSearchList = resolvconf.GetSearchDomains(resolvConf)
-		)
-
-		if len(container.config.dnsList) > 0 {
-			dnsList = container.config.dnsList
-		}
-
-		if len(container.config.dnsSearchList) > 0 {
-			dnsSearchList = container.config.dnsSearchList
-		}
-
-		return resolvconf.Build(container.config.resolvConfPath, dnsList, dnsSearchList)
-	}
-
-	return ep.updateDNS(resolvConf)
-}
-
 // EndpointOptionGeneric function returns an option setter for a Generic option defined
 // in a Dictionary of Key-Value pair
 func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
@@ -880,86 +480,6 @@ func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption {
 	}
 }
 
-// JoinOptionPriority function returns an option setter for priority option to
-// be passed to endpoint Join method.
-func JoinOptionPriority(prio int) EndpointOption {
-	return func(ep *endpoint) {
-		ep.container.config.prio = prio
-	}
-}
-
-// JoinOptionHostname function returns an option setter for hostname option to
-// be passed to endpoint Join method.
-func JoinOptionHostname(name string) EndpointOption {
-	return func(ep *endpoint) {
-		ep.container.config.hostName = name
-	}
-}
-
-// JoinOptionDomainname function returns an option setter for domainname option to
-// be passed to endpoint Join method.
-func JoinOptionDomainname(name string) EndpointOption {
-	return func(ep *endpoint) {
-		ep.container.config.domainName = name
-	}
-}
-
-// JoinOptionHostsPath function returns an option setter for hostspath option to
-// be passed to endpoint Join method.
-func JoinOptionHostsPath(path string) EndpointOption {
-	return func(ep *endpoint) {
-		ep.container.config.hostsPath = path
-	}
-}
-
-// JoinOptionExtraHost function returns an option setter for extra /etc/hosts options
-// which is a name and IP as strings.
-func JoinOptionExtraHost(name string, IP string) EndpointOption {
-	return func(ep *endpoint) {
-		ep.container.config.extraHosts = append(ep.container.config.extraHosts, extraHost{name: name, IP: IP})
-	}
-}
-
-// JoinOptionParentUpdate function returns an option setter for parent container
-// which needs to update the IP address for the linked container.
-func JoinOptionParentUpdate(eid string, name, ip string) EndpointOption {
-	return func(ep *endpoint) {
-		ep.container.config.parentUpdates = append(ep.container.config.parentUpdates, parentUpdate{eid: eid, name: name, ip: ip})
-	}
-}
-
-// JoinOptionResolvConfPath function returns an option setter for resolvconfpath option to
-// be passed to endpoint Join method.
-func JoinOptionResolvConfPath(path string) EndpointOption {
-	return func(ep *endpoint) {
-		ep.container.config.resolvConfPath = path
-	}
-}
-
-// JoinOptionDNS function returns an option setter for dns entry option to
-// be passed to endpoint Join method.
-func JoinOptionDNS(dns string) EndpointOption {
-	return func(ep *endpoint) {
-		ep.container.config.dnsList = append(ep.container.config.dnsList, dns)
-	}
-}
-
-// JoinOptionDNSSearch function returns an option setter for dns search entry option to
-// be passed to endpoint Join method.
-func JoinOptionDNSSearch(search string) EndpointOption {
-	return func(ep *endpoint) {
-		ep.container.config.dnsSearchList = append(ep.container.config.dnsSearchList, search)
-	}
-}
-
-// JoinOptionUseDefaultSandbox function returns an option setter for using default sandbox to
-// be passed to endpoint Join method.
-func JoinOptionUseDefaultSandbox() EndpointOption {
-	return func(ep *endpoint) {
-		ep.container.config.useDefaultSandBox = true
-	}
-}
-
 // CreateOptionExposedPorts function returns an option setter for the container exposed
 // ports option to be passed to network.CreateEndpoint() method.
 func CreateOptionExposedPorts(exposedPorts []types.TransportPort) EndpointOption {
@@ -984,11 +504,19 @@ func CreateOptionPortMapping(portBindings []types.PortBinding) EndpointOption {
 	}
 }
 
-// JoinOptionGeneric function returns an option setter for Generic configuration
-// that is not managed by libNetwork but can be used by the Drivers during the call to
-// endpoint join method. Container Labels are a good example.
-func JoinOptionGeneric(generic map[string]interface{}) EndpointOption {
+// JoinOptionPriority function returns an option setter for priority option to
+// be passed to the endpoint.Join() method.
+func JoinOptionPriority(ep Endpoint, prio int) EndpointOption {
 	return func(ep *endpoint) {
-		ep.container.config.generic = generic
+		// ep lock already acquired
+		c := ep.network.getController()
+		c.Lock()
+		sb, ok := c.sandboxes[ep.sandboxID]
+		c.Unlock()
+		if !ok {
+			log.Errorf("Could not set endpoint priority value during Join to endpoint %s: No sandbox id present in endpoint", ep.id)
+			return
+		}
+		sb.epPriority[ep.id] = prio
 	}
 }

+ 10 - 53
vendor/src/github.com/docker/libnetwork/endpoint_info.go

@@ -22,10 +22,8 @@ type EndpointInfo interface {
 	// This will only return a valid value if a container has joined the endpoint.
 	GatewayIPv6() net.IP
 
-	// SandboxKey returns the sanbox key for the container which has joined
-	// the endpoint. If there is no container joined then this will return an
-	// empty string.
-	SandboxKey() string
+	// Sandbox returns the attached sandbox if there, nil otherwise.
+	Sandbox() Sandbox
 }
 
 // InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
@@ -40,14 +38,6 @@ type InterfaceInfo interface {
 	AddressIPv6() net.IPNet
 }
 
-// ContainerInfo provides an interface to retrieve the info about the container attached to the endpoint
-type ContainerInfo interface {
-	// ID returns the ID of the container
-	ID() string
-	// Labels returns the container's labels
-	Labels() map[string]interface{}
-}
-
 type endpointInterface struct {
 	id        int
 	mac       net.HardwareAddr
@@ -115,23 +105,9 @@ func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) {
 }
 
 type endpointJoinInfo struct {
-	gw             net.IP
-	gw6            net.IP
-	hostsPath      string
-	resolvConfPath string
-	StaticRoutes   []*types.StaticRoute
-}
-
-func (ep *endpoint) ContainerInfo() ContainerInfo {
-	ep.Lock()
-	ci := ep.container
-	defer ep.Unlock()
-
-	// Need this since we return the interface
-	if ci == nil {
-		return nil
-	}
-	return ci
+	gw           net.IP
+	gw6          net.IP
+	StaticRoutes []*types.StaticRoute
 }
 
 func (ep *endpoint) Info() EndpointInfo {
@@ -257,15 +233,12 @@ func (ep *endpoint) addInterfaceRoute(route *types.StaticRoute) error {
 		route.InterfaceID)
 }
 
-func (ep *endpoint) SandboxKey() string {
-	ep.Lock()
-	defer ep.Unlock()
-
-	if ep.container == nil {
-		return ""
+func (ep *endpoint) Sandbox() Sandbox {
+	cnt, ok := ep.getSandbox()
+	if !ok {
+		return nil
 	}
-
-	return ep.container.data.SandboxKey
+	return cnt
 }
 
 func (ep *endpoint) Gateway() net.IP {
@@ -305,19 +278,3 @@ func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
 	ep.joinInfo.gw6 = types.GetIPCopy(gw6)
 	return nil
 }
-
-func (ep *endpoint) SetHostsPath(path string) error {
-	ep.Lock()
-	defer ep.Unlock()
-
-	ep.joinInfo.hostsPath = path
-	return nil
-}
-
-func (ep *endpoint) SetResolvConfPath(path string) error {
-	ep.Lock()
-	defer ep.Unlock()
-
-	ep.joinInfo.resolvConfPath = path
-	return nil
-}

+ 6 - 40
vendor/src/github.com/docker/libnetwork/idm/idm.go

@@ -1,4 +1,4 @@
-// Package idm manages resevation/release of numerical ids from a configured set of contiguos ids
+// Package idm manages reservation/release of numerical ids from a configured set of contiguous ids
 package idm
 
 import (
@@ -6,7 +6,6 @@ import (
 
 	"github.com/docker/libnetwork/bitseq"
 	"github.com/docker/libnetwork/datastore"
-	"github.com/docker/libnetwork/types"
 )
 
 // Idm manages the reservation/release of numerical ids from a contiguos set
@@ -25,7 +24,7 @@ func New(ds datastore.DataStore, id string, start, end uint32) (*Idm, error) {
 		return nil, fmt.Errorf("Invalid set range: [%d, %d]", start, end)
 	}
 
-	h, err := bitseq.NewHandle("idm", ds, id, uint32(1+end-start))
+	h, err := bitseq.NewHandle("idm", ds, id, 1+end-start)
 	if err != nil {
 		return nil, fmt.Errorf("failed to initialize bit sequence handler: %s", err.Error())
 	}
@@ -38,28 +37,8 @@ func (i *Idm) GetID() (uint32, error) {
 	if i.handle == nil {
 		return 0, fmt.Errorf("ID set is not initialized")
 	}
-
-	for {
-		bytePos, bitPos, err := i.handle.GetFirstAvailable()
-		if err != nil {
-			return 0, fmt.Errorf("no available ids")
-		}
-		id := i.start + uint32(bitPos+bytePos*8)
-
-		// for sets which length is non multiple of 32 this check is needed
-		if i.end < id {
-			return 0, fmt.Errorf("no available ids")
-		}
-
-		if err := i.handle.PushReservation(bytePos, bitPos, false); err != nil {
-			if _, ok := err.(types.RetryError); !ok {
-				return 0, fmt.Errorf("internal failure while reserving the id: %s", err.Error())
-			}
-			continue
-		}
-
-		return id, nil
-	}
+	ordinal, err := i.handle.SetAny()
+	return i.start + ordinal, err
 }
 
 // GetSpecificID tries to reserve the specified id
@@ -72,23 +51,10 @@ func (i *Idm) GetSpecificID(id uint32) error {
 		return fmt.Errorf("Requested id does not belong to the set")
 	}
 
-	for {
-		bytePos, bitPos, err := i.handle.CheckIfAvailable(int(id - i.start))
-		if err != nil {
-			return fmt.Errorf("requested id is not available")
-		}
-		if err := i.handle.PushReservation(bytePos, bitPos, false); err != nil {
-			if _, ok := err.(types.RetryError); !ok {
-				return fmt.Errorf("internal failure while reserving the id: %s", err.Error())
-			}
-			continue
-		}
-		return nil
-	}
+	return i.handle.Set(id - i.start)
 }
 
 // Release releases the specified id
 func (i *Idm) Release(id uint32) {
-	ordinal := id - i.start
-	i.handle.PushReservation(int(ordinal/8), int(ordinal%8), true)
+	i.handle.Unset(id - i.start)
 }

+ 1 - 32
vendor/src/github.com/docker/libnetwork/netutils/test_utils.go

@@ -1,11 +1,6 @@
 package netutils
 
-import (
-	"flag"
-	"runtime"
-	"syscall"
-	"testing"
-)
+import "flag"
 
 var runningInContainer = flag.Bool("incontainer", false, "Indicates if the test is running in a container")
 
@@ -13,29 +8,3 @@ var runningInContainer = flag.Bool("incontainer", false, "Indicates if the test
 func IsRunningInContainer() bool {
 	return (*runningInContainer)
 }
-
-// SetupTestNetNS joins a new network namespace, and returns its associated
-// teardown function.
-//
-// Example usage:
-//
-//     defer SetupTestNetNS(t)()
-//
-func SetupTestNetNS(t *testing.T) func() {
-	runtime.LockOSThread()
-	if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil {
-		t.Fatalf("Failed to enter netns: %v", err)
-	}
-
-	fd, err := syscall.Open("/proc/self/ns/net", syscall.O_RDONLY, 0)
-	if err != nil {
-		t.Fatal("Failed to open netns file")
-	}
-
-	return func() {
-		if err := syscall.Close(fd); err != nil {
-			t.Logf("Warning: netns closing failed (%v)", err)
-		}
-		runtime.UnlockOSThread()
-	}
-}

+ 1 - 61
vendor/src/github.com/docker/libnetwork/netutils/utils.go

@@ -59,17 +59,7 @@ func CheckRouteOverlaps(toCheck *net.IPNet) error {
 
 // NetworkOverlaps detects overlap between one IPNet and another
 func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
-	// Check if both netX and netY are ipv4 or ipv6
-	if (netX.IP.To4() != nil && netY.IP.To4() != nil) ||
-		(netX.IP.To4() == nil && netY.IP.To4() == nil) {
-		if firstIP, _ := NetworkRange(netX); netY.Contains(firstIP) {
-			return true
-		}
-		if firstIP, _ := NetworkRange(netY); netX.Contains(firstIP) {
-			return true
-		}
-	}
-	return false
+	return netX.Contains(netY.IP) || netY.Contains(netX.IP)
 }
 
 // NetworkRange calculates the first and last IP addresses in an IPNet
@@ -180,53 +170,3 @@ func GenerateIfaceName(prefix string, len int) (string, error) {
 	}
 	return "", types.InternalErrorf("could not generate interface name")
 }
-
-func byteArrayToInt(array []byte, numBytes int) uint64 {
-	if numBytes <= 0 || numBytes > 8 {
-		panic("Invalid argument")
-	}
-	num := 0
-	for i := 0; i <= len(array)-1; i++ {
-		num += int(array[len(array)-1-i]) << uint(i*8)
-	}
-	return uint64(num)
-}
-
-// ATo64 converts a byte array into a uint32
-func ATo64(array []byte) uint64 {
-	return byteArrayToInt(array, 8)
-}
-
-// ATo32 converts a byte array into a uint32
-func ATo32(array []byte) uint32 {
-	return uint32(byteArrayToInt(array, 4))
-}
-
-// ATo16 converts a byte array into a uint16
-func ATo16(array []byte) uint16 {
-	return uint16(byteArrayToInt(array, 2))
-}
-
-func intToByteArray(val uint64, numBytes int) []byte {
-	array := make([]byte, numBytes)
-	for i := numBytes - 1; i >= 0; i-- {
-		array[i] = byte(val & 0xff)
-		val = val >> 8
-	}
-	return array
-}
-
-// U64ToA converts a uint64 to a byte array
-func U64ToA(val uint64) []byte {
-	return intToByteArray(uint64(val), 8)
-}
-
-// U32ToA converts a uint64 to a byte array
-func U32ToA(val uint32) []byte {
-	return intToByteArray(uint64(val), 4)
-}
-
-// U16ToA converts a uint64 to a byte array
-func U16ToA(val uint16) []byte {
-	return intToByteArray(uint64(val), 2)
-}

+ 22 - 19
vendor/src/github.com/docker/libnetwork/network.go

@@ -59,7 +59,7 @@ type network struct {
 	ctrlr       *controller
 	name        string
 	networkType string
-	id          types.UUID
+	id          string
 	driver      driverapi.Driver
 	enableIPv6  bool
 	endpointCnt uint64
@@ -83,7 +83,7 @@ func (n *network) ID() string {
 	n.Lock()
 	defer n.Unlock()
 
-	return string(n.id)
+	return n.id
 }
 
 func (n *network) Type() string {
@@ -100,7 +100,7 @@ func (n *network) Type() string {
 func (n *network) Key() []string {
 	n.Lock()
 	defer n.Unlock()
-	return []string{datastore.NetworkKeyPrefix, string(n.id)}
+	return []string{datastore.NetworkKeyPrefix, n.id}
 }
 
 func (n *network) KeyPrefix() []string {
@@ -162,7 +162,7 @@ func (n *network) DecEndpointCnt() {
 func (n *network) MarshalJSON() ([]byte, error) {
 	netMap := make(map[string]interface{})
 	netMap["name"] = n.name
-	netMap["id"] = string(n.id)
+	netMap["id"] = n.id
 	netMap["networkType"] = n.networkType
 	netMap["endpointCnt"] = n.endpointCnt
 	netMap["enableIPv6"] = n.enableIPv6
@@ -177,7 +177,7 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
 		return err
 	}
 	n.name = netMap["name"].(string)
-	n.id = types.UUID(netMap["id"].(string))
+	n.id = netMap["id"].(string)
 	n.networkType = netMap["networkType"].(string)
 	n.endpointCnt = uint64(netMap["endpointCnt"].(float64))
 	n.enableIPv6 = netMap["enableIPv6"].(bool)
@@ -223,12 +223,12 @@ func (n *network) Delete() error {
 	ctrlr.Unlock()
 
 	if !ok {
-		return &UnknownNetworkError{name: n.name, id: string(n.id)}
+		return &UnknownNetworkError{name: n.name, id: n.id}
 	}
 
 	numEps := n.EndpointCnt()
 	if numEps != 0 {
-		return &ActiveEndpointsError{name: n.name, id: string(n.id)}
+		return &ActiveEndpointsError{name: n.name, id: n.id}
 	}
 
 	// deleteNetworkFromStore performs an atomic delete operation and the network.endpointCnt field will help
@@ -287,7 +287,7 @@ func (n *network) addEndpoint(ep *endpoint) error {
 
 	err = d.CreateEndpoint(n.id, ep.id, ep, ep.generic)
 	if err != nil {
-		return err
+		return types.InternalErrorf("failed to create endpoint %s on network %s: %v", ep.Name(), n.Name(), err)
 	}
 
 	n.updateSvcRecord(ep, true)
@@ -307,7 +307,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
 	ep := &endpoint{name: name,
 		iFaces:  []*endpointInterface{},
 		generic: make(map[string]interface{})}
-	ep.id = types.UUID(stringid.GenerateRandomID())
+	ep.id = stringid.GenerateRandomID()
 	ep.network = n
 	ep.processOptions(options...)
 
@@ -393,7 +393,7 @@ func (n *network) EndpointByID(id string) (Endpoint, error) {
 	}
 	n.Lock()
 	defer n.Unlock()
-	if e, ok := n.endpoints[types.UUID(id)]; ok {
+	if e, ok := n.endpoints[id]; ok {
 		return e, nil
 	}
 	return nil, ErrNoSuchEndpoint(id)
@@ -435,22 +435,19 @@ func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
 		return
 	}
 
-	var epList []*endpoint
+	var sbList []*sandbox
 	n.WalkEndpoints(func(e Endpoint) bool {
-		cEp := e.(*endpoint)
-		cEp.Lock()
-		if cEp.container != nil {
-			epList = append(epList, cEp)
+		if sb, hasSandbox := e.(*endpoint).getSandbox(); hasSandbox {
+			sbList = append(sbList, sb)
 		}
-		cEp.Unlock()
 		return false
 	})
 
-	for _, cEp := range epList {
+	for _, sb := range sbList {
 		if isAdd {
-			cEp.addHostEntries(recs)
+			sb.addHostsEntries(recs)
 		} else {
-			cEp.deleteHostEntries(recs)
+			sb.deleteHostsEntries(recs)
 		}
 	}
 }
@@ -469,3 +466,9 @@ func (n *network) getSvcRecords() []etchosts.Record {
 
 	return recs
 }
+
+func (n *network) getController() *controller {
+	n.Lock()
+	defer n.Unlock()
+	return n.ctrlr
+}

+ 15 - 0
vendor/src/github.com/docker/libnetwork/options/options.go

@@ -29,6 +29,18 @@ func (e CannotSetFieldError) Error() string {
 	return fmt.Sprintf("cannot set field %q of type %q", e.Field, e.Type)
 }
 
+// TypeMismatchError is the error returned when the type of the generic value
+// for a field mismatches the type of the destination structure.
+type TypeMismatchError struct {
+	Field      string
+	ExpectType string
+	ActualType string
+}
+
+func (e TypeMismatchError) Error() string {
+	return fmt.Sprintf("type mismatch, field %s require type %v, actual type %v", e.Field, e.ExpectType, e.ActualType)
+}
+
 // Generic is an basic type to store arbitrary settings.
 type Generic map[string]interface{}
 
@@ -62,6 +74,9 @@ func GenerateFromModel(options Generic, model interface{}) (interface{}, error)
 		if !field.CanSet() {
 			return nil, CannotSetFieldError{name, resType.String()}
 		}
+		if reflect.TypeOf(value) != field.Type() {
+			return nil, TypeMismatchError{name, field.Type().String(), reflect.TypeOf(value).String()}
+		}
 		field.Set(reflect.ValueOf(value))
 	}
 

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox/interface_freebsd.go → vendor/src/github.com/docker/libnetwork/osl/interface_freebsd.go

@@ -1,4 +1,4 @@
-package sandbox
+package osl
 
 // IfaceOption is a function option type to set interface options
 type IfaceOption func()

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox/interface_linux.go → vendor/src/github.com/docker/libnetwork/osl/interface_linux.go

@@ -1,4 +1,4 @@
-package sandbox
+package osl
 
 import (
 	"fmt"

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox/interface_windows.go → vendor/src/github.com/docker/libnetwork/osl/interface_windows.go

@@ -1,4 +1,4 @@
-package sandbox
+package osl
 
 // IfaceOption is a function option type to set interface options
 type IfaceOption func()

+ 33 - 9
vendor/src/github.com/docker/libnetwork/sandbox/namespace_linux.go → vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go

@@ -1,4 +1,4 @@
-package sandbox
+package osl
 
 import (
 	"fmt"
@@ -26,6 +26,8 @@ var (
 	gpmWg            sync.WaitGroup
 	gpmCleanupPeriod = 60 * time.Second
 	gpmChan          = make(chan chan struct{})
+	nsOnce           sync.Once
+	initNs           netns.NsHandle
 )
 
 // The networkNamespace type is the linux implementation of the Sandbox
@@ -242,15 +244,37 @@ func (n *networkNamespace) InvokeFunc(f func()) error {
 	})
 }
 
-func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD int) error) error {
+func getLink() (string, error) {
+	return os.Readlink(fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid()))
+}
+
+func nsInit() {
+	var err error
+
+	if initNs, err = netns.Get(); err != nil {
+		log.Errorf("could not get initial namespace: %v", err)
+	}
+}
+
+// InitOSContext initializes OS context while configuring network resources
+func InitOSContext() func() {
 	runtime.LockOSThread()
-	defer runtime.UnlockOSThread()
+	nsOnce.Do(nsInit)
+	if err := netns.Set(initNs); err != nil {
+		linkInfo, linkErr := getLink()
+		if linkErr != nil {
+			linkInfo = linkErr.Error()
+		}
 
-	origns, err := netns.Get()
-	if err != nil {
-		return err
+		log.Errorf("failed to set to initial namespace, %v, initns fd %d: %v",
+			linkInfo, initNs, err)
 	}
-	defer origns.Close()
+
+	return runtime.UnlockOSThread
+}
+
+func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD int) error) error {
+	defer InitOSContext()()
 
 	f, err := os.OpenFile(path, os.O_RDONLY, 0)
 	if err != nil {
@@ -269,10 +293,10 @@ func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD
 	if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
 		return err
 	}
-	defer netns.Set(origns)
+	defer netns.Set(initNs)
 
 	// Invoked after the namespace switch.
-	return postfunc(int(origns))
+	return postfunc(int(initNs))
 }
 
 func (n *networkNamespace) nsPath() string {

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox/namespace_unsupported.go → vendor/src/github.com/docker/libnetwork/osl/namespace_unsupported.go

@@ -1,6 +1,6 @@
 // +build !linux,!windows,!freebsd
 
-package sandbox
+package osl
 
 // GC triggers garbage collection of namespace path right away
 // and waits for it.

+ 13 - 1
vendor/src/github.com/docker/libnetwork/sandbox/namespace_windows.go → vendor/src/github.com/docker/libnetwork/osl/namespace_windows.go

@@ -1,4 +1,6 @@
-package sandbox
+package osl
+
+import "testing"
 
 // GenerateKey generates a sandbox key based on the passed
 // container id.
@@ -21,3 +23,13 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
 // and waits for it.
 func GC() {
 }
+
+// InitOSContext initializes OS context while configuring network resources
+func InitOSContext() func() {
+	return func() {}
+}
+
+// SetupTestOSContext sets up a separate test  OS context in which tests will be executed.
+func SetupTestOSContext(t *testing.T) func() {
+	return func() {}
+}

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox/neigh_freebsd.go → vendor/src/github.com/docker/libnetwork/osl/neigh_freebsd.go

@@ -1,4 +1,4 @@
-package sandbox
+package osl
 
 // NeighOption is a function option type to set neighbor options
 type NeighOption func()

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox/neigh_linux.go → vendor/src/github.com/docker/libnetwork/osl/neigh_linux.go

@@ -1,4 +1,4 @@
-package sandbox
+package osl
 
 import (
 	"bytes"

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox/neigh_windows.go → vendor/src/github.com/docker/libnetwork/osl/neigh_windows.go

@@ -1,4 +1,4 @@
-package sandbox
+package osl
 
 // NeighOption is a function option type to set neighbor options
 type NeighOption func()

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox/options_linux.go → vendor/src/github.com/docker/libnetwork/osl/options_linux.go

@@ -1,4 +1,4 @@
-package sandbox
+package osl
 
 import "net"
 

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox/route_linux.go → vendor/src/github.com/docker/libnetwork/osl/route_linux.go

@@ -1,4 +1,4 @@
-package sandbox
+package osl
 
 import (
 	"fmt"

+ 2 - 1
vendor/src/github.com/docker/libnetwork/sandbox/sandbox.go → vendor/src/github.com/docker/libnetwork/osl/sandbox.go

@@ -1,4 +1,5 @@
-package sandbox
+// Package osl describes structures and interfaces which abstract os entities
+package osl
 
 import (
 	"fmt"

+ 13 - 1
vendor/src/github.com/docker/libnetwork/sandbox/sandbox_freebsd.go → vendor/src/github.com/docker/libnetwork/osl/sandbox_freebsd.go

@@ -1,4 +1,6 @@
-package sandbox
+package osl
+
+import "testing"
 
 // GenerateKey generates a sandbox key based on the passed
 // container id.
@@ -21,3 +23,13 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
 // and waits for it.
 func GC() {
 }
+
+// InitOSContext initializes OS context while configuring network resources
+func InitOSContext() func() {
+	return func() {}
+}
+
+// SetupTestOSContext sets up a separate test  OS context in which tests will be executed.
+func SetupTestOSContext(t *testing.T) func() {
+	return func() {}
+}

+ 1 - 1
vendor/src/github.com/docker/libnetwork/sandbox/sandbox_unsupported.go → vendor/src/github.com/docker/libnetwork/osl/sandbox_unsupported.go

@@ -1,6 +1,6 @@
 // +build !linux,!windows,!freebsd
 
-package sandbox
+package osl
 
 import "errors"
 

+ 2 - 0
vendor/src/github.com/docker/libnetwork/portmapper/mapper.go

@@ -188,6 +188,8 @@ func (pm *PortMapper) Unmap(host net.Addr) error {
 
 //ReMapAll will re-apply all port mappings
 func (pm *PortMapper) ReMapAll() {
+	pm.lock.Lock()
+	defer pm.lock.Unlock()
 	logrus.Debugln("Re-applying all port mappings.")
 	for _, data := range pm.currentMappings {
 		containerIP, containerPort := getIPAndPort(data.container)

+ 75 - 25
vendor/src/github.com/docker/libnetwork/resolvconf/resolvconf.go

@@ -30,6 +30,7 @@ var (
 	nsIPv6Regexp      = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`)
 	nsRegexp          = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`)
 	searchRegexp      = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
+	optionsRegexp     = regexp.MustCompile(`^\s*options\s*(([^\s]+\s*)*)$`)
 )
 
 var lastModified struct {
@@ -38,46 +39,69 @@ var lastModified struct {
 	contents []byte
 }
 
-// Get returns the contents of /etc/resolv.conf
-func Get() ([]byte, error) {
+// File contains the resolv.conf content and its hash
+type File struct {
+	Content []byte
+	Hash    string
+}
+
+// Get returns the contents of /etc/resolv.conf and its hash
+func Get() (*File, error) {
 	resolv, err := ioutil.ReadFile("/etc/resolv.conf")
 	if err != nil {
 		return nil, err
 	}
-	return resolv, nil
+	hash, err := ioutils.HashData(bytes.NewReader(resolv))
+	if err != nil {
+		return nil, err
+	}
+	return &File{Content: resolv, Hash: hash}, nil
+}
+
+// GetSpecific returns the contents of the user specified resolv.conf file and its hash
+func GetSpecific(path string) (*File, error) {
+	resolv, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+	hash, err := ioutils.HashData(bytes.NewReader(resolv))
+	if err != nil {
+		return nil, err
+	}
+	return &File{Content: resolv, Hash: hash}, nil
 }
 
 // GetIfChanged retrieves the host /etc/resolv.conf file, checks against the last hash
 // and, if modified since last check, returns the bytes and new hash.
 // This feature is used by the resolv.conf updater for containers
-func GetIfChanged() ([]byte, string, error) {
+func GetIfChanged() (*File, error) {
 	lastModified.Lock()
 	defer lastModified.Unlock()
 
 	resolv, err := ioutil.ReadFile("/etc/resolv.conf")
 	if err != nil {
-		return nil, "", err
+		return nil, err
 	}
 	newHash, err := ioutils.HashData(bytes.NewReader(resolv))
 	if err != nil {
-		return nil, "", err
+		return nil, err
 	}
 	if lastModified.sha256 != newHash {
 		lastModified.sha256 = newHash
 		lastModified.contents = resolv
-		return resolv, newHash, nil
+		return &File{Content: resolv, Hash: newHash}, nil
 	}
 	// nothing changed, so return no data
-	return nil, "", nil
+	return nil, nil
 }
 
 // GetLastModified retrieves the last used contents and hash of the host resolv.conf.
 // Used by containers updating on restart
-func GetLastModified() ([]byte, string) {
+func GetLastModified() *File {
 	lastModified.Lock()
 	defer lastModified.Unlock()
 
-	return lastModified.contents, lastModified.sha256
+	return &File{Content: lastModified.contents, Hash: lastModified.sha256}
 }
 
 // FilterResolvDNS cleans up the config in resolvConf.  It has two main jobs:
@@ -87,9 +111,7 @@ func GetLastModified() ([]byte, string) {
 // 2. Given the caller provides the enable/disable state of IPv6, the filter
 //    code will remove all IPv6 nameservers if it is not enabled for containers
 //
-// It returns a boolean to notify the caller if changes were made at all
-func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) ([]byte, bool) {
-	changed := false
+func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) {
 	cleanedResolvConf := localhostNSRegexp.ReplaceAll(resolvConf, []byte{})
 	// if IPv6 is not enabled, also clean out any IPv6 address nameserver
 	if !ipv6Enabled {
@@ -106,10 +128,11 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) ([]byte, bool) {
 		}
 		cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...)
 	}
-	if !bytes.Equal(resolvConf, cleanedResolvConf) {
-		changed = true
+	hash, err := ioutils.HashData(bytes.NewReader(cleanedResolvConf))
+	if err != nil {
+		return nil, err
 	}
-	return cleanedResolvConf, changed
+	return &File{Content: cleanedResolvConf, Hash: hash}, nil
 }
 
 // getLines parses input into lines and strips away comments.
@@ -165,23 +188,50 @@ func GetSearchDomains(resolvConf []byte) []string {
 	return domains
 }
 
+// GetOptions returns options (if any) listed in /etc/resolv.conf
+// If more than one options line is encountered, only the contents of the last
+// one is returned.
+func GetOptions(resolvConf []byte) []string {
+	options := []string{}
+	for _, line := range getLines(resolvConf, []byte("#")) {
+		match := optionsRegexp.FindSubmatch(line)
+		if match == nil {
+			continue
+		}
+		options = strings.Fields(string(match[1]))
+	}
+	return options
+}
+
 // Build writes a configuration file to path containing a "nameserver" entry
-// for every element in dns, and a "search" entry for every element in
-// dnsSearch.
-func Build(path string, dns, dnsSearch []string) error {
+// for every element in dns, a "search" entry for every element in
+// dnsSearch, and an "options" entry for every element in dnsOptions.
+func Build(path string, dns, dnsSearch, dnsOptions []string) (*File, error) {
 	content := bytes.NewBuffer(nil)
+	if len(dnsSearch) > 0 {
+		if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
+			if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
+				return nil, err
+			}
+		}
+	}
 	for _, dns := range dns {
 		if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil {
-			return err
+			return nil, err
 		}
 	}
-	if len(dnsSearch) > 0 {
-		if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
-			if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
-				return err
+	if len(dnsOptions) > 0 {
+		if optsString := strings.Join(dnsOptions, " "); strings.Trim(optsString, " ") != "" {
+			if _, err := content.WriteString("options " + optsString + "\n"); err != nil {
+				return nil, err
 			}
 		}
 	}
 
-	return ioutil.WriteFile(path, content.Bytes(), 0644)
+	hash, err := ioutils.HashData(bytes.NewReader(content.Bytes()))
+	if err != nil {
+		return nil, err
+	}
+
+	return &File{Content: content.Bytes(), Hash: hash}, ioutil.WriteFile(path, content.Bytes(), 0644)
 }

+ 744 - 0
vendor/src/github.com/docker/libnetwork/sandbox.go

@@ -0,0 +1,744 @@
+package libnetwork
+
+import (
+	"container/heap"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path"
+	"path/filepath"
+	"sync"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/docker/libnetwork/etchosts"
+	"github.com/docker/libnetwork/osl"
+	"github.com/docker/libnetwork/resolvconf"
+	"github.com/docker/libnetwork/types"
+)
+
+// Sandbox provides the control over the network container entity. It is a one to one mapping with the container.
+type Sandbox interface {
+	// ID returns the ID of the sandbox
+	ID() string
+	// Key returns the sandbox's key
+	Key() string
+	// ContainerID returns the container id associated to this sandbox
+	ContainerID() string
+	// Labels returns the sandbox's labels
+	Labels() map[string]interface{}
+	// Statistics retrieves the interfaces' statistics for the sandbox
+	Statistics() (map[string]*osl.InterfaceStatistics, error)
+	// Refresh leaves all the endpoints, resets and re-apply the options,
+	// re-joins all the endpoints without destroying the osl sandbox
+	Refresh(options ...SandboxOption) error
+	// Delete destroys this container after detaching it from all connected endpoints.
+	Delete() error
+}
+
+// SandboxOption is a option setter function type used to pass varios options to
+// NewNetContainer method. The various setter functions of type SandboxOption are
+// provided by libnetwork, they look like ContainerOptionXXXX(...)
+type SandboxOption func(sb *sandbox)
+
+func (sb *sandbox) processOptions(options ...SandboxOption) {
+	for _, opt := range options {
+		if opt != nil {
+			opt(sb)
+		}
+	}
+}
+
+type epHeap []*endpoint
+
+type sandbox struct {
+	id          string
+	containerID string
+	config      containerConfig
+	osSbox      osl.Sandbox
+	controller  *controller
+	refCnt      int
+	endpoints   epHeap
+	epPriority  map[string]int
+	//hostsPath      string
+	//resolvConfPath string
+	joinLeaveDone chan struct{}
+	sync.Mutex
+}
+
+// These are the container configs used to customize container /etc/hosts file.
+type hostsPathConfig struct {
+	hostName        string
+	domainName      string
+	hostsPath       string
+	originHostsPath string
+	extraHosts      []extraHost
+	parentUpdates   []parentUpdate
+}
+
+type parentUpdate struct {
+	cid  string
+	name string
+	ip   string
+}
+
+type extraHost struct {
+	name string
+	IP   string
+}
+
+// These are the container configs used to customize container /etc/resolv.conf file.
+type resolvConfPathConfig struct {
+	resolvConfPath       string
+	originResolvConfPath string
+	resolvConfHashFile   string
+	dnsList              []string
+	dnsSearchList        []string
+	dnsOptionsList       []string
+}
+
+type containerConfig struct {
+	hostsPathConfig
+	resolvConfPathConfig
+	generic           map[string]interface{}
+	useDefaultSandBox bool
+	prio              int // higher the value, more the priority
+}
+
+func (sb *sandbox) ID() string {
+	return sb.id
+}
+
+func (sb *sandbox) ContainerID() string {
+	return sb.containerID
+}
+
+func (sb *sandbox) Key() string {
+	if sb.config.useDefaultSandBox {
+		return osl.GenerateKey("default")
+	}
+	return osl.GenerateKey(sb.id)
+}
+
+func (sb *sandbox) Labels() map[string]interface{} {
+	return sb.config.generic
+}
+
+func (sb *sandbox) Statistics() (map[string]*osl.InterfaceStatistics, error) {
+	m := make(map[string]*osl.InterfaceStatistics)
+
+	if sb.osSbox == nil {
+		return m, nil
+	}
+
+	var err error
+	for _, i := range sb.osSbox.Info().Interfaces() {
+		if m[i.DstName()], err = i.Statistics(); err != nil {
+			return m, err
+		}
+	}
+
+	return m, nil
+}
+
+func (sb *sandbox) Delete() error {
+	c := sb.controller
+
+	// Detach from all endpoints
+	for _, ep := range sb.getConnectedEndpoints() {
+		if err := ep.Leave(sb); err != nil {
+			log.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err)
+		}
+	}
+
+	if sb.osSbox != nil {
+		sb.osSbox.Destroy()
+	}
+
+	c.Lock()
+	delete(c.sandboxes, sb.ID())
+	c.Unlock()
+
+	return nil
+}
+
+func (sb *sandbox) Refresh(options ...SandboxOption) error {
+	// Store connected endpoints
+	epList := sb.getConnectedEndpoints()
+
+	// Detach from all endpoints
+	for _, ep := range epList {
+		if err := ep.Leave(sb); err != nil {
+			log.Warnf("Failed detaching sandbox %s from endpoint %s: %v\n", sb.ID(), ep.ID(), err)
+		}
+	}
+
+	// Re-apply options
+	sb.config = containerConfig{}
+	sb.processOptions(options...)
+
+	// Setup discovery files
+	if err := sb.setupResolutionFiles(); err != nil {
+		return err
+	}
+
+	// Re -connect to all endpoints
+	for _, ep := range epList {
+		if err := ep.Join(sb); err != nil {
+			log.Warnf("Failed attach sandbox %s to endpoint %s: %v\n", sb.ID(), ep.ID(), err)
+		}
+	}
+
+	return nil
+}
+
+func (sb *sandbox) MarshalJSON() ([]byte, error) {
+	sb.Lock()
+	defer sb.Unlock()
+
+	// We are just interested in the container ID. This can be expanded to include all of containerInfo if there is a need
+	return json.Marshal(sb.id)
+}
+
+func (sb *sandbox) UnmarshalJSON(b []byte) (err error) {
+	sb.Lock()
+	defer sb.Unlock()
+
+	var id string
+	if err := json.Unmarshal(b, &id); err != nil {
+		return err
+	}
+	sb.id = id
+	return nil
+}
+
+func (sb *sandbox) setupResolutionFiles() error {
+	if err := sb.buildHostsFile(); err != nil {
+		return err
+	}
+
+	if err := sb.updateParentHosts(); err != nil {
+		return err
+	}
+
+	if err := sb.setupDNS(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (sb *sandbox) getConnectedEndpoints() []*endpoint {
+	sb.Lock()
+	defer sb.Unlock()
+
+	eps := make([]*endpoint, len(sb.endpoints))
+	for i, ep := range sb.endpoints {
+		eps[i] = ep
+	}
+
+	return eps
+}
+
+func (sb *sandbox) updateGateway(ep *endpoint) error {
+	sb.osSbox.UnsetGateway()
+	sb.osSbox.UnsetGatewayIPv6()
+
+	if ep == nil {
+		return nil
+	}
+
+	ep.Lock()
+	joinInfo := ep.joinInfo
+	ep.Unlock()
+
+	if err := sb.osSbox.SetGateway(joinInfo.gw); err != nil {
+		return fmt.Errorf("failed to set gateway while updating gateway: %v", err)
+	}
+
+	if err := sb.osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil {
+		return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err)
+	}
+
+	return nil
+}
+
+func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
+	ep.Lock()
+	joinInfo := ep.joinInfo
+	ifaces := ep.iFaces
+	ep.Unlock()
+
+	for _, i := range ifaces {
+		var ifaceOptions []osl.IfaceOption
+
+		ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(&i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes))
+		if i.addrv6.IP.To16() != nil {
+			ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(&i.addrv6))
+		}
+
+		if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
+			return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)
+		}
+	}
+
+	if joinInfo != nil {
+		// Set up non-interface routes.
+		for _, r := range joinInfo.StaticRoutes {
+			if err := sb.osSbox.AddStaticRoute(r); err != nil {
+				return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err)
+			}
+		}
+	}
+
+	sb.Lock()
+	heap.Push(&sb.endpoints, ep)
+	highEp := sb.endpoints[0]
+	sb.Unlock()
+	if ep == highEp {
+		if err := sb.updateGateway(ep); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (sb *sandbox) clearNetworkResources(ep *endpoint) error {
+
+	for _, i := range sb.osSbox.Info().Interfaces() {
+		// Only remove the interfaces owned by this endpoint from the sandbox.
+		if ep.hasInterface(i.SrcName()) {
+			if err := i.Remove(); err != nil {
+				log.Debugf("Remove interface failed: %v", err)
+			}
+		}
+	}
+
+	ep.Lock()
+	joinInfo := ep.joinInfo
+	ep.Unlock()
+
+	// Remove non-interface routes.
+	for _, r := range joinInfo.StaticRoutes {
+		if err := sb.osSbox.RemoveStaticRoute(r); err != nil {
+			log.Debugf("Remove route failed: %v", err)
+		}
+	}
+
+	sb.Lock()
+	if len(sb.endpoints) == 0 {
+		// sb.endpoints should never be empty and this is unexpected error condition
+		// We log an error message to note this down for debugging purposes.
+		log.Errorf("No endpoints in sandbox while trying to remove endpoint %s", ep.Name())
+		sb.Unlock()
+		return nil
+	}
+
+	highEpBefore := sb.endpoints[0]
+	var (
+		i int
+		e *endpoint
+	)
+	for i, e = range sb.endpoints {
+		if e == ep {
+			break
+		}
+	}
+	heap.Remove(&sb.endpoints, i)
+	var highEpAfter *endpoint
+	if len(sb.endpoints) > 0 {
+		highEpAfter = sb.endpoints[0]
+	}
+	delete(sb.epPriority, ep.ID())
+	sb.Unlock()
+
+	if highEpBefore != highEpAfter {
+		sb.updateGateway(highEpAfter)
+	}
+
+	return nil
+}
+
+const (
+	defaultPrefix = "/var/lib/docker/network/files"
+	filePerm      = 0644
+)
+
+func (sb *sandbox) buildHostsFile() error {
+	if sb.config.hostsPath == "" {
+		sb.config.hostsPath = defaultPrefix + "/" + sb.id + "/hosts"
+	}
+
+	dir, _ := filepath.Split(sb.config.hostsPath)
+	if err := createBasePath(dir); err != nil {
+		return err
+	}
+
+	// This is for the host mode networking
+	if sb.config.originHostsPath != "" {
+		if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
+			return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
+		}
+		return nil
+	}
+
+	extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts))
+	for _, extraHost := range sb.config.extraHosts {
+		extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
+	}
+
+	return etchosts.Build(sb.config.hostsPath, "", sb.config.hostName, sb.config.domainName, extraContent)
+}
+
+func (sb *sandbox) updateHostsFile(ifaceIP string, svcRecords []etchosts.Record) error {
+	if sb.config.originHostsPath != "" {
+		return nil
+	}
+
+	// Rebuild the hosts file accounting for the passed interface IP and service records
+	extraContent := make([]etchosts.Record, 0, len(sb.config.extraHosts)+len(svcRecords))
+
+	for _, extraHost := range sb.config.extraHosts {
+		extraContent = append(extraContent, etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
+	}
+
+	for _, svc := range svcRecords {
+		extraContent = append(extraContent, svc)
+	}
+
+	return etchosts.Build(sb.config.hostsPath, ifaceIP, sb.config.hostName, sb.config.domainName, extraContent)
+}
+
+func (sb *sandbox) addHostsEntries(recs []etchosts.Record) {
+	if err := etchosts.Add(sb.config.hostsPath, recs); err != nil {
+		log.Warnf("Failed adding service host entries to the running container: %v", err)
+	}
+}
+
+func (sb *sandbox) deleteHostsEntries(recs []etchosts.Record) {
+	if err := etchosts.Delete(sb.config.hostsPath, recs); err != nil {
+		log.Warnf("Failed deleting service host entries to the running container: %v", err)
+	}
+}
+
+func (sb *sandbox) updateParentHosts() error {
+	var pSb Sandbox
+
+	for _, update := range sb.config.parentUpdates {
+		sb.controller.WalkSandboxes(SandboxContainerWalker(&pSb, update.cid))
+		if pSb == nil {
+			continue
+		}
+		if err := etchosts.Update(pSb.(*sandbox).config.hostsPath, update.ip, update.name); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (sb *sandbox) setupDNS() error {
+	var newRC *resolvconf.File
+
+	if sb.config.resolvConfPath == "" {
+		sb.config.resolvConfPath = defaultPrefix + "/" + sb.id + "/resolv.conf"
+	}
+
+	sb.config.resolvConfHashFile = sb.config.resolvConfPath + ".hash"
+
+	dir, _ := filepath.Split(sb.config.resolvConfPath)
+	if err := createBasePath(dir); err != nil {
+		return err
+	}
+
+	// This is for the host mode networking
+	if sb.config.originResolvConfPath != "" {
+		if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
+			return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
+		}
+		return nil
+	}
+
+	currRC, err := resolvconf.Get()
+	if err != nil {
+		return err
+	}
+
+	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
+		var (
+			err            error
+			dnsList        = resolvconf.GetNameservers(currRC.Content)
+			dnsSearchList  = resolvconf.GetSearchDomains(currRC.Content)
+			dnsOptionsList = resolvconf.GetOptions(currRC.Content)
+		)
+		if len(sb.config.dnsList) > 0 {
+			dnsList = sb.config.dnsList
+		}
+		if len(sb.config.dnsSearchList) > 0 {
+			dnsSearchList = sb.config.dnsSearchList
+		}
+		if len(sb.config.dnsOptionsList) > 0 {
+			dnsOptionsList = sb.config.dnsOptionsList
+		}
+		newRC, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
+		if err != nil {
+			return err
+		}
+	} else {
+		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
+		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
+			return err
+		}
+		// No contention on container resolv.conf file at sandbox creation
+		if err := ioutil.WriteFile(sb.config.resolvConfPath, newRC.Content, filePerm); err != nil {
+			return types.InternalErrorf("failed to write unhaltered resolv.conf file content when setting up dns for sandbox %s: %v", sb.ID(), err)
+		}
+	}
+
+	// Write hash
+	if err := ioutil.WriteFile(sb.config.resolvConfHashFile, []byte(newRC.Hash), filePerm); err != nil {
+		return types.InternalErrorf("failed to write resolv.conf hash file when setting up dns for sandbox %s: %v", sb.ID(), err)
+	}
+
+	return nil
+}
+
+func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
+	var (
+		currHash string
+		hashFile = sb.config.resolvConfHashFile
+	)
+
+	if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(sb.config.dnsOptionsList) > 0 {
+		return nil
+	}
+
+	currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
+	if err != nil {
+		if !os.IsNotExist(err) {
+			return err
+		}
+	} else {
+		h, err := ioutil.ReadFile(hashFile)
+		if err != nil {
+			if !os.IsNotExist(err) {
+				return err
+			}
+		} else {
+			currHash = string(h)
+		}
+	}
+
+	if currHash != "" && currHash != currRC.Hash {
+		// Seems the user has changed the container resolv.conf since the last time
+		// we checked so return without doing anything.
+		log.Infof("Skipping update of resolv.conf file with ipv6Enabled: %t because file was touched by user", ipv6Enabled)
+		return nil
+	}
+
+	// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
+	newRC, err := resolvconf.FilterResolvDNS(currRC.Content, ipv6Enabled)
+	if err != nil {
+		return err
+	}
+
+	// for atomic updates to these files, use temporary files with os.Rename:
+	dir := path.Dir(sb.config.resolvConfPath)
+	tmpHashFile, err := ioutil.TempFile(dir, "hash")
+	if err != nil {
+		return err
+	}
+	tmpResolvFile, err := ioutil.TempFile(dir, "resolv")
+	if err != nil {
+		return err
+	}
+
+	// Change the perms to filePerm (0644) since ioutil.TempFile creates it by default as 0600
+	if err := os.Chmod(tmpResolvFile.Name(), filePerm); err != nil {
+		return err
+	}
+
+	// write the updates to the temp files
+	if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newRC.Hash), filePerm); err != nil {
+		return err
+	}
+	if err = ioutil.WriteFile(tmpResolvFile.Name(), newRC.Content, filePerm); err != nil {
+		return err
+	}
+
+	// rename the temp files for atomic replace
+	if err = os.Rename(tmpHashFile.Name(), hashFile); err != nil {
+		return err
+	}
+	return os.Rename(tmpResolvFile.Name(), sb.config.resolvConfPath)
+}
+
+// OptionHostname function returns an option setter for hostname option to
+// be passed to NewSandbox method.
+func OptionHostname(name string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.hostName = name
+	}
+}
+
+// OptionDomainname function returns an option setter for domainname option to
+// be passed to NewSandbox method.
+func OptionDomainname(name string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.domainName = name
+	}
+}
+
+// OptionHostsPath function returns an option setter for hostspath option to
+// be passed to NewSandbox method.
+func OptionHostsPath(path string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.hostsPath = path
+	}
+}
+
+// OptionOriginHostsPath function returns an option setter for origin hosts file path
+// tbeo  passed to NewSandbox method.
+func OptionOriginHostsPath(path string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.originHostsPath = path
+	}
+}
+
+// OptionExtraHost function returns an option setter for extra /etc/hosts options
+// which is a name and IP as strings.
+func OptionExtraHost(name string, IP string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.extraHosts = append(sb.config.extraHosts, extraHost{name: name, IP: IP})
+	}
+}
+
+// OptionParentUpdate function returns an option setter for parent container
+// which needs to update the IP address for the linked container.
+func OptionParentUpdate(cid string, name, ip string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.parentUpdates = append(sb.config.parentUpdates, parentUpdate{cid: cid, name: name, ip: ip})
+	}
+}
+
+// OptionResolvConfPath function returns an option setter for resolvconfpath option to
+// be passed to net container methods.
+func OptionResolvConfPath(path string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.resolvConfPath = path
+	}
+}
+
+// OptionOriginResolvConfPath function returns an option setter to set the path to the
+// origin resolv.conf file to be passed to net container methods.
+func OptionOriginResolvConfPath(path string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.originResolvConfPath = path
+	}
+}
+
+// OptionDNS function returns an option setter for dns entry option to
+// be passed to container Create method.
+func OptionDNS(dns string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.dnsList = append(sb.config.dnsList, dns)
+	}
+}
+
+// OptionDNSSearch function returns an option setter for dns search entry option to
+// be passed to container Create method.
+func OptionDNSSearch(search string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.dnsSearchList = append(sb.config.dnsSearchList, search)
+	}
+}
+
+// OptionDNSOptions function returns an option setter for dns options entry option to
+// be passed to container Create method.
+func OptionDNSOptions(options string) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.dnsOptionsList = append(sb.config.dnsOptionsList, options)
+	}
+}
+
+// OptionUseDefaultSandbox function returns an option setter for using default sandbox to
+// be passed to container Create method.
+func OptionUseDefaultSandbox() SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.useDefaultSandBox = true
+	}
+}
+
+// OptionGeneric function returns an option setter for Generic configuration
+// that is not managed by libNetwork but can be used by the Drivers during the call to
+// net container creation method. Container Labels are a good example.
+func OptionGeneric(generic map[string]interface{}) SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.generic = generic
+	}
+}
+
+func (eh epHeap) Len() int { return len(eh) }
+
+func (eh epHeap) Less(i, j int) bool {
+	ci, _ := eh[i].getSandbox()
+	cj, _ := eh[j].getSandbox()
+
+	cip, ok := ci.epPriority[eh[i].ID()]
+	if !ok {
+		cip = 0
+	}
+	cjp, ok := cj.epPriority[eh[j].ID()]
+	if !ok {
+		cjp = 0
+	}
+	if cip == cjp {
+		return eh[i].getNetwork().Name() < eh[j].getNetwork().Name()
+	}
+
+	return cip > cjp
+}
+
+func (eh epHeap) Swap(i, j int) { eh[i], eh[j] = eh[j], eh[i] }
+
+func (eh *epHeap) Push(x interface{}) {
+	*eh = append(*eh, x.(*endpoint))
+}
+
+func (eh *epHeap) Pop() interface{} {
+	old := *eh
+	n := len(old)
+	x := old[n-1]
+	*eh = old[0 : n-1]
+	return x
+}
+
+func createBasePath(dir string) error {
+	return os.MkdirAll(dir, filePerm)
+}
+
+func createFile(path string) error {
+	var f *os.File
+
+	dir, _ := filepath.Split(path)
+	err := createBasePath(dir)
+	if err != nil {
+		return err
+	}
+
+	f, err = os.Create(path)
+	if err == nil {
+		f.Close()
+	}
+
+	return err
+}
+
+func copyFile(src, dst string) error {
+	sBytes, err := ioutil.ReadFile(src)
+	if err != nil {
+		return err
+	}
+	return ioutil.WriteFile(dst, sBytes, filePerm)
+}

+ 0 - 259
vendor/src/github.com/docker/libnetwork/sandboxdata.go

@@ -1,259 +0,0 @@
-package libnetwork
-
-import (
-	"container/heap"
-	"fmt"
-	"sync"
-
-	"github.com/Sirupsen/logrus"
-	"github.com/docker/libnetwork/sandbox"
-)
-
-type epHeap []*endpoint
-
-type sandboxData struct {
-	sbox      sandbox.Sandbox
-	refCnt    int
-	endpoints epHeap
-	sync.Mutex
-}
-
-func (eh epHeap) Len() int { return len(eh) }
-
-func (eh epHeap) Less(i, j int) bool {
-	eh[i].Lock()
-	eh[j].Lock()
-	defer eh[j].Unlock()
-	defer eh[i].Unlock()
-
-	if eh[i].container.config.prio == eh[j].container.config.prio {
-		return eh[i].network.Name() < eh[j].network.Name()
-	}
-
-	return eh[i].container.config.prio > eh[j].container.config.prio
-}
-
-func (eh epHeap) Swap(i, j int) { eh[i], eh[j] = eh[j], eh[i] }
-
-func (eh *epHeap) Push(x interface{}) {
-	*eh = append(*eh, x.(*endpoint))
-}
-
-func (eh *epHeap) Pop() interface{} {
-	old := *eh
-	n := len(old)
-	x := old[n-1]
-	*eh = old[0 : n-1]
-	return x
-}
-
-func (s *sandboxData) updateGateway(ep *endpoint) error {
-	sb := s.sandbox()
-
-	sb.UnsetGateway()
-	sb.UnsetGatewayIPv6()
-
-	if ep == nil {
-		return nil
-	}
-
-	ep.Lock()
-	joinInfo := ep.joinInfo
-	ep.Unlock()
-
-	if err := sb.SetGateway(joinInfo.gw); err != nil {
-		return fmt.Errorf("failed to set gateway while updating gateway: %v", err)
-	}
-
-	if err := sb.SetGatewayIPv6(joinInfo.gw6); err != nil {
-		return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err)
-	}
-
-	return nil
-}
-
-func (s *sandboxData) addEndpoint(ep *endpoint) error {
-	ep.Lock()
-	joinInfo := ep.joinInfo
-	ifaces := ep.iFaces
-	ep.Unlock()
-
-	sb := s.sandbox()
-	for _, i := range ifaces {
-		var ifaceOptions []sandbox.IfaceOption
-
-		ifaceOptions = append(ifaceOptions, sb.InterfaceOptions().Address(&i.addr),
-			sb.InterfaceOptions().Routes(i.routes))
-		if i.addrv6.IP.To16() != nil {
-			ifaceOptions = append(ifaceOptions,
-				sb.InterfaceOptions().AddressIPv6(&i.addrv6))
-		}
-
-		if err := sb.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
-			return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)
-		}
-	}
-
-	if joinInfo != nil {
-		// Set up non-interface routes.
-		for _, r := range ep.joinInfo.StaticRoutes {
-			if err := sb.AddStaticRoute(r); err != nil {
-				return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err)
-			}
-		}
-	}
-
-	s.Lock()
-	heap.Push(&s.endpoints, ep)
-	highEp := s.endpoints[0]
-	s.Unlock()
-
-	if ep == highEp {
-		if err := s.updateGateway(ep); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-func (s *sandboxData) rmEndpoint(ep *endpoint) {
-	ep.Lock()
-	joinInfo := ep.joinInfo
-	ep.Unlock()
-
-	sb := s.sandbox()
-	for _, i := range sb.Info().Interfaces() {
-		// Only remove the interfaces owned by this endpoint from the sandbox.
-		if ep.hasInterface(i.SrcName()) {
-			if err := i.Remove(); err != nil {
-				logrus.Debugf("Remove interface failed: %v", err)
-			}
-		}
-	}
-
-	// Remove non-interface routes.
-	for _, r := range joinInfo.StaticRoutes {
-		if err := sb.RemoveStaticRoute(r); err != nil {
-			logrus.Debugf("Remove route failed: %v", err)
-		}
-	}
-
-	s.Lock()
-	if len(s.endpoints) == 0 {
-		// s.endpoints should never be empty and this is unexpected error condition
-		// We log an error message to note this down for debugging purposes.
-		logrus.Errorf("No endpoints in sandbox while trying to remove endpoint %s", ep.Name())
-		s.Unlock()
-		return
-	}
-
-	highEpBefore := s.endpoints[0]
-	var (
-		i int
-		e *endpoint
-	)
-	for i, e = range s.endpoints {
-		if e == ep {
-			break
-		}
-	}
-	heap.Remove(&s.endpoints, i)
-	var highEpAfter *endpoint
-	if len(s.endpoints) > 0 {
-		highEpAfter = s.endpoints[0]
-	}
-
-	s.Unlock()
-
-	if highEpBefore != highEpAfter {
-		s.updateGateway(highEpAfter)
-	}
-}
-
-func (s *sandboxData) sandbox() sandbox.Sandbox {
-	s.Lock()
-	defer s.Unlock()
-
-	return s.sbox
-}
-
-func (c *controller) sandboxAdd(key string, create bool, ep *endpoint) (sandbox.Sandbox, error) {
-	c.Lock()
-	sData, ok := c.sandboxes[key]
-	c.Unlock()
-
-	if !ok {
-		sb, err := sandbox.NewSandbox(key, create)
-		if err != nil {
-			return nil, fmt.Errorf("failed to create new sandbox: %v", err)
-		}
-
-		sData = &sandboxData{
-			sbox:      sb,
-			endpoints: epHeap{},
-		}
-
-		heap.Init(&sData.endpoints)
-		c.Lock()
-		c.sandboxes[key] = sData
-		c.Unlock()
-	}
-
-	if err := sData.addEndpoint(ep); err != nil {
-		return nil, err
-	}
-
-	return sData.sandbox(), nil
-}
-
-func (c *controller) sandboxRm(key string, ep *endpoint) {
-	c.Lock()
-	sData := c.sandboxes[key]
-	c.Unlock()
-
-	sData.rmEndpoint(ep)
-}
-
-func (c *controller) sandboxGet(key string) sandbox.Sandbox {
-	c.Lock()
-	sData, ok := c.sandboxes[key]
-	c.Unlock()
-
-	if !ok {
-		return nil
-	}
-
-	return sData.sandbox()
-}
-
-func (c *controller) LeaveAll(id string) error {
-	c.Lock()
-	sData, ok := c.sandboxes[sandbox.GenerateKey(id)]
-	c.Unlock()
-
-	if !ok {
-		return fmt.Errorf("could not find sandbox for container id %s", id)
-	}
-
-	sData.Lock()
-	eps := make([]*endpoint, len(sData.endpoints))
-	for i, ep := range sData.endpoints {
-		eps[i] = ep
-	}
-	sData.Unlock()
-
-	for _, ep := range eps {
-		if err := ep.Leave(id); err != nil {
-			logrus.Warnf("Failed leaving endpoint id %s: %v\n", ep.ID(), err)
-		}
-	}
-
-	sData.sandbox().Destroy()
-
-	c.Lock()
-	delete(c.sandboxes, sandbox.GenerateKey(id))
-	c.Unlock()
-
-	return nil
-}

+ 5 - 12
vendor/src/github.com/docker/libnetwork/store.go

@@ -7,7 +7,6 @@ import (
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libkv/store"
 	"github.com/docker/libnetwork/datastore"
-	"github.com/docker/libnetwork/types"
 )
 
 func (c *controller) validateDatastoreConfig() bool {
@@ -91,7 +90,7 @@ func (c *controller) deleteNetworkFromStore(n *network) error {
 	return nil
 }
 
-func (c *controller) getNetworkFromStore(nid types.UUID) (*network, error) {
+func (c *controller) getNetworkFromStore(nid string) (*network, error) {
 	n := network{id: nid}
 	if err := c.store.GetObject(datastore.Key(n.Key()...), &n); err != nil {
 		return nil, err
@@ -105,7 +104,7 @@ func (c *controller) newEndpointFromStore(key string, ep *endpoint) error {
 	id := ep.id
 	ep.Unlock()
 
-	_, err := n.EndpointByID(string(id))
+	_, err := n.EndpointByID(id)
 	if err != nil {
 		if _, ok := err.(ErrNoSuchEndpoint); ok {
 			return n.addEndpoint(ep)
@@ -134,7 +133,7 @@ func (c *controller) updateEndpointToStore(ep *endpoint) error {
 	return cs.PutObjectAtomic(ep)
 }
 
-func (c *controller) getEndpointFromStore(eid types.UUID) (*endpoint, error) {
+func (c *controller) getEndpointFromStore(eid string) (*endpoint, error) {
 	ep := endpoint{id: eid}
 	if err := c.store.GetObject(datastore.Key(ep.Key()...), &ep); err != nil {
 		return nil, err
@@ -346,7 +345,7 @@ func (c *controller) processEndpointUpdate(ep *endpoint) bool {
 	if !ok {
 		return true
 	}
-	existing, _ := n.EndpointByID(string(ep.id))
+	existing, _ := n.EndpointByID(ep.id)
 	if existing == nil {
 		return true
 	}
@@ -357,13 +356,7 @@ func (c *controller) processEndpointUpdate(ep *endpoint) bool {
 		// Can't use SetIndex() because ee is locked.
 		ee.dbIndex = ep.Index()
 		ee.dbExists = true
-		if ee.container != nil && ep.container != nil {
-			// we care only about the container id
-			ee.container.id = ep.container.id
-		} else {
-			// we still care only about the container id, but this is a short-cut to communicate join or leave operation
-			ee.container = ep.container
-		}
+		ee.sandboxID = ep.sandboxID
 	}
 	ee.Unlock()
 

+ 53 - 0
vendor/src/github.com/docker/libnetwork/types/types.go

@@ -197,6 +197,59 @@ func CompareIPNet(a, b *net.IPNet) bool {
 	return a.IP.Equal(b.IP) && bytes.Equal(a.Mask, b.Mask)
 }
 
+// GetMinimalIP returns the address in its shortest form
+func GetMinimalIP(ip net.IP) net.IP {
+	if ip != nil && ip.To4() != nil {
+		return ip.To4()
+	}
+	return ip
+}
+
+// GetMinimalIPNet returns a copy of the passed IP Network with congruent ip and mask notation
+func GetMinimalIPNet(nw *net.IPNet) *net.IPNet {
+	if nw == nil {
+		return nil
+	}
+	if len(nw.IP) == 16 && nw.IP.To4() != nil {
+		m := nw.Mask
+		if len(m) == 16 {
+			m = m[12:16]
+		}
+		return &net.IPNet{IP: nw.IP.To4(), Mask: m}
+	}
+	return nw
+}
+
+var v4inV6MaskPrefix = []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+
+// GetHostPartIP returns the host portion of the ip address identified by the mask.
+// IP address representation is not modified. If address and mask are not compatible
+// an error is returned.
+func GetHostPartIP(ip net.IP, mask net.IPMask) (net.IP, error) {
+	// Find the effective starting of address and mask
+	is := 0
+	ms := 0
+	if len(ip) == net.IPv6len && ip.To4() != nil {
+		is = 12
+	}
+	if len(ip[is:]) == net.IPv4len && len(mask) == net.IPv6len && bytes.Equal(mask[:12], v4inV6MaskPrefix) {
+		ms = 12
+	}
+
+	// Check if address and mask are semantically compatible
+	if len(ip[is:]) != len(mask[ms:]) {
+		return nil, fmt.Errorf("cannot compute host portion ip address as ip and mask are not compatible: (%#v, %#v)", ip, mask)
+	}
+
+	// Compute host portion
+	out := GetIPCopy(ip)
+	for i := 0; i < len(mask[ms:]); i++ {
+		out[is+i] &= ^mask[ms+i]
+	}
+
+	return out, nil
+}
+
 const (
 	// NEXTHOP indicates a StaticRoute with an IP next hop.
 	NEXTHOP = iota

+ 11 - 0
vendor/src/github.com/docker/libnetwork/wrapmake.sh

@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+set -e
+
+function raise()
+{
+    kill -$1 0
+}
+
+trap "raise SIGINT" SIGINT
+make $1