Przeglądaj źródła

Vendor-in 2baa2ddc78b42f011f55633282ac63a72e1b09c1 for userns support

Changes include :
* libnetwork support for userns
* driver api change to have 1 interface per endpoint

Signed-off-by: Madhu Venugopal <madhu@docker.com>
Madhu Venugopal 9 lat temu
rodzic
commit
d0e0c13b60
25 zmienionych plików z 491 dodań i 247 usunięć
  1. 2 22
      daemon/container_unix.go
  2. 2 2
      daemon/daemon.go
  3. 1 1
      hack/vendor.sh
  4. 1 0
      vendor/src/github.com/docker/libnetwork/.gitignore
  5. 18 7
      vendor/src/github.com/docker/libnetwork/Makefile
  6. 3 0
      vendor/src/github.com/docker/libnetwork/api/api.go
  7. 1 0
      vendor/src/github.com/docker/libnetwork/api/types.go
  8. 7 2
      vendor/src/github.com/docker/libnetwork/client/service.go
  9. 1 1
      vendor/src/github.com/docker/libnetwork/config/config.go
  10. 26 11
      vendor/src/github.com/docker/libnetwork/controller.go
  11. 14 24
      vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go
  12. 7 12
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
  13. 4 7
      vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go
  14. 4 4
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_endpoint.go
  15. 6 9
      vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go
  16. 36 39
      vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go
  17. 23 18
      vendor/src/github.com/docker/libnetwork/endpoint.go
  18. 27 41
      vendor/src/github.com/docker/libnetwork/endpoint_info.go
  19. 1 2
      vendor/src/github.com/docker/libnetwork/network.go
  20. 28 15
      vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go
  21. 4 0
      vendor/src/github.com/docker/libnetwork/osl/namespace_unsupported.go
  22. 4 0
      vendor/src/github.com/docker/libnetwork/osl/namespace_windows.go
  23. 83 21
      vendor/src/github.com/docker/libnetwork/sandbox.go
  24. 185 0
      vendor/src/github.com/docker/libnetwork/sandbox_externalkey.go
  25. 3 9
      vendor/src/github.com/docker/libnetwork/types/types.go

+ 2 - 22
daemon/container_unix.go

@@ -580,13 +580,11 @@ func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSet
 		return networkSettings, nil
 	}
 
-	ifaceList := epInfo.InterfaceList()
-	if len(ifaceList) == 0 {
+	iface := epInfo.Iface()
+	if iface == nil {
 		return networkSettings, nil
 	}
 
-	iface := ifaceList[0]
-
 	ones, _ := iface.Address().Mask.Size()
 	networkSettings.IPAddress = iface.Address().IP.String()
 	networkSettings.IPPrefixLen = ones
@@ -597,24 +595,6 @@ func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSet
 		networkSettings.GlobalIPv6PrefixLen = onesv6
 	}
 
-	if len(ifaceList) == 1 {
-		return networkSettings, nil
-	}
-
-	networkSettings.SecondaryIPAddresses = make([]network.Address, 0, len(ifaceList)-1)
-	networkSettings.SecondaryIPv6Addresses = make([]network.Address, 0, len(ifaceList)-1)
-	for _, iface := range ifaceList[1:] {
-		ones, _ := iface.Address().Mask.Size()
-		addr := network.Address{Addr: iface.Address().IP.String(), PrefixLen: ones}
-		networkSettings.SecondaryIPAddresses = append(networkSettings.SecondaryIPAddresses, addr)
-
-		if iface.AddressIPv6().IP.To16() != nil {
-			onesv6, _ := iface.AddressIPv6().Mask.Size()
-			addrv6 := network.Address{Addr: iface.AddressIPv6().IP.String(), PrefixLen: onesv6}
-			networkSettings.SecondaryIPv6Addresses = append(networkSettings.SecondaryIPv6Addresses, addrv6)
-		}
-	}
-
 	return networkSettings, nil
 }
 

+ 2 - 2
daemon/daemon.go

@@ -820,9 +820,9 @@ func (daemon *Daemon) Shutdown() error {
 		}
 		group.Wait()
 
-		// trigger libnetwork GC only if it's initialized
+		// trigger libnetwork Stop only if it's initialized
 		if daemon.netController != nil {
-			daemon.netController.GC()
+			daemon.netController.Stop()
 		}
 	}
 

+ 1 - 1
hack/vendor.sh

@@ -20,7 +20,7 @@ clone git github.com/tchap/go-patricia v2.1.0
 clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
 
 #get libnetwork packages
-clone git github.com/docker/libnetwork 3e31cead05cba8ec20241630d051e6d73765b3a2
+clone git github.com/docker/libnetwork 2baa2ddc78b42f011f55633282ac63a72e1b09c1
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4

+ 1 - 0
vendor/src/github.com/docker/libnetwork/.gitignore

@@ -4,6 +4,7 @@
 *.so
 
 # Folders
+integration-tmp/
 _obj
 _test
 

+ 18 - 7
vendor/src/github.com/docker/libnetwork/Makefile

@@ -1,4 +1,4 @@
-.PHONY: all all-local build build-local check check-code check-format run-tests check-local install-deps coveralls circle-ci
+.PHONY: all all-local build build-local check check-code check-format run-tests check-local integration-tests install-deps coveralls circle-ci
 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
@@ -7,8 +7,15 @@ 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} ./wrapmake.sh all-local
+all: ${build_image}.created build check integration-tests
+
+integration-tests:
+	@if [ ! -d ./integration-tmp ]; then \
+	    mkdir -p ./integration-tmp;	\
+	    git clone https://github.com/sstephenson/bats.git ./integration-tmp/bats; \
+	    ./integration-tmp/bats/install.sh ./integration-tmp; \
+	fi
+	@./integration-tmp/bin/bats ./test/integration/dnet
 
 all-local: check-local build-local
 
@@ -19,13 +26,16 @@ ${build_image}.created:
 	touch ${build_image}.created
 
 build: ${build_image}.created
-	${docker} ./wrapmake.sh build-local
+	@echo "Building code... "
+	@${docker} ./wrapmake.sh build-local
+	@echo "Done building code"
 
 build-local:
-	$(shell which godep) go build -tags libnetwork_discovery ./...
+	@$(shell which godep) go build -tags libnetwork_discovery ./...
+	@$(shell which godep) go build -o ./cmd/dnet/dnet ./cmd/dnet
 
 check: ${build_image}.created
-	${docker} ./wrapmake.sh check-local
+	@${docker} ./wrapmake.sh check-local
 
 check-code:
 	@echo "Checking code... "
@@ -76,4 +86,5 @@ coveralls:
 # The following target is a workaround for this
 
 circle-ci:
-	@${cidocker} make install-deps check-local coveralls
+	@${cidocker} make install-deps build-local check-local coveralls
+	make integration-tests

+ 3 - 0
vendor/src/github.com/docker/libnetwork/api/api.go

@@ -249,6 +249,9 @@ func (sc *sandboxCreate) parseOptions() []libnetwork.SandboxOption {
 	if sc.UseDefaultSandbox {
 		setFctList = append(setFctList, libnetwork.OptionUseDefaultSandbox())
 	}
+	if sc.UseExternalKey {
+		setFctList = append(setFctList, libnetwork.OptionUseExternalKey())
+	}
 	if sc.DNS != nil {
 		for _, d := range sc.DNS {
 			setFctList = append(setFctList, libnetwork.OptionDNS(d))

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

@@ -57,6 +57,7 @@ type sandboxCreate struct {
 	DNS               []string    `json:"dns"`
 	ExtraHosts        []extraHost `json:"extra_hosts"`
 	UseDefaultSandbox bool        `json:"use_default_sandbox"`
+	UseExternalKey    bool        `json:"use_external_key"`
 }
 
 // endpointJoin represents the expected body of the "join endpoint" or "leave endpoint" http request messages

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

@@ -115,7 +115,7 @@ func lookupContainerID(cli *NetworkCli, cnNameID string) (string, error) {
 }
 
 func lookupSandboxID(cli *NetworkCli, containerID string) (string, error) {
-	obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/sandboxes?container-id=%s", containerID), nil, nil))
+	obj, _, err := readBody(cli.call("GET", fmt.Sprintf("/sandboxes?partial-container-id=%s", containerID), nil, nil))
 	if err != nil {
 		return "", err
 	}
@@ -360,12 +360,17 @@ func (cli *NetworkCli) CmdServiceDetach(chain string, args ...string) error {
 		return err
 	}
 
+	sandboxID, err := lookupSandboxID(cli, containerID)
+	if err != nil {
+		return err
+	}
+
 	serviceID, err := lookupServiceID(cli, nn, sn)
 	if err != nil {
 		return err
 	}
 
-	_, _, err = readBody(cli.call("DELETE", "/services/"+serviceID+"/backend/"+containerID, nil, nil))
+	_, _, err = readBody(cli.call("DELETE", "/services/"+serviceID+"/backend/"+sandboxID, nil, nil))
 	if err != nil {
 		return err
 	}

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

@@ -109,7 +109,7 @@ func (c *Config) ProcessOptions(options ...Option) {
 
 // IsValidName validates configuration objects supported by libnetwork
 func IsValidName(name string) bool {
-	if name == "" || strings.Contains(name, ".") {
+	if strings.TrimSpace(name) == "" || strings.Contains(name, ".") {
 		return false
 	}
 	return true

+ 26 - 11
vendor/src/github.com/docker/libnetwork/controller.go

@@ -65,6 +65,9 @@ import (
 // NetworkController provides the interface for controller instance which manages
 // networks.
 type NetworkController interface {
+	// ID provides an unique identity for the controller
+	ID() string
+
 	// ConfigureNetworkDriver applies the passed options to the driver instance for the specified network type
 	ConfigureNetworkDriver(networkType string, options map[string]interface{}) error
 
@@ -99,8 +102,8 @@ type NetworkController interface {
 	// 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()
+	// Stop network controller
+	Stop()
 }
 
 // NetworkWalker is a client provided function which will be used to walk the Networks.
@@ -122,11 +125,13 @@ type endpointTable map[string]*endpoint
 type sandboxTable map[string]*sandbox
 
 type controller struct {
-	networks  networkTable
-	drivers   driverTable
-	sandboxes sandboxTable
-	cfg       *config.Config
-	store     datastore.DataStore
+	id             string
+	networks       networkTable
+	drivers        driverTable
+	sandboxes      sandboxTable
+	cfg            *config.Config
+	store          datastore.DataStore
+	extKeyListener net.Listener
 	sync.Mutex
 }
 
@@ -138,6 +143,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
 		cfg.ProcessOptions(cfgOptions...)
 	}
 	c := &controller{
+		id:        stringid.GenerateRandomID(),
 		cfg:       cfg,
 		networks:  networkTable{},
 		sandboxes: sandboxTable{},
@@ -159,9 +165,17 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
 		}
 	}
 
+	if err := c.startExternalKeyListener(); err != nil {
+		return nil, err
+	}
+
 	return c, nil
 }
 
+func (c *controller) ID() string {
+	return c.id
+}
+
 func (c *controller) validateHostDiscoveryConfig() bool {
 	if c.cfg == nil || c.cfg.Cluster.Discovery == "" || c.cfg.Cluster.Address == "" {
 		return false
@@ -204,11 +218,11 @@ func (c *controller) ConfigureNetworkDriver(networkType string, options map[stri
 }
 
 func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, capability driverapi.Capability) error {
-	c.Lock()
 	if !config.IsValidName(networkType) {
-		c.Unlock()
 		return ErrInvalidName(networkType)
 	}
+
+	c.Lock()
 	if _, ok := c.drivers[networkType]; ok {
 		c.Unlock()
 		return driverapi.ErrActiveRegistration(networkType)
@@ -414,7 +428,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
 		return nil, err
 	}
 
-	if sb.osSbox == nil {
+	if sb.osSbox == nil && !sb.config.useExternalKey {
 		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)
 		}
@@ -514,6 +528,7 @@ func (c *controller) isDriverGlobalScoped(networkType string) (bool, error) {
 	return false, nil
 }
 
-func (c *controller) GC() {
+func (c *controller) Stop() {
+	c.stopExternalKeyListener()
 	osl.GC()
 }

+ 14 - 24
vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go

@@ -45,18 +45,16 @@ type Driver interface {
 
 // EndpointInfo provides a go interface to fetch or populate endpoint assigned network resources.
 type EndpointInfo interface {
-	// Interfaces returns a list of interfaces bound to the endpoint.
-	// If the list is not empty the driver is only expected to consume the interfaces.
-	// It is an error to try to add interfaces to a non-empty list.
-	// If the list is empty the driver is expected to populate with 0 or more interfaces.
-	Interfaces() []InterfaceInfo
-
-	// AddInterface is used by the driver to add an interface to the interface list.
-	// This method will return an error if the driver attempts to add interfaces
-	// if the Interfaces() method returned a non-empty list.
-	// ID field need only have significance within the endpoint so it can be a simple
-	// monotonically increasing number
-	AddInterface(ID int, mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error
+	// Interface returns the interface bound to the endpoint.
+	// If the value is not nil the driver is only expected to consume the interface.
+	// It is an error to try to add interface if the passed down value is non-nil
+	// If the value is nil the driver is expected to add an interface
+	Interface() InterfaceInfo
+
+	// AddInterface is used by the driver to add an interface for the endpoint.
+	// This method will return an error if the driver attempts to add interface
+	// if the Interface() method returned a non-nil value.
+	AddInterface(mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error
 }
 
 // InterfaceInfo provides a go interface for drivers to retrive
@@ -70,10 +68,6 @@ type InterfaceInfo interface {
 
 	// AddressIPv6 returns the IPv6 address.
 	AddressIPv6() net.IPNet
-
-	// ID returns the numerical id of the interface and has significance only within
-	// the endpoint.
-	ID() int
 }
 
 // InterfaceNameInfo provides a go interface for the drivers to assign names
@@ -81,18 +75,14 @@ type InterfaceInfo interface {
 type InterfaceNameInfo interface {
 	// SetNames method assigns the srcName and dstPrefix for the interface.
 	SetNames(srcName, dstPrefix string) error
-
-	// ID returns the numerical id that was assigned to the interface by the driver
-	// CreateEndpoint.
-	ID() int
 }
 
 // JoinInfo represents a set of resources that the driver has the ability to provide during
 // join time.
 type JoinInfo interface {
-	// InterfaceNames returns a list of InterfaceNameInfo go interface to facilitate
-	// setting the names for the interfaces.
-	InterfaceNames() []InterfaceNameInfo
+	// InterfaceName returns a InterfaceNameInfo go interface to facilitate
+	// setting the names for the interface.
+	InterfaceName() InterfaceNameInfo
 
 	// SetGateway sets the default IPv4 gateway when a container joins the endpoint.
 	SetGateway(net.IP) error
@@ -102,7 +92,7 @@ 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
+	AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error
 }
 
 // DriverCallback provides a Callback interface for Drivers into LibNetwork

+ 7 - 12
vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go

@@ -32,7 +32,6 @@ const (
 	vethLen                 = 7
 	containerVethPrefix     = "eth"
 	maxAllocatePortAttempts = 10
-	ifaceID                 = 1
 )
 
 var (
@@ -883,8 +882,8 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 		return errors.New("invalid endpoint info passed")
 	}
 
-	if len(epInfo.Interfaces()) != 0 {
-		return errors.New("non empty interface list passed to bridge(local) driver")
+	if epInfo.Interface() != nil {
+		return errors.New("non-nil interface passed to bridge(local) driver")
 	}
 
 	// Get the network handler and make sure it exists
@@ -1070,7 +1069,7 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 		endpoint.addrv6 = ipv6Addr
 	}
 
-	err = epInfo.AddInterface(ifaceID, endpoint.macAddress, *ipv4Addr, *ipv6Addr)
+	err = epInfo.AddInterface(endpoint.macAddress, *ipv4Addr, *ipv6Addr)
 	if err != nil {
 		return err
 	}
@@ -1244,14 +1243,10 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		return EndpointNotFoundError(eid)
 	}
 
-	for _, iNames := range jinfo.InterfaceNames() {
-		// Make sure to set names on the correct interface ID.
-		if iNames.ID() == ifaceID {
-			err = iNames.SetNames(endpoint.srcName, containerVethPrefix)
-			if err != nil {
-				return err
-			}
-		}
+	iNames := jinfo.InterfaceName()
+	err = iNames.SetNames(endpoint.srcName, containerVethPrefix)
+	if err != nil {
+		return err
 	}
 
 	err = jinfo.SetGateway(network.bridge.gatewayIPv4)

+ 4 - 7
vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go

@@ -65,13 +65,10 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		return fmt.Errorf("could not set mac address to the container interface: %v", err)
 	}
 
-	for _, iNames := range jinfo.InterfaceNames() {
-		// Make sure to set names on the correct interface ID.
-		if iNames.ID() == 1 {
-			err = iNames.SetNames(name2, "eth")
-			if err != nil {
-				return err
-			}
+	if iNames := jinfo.InterfaceName(); iNames != nil {
+		err = iNames.SetNames(name2, "eth")
+		if err != nil {
+			return err
 		}
 	}
 

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

@@ -51,10 +51,10 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 		id: eid,
 	}
 
-	if epInfo != nil && (len(epInfo.Interfaces()) > 0) {
-		addr := epInfo.Interfaces()[0].Address()
+	if epInfo != nil && epInfo.Interface() != nil {
+		addr := epInfo.Interface().Address()
 		ep.addr = &addr
-		ep.mac = epInfo.Interfaces()[0].MacAddress()
+		ep.mac = epInfo.Interface().MacAddress()
 		n.addEndpoint(ep)
 		return nil
 	}
@@ -74,7 +74,7 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 
 	ep.mac = netutils.GenerateMACFromIP(ep.addr.IP)
 
-	err = epInfo.AddInterface(1, ep.mac, *ep.addr, net.IPNet{})
+	err = epInfo.AddInterface(ep.mac, *ep.addr, net.IPNet{})
 	if err != nil {
 		return fmt.Errorf("could not add interface to endpoint info: %v", err)
 	}

+ 6 - 9
vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go

@@ -48,13 +48,12 @@ type CreateEndpointRequest struct {
 	NetworkID string
 	// The ID of the endpoint for later reference.
 	EndpointID string
-	Interfaces []*EndpointInterface
+	Interface  *EndpointInterface
 	Options    map[string]interface{}
 }
 
 // EndpointInterface represents an interface endpoint.
 type EndpointInterface struct {
-	ID          int
 	Address     string
 	AddressIPv6 string
 	MacAddress  string
@@ -63,12 +62,11 @@ type EndpointInterface struct {
 // CreateEndpointResponse is the response to the CreateEndpoint action.
 type CreateEndpointResponse struct {
 	Response
-	Interfaces []*EndpointInterface
+	Interface *EndpointInterface
 }
 
 // Interface is the representation of a linux interface.
 type Interface struct {
-	ID          int
 	Address     *net.IPNet
 	AddressIPv6 *net.IPNet
 	MacAddress  net.HardwareAddr
@@ -118,16 +116,15 @@ type StaticRoute struct {
 	Destination string
 	RouteType   int
 	NextHop     string
-	InterfaceID int
 }
 
 // JoinResponse is the response to a JoinRequest.
 type JoinResponse struct {
 	Response
-	InterfaceNames []*InterfaceName
-	Gateway        string
-	GatewayIPv6    string
-	StaticRoutes   []StaticRoute
+	InterfaceName *InterfaceName
+	Gateway       string
+	GatewayIPv6   string
+	StaticRoutes  []StaticRoute
 }
 
 // LeaveRequest describes the API for detaching an endpoint from a sandbox.

+ 36 - 39
vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go

@@ -71,16 +71,17 @@ func (d *driver) DeleteNetwork(nid string) error {
 }
 
 func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
+	var reqIface *api.EndpointInterface
+
 	if epInfo == nil {
 		return fmt.Errorf("must not be called with nil EndpointInfo")
 	}
 
-	reqIfaces := make([]*api.EndpointInterface, len(epInfo.Interfaces()))
-	for i, iface := range epInfo.Interfaces() {
+	iface := epInfo.Interface()
+	if iface != nil {
 		addr4 := iface.Address()
 		addr6 := iface.AddressIPv6()
-		reqIfaces[i] = &api.EndpointInterface{
-			ID:          iface.ID(),
+		reqIface = &api.EndpointInterface{
 			Address:     addr4.String(),
 			AddressIPv6: addr6.String(),
 			MacAddress:  iface.MacAddress().String(),
@@ -89,7 +90,7 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 	create := &api.CreateEndpointRequest{
 		NetworkID:  nid,
 		EndpointID: eid,
-		Interfaces: reqIfaces,
+		Interface:  reqIface,
 		Options:    epOptions,
 	}
 	var res api.CreateEndpointResponse
@@ -97,25 +98,26 @@ func (d *driver) CreateEndpoint(nid, eid string, epInfo driverapi.EndpointInfo,
 		return err
 	}
 
-	ifaces, err := parseInterfaces(res)
+	inIface, err := parseInterface(res)
 	if err != nil {
 		return err
 	}
-	if len(reqIfaces) > 0 && len(ifaces) > 0 {
-		// We're not supposed to add interfaces if there already are
-		// some. Attempt to roll back
-		return errorWithRollback("driver attempted to add more interfaces", d.DeleteEndpoint(nid, eid))
+	if reqIface != nil && inIface != nil {
+		// We're not supposed to add interface if there is already
+		// one. Attempt to roll back
+		return errorWithRollback("driver attempted to add interface ignoring the one provided", d.DeleteEndpoint(nid, eid))
 	}
-	for _, iface := range ifaces {
+
+	if inIface != nil {
 		var addr4, addr6 net.IPNet
-		if iface.Address != nil {
-			addr4 = *(iface.Address)
+		if inIface.Address != nil {
+			addr4 = *(inIface.Address)
 		}
-		if iface.AddressIPv6 != nil {
-			addr6 = *(iface.AddressIPv6)
+		if inIface.AddressIPv6 != nil {
+			addr6 = *(inIface.AddressIPv6)
 		}
-		if err := epInfo.AddInterface(iface.ID, iface.MacAddress, addr4, addr6); err != nil {
-			return errorWithRollback(fmt.Sprintf("failed to AddInterface %v: %s", iface, err), d.DeleteEndpoint(nid, eid))
+		if err := epInfo.AddInterface(inIface.MacAddress, addr4, addr6); err != nil {
+			return errorWithRollback(fmt.Sprintf("failed to AddInterface %v: %s", inIface, err), d.DeleteEndpoint(nid, eid))
 		}
 	}
 	return nil
@@ -165,18 +167,13 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		return err
 	}
 
-	// Expect each interface ID given by CreateEndpoint to have an
-	// entry at that index in the names supplied here. In other words,
-	// if you supply 0..n interfaces with IDs 0..n above, you should
-	// supply the names in the same order.
-	ifaceNames := res.InterfaceNames
-	for _, iface := range jinfo.InterfaceNames() {
-		i := iface.ID()
-		if i >= len(ifaceNames) || i < 0 {
-			return fmt.Errorf("no correlating interface %d in supplied interface names", i)
-		}
-		supplied := ifaceNames[i]
-		if err := iface.SetNames(supplied.SrcName, supplied.DstPrefix); err != nil {
+	ifaceName := res.InterfaceName
+	if ifaceName == nil {
+		return fmt.Errorf("no interface name information received")
+	}
+
+	if iface := jinfo.InterfaceName(); iface != nil {
+		if err := iface.SetNames(ifaceName.SrcName, ifaceName.DstPrefix); err != nil {
 			return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid))
 		}
 	}
@@ -204,7 +201,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 			return err
 		}
 		for _, route := range routes {
-			if jinfo.AddStaticRoute(route.Destination, route.RouteType, route.NextHop, route.InterfaceID) != nil {
+			if jinfo.AddStaticRoute(route.Destination, route.RouteType, route.NextHop) != nil {
 				return errorWithRollback(fmt.Sprintf("failed to set static route: %v", route), d.Leave(nid, eid))
 			}
 		}
@@ -229,7 +226,7 @@ func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
 	var routes = make([]*types.StaticRoute, len(r.StaticRoutes))
 	for i, inRoute := range r.StaticRoutes {
 		var err error
-		outRoute := &types.StaticRoute{InterfaceID: inRoute.InterfaceID, RouteType: inRoute.RouteType}
+		outRoute := &types.StaticRoute{RouteType: inRoute.RouteType}
 
 		if inRoute.Destination != "" {
 			if outRoute.Destination, err = toAddr(inRoute.Destination); err != nil {
@@ -250,13 +247,13 @@ func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
 }
 
 // parseInterfaces validates all the parameters of an Interface and returns them.
-func parseInterfaces(r api.CreateEndpointResponse) ([]*api.Interface, error) {
-	var (
-		Interfaces = make([]*api.Interface, len(r.Interfaces))
-	)
-	for i, inIf := range r.Interfaces {
+func parseInterface(r api.CreateEndpointResponse) (*api.Interface, error) {
+	var outIf *api.Interface
+
+	inIf := r.Interface
+	if inIf != nil {
 		var err error
-		outIf := &api.Interface{ID: inIf.ID}
+		outIf = &api.Interface{}
 		if inIf.Address != "" {
 			if outIf.Address, err = toAddr(inIf.Address); err != nil {
 				return nil, err
@@ -272,9 +269,9 @@ func parseInterfaces(r api.CreateEndpointResponse) ([]*api.Interface, error) {
 				return nil, err
 			}
 		}
-		Interfaces[i] = outIf
 	}
-	return Interfaces, nil
+
+	return outIf, nil
 }
 
 func toAddr(ipAddr string) (*net.IPNet, error) {

+ 23 - 18
vendor/src/github.com/docker/libnetwork/endpoint.go

@@ -1,6 +1,7 @@
 package libnetwork
 
 import (
+	"container/heap"
 	"encoding/json"
 	"fmt"
 	"net"
@@ -49,7 +50,7 @@ type endpoint struct {
 	name          string
 	id            string
 	network       *network
-	iFaces        []*endpointInterface
+	iface         *endpointInterface
 	joinInfo      *endpointJoinInfo
 	sandboxID     string
 	exposedPorts  []types.TransportPort
@@ -67,7 +68,7 @@ func (ep *endpoint) MarshalJSON() ([]byte, error) {
 	epMap := make(map[string]interface{})
 	epMap["name"] = ep.name
 	epMap["id"] = ep.id
-	epMap["ep_iface"] = ep.iFaces
+	epMap["ep_iface"] = ep.iface
 	epMap["exposed_ports"] = ep.exposedPorts
 	epMap["generic"] = ep.generic
 	epMap["sandbox"] = ep.sandboxID
@@ -86,12 +87,7 @@ func (ep *endpoint) UnmarshalJSON(b []byte) (err error) {
 	ep.id = epMap["id"].(string)
 
 	ib, _ := json.Marshal(epMap["ep_iface"])
-	var ifaces []endpointInterface
-	json.Unmarshal(ib, &ifaces)
-	ep.iFaces = make([]*endpointInterface, 0)
-	for _, iface := range ifaces {
-		ep.iFaces = append(ep.iFaces, &iface)
-	}
+	json.Unmarshal(ib, ep.iface)
 
 	tb, _ := json.Marshal(epMap["exposed_ports"])
 	var tPorts []types.TransportPort
@@ -289,10 +285,25 @@ func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
 		return err
 	}
 
+	sb.Lock()
+	heap.Push(&sb.endpoints, ep)
+	sb.Unlock()
+	defer func() {
+		if err != nil {
+			for i, e := range sb.getConnectedEndpoints() {
+				if e == ep {
+					sb.Lock()
+					heap.Remove(&sb.endpoints, i)
+					sb.Unlock()
+					return
+				}
+			}
+		}
+	}()
+
 	if err = sb.populateNetworkResources(ep); err != nil {
 		return err
 	}
-
 	return nil
 }
 
@@ -300,13 +311,7 @@ func (ep *endpoint) hasInterface(iName string) bool {
 	ep.Lock()
 	defer ep.Unlock()
 
-	for _, iface := range ep.iFaces {
-		if iface.srcName == iName {
-			return true
-		}
-	}
-
-	return false
+	return ep.iface != nil && ep.iface.srcName == iName
 }
 
 func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error {
@@ -463,8 +468,8 @@ func (ep *endpoint) getFirstInterfaceAddress() net.IP {
 	ep.Lock()
 	defer ep.Unlock()
 
-	if len(ep.iFaces) != 0 && ep.iFaces[0] != nil {
-		return ep.iFaces[0].addr.IP
+	if ep.iface != nil {
+		return ep.iface.addr.IP
 	}
 
 	return nil

+ 27 - 41
vendor/src/github.com/docker/libnetwork/endpoint_info.go

@@ -10,9 +10,11 @@ import (
 
 // EndpointInfo provides an interface to retrieve network resources bound to the endpoint.
 type EndpointInfo interface {
-	// InterfaceList returns an interface list which were assigned to the endpoint
-	// by the driver. This can be used after the endpoint has been created.
-	InterfaceList() []InterfaceInfo
+	// Iface returns InterfaceInfo, go interface that can be used
+	// to get more information on the interface which was assigned to
+	// the endpoint by the driver. This can be used after the
+	// endpoint has been created.
+	Iface() InterfaceInfo
 
 	// Gateway returns the IPv4 gateway assigned by the driver.
 	// This will only return a valid value if a container has joined the endpoint.
@@ -39,7 +41,6 @@ type InterfaceInfo interface {
 }
 
 type endpointInterface struct {
-	id        int
 	mac       net.HardwareAddr
 	addr      net.IPNet
 	addrv6    net.IPNet
@@ -50,7 +51,6 @@ type endpointInterface struct {
 
 func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
 	epMap := make(map[string]interface{})
-	epMap["id"] = epi.id
 	epMap["mac"] = epi.mac.String()
 	epMap["addr"] = epi.addr.String()
 	epMap["addrv6"] = epi.addrv6.String()
@@ -69,7 +69,6 @@ func (epi *endpointInterface) UnmarshalJSON(b []byte) (err error) {
 	if err := json.Unmarshal(b, &epMap); err != nil {
 		return err
 	}
-	epi.id = int(epMap["id"].(float64))
 
 	mac, _ := net.ParseMAC(epMap["mac"].(string))
 	epi.mac = mac
@@ -128,51 +127,42 @@ func (ep *endpoint) DriverInfo() (map[string]interface{}, error) {
 	return driver.EndpointOperInfo(nid, epid)
 }
 
-func (ep *endpoint) InterfaceList() []InterfaceInfo {
+func (ep *endpoint) Iface() InterfaceInfo {
 	ep.Lock()
 	defer ep.Unlock()
 
-	iList := make([]InterfaceInfo, len(ep.iFaces))
-
-	for i, iface := range ep.iFaces {
-		iList[i] = iface
+	if ep.iface != nil {
+		return ep.iface
 	}
 
-	return iList
+	return nil
 }
 
-func (ep *endpoint) Interfaces() []driverapi.InterfaceInfo {
+func (ep *endpoint) Interface() driverapi.InterfaceInfo {
 	ep.Lock()
 	defer ep.Unlock()
 
-	iList := make([]driverapi.InterfaceInfo, len(ep.iFaces))
-
-	for i, iface := range ep.iFaces {
-		iList[i] = iface
+	if ep.iface != nil {
+		return ep.iface
 	}
 
-	return iList
+	return nil
 }
 
-func (ep *endpoint) AddInterface(id int, mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error {
+func (ep *endpoint) AddInterface(mac net.HardwareAddr, ipv4 net.IPNet, ipv6 net.IPNet) error {
 	ep.Lock()
 	defer ep.Unlock()
 
 	iface := &endpointInterface{
-		id:     id,
 		addr:   *types.GetIPNetCopy(&ipv4),
 		addrv6: *types.GetIPNetCopy(&ipv6),
 	}
 	iface.mac = types.GetMacCopy(mac)
 
-	ep.iFaces = append(ep.iFaces, iface)
+	ep.iface = iface
 	return nil
 }
 
-func (epi *endpointInterface) ID() int {
-	return epi.id
-}
-
 func (epi *endpointInterface) MacAddress() net.HardwareAddr {
 	return types.GetMacCopy(epi.mac)
 }
@@ -191,24 +181,22 @@ func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
 	return nil
 }
 
-func (ep *endpoint) InterfaceNames() []driverapi.InterfaceNameInfo {
+func (ep *endpoint) InterfaceName() driverapi.InterfaceNameInfo {
 	ep.Lock()
 	defer ep.Unlock()
 
-	iList := make([]driverapi.InterfaceNameInfo, len(ep.iFaces))
-
-	for i, iface := range ep.iFaces {
-		iList[i] = iface
+	if ep.iface != nil {
+		return ep.iface
 	}
 
-	return iList
+	return nil
 }
 
-func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP, interfaceID int) error {
+func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
 	ep.Lock()
 	defer ep.Unlock()
 
-	r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop, InterfaceID: interfaceID}
+	r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop}
 
 	if routeType == types.NEXTHOP {
 		// If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface).
@@ -223,14 +211,12 @@ func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHo
 }
 
 func (ep *endpoint) addInterfaceRoute(route *types.StaticRoute) error {
-	for _, iface := range ep.iFaces {
-		if iface.id == route.InterfaceID {
-			iface.routes = append(iface.routes, route.Destination)
-			return nil
-		}
-	}
-	return types.BadRequestErrorf("Interface with ID %d doesn't exist.",
-		route.InterfaceID)
+	ep.Lock()
+	defer ep.Unlock()
+
+	iface := ep.iface
+	iface.routes = append(iface.routes, route.Destination)
+	return nil
 }
 
 func (ep *endpoint) Sandbox() Sandbox {

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

@@ -305,7 +305,6 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
 	}
 
 	ep := &endpoint{name: name,
-		iFaces:  []*endpointInterface{},
 		generic: make(map[string]interface{})}
 	ep.id = stringid.GenerateRandomID()
 	ep.network = n
@@ -409,7 +408,7 @@ func (n *network) isGlobalScoped() (bool, error) {
 func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
 	n.Lock()
 	var recs []etchosts.Record
-	for _, iface := range ep.InterfaceList() {
+	if iface := ep.Iface(); iface != nil {
 		if isAdd {
 			n.svcRecords[ep.Name()] = iface.Address().IP
 			n.svcRecords[ep.Name()+"."+n.name] = iface.Address().IP

+ 28 - 15
vendor/src/github.com/docker/libnetwork/osl/namespace_linux.go

@@ -157,30 +157,43 @@ func (n *networkNamespace) NeighborOptions() NeighborOptionSetter {
 	return n
 }
 
-func reexecCreateNamespace() {
-	if len(os.Args) < 2 {
-		log.Fatal("no namespace path provided")
-	}
-
-	if err := syscall.Mount("/proc/self/ns/net", os.Args[1], "bind", syscall.MS_BIND, ""); err != nil {
-		log.Fatal(err)
+func mountNetworkNamespace(basePath string, lnPath string) error {
+	if err := syscall.Mount(basePath, lnPath, "bind", syscall.MS_BIND, ""); err != nil {
+		return err
 	}
 
 	if err := loopbackUp(); err != nil {
-		log.Fatal(err)
+		return err
 	}
+	return nil
 }
 
-func createNetworkNamespace(path string, osCreate bool) error {
-	runtime.LockOSThread()
-	defer runtime.UnlockOSThread()
-
-	origns, err := netns.Get()
+// GetSandboxForExternalKey returns sandbox object for the supplied path
+func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) {
+	var err error
+	if err = createNamespaceFile(key); err != nil {
+		return nil, err
+	}
+	n := &networkNamespace{path: basePath}
+	n.InvokeFunc(func() {
+		err = mountNetworkNamespace(basePath, key)
+	})
 	if err != nil {
-		return err
+		return nil, err
+	}
+	return &networkNamespace{path: key}, nil
+}
+
+func reexecCreateNamespace() {
+	if len(os.Args) < 2 {
+		log.Fatal("no namespace path provided")
 	}
-	defer origns.Close()
+	if err := mountNetworkNamespace("/proc/self/ns/net", os.Args[1]); err != nil {
+		log.Fatal(err)
+	}
+}
 
+func createNetworkNamespace(path string, osCreate bool) error {
 	if err := createNamespaceFile(path); err != nil {
 		return err
 	}

+ 4 - 0
vendor/src/github.com/docker/libnetwork/osl/namespace_unsupported.go

@@ -6,3 +6,7 @@ package osl
 // and waits for it.
 func GC() {
 }
+
+func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
+	return nil, nil
+}

+ 4 - 0
vendor/src/github.com/docker/libnetwork/osl/namespace_windows.go

@@ -19,6 +19,10 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
 	return nil, nil
 }
 
+func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
+	return nil, nil
+}
+
 // GC triggers garbage collection of namespace path right away
 // and waits for it.
 func GC() {

+ 83 - 21
vendor/src/github.com/docker/libnetwork/sandbox.go

@@ -32,6 +32,8 @@ type Sandbox interface {
 	// 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
+	// SetKey updates the Sandbox Key
+	SetKey(key string) error
 	// Delete destroys this container after detaching it from all connected endpoints.
 	Delete() error
 }
@@ -102,6 +104,7 @@ type containerConfig struct {
 	resolvConfPathConfig
 	generic           map[string]interface{}
 	useDefaultSandBox bool
+	useExternalKey    bool
 	prio              int // higher the value, more the priority
 }
 
@@ -241,8 +244,14 @@ func (sb *sandbox) getConnectedEndpoints() []*endpoint {
 }
 
 func (sb *sandbox) updateGateway(ep *endpoint) error {
-	sb.osSbox.UnsetGateway()
-	sb.osSbox.UnsetGatewayIPv6()
+	sb.Lock()
+	osSbox := sb.osSbox
+	sb.Unlock()
+	if osSbox == nil {
+		return nil
+	}
+	osSbox.UnsetGateway()
+	osSbox.UnsetGatewayIPv6()
 
 	if ep == nil {
 		return nil
@@ -252,24 +261,66 @@ func (sb *sandbox) updateGateway(ep *endpoint) error {
 	joinInfo := ep.joinInfo
 	ep.Unlock()
 
-	if err := sb.osSbox.SetGateway(joinInfo.gw); err != nil {
+	if err := 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 {
+	if err := osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil {
 		return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err)
 	}
 
 	return nil
 }
 
+func (sb *sandbox) SetKey(basePath string) error {
+	var err error
+	if basePath == "" {
+		return types.BadRequestErrorf("invalid sandbox key")
+	}
+
+	sb.Lock()
+	if sb.osSbox != nil {
+		sb.Unlock()
+		return types.ForbiddenErrorf("failed to set sandbox key : already assigned")
+	}
+	sb.Unlock()
+	osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key())
+	if err != nil {
+		return err
+	}
+	sb.Lock()
+	sb.osSbox = osSbox
+	sb.Unlock()
+	defer func() {
+		if err != nil {
+			sb.Lock()
+			sb.osSbox = nil
+			sb.Unlock()
+		}
+	}()
+
+	for _, ep := range sb.getConnectedEndpoints() {
+		if err = sb.populateNetworkResources(ep); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
+	sb.Lock()
+	if sb.osSbox == nil {
+		sb.Unlock()
+		return nil
+	}
+	sb.Unlock()
+
 	ep.Lock()
 	joinInfo := ep.joinInfo
-	ifaces := ep.iFaces
+	i := ep.iface
 	ep.Unlock()
 
-	for _, i := range ifaces {
+	if i != nil {
 		var ifaceOptions []osl.IfaceOption
 
 		ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().Address(&i.addr), sb.osSbox.InterfaceOptions().Routes(i.routes))
@@ -292,7 +343,6 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
 	}
 
 	sb.Lock()
-	heap.Push(&sb.endpoints, ep)
 	highEp := sb.endpoints[0]
 	sb.Unlock()
 	if ep == highEp {
@@ -305,24 +355,28 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
 }
 
 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)
+	sb.Lock()
+	osSbox := sb.osSbox
+	sb.Unlock()
+	if osSbox != nil {
+		for _, i := range 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()
+		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)
+		// Remove non-interface routes.
+		for _, r := range joinInfo.StaticRoutes {
+			if err := osSbox.RemoveStaticRoute(r); err != nil {
+				log.Debugf("Remove route failed: %v", err)
+			}
 		}
 	}
 
@@ -670,6 +724,14 @@ func OptionUseDefaultSandbox() SandboxOption {
 	}
 }
 
+// OptionUseExternalKey function returns an option setter for using provided namespace
+// instead of creating one.
+func OptionUseExternalKey() SandboxOption {
+	return func(sb *sandbox) {
+		sb.config.useExternalKey = 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.

+ 185 - 0
vendor/src/github.com/docker/libnetwork/sandbox_externalkey.go

@@ -0,0 +1,185 @@
+package libnetwork
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net"
+	"os"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/pkg/reexec"
+	"github.com/docker/libnetwork/types"
+	"github.com/opencontainers/runc/libcontainer"
+	"github.com/opencontainers/runc/libcontainer/configs"
+)
+
+type setKeyData struct {
+	ContainerID string
+	Key         string
+}
+
+func init() {
+	reexec.Register("libnetwork-setkey", processSetKeyReexec)
+}
+
+const udsBase = "/var/lib/docker/network/files/"
+const success = "success"
+
+// processSetKeyReexec is a private function that must be called only on an reexec path
+// It expects 3 args { [0] = "libnetwork-setkey", [1] = <container-id>, [2] = <controller-id> }
+// It also expects libcontainer.State as a json string in <stdin>
+// Refer to https://github.com/opencontainers/runc/pull/160/ for more information
+func processSetKeyReexec() {
+	var err error
+
+	// Return a failure to the calling process via ExitCode
+	defer func() {
+		if err != nil {
+			logrus.Fatalf("%v", err)
+		}
+	}()
+
+	// expecting 3 args {[0]="libnetwork-setkey", [1]=<container-id>, [2]=<controller-id> }
+	if len(os.Args) < 3 {
+		err = fmt.Errorf("Re-exec expects 3 args, received : %d", len(os.Args))
+		return
+	}
+	containerID := os.Args[1]
+
+	// We expect libcontainer.State as a json string in <stdin>
+	stateBuf, err := ioutil.ReadAll(os.Stdin)
+	if err != nil {
+		return
+	}
+	var state libcontainer.State
+	if err = json.Unmarshal(stateBuf, &state); err != nil {
+		return
+	}
+
+	controllerID := os.Args[2]
+	key := state.NamespacePaths[configs.NamespaceType("NEWNET")]
+
+	err = SetExternalKey(controllerID, containerID, key)
+	return
+}
+
+// SetExternalKey provides a convenient way to set an External key to a sandbox
+func SetExternalKey(controllerID string, containerID string, key string) error {
+	keyData := setKeyData{
+		ContainerID: containerID,
+		Key:         key}
+
+	c, err := net.Dial("unix", udsBase+controllerID+".sock")
+	if err != nil {
+		return err
+	}
+	defer c.Close()
+
+	if err = sendKey(c, keyData); err != nil {
+		return fmt.Errorf("sendKey failed with : %v", err)
+	}
+	return processReturn(c)
+}
+
+func sendKey(c net.Conn, data setKeyData) error {
+	var err error
+	defer func() {
+		if err != nil {
+			c.Close()
+		}
+	}()
+
+	var b []byte
+	if b, err = json.Marshal(data); err != nil {
+		return err
+	}
+
+	_, err = c.Write(b)
+	return err
+}
+
+func processReturn(r io.Reader) error {
+	buf := make([]byte, 1024)
+	n, err := r.Read(buf[:])
+	if err != nil {
+		return fmt.Errorf("failed to read buf in processReturn : %v", err)
+	}
+	if string(buf[0:n]) != success {
+		return fmt.Errorf(string(buf[0:n]))
+	}
+	return nil
+}
+
+func (c *controller) startExternalKeyListener() error {
+	if err := os.MkdirAll(udsBase, 0600); err != nil {
+		return err
+	}
+	uds := udsBase + c.id + ".sock"
+	l, err := net.Listen("unix", uds)
+	if err != nil {
+		return err
+	}
+	if err := os.Chmod(uds, 0600); err != nil {
+		l.Close()
+		return err
+	}
+	c.Lock()
+	c.extKeyListener = l
+	c.Unlock()
+
+	go c.acceptClientConnections(uds, l)
+	return nil
+}
+
+func (c *controller) acceptClientConnections(sock string, l net.Listener) {
+	for {
+		conn, err := l.Accept()
+		if err != nil {
+			if _, err1 := os.Stat(sock); os.IsNotExist(err1) {
+				logrus.Warnf("Unix socket %s doesnt exist. cannot accept client connections", sock)
+				return
+			}
+			logrus.Errorf("Error accepting connection %v", err)
+			continue
+		}
+		go func() {
+			err := c.processExternalKey(conn)
+			ret := success
+			if err != nil {
+				ret = err.Error()
+			}
+
+			_, err = conn.Write([]byte(ret))
+			if err != nil {
+				logrus.Errorf("Error returning to the client %v", err)
+			}
+		}()
+	}
+}
+
+func (c *controller) processExternalKey(conn net.Conn) error {
+	buf := make([]byte, 1280)
+	nr, err := conn.Read(buf)
+	if err != nil {
+		return err
+	}
+	var s setKeyData
+	if err = json.Unmarshal(buf[0:nr], &s); err != nil {
+		return err
+	}
+
+	var sandbox Sandbox
+	search := SandboxContainerWalker(&sandbox, s.ContainerID)
+	c.WalkSandboxes(search)
+	if sandbox == nil {
+		return types.BadRequestErrorf("no sandbox present for %s", s.ContainerID)
+	}
+
+	return sandbox.SetKey(s.Key)
+}
+
+func (c *controller) stopExternalKeyListener() {
+	c.extKeyListener.Close()
+}

+ 3 - 9
vendor/src/github.com/docker/libnetwork/types/types.go

@@ -266,12 +266,6 @@ type StaticRoute struct {
 
 	// NextHop will be resolved by the kernel (i.e. as a loose hop).
 	NextHop net.IP
-
-	// InterfaceID must refer to a defined interface on the
-	// Endpoint to which the routes are specified.  Routes specified this way
-	// are interpreted as directly connected to the specified interface (no
-	// next hop will be used).
-	InterfaceID int
 }
 
 // GetCopy returns a copy of this StaticRoute structure
@@ -279,9 +273,9 @@ func (r *StaticRoute) GetCopy() *StaticRoute {
 	d := GetIPNetCopy(r.Destination)
 	nh := GetIPCopy(r.NextHop)
 	return &StaticRoute{Destination: d,
-		RouteType:   r.RouteType,
-		NextHop:     nh,
-		InterfaceID: r.InterfaceID}
+		RouteType: r.RouteType,
+		NextHop:   nh,
+	}
 }
 
 /******************************