Explorar el Código

Merge pull request #21019 from aboch/se

Add port configs to Sandbox and libnetwork vendoring
Brian Goff hace 9 años
padre
commit
d99be399c3
Se han modificado 49 ficheros con 1274 adiciones y 277 borrados
  1. 1 5
      container/container_unix.go
  2. 59 0
      daemon/container_operations_unix.go
  3. 2 2
      hack/vendor.sh
  4. 1 1
      integration-cli/docker_cli_network_unix_test.go
  5. 21 1
      vendor/src/github.com/docker/libnetwork/CHANGELOG.md
  6. 6 0
      vendor/src/github.com/docker/libnetwork/MAINTAINERS
  7. 1 1
      vendor/src/github.com/docker/libnetwork/bitseq/sequence.go
  8. 1 1
      vendor/src/github.com/docker/libnetwork/controller.go
  9. 1 1
      vendor/src/github.com/docker/libnetwork/datastore/datastore.go
  10. 26 18
      vendor/src/github.com/docker/libnetwork/default_gateway.go
  11. 1 1
      vendor/src/github.com/docker/libnetwork/discoverapi/discoverapi.go
  12. 10 2
      vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go
  13. 2 2
      vendor/src/github.com/docker/libnetwork/driverapi/ipamdata.go
  14. 2 0
      vendor/src/github.com/docker/libnetwork/drivers.go
  15. 124 72
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
  16. 3 3
      vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go
  17. 8 0
      vendor/src/github.com/docker/libnetwork/drivers/host/host.go
  18. 8 0
      vendor/src/github.com/docker/libnetwork/drivers/null/null.go
  19. 1 1
      vendor/src/github.com/docker/libnetwork/drivers/overlay/filter.go
  20. 1 1
      vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go
  21. 11 0
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go
  22. 23 0
      vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go
  23. 34 0
      vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go
  24. 128 20
      vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go
  25. 4 4
      vendor/src/github.com/docker/libnetwork/drivers_windows.go
  26. 90 48
      vendor/src/github.com/docker/libnetwork/endpoint.go
  27. 14 2
      vendor/src/github.com/docker/libnetwork/etchosts/etchosts.go
  28. 1 1
      vendor/src/github.com/docker/libnetwork/idm/idm.go
  29. 2 2
      vendor/src/github.com/docker/libnetwork/ipam/structures.go
  30. 1 1
      vendor/src/github.com/docker/libnetwork/ipam/utils.go
  31. 3 1
      vendor/src/github.com/docker/libnetwork/ipamapi/contract.go
  32. 71 0
      vendor/src/github.com/docker/libnetwork/ipams/null/null.go
  33. 9 3
      vendor/src/github.com/docker/libnetwork/ipams/windowsipam/windowsipam.go
  34. 42 12
      vendor/src/github.com/docker/libnetwork/iptables/iptables.go
  35. 14 3
      vendor/src/github.com/docker/libnetwork/network.go
  36. 16 0
      vendor/src/github.com/docker/libnetwork/osl/interface_linux.go
  37. 6 0
      vendor/src/github.com/docker/libnetwork/osl/options_linux.go
  38. 3 0
      vendor/src/github.com/docker/libnetwork/osl/sandbox.go
  39. 138 36
      vendor/src/github.com/docker/libnetwork/resolver.go
  40. 86 19
      vendor/src/github.com/docker/libnetwork/sandbox.go
  41. 1 1
      vendor/src/github.com/docker/libnetwork/sandbox_externalkey_unix.go
  42. 5 5
      vendor/src/github.com/docker/libnetwork/types/types.go
  43. 4 0
      vendor/src/github.com/vishvananda/netlink/addr_linux.go
  44. 1 0
      vendor/src/github.com/vishvananda/netlink/class.go
  45. 20 2
      vendor/src/github.com/vishvananda/netlink/class_linux.go
  46. 1 0
      vendor/src/github.com/vishvananda/netlink/link.go
  47. 55 2
      vendor/src/github.com/vishvananda/netlink/link_linux.go
  48. 212 0
      vendor/src/github.com/vishvananda/netlink/nl/link_linux.go
  49. 0 3
      vendor/src/github.com/vishvananda/netlink/xfrm_state_linux.go

+ 1 - 5
container/container_unix.go

@@ -290,7 +290,6 @@ func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork
 // BuildCreateEndpointOptions builds endpoint options from a given network.
 func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *network.EndpointSettings, sb libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) {
 	var (
-		portSpecs     = make(nat.PortSet)
 		bindings      = make(nat.PortMap)
 		pbList        []types.PortBinding
 		exposeList    []types.TransportPort
@@ -343,10 +342,6 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC
 		return createOptions, nil
 	}
 
-	if container.Config.ExposedPorts != nil {
-		portSpecs = container.Config.ExposedPorts
-	}
-
 	if container.HostConfig.PortBindings != nil {
 		for p, b := range container.HostConfig.PortBindings {
 			bindings[p] = []nat.PortBinding{}
@@ -359,6 +354,7 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC
 		}
 	}
 
+	portSpecs := container.Config.ExposedPorts
 	ports := make([]nat.Port, len(portSpecs))
 	var i int
 	for p := range portSpecs {

+ 59 - 0
daemon/container_operations_unix.go

@@ -4,6 +4,7 @@ package daemon
 
 import (
 	"fmt"
+	"net"
 	"os"
 	"path"
 	"path/filepath"
@@ -25,10 +26,12 @@ import (
 	"github.com/docker/docker/runconfig"
 	containertypes "github.com/docker/engine-api/types/container"
 	networktypes "github.com/docker/engine-api/types/network"
+	"github.com/docker/go-connections/nat"
 	"github.com/docker/go-units"
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
+	"github.com/docker/libnetwork/types"
 	"github.com/opencontainers/runc/libcontainer/configs"
 	"github.com/opencontainers/runc/libcontainer/devices"
 	"github.com/opencontainers/runc/libcontainer/label"
@@ -320,6 +323,9 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libn
 		dns         []string
 		dnsSearch   []string
 		dnsOptions  []string
+		bindings    = make(nat.PortMap)
+		pbList      []types.PortBinding
+		exposeList  []types.TransportPort
 	)
 
 	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
@@ -394,6 +400,59 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container, n libn
 		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
 	}
 
+	if container.HostConfig.PortBindings != nil {
+		for p, b := range container.HostConfig.PortBindings {
+			bindings[p] = []nat.PortBinding{}
+			for _, bb := range b {
+				bindings[p] = append(bindings[p], nat.PortBinding{
+					HostIP:   bb.HostIP,
+					HostPort: bb.HostPort,
+				})
+			}
+		}
+	}
+
+	portSpecs := container.Config.ExposedPorts
+	ports := make([]nat.Port, len(portSpecs))
+	var i int
+	for p := range portSpecs {
+		ports[i] = p
+		i++
+	}
+	nat.SortPortMap(ports, bindings)
+	for _, port := range ports {
+		expose := types.TransportPort{}
+		expose.Proto = types.ParseProtocol(port.Proto())
+		expose.Port = uint16(port.Int())
+		exposeList = append(exposeList, expose)
+
+		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
+		binding := bindings[port]
+		for i := 0; i < len(binding); i++ {
+			pbCopy := pb.GetCopy()
+			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
+			var portStart, portEnd int
+			if err == nil {
+				portStart, portEnd, err = newP.Range()
+			}
+			if err != nil {
+				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
+			}
+			pbCopy.HostPort = uint16(portStart)
+			pbCopy.HostPortEnd = uint16(portEnd)
+			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
+			pbList = append(pbList, pbCopy)
+		}
+
+		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
+			pbList = append(pbList, pb)
+		}
+	}
+
+	sboxOptions = append(sboxOptions,
+		libnetwork.OptionPortMapping(pbList),
+		libnetwork.OptionExposedPorts(exposeList))
+
 	// Link feature is supported only for the default bridge network.
 	// return if this call to build join options is not for default bridge network
 	if n.Name() != "bridge" {

+ 2 - 2
hack/vendor.sh

@@ -29,14 +29,14 @@ clone git github.com/RackSec/srslog 6eb773f331e46fbba8eecb8e794e635e75fc04de
 clone git github.com/imdario/mergo 0.2.1
 
 #get libnetwork packages
-clone git github.com/docker/libnetwork v0.7.0-dev.3
+clone git github.com/docker/libnetwork v0.7.0-dev.5
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
 clone git github.com/hashicorp/serf 7151adcef72687bf95f451a2e0ba15cb19412bf2
 clone git github.com/docker/libkv c2aac5dbbaa5c872211edea7c0f32b3bd67e7410
 clone git github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
-clone git github.com/vishvananda/netlink bfd70f556483c008636b920dda142fdaa0d59ef9
+clone git github.com/vishvananda/netlink 631962935bff4f3d20ff32a72e8944f6d2836a26
 clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
 clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
 clone git github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d

+ 1 - 1
integration-cli/docker_cli_network_unix_test.go

@@ -1432,7 +1432,7 @@ func (s *DockerSuite) TestDockerNetworkInternalMode(c *check.C) {
 	c.Assert(waitRun("second"), check.IsNil)
 	out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "www.google.com")
 	c.Assert(err, check.NotNil)
-	c.Assert(out, checker.Contains, "100% packet loss")
+	c.Assert(out, checker.Contains, "ping: bad address")
 	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
 	c.Assert(err, check.IsNil)
 }

+ 21 - 1
vendor/src/github.com/docker/libnetwork/CHANGELOG.md

@@ -1,5 +1,25 @@
 # Changelog
 
+## 0.7.0-dev.5 (2016-03-08)
+- Fixes https://github.com/docker/docker/issues/20847
+- Fixes https://github.com/docker/docker/issues/20997
+- Fixes issues unveiled by docker integ test over 0.7.0-dev.4
+
+## 0.7.0-dev.4 (2016-03-07)
+- Changed ownership of exposed ports and port-mapping options from Endpoint to Sandbox
+- Implement DNS RR in the Docker embedded DNS server
+- Fixes https://github.com/docker/libnetwork/issues/984 (multi container overlay veth leak)
+- Libnetwork to program container's interface MAC address
+- Fixed bug in iptables.Exists() logic
+- Fixes https://github.com/docker/docker/issues/20694
+- Source external DNS queries from container namespace
+- Added inbuilt nil IPAM driver
+- Windows drivers integration fixes
+- Extract hostname from (hostname.domainname). Related to https://github.com/docker/docker/issues/14282
+- Fixed race in sandbox statistics read
+- Fixes https://github.com/docker/libnetwork/issues/892 (docker start fails when ipv6.disable=1)
+- Fixed error message on bridge network creation conflict
+
 ## 0.7.0-dev.3 (2016-02-17)
 - Fixes https://github.com/docker/docker/issues/20350
 - Fixes https://github.com/docker/docker/issues/20145
@@ -90,7 +110,7 @@
 - DEPRECATE service discovery from default bridge network
 - Introduced new network UX
 - Support for multiple networks in bridge driver
-- Local persistance with boltdb
+- Local persistence with boltdb
 
 ## 0.4.0 (2015-07-24)
 

+ 6 - 0
vendor/src/github.com/docker/libnetwork/MAINTAINERS

@@ -17,6 +17,7 @@
 			"mrjana",
 			"mavenugo",
                         "sanimej",
+                        "chenchun",
 		]
 
 [people]
@@ -37,6 +38,11 @@
 	Email = "lk4d4@docker.com"
 	GitHub = "LK4D4"
 
+	[people.chenchun]
+	Name = "Chun Chen"
+	Email = "ramichen@tencent.com"
+	GitHub = "chenchun"
+
 	[people.icecrime]
 	Name = "Arnaud Porterie"
 	Email = "arnaud@docker.com"

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

@@ -163,7 +163,7 @@ func (s *sequence) toByteArray() ([]byte, error) {
 func (s *sequence) fromByteArray(data []byte) error {
 	l := len(data)
 	if l%12 != 0 {
-		return fmt.Errorf("cannot deserialize byte sequence of lenght %d (%v)", l, data)
+		return fmt.Errorf("cannot deserialize byte sequence of length %d (%v)", l, data)
 	}
 
 	p := s

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

@@ -170,7 +170,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
 
 	if c.cfg != nil && c.cfg.Cluster.Watcher != nil {
 		if err := c.initDiscovery(c.cfg.Cluster.Watcher); err != nil {
-			// Failing to initalize discovery is a bad situation to be in.
+			// Failing to initialize discovery is a bad situation to be in.
 			// But it cannot fail creating the Controller
 			log.Errorf("Failed to Initialize Discovery : %v", err)
 		}

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

@@ -31,7 +31,7 @@ type DataStore interface {
 	DeleteObjectAtomic(kvObject KVObject) error
 	// DeleteTree deletes a record
 	DeleteTree(kvObject KVObject) error
-	// Watchable returns whether the store is watchable are not
+	// Watchable returns whether the store is watchable or not
 	Watchable() bool
 	// Watch for changes on a KVObject
 	Watch(kvObject KVObject, stopCh <-chan struct{}) (<-chan KVObject, error)

+ 26 - 18
vendor/src/github.com/docker/libnetwork/default_gateway.go

@@ -3,7 +3,6 @@ package libnetwork
 import (
 	"fmt"
 
-	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -28,15 +27,15 @@ var procGwNetwork = make(chan (bool), 1)
    - its deleted when an endpoint with GW joins the container
 */
 
-func (sb *sandbox) setupDefaultGW(srcEp *endpoint) error {
-	var createOptions []EndpointOption
-	c := srcEp.getNetwork().getController()
+func (sb *sandbox) setupDefaultGW() error {
 
 	// check if the conitainer already has a GW endpoint
 	if ep := sb.getEndpointInGWNetwork(); ep != nil {
 		return nil
 	}
 
+	c := sb.controller
+
 	// Look for default gw network. In case of error (includes not found),
 	// retry and create it if needed in a serialized execution.
 	n, err := c.NetworkByName(libnGWNetwork)
@@ -46,19 +45,7 @@ func (sb *sandbox) setupDefaultGW(srcEp *endpoint) error {
 		}
 	}
 
-	if opt, ok := srcEp.generic[netlabel.PortMap]; ok {
-		if pb, ok := opt.([]types.PortBinding); ok {
-			createOptions = append(createOptions, CreateOptionPortMapping(pb))
-		}
-	}
-
-	if opt, ok := srcEp.generic[netlabel.ExposedPorts]; ok {
-		if exp, ok := opt.([]types.TransportPort); ok {
-			createOptions = append(createOptions, CreateOptionExposedPorts(exp))
-		}
-	}
-
-	createOptions = append(createOptions, CreateOptionAnonymous())
+	createOptions := []EndpointOption{CreateOptionAnonymous()}
 
 	eplen := gwEPlen
 	if len(sb.containerID) < gwEPlen {
@@ -74,9 +61,13 @@ func (sb *sandbox) setupDefaultGW(srcEp *endpoint) error {
 	if err := epLocal.sbJoin(sb); err != nil {
 		return fmt.Errorf("container %s: endpoint join on GW Network failed: %v", sb.containerID, err)
 	}
+
 	return nil
 }
 
+// If present, removes the endpoint connecting the sandbox to the default gw network.
+// Unless it is the endpoint designated to provide the external connectivity.
+// If the sandbox is being deleted, removes the endpoint unconditionally.
 func (sb *sandbox) clearDefaultGW() error {
 	var ep *endpoint
 
@@ -84,6 +75,10 @@ func (sb *sandbox) clearDefaultGW() error {
 		return nil
 	}
 
+	if ep == sb.getGatewayEndpoint() && !sb.inDelete {
+		return nil
+	}
+
 	if err := ep.sbLeave(sb, false); err != nil {
 		return fmt.Errorf("container %s: endpoint leaving GW Network failed: %v", sb.containerID, err)
 	}
@@ -98,7 +93,7 @@ func (sb *sandbox) needDefaultGW() bool {
 
 	for _, ep := range sb.getConnectedEndpoints() {
 		if ep.endpointInGWNetwork() {
-			continue
+			return false
 		}
 		if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" {
 			continue
@@ -165,3 +160,16 @@ func (c *controller) defaultGwNetwork() (Network, error) {
 	}
 	return n, err
 }
+
+// Returns the endpoint which is providing external connectivity to the sandbox
+func (sb *sandbox) getGatewayEndpoint() *endpoint {
+	for _, ep := range sb.getConnectedEndpoints() {
+		if ep.getNetwork().Type() == "null" || ep.getNetwork().Type() == "host" {
+			continue
+		}
+		if len(ep.Gateway()) != 0 {
+			return ep
+		}
+	}
+	return nil
+}

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

@@ -16,7 +16,7 @@ type DiscoveryType int
 const (
 	// NodeDiscovery represents Node join/leave events provided by discovery
 	NodeDiscovery = iota + 1
-	// DatastoreConfig represents a add/remove datastore event
+	// DatastoreConfig represents an add/remove datastore event
 	DatastoreConfig
 )
 

+ 10 - 2
vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go

@@ -42,6 +42,14 @@ type Driver interface {
 	// Leave method is invoked when a Sandbox detaches from an endpoint.
 	Leave(nid, eid string) error
 
+	// ProgramExternalConnectivity invokes the driver method which does the necessary
+	// programming to allow the external connectivity dictated by the passed options
+	ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error
+
+	// RevokeExternalConnectivity aks the driver to remove any external connectivity
+	// programming that was done so far
+	RevokeExternalConnectivity(nid, eid string) error
+
 	// Type returns the the type of this driver, the network type this driver manages
 	Type() string
 }
@@ -88,8 +96,8 @@ type JoinInfo interface {
 	// SetGatewayIPv6 sets the default IPv6 gateway when a container joins the endpoint.
 	SetGatewayIPv6(net.IP) error
 
-	// AddStaticRoute adds a routes to the sandbox.
-	// It may be used in addtion to or instead of a default gateway (as above).
+	// AddStaticRoute adds a route to the sandbox.
+	// It may be used in addition to or instead of a default gateway (as above).
 	AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error
 
 	// DisableGatewayService tells libnetwork not to provide Default GW for the container

+ 2 - 2
vendor/src/github.com/docker/libnetwork/driverapi/ipamdata.go

@@ -64,7 +64,7 @@ func (i *IPAMData) UnmarshalJSON(data []byte) error {
 	return nil
 }
 
-// Validate checks wheter the IPAMData structure contains congruent data
+// Validate checks whether the IPAMData structure contains congruent data
 func (i *IPAMData) Validate() error {
 	var isV6 bool
 	if i.Pool == nil {
@@ -93,7 +93,7 @@ func (i *IPAMData) Validate() error {
 	return nil
 }
 
-// IsV6 returns wheter this is an IPv6 IPAMData structure
+// IsV6 returns whether this is an IPv6 IPAMData structure
 func (i *IPAMData) IsV6() bool {
 	return nil == i.Pool.IP.To4()
 }

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

@@ -9,6 +9,7 @@ import (
 	"github.com/docker/libnetwork/netlabel"
 
 	builtinIpam "github.com/docker/libnetwork/ipams/builtin"
+	nullIpam "github.com/docker/libnetwork/ipams/null"
 	remoteIpam "github.com/docker/libnetwork/ipams/remote"
 )
 
@@ -73,6 +74,7 @@ func initIpams(ic ipamapi.Callback, lDs, gDs interface{}) error {
 	for _, fn := range [](func(ipamapi.Callback, interface{}, interface{}) error){
 		builtinIpam.Init,
 		remoteIpam.Init,
+		nullIpam.Init,
 	} {
 		if err := fn(ic, lDs, gDs); err != nil {
 			return err

+ 124 - 72
vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go

@@ -74,9 +74,7 @@ type networkConfiguration struct {
 
 // endpointConfiguration represents the user specified configuration for the sandbox endpoint
 type endpointConfiguration struct {
-	MacAddress   net.HardwareAddr
-	PortBindings []types.PortBinding
-	ExposedPorts []types.TransportPort
+	MacAddress net.HardwareAddr
 }
 
 // containerConfiguration represents the user specified configuration for a container
@@ -85,6 +83,12 @@ type containerConfiguration struct {
 	ChildEndpoints  []string
 }
 
+// cnnectivityConfiguration represents the user specified configuration regarding the external connectivity
+type connectivityConfiguration struct {
+	PortBindings []types.PortBinding
+	ExposedPorts []types.TransportPort
+}
+
 type bridgeEndpoint struct {
 	id              string
 	srcName         string
@@ -93,6 +97,7 @@ type bridgeEndpoint struct {
 	macAddress      net.HardwareAddr
 	config          *endpointConfiguration // User specified parameters
 	containerConfig *containerConfiguration
+	extConnConfig   *connectivityConfiguration
 	portMapping     []types.PortBinding // Operation port bindings
 }
 
@@ -183,7 +188,7 @@ func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
 		return fmt.Errorf("same configuration")
 	}
 
-	// Also empty, becasue only one network with empty name is allowed
+	// Also empty, because only one network with empty name is allowed
 	if c.BridgeName == o.BridgeName {
 		return fmt.Errorf("networks have same bridge name")
 	}
@@ -450,7 +455,7 @@ func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error)
 
 func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
 	if len(ipamV4Data) > 1 || len(ipamV6Data) > 1 {
-		return types.ForbiddenErrorf("bridge driver doesnt support multiple subnets")
+		return types.ForbiddenErrorf("bridge driver doesn't support multiple subnets")
 	}
 
 	if len(ipamV4Data) == 0 {
@@ -543,6 +548,9 @@ func (d *driver) getNetworks() []*bridgeNetwork {
 
 // Create a new network using bridge plugin
 func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
+	if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
+		return types.BadRequestErrorf("ipv4 pool is empty")
+	}
 	// Sanity checks
 	d.Lock()
 	if _, ok := d.networks[id]; ok {
@@ -581,7 +589,7 @@ func (d *driver) createNetwork(config *networkConfiguration) error {
 		nw.Unlock()
 		if err := nwConfig.Conflicts(config); err != nil {
 			return types.ForbiddenErrorf("cannot create network %s (%s): conflicts with network %s (%s): %s",
-				nwConfig.BridgeName, config.ID, nw.id, nw.config.BridgeName, err.Error())
+				config.ID, config.BridgeName, nwConfig.ID, nwConfig.BridgeName, err.Error())
 		}
 	}
 
@@ -948,28 +956,19 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 		}
 	}
 
-	// Create the sandbox side pipe interface
+	// Store the sandbox side pipe interface parameters
 	endpoint.srcName = containerIfName
 	endpoint.macAddress = ifInfo.MacAddress()
 	endpoint.addr = ifInfo.Address()
 	endpoint.addrv6 = ifInfo.AddressIPv6()
 
-	// Down the interface before configuring mac address.
-	if err = netlink.LinkSetDown(sbox); err != nil {
-		return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err)
-	}
-
-	// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
+	// Set the sbox's MAC if not provided. If specified, use the one configured by user, otherwise generate one based on IP.
 	if endpoint.macAddress == nil {
 		endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP)
-		if err := ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
+		if err = ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
 			return err
 		}
 	}
-	err = netlink.LinkSetHardwareAddr(sbox, endpoint.macAddress)
-	if err != nil {
-		return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err)
-	}
 
 	// Up the host interface after finishing all netlink configuration
 	if err = netlink.LinkSetUp(host); err != nil {
@@ -996,17 +995,11 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 		}
 
 		endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
-		if err := ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
+		if err = ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
 			return err
 		}
 	}
 
-	// Program any required port mapping and store them in the endpoint
-	endpoint.portMapping, err = n.allocatePorts(epConfig, endpoint, config.DefaultBindingIP, d.config.EnableUserlandProxy)
-	if err != nil {
-		return err
-	}
-
 	return nil
 }
 
@@ -1061,9 +1054,6 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
 		}
 	}()
 
-	// Remove port mappings. Do not stop endpoint delete on unmap failure
-	n.releasePorts(ep)
-
 	// Try removal of link. Discard error: it is a best effort.
 	// Also make sure defer does not see this error either.
 	if link, err := netlink.LinkByName(ep.srcName); err == nil {
@@ -1104,10 +1094,10 @@ func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, erro
 
 	m := make(map[string]interface{})
 
-	if ep.config.ExposedPorts != nil {
+	if ep.extConnConfig != nil && ep.extConnConfig.ExposedPorts != nil {
 		// Return a copy of the config data
-		epc := make([]types.TransportPort, 0, len(ep.config.ExposedPorts))
-		for _, tp := range ep.config.ExposedPorts {
+		epc := make([]types.TransportPort, 0, len(ep.extConnConfig.ExposedPorts))
+		for _, tp := range ep.extConnConfig.ExposedPorts {
 			epc = append(epc, tp.GetCopy())
 		}
 		m[netlabel.ExposedPorts] = epc
@@ -1147,6 +1137,11 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		return EndpointNotFoundError(eid)
 	}
 
+	endpoint.containerConfig, err = parseContainerOptions(options)
+	if err != nil {
+		return err
+	}
+
 	iNames := jinfo.InterfaceName()
 	err = iNames.SetNames(endpoint.srcName, containerVethPrefix)
 	if err != nil {
@@ -1163,10 +1158,6 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		return err
 	}
 
-	if !network.config.EnableICC {
-		return d.link(network, endpoint, options, true)
-	}
-
 	return nil
 }
 
@@ -1189,32 +1180,87 @@ func (d *driver) Leave(nid, eid string) error {
 	}
 
 	if !network.config.EnableICC {
-		return d.link(network, endpoint, nil, false)
+		if err = d.link(network, endpoint, false); err != nil {
+			return err
+		}
 	}
 
 	return nil
 }
 
-func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options map[string]interface{}, enable bool) error {
-	var (
-		cc  *containerConfiguration
-		err error
-	)
+func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
+	defer osl.InitOSContext()()
 
-	if enable {
-		cc, err = parseContainerOptions(options)
-		if err != nil {
-			return err
-		}
-	} else {
-		cc = endpoint.containerConfig
+	network, err := d.getNetwork(nid)
+	if err != nil {
+		return err
 	}
 
+	endpoint, err := network.getEndpoint(eid)
+	if err != nil {
+		return err
+	}
+
+	if endpoint == nil {
+		return EndpointNotFoundError(eid)
+	}
+
+	endpoint.extConnConfig, err = parseConnectivityOptions(options)
+	if err != nil {
+		return err
+	}
+
+	// Program any required port mapping and store them in the endpoint
+	endpoint.portMapping, err = network.allocatePorts(endpoint, network.config.DefaultBindingIP, d.config.EnableUserlandProxy)
+	if err != nil {
+		return err
+	}
+
+	if !network.config.EnableICC {
+		return d.link(network, endpoint, true)
+	}
+
+	return nil
+}
+
+func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
+	defer osl.InitOSContext()()
+
+	network, err := d.getNetwork(nid)
+	if err != nil {
+		return err
+	}
+
+	endpoint, err := network.getEndpoint(eid)
+	if err != nil {
+		return err
+	}
+
+	if endpoint == nil {
+		return EndpointNotFoundError(eid)
+	}
+
+	err = network.releasePorts(endpoint)
+	if err != nil {
+		logrus.Warn(err)
+	}
+
+	return nil
+}
+
+func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, enable bool) error {
+	var err error
+
+	cc := endpoint.containerConfig
 	if cc == nil {
 		return nil
 	}
+	ec := endpoint.extConnConfig
+	if ec == nil {
+		return nil
+	}
 
-	if endpoint.config != nil && endpoint.config.ExposedPorts != nil {
+	if ec.ExposedPorts != nil {
 		for _, p := range cc.ParentEndpoints {
 			var parentEndpoint *bridgeEndpoint
 			parentEndpoint, err = network.getEndpoint(p)
@@ -1228,7 +1274,7 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
 
 			l := newLink(parentEndpoint.addr.IP.String(),
 				endpoint.addr.IP.String(),
-				endpoint.config.ExposedPorts, network.config.BridgeName)
+				ec.ExposedPorts, network.config.BridgeName)
 			if enable {
 				err = l.Enable()
 				if err != nil {
@@ -1255,13 +1301,13 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
 			err = InvalidEndpointIDError(c)
 			return err
 		}
-		if childEndpoint.config == nil || childEndpoint.config.ExposedPorts == nil {
+		if childEndpoint.extConnConfig == nil || childEndpoint.extConnConfig.ExposedPorts == nil {
 			continue
 		}
 
 		l := newLink(endpoint.addr.IP.String(),
 			childEndpoint.addr.IP.String(),
-			childEndpoint.config.ExposedPorts, network.config.BridgeName)
+			childEndpoint.extConnConfig.ExposedPorts, network.config.BridgeName)
 		if enable {
 			err = l.Enable()
 			if err != nil {
@@ -1277,10 +1323,6 @@ func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, options
 		}
 	}
 
-	if enable {
-		endpoint.containerConfig = cc
-	}
-
 	return nil
 }
 
@@ -1313,22 +1355,6 @@ func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfigurat
 		}
 	}
 
-	if opt, ok := epOptions[netlabel.PortMap]; ok {
-		if bs, ok := opt.([]types.PortBinding); ok {
-			ec.PortBindings = bs
-		} else {
-			return nil, &ErrInvalidEndpointConfig{}
-		}
-	}
-
-	if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
-		if ports, ok := opt.([]types.TransportPort); ok {
-			ec.ExposedPorts = ports
-		} else {
-			return nil, &ErrInvalidEndpointConfig{}
-		}
-	}
-
 	return ec, nil
 }
 
@@ -1354,6 +1380,32 @@ func parseContainerOptions(cOptions map[string]interface{}) (*containerConfigura
 	}
 }
 
+func parseConnectivityOptions(cOptions map[string]interface{}) (*connectivityConfiguration, error) {
+	if cOptions == nil {
+		return nil, nil
+	}
+
+	cc := &connectivityConfiguration{}
+
+	if opt, ok := cOptions[netlabel.PortMap]; ok {
+		if pb, ok := opt.([]types.PortBinding); ok {
+			cc.PortBindings = pb
+		} else {
+			return nil, types.BadRequestErrorf("Invalid port mapping data in connectivity configuration: %v", opt)
+		}
+	}
+
+	if opt, ok := cOptions[netlabel.ExposedPorts]; ok {
+		if ports, ok := opt.([]types.TransportPort); ok {
+			cc.ExposedPorts = ports
+		} else {
+			return nil, types.BadRequestErrorf("Invalid exposed ports data in connectivity configuration: %v", opt)
+		}
+	}
+
+	return cc, nil
+}
+
 func electMacAddress(epConfig *endpointConfiguration, ip net.IP) net.HardwareAddr {
 	if epConfig != nil && epConfig.MacAddress != nil {
 		return epConfig.MacAddress

+ 3 - 3
vendor/src/github.com/docker/libnetwork/drivers/bridge/port_mapping.go

@@ -14,8 +14,8 @@ var (
 	defaultBindingIP = net.IPv4(0, 0, 0, 0)
 )
 
-func (n *bridgeNetwork) allocatePorts(epConfig *endpointConfiguration, ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
-	if epConfig == nil || epConfig.PortBindings == nil {
+func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
+	if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
 		return nil, nil
 	}
 
@@ -24,7 +24,7 @@ func (n *bridgeNetwork) allocatePorts(epConfig *endpointConfiguration, ep *bridg
 		defHostIP = reqDefBindIP
 	}
 
-	return n.allocatePortsInternal(epConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
+	return n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
 }
 
 func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {

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

@@ -63,6 +63,14 @@ func (d *driver) Leave(nid, eid string) error {
 	return nil
 }
 
+func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
+	return nil
+}
+
+func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
+	return nil
+}
+
 func (d *driver) Type() string {
 	return networkType
 }

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

@@ -63,6 +63,14 @@ func (d *driver) Leave(nid, eid string) error {
 	return nil
 }
 
+func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
+	return nil
+}
+
+func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
+	return nil
+}
+
 func (d *driver) Type() string {
 	return networkType
 }

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

@@ -78,7 +78,7 @@ func setFilters(cname, brName string, remove bool) error {
 		opt = "-D"
 	}
 
-	// Everytime we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains
+	// Every time we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains
 	if !remove {
 		for _, chain := range []string{"OUTPUT", "FORWARD"} {
 			exists := iptables.Exists(iptables.Filter, chain, "-j", globalChain)

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

@@ -54,7 +54,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
 		return err
 	}
 
-	ep.ifName = overlayIfName
+	ep.ifName = containerIfName
 
 	// Set the container interface and its peer MTU to 1450 to allow
 	// for 50 bytes vxlan encap (inner eth header(14) + outer IP(20) +

+ 11 - 0
vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go

@@ -63,6 +63,9 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
 	if id == "" {
 		return fmt.Errorf("invalid network id")
 	}
+	if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
+		return types.BadRequestErrorf("ipv4 pool is empty")
+	}
 
 	// Since we perform lazy configuration make sure we try
 	// configuring the driver when we enter CreateNetwork
@@ -111,6 +114,14 @@ func (d *driver) DeleteNetwork(nid string) error {
 	return n.releaseVxlanID()
 }
 
+func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
+	return nil
+}
+
+func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
+	return nil
+}
+
 func (n *network) incEndpointCount() {
 	n.Lock()
 	defer n.Unlock()

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

@@ -153,6 +153,29 @@ type LeaveResponse struct {
 	Response
 }
 
+// ProgramExternalConnectivityRequest describes the API for programming the external connectivity for the given endpoint.
+type ProgramExternalConnectivityRequest struct {
+	NetworkID  string
+	EndpointID string
+	Options    map[string]interface{}
+}
+
+// ProgramExternalConnectivityResponse is the answer to ProgramExternalConnectivityRequest.
+type ProgramExternalConnectivityResponse struct {
+	Response
+}
+
+// RevokeExternalConnectivityRequest describes the API for revoking the external connectivity for the given endpoint.
+type RevokeExternalConnectivityRequest struct {
+	NetworkID  string
+	EndpointID string
+}
+
+// RevokeExternalConnectivityResponse is the answer to RevokeExternalConnectivityRequest.
+type RevokeExternalConnectivityResponse struct {
+	Response
+}
+
 // DiscoveryNotification represents a discovery notification
 type DiscoveryNotification struct {
 	DiscoveryType discoverapi.DiscoveryType

+ 34 - 0
vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go

@@ -3,6 +3,7 @@ package remote
 import (
 	"fmt"
 	"net"
+	"strings"
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/plugins"
@@ -13,6 +14,10 @@ import (
 	"github.com/docker/libnetwork/types"
 )
 
+const (
+	missingMethod = "404 page not found"
+)
+
 type driver struct {
 	endpoint    *plugins.Client
 	networkType string
@@ -247,6 +252,35 @@ func (d *driver) Leave(nid, eid string) error {
 	return d.call("Leave", leave, &api.LeaveResponse{})
 }
 
+// ProgramExternalConnectivity is invoked to program the rules to allow external connectivity for the endpoint.
+func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
+	data := &api.ProgramExternalConnectivityRequest{
+		NetworkID:  nid,
+		EndpointID: eid,
+		Options:    options,
+	}
+	err := d.call("ProgramExternalConnectivity", data, &api.ProgramExternalConnectivityResponse{})
+	if err != nil && strings.Contains(err.Error(), missingMethod) {
+		// It is not mandatory yet to support this method
+		return nil
+	}
+	return err
+}
+
+// RevokeExternalConnectivity method is invoked to remove any external connectivity programming related to the endpoint.
+func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
+	data := &api.RevokeExternalConnectivityRequest{
+		NetworkID:  nid,
+		EndpointID: eid,
+	}
+	err := d.call("RevokeExternalConnectivity", data, &api.RevokeExternalConnectivityResponse{})
+	if err != nil && strings.Contains(err.Error(), missingMethod) {
+		// It is not mandatory yet to support this method
+		return nil
+	}
+	return err
+}
+
 func (d *driver) Type() string {
 	return d.networkType
 }

+ 128 - 20
vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go

@@ -36,11 +36,20 @@ type networkConfiguration struct {
 	RDID  string
 }
 
+// endpointConfiguration represents the user specified configuration for the sandbox endpoint
+type endpointConfiguration struct {
+	MacAddress   net.HardwareAddr
+	PortBindings []types.PortBinding
+	ExposedPorts []types.TransportPort
+}
+
 type hnsEndpoint struct {
-	id         string
-	profileID  string
-	macAddress net.HardwareAddr
-	addr       *net.IPNet
+	id          string
+	profileID   string
+	macAddress  net.HardwareAddr
+	config      *endpointConfiguration // User specified parameters
+	portMapping []types.PortBinding    // Operation port bindings
+	addr        *net.IPNet
 }
 
 type hnsNetwork struct {
@@ -58,7 +67,7 @@ type driver struct {
 }
 
 func isValidNetworkType(networkType string) bool {
-	if "L2Bridge" == networkType || "L2Tunnel" == networkType || "NAT" == networkType || "Transparent" == networkType {
+	if "l2bridge" == networkType || "l2tunnel" == networkType || "nat" == networkType || "transparent" == networkType {
 		return true
 	}
 
@@ -126,7 +135,7 @@ func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string
 
 func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
 	if len(ipamV6Data) > 0 {
-		return types.ForbiddenErrorf("windowsshim driver doesnt support v6 subnets")
+		return types.ForbiddenErrorf("windowsshim driver doesn't support v6 subnets")
 	}
 
 	if len(ipamV4Data) == 0 {
@@ -177,8 +186,11 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Dat
 
 		for _, ipData := range ipV4Data {
 			subnet := hcsshim.Subnet{
-				AddressPrefix:  ipData.Pool.String(),
-				GatewayAddress: ipData.Gateway.IP.String(),
+				AddressPrefix: ipData.Pool.String(),
+			}
+
+			if ipData.Gateway != nil {
+				subnet.GatewayAddress = ipData.Gateway.IP.String()
 			}
 
 			subnets = append(subnets, subnet)
@@ -276,6 +288,64 @@ func convertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, e
 	return pbs, nil
 }
 
+func parsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, error) {
+	var bindings []types.PortBinding
+	hcsPolicy := &hcsshim.NatPolicy{}
+
+	for _, elem := range policies {
+
+		if err := json.Unmarshal([]byte(elem), &hcsPolicy); err != nil || hcsPolicy.Type != "NAT" {
+			continue
+		}
+
+		binding := types.PortBinding{
+			HostPort:    hcsPolicy.ExternalPort,
+			HostPortEnd: hcsPolicy.ExternalPort,
+			Port:        hcsPolicy.InternalPort,
+			Proto:       types.ParseProtocol(hcsPolicy.Protocol),
+			HostIP:      net.IPv4(0, 0, 0, 0),
+		}
+
+		bindings = append(bindings, binding)
+	}
+
+	return bindings, nil
+}
+
+func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) {
+	if epOptions == nil {
+		return nil, nil
+	}
+
+	ec := &endpointConfiguration{}
+
+	if opt, ok := epOptions[netlabel.MacAddress]; ok {
+		if mac, ok := opt.(net.HardwareAddr); ok {
+			ec.MacAddress = mac
+		} else {
+			return nil, fmt.Errorf("Invalid endpoint configuration")
+		}
+	}
+
+	if opt, ok := epOptions[netlabel.PortMap]; ok {
+		if bs, ok := opt.([]types.PortBinding); ok {
+			ec.PortBindings = bs
+		} else {
+			return nil, fmt.Errorf("Invalid endpoint configuration")
+		}
+	}
+
+	if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
+		if ports, ok := opt.([]types.TransportPort); ok {
+			ec.ExposedPorts = ports
+		} else {
+			return nil, fmt.Errorf("Invalid endpoint configuration")
+		}
+	}
+
+	return ec, nil
+}
+
 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
 	n, err := d.getNetwork(nid)
 	if err != nil {
@@ -292,16 +362,16 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 		VirtualNetwork: n.config.HnsID,
 	}
 
-	// Convert the port mapping for the network
-	if opt, ok := epOptions[netlabel.PortMap]; ok {
-		if bs, ok := opt.([]types.PortBinding); ok {
-			endpointStruct.Policies, err = convertPortBindings(bs)
-			if err != nil {
-				return err
-			}
-		} else {
-			return fmt.Errorf("Invalid endpoint configuration for endpoint id%s", eid)
-		}
+	ec, err := parseEndpointOptions(epOptions)
+
+	if err != nil {
+		return err
+	}
+
+	endpointStruct.Policies, err = convertPortBindings(ec.PortBindings)
+
+	if err != nil {
+		return err
 	}
 
 	configurationb, err := json.Marshal(endpointStruct)
@@ -325,7 +395,16 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
 		addr:       &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()},
 		macAddress: mac,
 	}
+
 	endpoint.profileID = hnsresponse.Id
+	endpoint.config = ec
+	endpoint.portMapping, err = parsePortBindingPolicies(hnsresponse.Policies)
+
+	if err != nil {
+		hcsshim.HNSEndpointRequest("DELETE", hnsresponse.Id, "")
+		return err
+	}
+
 	n.Lock()
 	n.endpoints[eid] = endpoint
 	n.Unlock()
@@ -365,13 +444,34 @@ func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, erro
 		return nil, err
 	}
 
-	endpoint, err := network.getEndpoint(eid)
+	ep, err := network.getEndpoint(eid)
 	if err != nil {
 		return nil, err
 	}
 
 	data := make(map[string]interface{}, 1)
-	data["hnsid"] = endpoint.profileID
+	data["hnsid"] = ep.profileID
+	if ep.config.ExposedPorts != nil {
+		// Return a copy of the config data
+		epc := make([]types.TransportPort, 0, len(ep.config.ExposedPorts))
+		for _, tp := range ep.config.ExposedPorts {
+			epc = append(epc, tp.GetCopy())
+		}
+		data[netlabel.ExposedPorts] = epc
+	}
+
+	if ep.portMapping != nil {
+		// Return a copy of the operational data
+		pmc := make([]types.PortBinding, 0, len(ep.portMapping))
+		for _, pm := range ep.portMapping {
+			pmc = append(pmc, pm.GetCopy())
+		}
+		data[netlabel.PortMap] = pmc
+	}
+
+	if len(ep.macAddress) != 0 {
+		data[netlabel.MacAddress] = ep.macAddress
+	}
 	return data, nil
 }
 
@@ -412,6 +512,14 @@ func (d *driver) Leave(nid, eid string) error {
 	return nil
 }
 
+func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
+	return nil
+}
+
+func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
+	return nil
+}
+
 func (d *driver) Type() string {
 	return d.name
 }

+ 4 - 4
vendor/src/github.com/docker/libnetwork/drivers_windows.go

@@ -8,9 +8,9 @@ import (
 func getInitializers() []initializer {
 	return []initializer{
 		{null.Init, "null"},
-		{windows.GetInit("Transparent"), "Transparent"},
-		{windows.GetInit("L2Bridge"), "L2Bridge"},
-		{windows.GetInit("L2Tunnel"), "L2Tunnel"},
-		{windows.GetInit("NAT"), "NAT"},
+		{windows.GetInit("transparent"), "transparent"},
+		{windows.GetInit("l2bridge"), "l2bridge"},
+		{windows.GetInit("l2tunnel"), "l2tunnel"},
+		{windows.GetInit("nat"), "nat"},
 	}
 }

+ 90 - 48
vendor/src/github.com/docker/libnetwork/endpoint.go

@@ -359,22 +359,16 @@ func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {
 	sb.joinLeaveStart()
 	defer sb.joinLeaveEnd()
 
-	return ep.sbJoin(sbox, options...)
+	return ep.sbJoin(sb, options...)
 }
 
-func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
-	var err error
-	sb, ok := sbox.(*sandbox)
-	if !ok {
-		return types.BadRequestErrorf("not a valid Sandbox interface")
-	}
-
-	network, err := ep.getNetworkFromStore()
+func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
+	n, err := ep.getNetworkFromStore()
 	if err != nil {
 		return fmt.Errorf("failed to get network from store during join: %v", err)
 	}
 
-	ep, err = network.getEndpointFromStore(ep.ID())
+	ep, err = n.getEndpointFromStore(ep.ID())
 	if err != nil {
 		return fmt.Errorf("failed to get endpoint from store during join: %v", err)
 	}
@@ -384,11 +378,8 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
 		ep.Unlock()
 		return types.ForbiddenErrorf("another container is attached to the same network endpoint")
 	}
-	ep.Unlock()
-
-	ep.Lock()
-	ep.network = network
-	ep.sandboxID = sbox.ID()
+	ep.network = n
+	ep.sandboxID = sb.ID()
 	ep.joinInfo = &endpointJoinInfo{}
 	epid := ep.id
 	ep.Unlock()
@@ -400,32 +391,29 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
 		}
 	}()
 
-	network.Lock()
-	nid := network.id
-	network.Unlock()
+	nid := n.ID()
 
 	ep.processOptions(options...)
 
-	driver, err := network.driver(true)
+	d, err := n.driver(true)
 	if err != nil {
 		return fmt.Errorf("failed to join endpoint: %v", err)
 	}
 
-	err = driver.Join(nid, epid, sbox.Key(), ep, sbox.Labels())
+	err = d.Join(nid, epid, sb.Key(), ep, sb.Labels())
 	if err != nil {
 		return err
 	}
 	defer func() {
 		if err != nil {
-			// Do not alter global err variable, it's needed by the previous defer
-			if err := driver.Leave(nid, epid); err != nil {
+			if err := d.Leave(nid, epid); err != nil {
 				log.Warnf("driver leave failed while rolling back join: %v", err)
 			}
 		}
 	}()
 
 	// Watch for service records
-	network.getController().watchSvcRecord(ep)
+	n.getController().watchSvcRecord(ep)
 
 	address := ""
 	if ip := ep.getFirstInterfaceAddress(); ip != nil {
@@ -434,27 +422,23 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
 	if err = sb.updateHostsFile(address); err != nil {
 		return err
 	}
-	if err = sb.updateDNS(network.enableIPv6); err != nil {
+	if err = sb.updateDNS(n.enableIPv6); err != nil {
 		return err
 	}
 
-	if err = network.getController().updateToStore(ep); err != nil {
+	if err = n.getController().updateToStore(ep); err != nil {
 		return err
 	}
 
+	// Current endpoint providing external connectivity for the sandbox
+	extEp := sb.getGatewayEndpoint()
+
 	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
-				}
-			}
+			sb.removeEndpoint(ep)
 		}
 	}()
 
@@ -463,9 +447,39 @@ func (ep *endpoint) sbJoin(sbox Sandbox, options ...EndpointOption) error {
 	}
 
 	if sb.needDefaultGW() {
-		return sb.setupDefaultGW(ep)
+		return sb.setupDefaultGW()
 	}
-	return nil
+
+	moveExtConn := sb.getGatewayEndpoint() != extEp
+
+	if moveExtConn {
+		if extEp != nil {
+			log.Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
+			if err = d.RevokeExternalConnectivity(extEp.network.ID(), extEp.ID()); err != nil {
+				return types.InternalErrorf(
+					"driver failed revoking external connectivity on endpoint %s (%s): %v",
+					extEp.Name(), extEp.ID(), err)
+			}
+			defer func() {
+				if err != nil {
+					if e := d.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); e != nil {
+						log.Warnf("Failed to roll-back external connectivity on endpoint %s (%s): %v",
+							extEp.Name(), extEp.ID(), e)
+					}
+				}
+			}()
+		}
+		if !n.internal {
+			log.Debugf("Programming external connectivity on endpoint %s (%s)", ep.Name(), ep.ID())
+			if err = d.ProgramExternalConnectivity(n.ID(), ep.ID(), sb.Labels()); err != nil {
+				return types.InternalErrorf(
+					"driver failed programming external connectivity on endpoint %s (%s): %v",
+					ep.Name(), ep.ID(), err)
+			}
+		}
+	}
+
+	return sb.clearDefaultGW()
 }
 
 func (ep *endpoint) rename(name string) error {
@@ -533,15 +547,10 @@ func (ep *endpoint) Leave(sbox Sandbox, options ...EndpointOption) error {
 	sb.joinLeaveStart()
 	defer sb.joinLeaveEnd()
 
-	return ep.sbLeave(sbox, false, options...)
+	return ep.sbLeave(sb, false, options...)
 }
 
-func (ep *endpoint) sbLeave(sbox Sandbox, force bool, options ...EndpointOption) error {
-	sb, ok := sbox.(*sandbox)
-	if !ok {
-		return types.BadRequestErrorf("not a valid Sandbox interface")
-	}
-
+func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption) error {
 	n, err := ep.getNetworkFromStore()
 	if err != nil {
 		return fmt.Errorf("failed to get network from store during leave: %v", err)
@@ -559,8 +568,8 @@ func (ep *endpoint) sbLeave(sbox Sandbox, force bool, options ...EndpointOption)
 	if sid == "" {
 		return types.ForbiddenErrorf("cannot leave endpoint with no attached sandbox")
 	}
-	if sid != sbox.ID() {
-		return types.ForbiddenErrorf("unexpected sandbox ID in leave request. Expected %s. Got %s", ep.sandboxID, sbox.ID())
+	if sid != sb.ID() {
+		return types.ForbiddenErrorf("unexpected sandbox ID in leave request. Expected %s. Got %s", ep.sandboxID, sb.ID())
 	}
 
 	ep.processOptions(options...)
@@ -575,7 +584,19 @@ func (ep *endpoint) sbLeave(sbox Sandbox, force bool, options ...EndpointOption)
 	ep.network = n
 	ep.Unlock()
 
+	// Current endpoint providing external connectivity to the sandbox
+	extEp := sb.getGatewayEndpoint()
+	moveExtConn := extEp != nil && (extEp.ID() == ep.ID())
+
 	if d != nil {
+		if moveExtConn {
+			log.Debugf("Revoking external connectivity on endpoint %s (%s)", ep.Name(), ep.ID())
+			if err := d.RevokeExternalConnectivity(n.id, ep.id); err != nil {
+				log.Warnf("driver failed revoking external connectivity on endpoint %s (%s): %v",
+					ep.Name(), ep.ID(), err)
+			}
+		}
+
 		if err := d.Leave(n.id, ep.id); err != nil {
 			if _, ok := err.(types.MaskableError); !ok {
 				log.Warnf("driver error disconnecting container %s : %v", ep.name, err)
@@ -597,7 +618,24 @@ func (ep *endpoint) sbLeave(sbox Sandbox, force bool, options ...EndpointOption)
 	}
 
 	sb.deleteHostsEntries(n.getSvcRecords(ep))
-	return nil
+	if !sb.inDelete && sb.needDefaultGW() {
+		if sb.getEPwithoutGateway() == nil {
+			return fmt.Errorf("endpoint without GW expected, but not found")
+		}
+		return sb.setupDefaultGW()
+	}
+
+	// New endpoint providing external connectivity for the sandbox
+	extEp = sb.getGatewayEndpoint()
+	if moveExtConn && extEp != nil {
+		log.Debugf("Programming external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
+		if err := d.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); err != nil {
+			log.Warnf("driver failed programming external connectivity on endpoint %s: (%s) %v",
+				extEp.Name(), extEp.ID(), err)
+		}
+	}
+
+	return sb.clearDefaultGW()
 }
 
 func (n *network) validateForceDelete(locator string) error {
@@ -643,7 +681,7 @@ func (ep *endpoint) Delete(force bool) error {
 	}
 
 	if sb != nil {
-		if e := ep.sbLeave(sb, force); e != nil {
+		if e := ep.sbLeave(sb.(*sandbox), force); e != nil {
 			log.Warnf("failed to leave sandbox for endpoint %s : %v", name, e)
 		}
 	}
@@ -929,9 +967,13 @@ func (ep *endpoint) releaseAddress() {
 		log.Warnf("Failed to retrieve ipam driver to release interface address on delete of endpoint %s (%s): %v", ep.Name(), ep.ID(), err)
 		return
 	}
-	if err := ipam.ReleaseAddress(ep.iface.v4PoolID, ep.iface.addr.IP); err != nil {
-		log.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addr.IP, ep.Name(), ep.ID(), err)
+
+	if ep.iface.addr != nil {
+		if err := ipam.ReleaseAddress(ep.iface.v4PoolID, ep.iface.addr.IP); err != nil {
+			log.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addr.IP, ep.Name(), ep.ID(), err)
+		}
 	}
+
 	if ep.iface.addrv6 != nil && ep.iface.addrv6.IP.IsGlobalUnicast() {
 		if err := ipam.ReleaseAddress(ep.iface.v6PoolID, ep.iface.addrv6.IP); err != nil {
 			log.Warnf("Failed to release ip address %s on delete of endpoint %s (%s): %v", ep.iface.addrv6.IP, ep.Name(), ep.ID(), err)

+ 14 - 2
vendor/src/github.com/docker/libnetwork/etchosts/etchosts.go

@@ -8,6 +8,7 @@ import (
 	"io/ioutil"
 	"os"
 	"regexp"
+	"strings"
 	"sync"
 )
 
@@ -78,10 +79,17 @@ func Build(path, IP, hostname, domainname string, extraContent []Record) error {
 		//set main record
 		var mainRec Record
 		mainRec.IP = IP
+		// User might have provided a FQDN in hostname or split it across hostname
+		// and domainname.  We want the FQDN and the bare hostname.
+		fqdn := hostname
 		if domainname != "" {
-			mainRec.Hosts = fmt.Sprintf("%s.%s %s", hostname, domainname, hostname)
+			fqdn = fmt.Sprintf("%s.%s", fqdn, domainname)
+		}
+		parts := strings.SplitN(fqdn, ".", 2)
+		if len(parts) == 2 {
+			mainRec.Hosts = fmt.Sprintf("%s %s", fqdn, parts[0])
 		} else {
-			mainRec.Hosts = hostname
+			mainRec.Hosts = fqdn
 		}
 		if _, err := mainRec.WriteTo(content); err != nil {
 			return err
@@ -151,6 +159,10 @@ func Delete(path string, recs []Record) error {
 loop:
 	for s.Scan() {
 		b := s.Bytes()
+		if len(b) == 0 {
+			continue
+		}
+
 		if b[0] == '#' {
 			buf.Write(b)
 			buf.Write(eol)

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

@@ -8,7 +8,7 @@ import (
 	"github.com/docker/libnetwork/datastore"
 )
 
-// Idm manages the reservation/release of numerical ids from a contiguos set
+// Idm manages the reservation/release of numerical ids from a contiguous set
 type Idm struct {
 	start  uint64
 	end    uint64

+ 2 - 2
vendor/src/github.com/docker/libnetwork/ipam/structures.go

@@ -40,7 +40,7 @@ type addrSpace struct {
 }
 
 // AddressRange specifies first and last ip ordinal which
-// identify a range in a a pool of addresses
+// identifies a range in a pool of addresses
 type AddressRange struct {
 	Sub        *net.IPNet
 	Start, End uint64
@@ -85,7 +85,7 @@ func (s *SubnetKey) String() string {
 	return k
 }
 
-// FromString populate the SubnetKey object reading it from string
+// FromString populates the SubnetKey object reading it from string
 func (s *SubnetKey) FromString(str string) error {
 	if str == "" || !strings.Contains(str, "/") {
 		return types.BadRequestErrorf("invalid string form for subnetkey: %s", str)

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

@@ -62,7 +62,7 @@ func getAddressVersion(ip net.IP) ipVersion {
 }
 
 // Adds the ordinal IP to the current array
-// 192.168.0.0 + 53 => 192.168.53
+// 192.168.0.0 + 53 => 192.168.0.53
 func addIntToIP(array []byte, ordinal uint64) {
 	for i := len(array) - 1; i >= 0; i-- {
 		array[i] |= (byte)(ordinal & 0xff)

+ 3 - 1
vendor/src/github.com/docker/libnetwork/ipamapi/contract.go

@@ -15,6 +15,8 @@ import (
 const (
 	// DefaultIPAM is the name of the built-in default ipam driver
 	DefaultIPAM = "default"
+	// NullIPAM is the name of the built-in null ipam driver
+	NullIPAM = "null"
 	// PluginEndpointType represents the Endpoint Type used by Plugin system
 	PluginEndpointType = "IpamDriver"
 	// RequestAddressType represents the Address Type used when requesting an address
@@ -33,7 +35,7 @@ type Callback interface {
  * IPAM Errors
  **************/
 
-// Weel-known errors returned by IPAM
+// Well-known errors returned by IPAM
 var (
 	ErrIpamInternalError   = types.InternalErrorf("IPAM Internal Error")
 	ErrInvalidAddressSpace = types.BadRequestErrorf("Invalid Address Space")

+ 71 - 0
vendor/src/github.com/docker/libnetwork/ipams/null/null.go

@@ -0,0 +1,71 @@
+// Package null implements the null ipam driver. Null ipam driver satisfies ipamapi contract,
+// but does not effectively reserve/allocate any address pool or address
+package null
+
+import (
+	"fmt"
+	"net"
+
+	"github.com/docker/libnetwork/discoverapi"
+	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/types"
+)
+
+var (
+	defaultAS      = "null"
+	defaultPool, _ = types.ParseCIDR("0.0.0.0/0")
+	defaultPoolID  = fmt.Sprintf("%s/%s", defaultAS, defaultPool.String())
+)
+
+type allocator struct{}
+
+func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
+	return defaultAS, defaultAS, nil
+}
+
+func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
+	if addressSpace != defaultAS {
+		return "", nil, nil, types.BadRequestErrorf("unknown address space: %s", addressSpace)
+	}
+	if pool != "" {
+		return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle specific address pool requests")
+	}
+	if subPool != "" {
+		return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle specific address subpool requests")
+	}
+	if v6 {
+		return "", nil, nil, types.BadRequestErrorf("null ipam driver does not handle IPv6 address pool pool requests")
+	}
+	return defaultPoolID, defaultPool, nil, nil
+}
+
+func (a *allocator) ReleasePool(poolID string) error {
+	return nil
+}
+
+func (a *allocator) RequestAddress(poolID string, ip net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
+	if poolID != defaultPoolID {
+		return nil, nil, types.BadRequestErrorf("unknown pool id: %s", poolID)
+	}
+	return nil, nil, nil
+}
+
+func (a *allocator) ReleaseAddress(poolID string, ip net.IP) error {
+	if poolID != defaultPoolID {
+		return types.BadRequestErrorf("unknown pool id: %s", poolID)
+	}
+	return nil
+}
+
+func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
+	return nil
+}
+
+func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
+	return nil
+}
+
+// Init registers a remote ipam when its plugin is activated
+func Init(ic ipamapi.Callback, l, g interface{}) error {
+	return ic.RegisterIpamDriver(ipamapi.NullIPAM, &allocator{})
+}

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

@@ -6,6 +6,7 @@ import (
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/ipamapi"
+	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -33,7 +34,7 @@ func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
 }
 
 // RequestPool returns an address pool along with its unique id. This is a null ipam driver. It allocates the
-// subnet user asked and does not validate anything. Doesnt support subpool allocation
+// subnet user asked and does not validate anything. Doesn't support subpool allocation
 func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
 	log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6)
 	if subPool != "" || v6 {
@@ -64,14 +65,19 @@ func (a *allocator) ReleasePool(poolID string) error {
 // RequestAddress returns an address from the specified pool ID.
 // Always allocate the 0.0.0.0/32 ip if no preferred address was specified
 func (a *allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[string]string) (*net.IPNet, map[string]string, error) {
-	log.Debugf("RequestAddress(%s, %v, %v) %s", poolID, prefAddress, opts, opts["RequestAddressType"])
+	log.Debugf("RequestAddress(%s, %v, %v)", poolID, prefAddress, opts)
 	_, ipNet, err := net.ParseCIDR(poolID)
 
 	if err != nil {
 		return nil, nil, err
 	}
-	if prefAddress == nil {
+
+	// TODO Windows: Remove this once the bug in docker daemon is fixed
+	// that causes it to throw an exception on nil gateway
+	if opts[ipamapi.RequestAddressType] == netlabel.Gateway {
 		return ipNet, nil, nil
+	} else if prefAddress == nil {
+		return nil, nil, nil
 	}
 	return &net.IPNet{IP: prefAddress, Mask: ipNet.Mask}, nil, nil
 }

+ 42 - 12
vendor/src/github.com/docker/libnetwork/iptables/iptables.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"net"
 	"os/exec"
+	"regexp"
 	"strconv"
 	"strings"
 	"sync"
@@ -36,6 +37,7 @@ const (
 var (
 	iptablesPath  string
 	supportsXlock = false
+	supportsCOpt  = false
 	// used to lock iptables commands if xtables lock is not supported
 	bestEffortLock sync.Mutex
 	// ErrIptablesNotFound is returned when the rule is not found.
@@ -60,7 +62,6 @@ func (e ChainError) Error() string {
 }
 
 func initCheck() error {
-
 	if iptablesPath == "" {
 		path, err := exec.LookPath("iptables")
 		if err != nil {
@@ -68,6 +69,12 @@ func initCheck() error {
 		}
 		iptablesPath = path
 		supportsXlock = exec.Command(iptablesPath, "--wait", "-L", "-n").Run() == nil
+		mj, mn, mc, err := GetVersion()
+		if err != nil {
+			logrus.Warnf("Failed to read iptables version: %v", err)
+			return nil
+		}
+		supportsCOpt = supportsCOption(mj, mn, mc)
 	}
 	return nil
 }
@@ -299,20 +306,21 @@ func Exists(table Table, chain string, rule ...string) bool {
 		table = Filter
 	}
 
-	// iptables -C, --check option was added in v.1.4.11
-	// http://ftp.netfilter.org/pub/iptables/changes-iptables-1.4.11.txt
+	initCheck()
 
-	// try -C
-	// if exit status is 0 then return true, the rule exists
-	if _, err := Raw(append([]string{
-		"-t", string(table), "-C", chain}, rule...)...); err == nil {
-		return true
+	if supportsCOpt {
+		// if exit status is 0 then return true, the rule exists
+		_, err := Raw(append([]string{"-t", string(table), "-C", chain}, rule...)...)
+		return err == nil
 	}
 
-	// parse "iptables -S" for the rule (this checks rules in a specific chain
-	// in a specific table)
-	ruleString := strings.Join(rule, " ")
-	ruleString = chain + " " + ruleString
+	// parse "iptables -S" for the rule (it checks rules in a specific chain
+	// in a specific table and it is very unreliable)
+	return existsRaw(table, chain, rule...)
+}
+
+func existsRaw(table Table, chain string, rule ...string) bool {
+	ruleString := fmt.Sprintf("%s %s\n", chain, strings.Join(rule, " "))
 	existingRules, _ := exec.Command(iptablesPath, "-t", string(table), "-S", chain).Output()
 
 	return strings.Contains(string(existingRules), ruleString)
@@ -380,3 +388,25 @@ func ExistChain(chain string, table Table) bool {
 	}
 	return false
 }
+
+// GetVersion reads the iptables version numbers
+func GetVersion() (major, minor, micro int, err error) {
+	out, err := Raw("--version")
+	if err == nil {
+		major, minor, micro = parseVersionNumbers(string(out))
+	}
+	return
+}
+
+func parseVersionNumbers(input string) (major, minor, micro int) {
+	re := regexp.MustCompile(`v\d*.\d*.\d*`)
+	line := re.FindString(input)
+	fmt.Sscanf(line, "v%d.%d.%d", &major, &minor, &micro)
+	return
+}
+
+// iptables -C, --check option was added in v.1.4.11
+// http://ftp.netfilter.org/pub/iptables/changes-iptables-1.4.11.txt
+func supportsCOption(mj, mn, mc int) bool {
+	return mj > 1 || (mj == 1 && (mn > 4 || (mn == 4 && mc >= 11)))
+}

+ 14 - 3
vendor/src/github.com/docker/libnetwork/network.go

@@ -600,7 +600,7 @@ func (n *network) driver(load bool) (driverapi.Driver, error) {
 			return nil, err
 		}
 	} else if !ok {
-		// dont fail if driver loading is not required
+		// don't fail if driver loading is not required
 		return nil, nil
 	}
 
@@ -851,14 +851,25 @@ func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool
 	if iface := ep.Iface(); iface.Address() != nil {
 		myAliases := ep.MyAliases()
 		if isAdd {
-			if !ep.isAnonymous() {
+			// If anonymous endpoint has an alias use the first alias
+			// for ip->name mapping. Not having the reverse mapping
+			// breaks some apps
+			if ep.isAnonymous() {
+				if len(myAliases) > 0 {
+					n.addSvcRecords(myAliases[0], iface.Address().IP, true)
+				}
+			} else {
 				n.addSvcRecords(epName, iface.Address().IP, true)
 			}
 			for _, alias := range myAliases {
 				n.addSvcRecords(alias, iface.Address().IP, false)
 			}
 		} else {
-			if !ep.isAnonymous() {
+			if ep.isAnonymous() {
+				if len(myAliases) > 0 {
+					n.deleteSvcRecords(myAliases[0], iface.Address().IP, true)
+				}
+			} else {
 				n.deleteSvcRecords(epName, iface.Address().IP, true)
 			}
 			for _, alias := range myAliases {

+ 16 - 0
vendor/src/github.com/docker/libnetwork/osl/interface_linux.go

@@ -21,6 +21,7 @@ type nwIface struct {
 	dstName     string
 	master      string
 	dstMaster   string
+	mac         net.HardwareAddr
 	address     *net.IPNet
 	addressIPv6 *net.IPNet
 	routes      []*net.IPNet
@@ -64,6 +65,13 @@ func (i *nwIface) Master() string {
 	return i.master
 }
 
+func (i *nwIface) MacAddress() net.HardwareAddr {
+	i.Lock()
+	defer i.Unlock()
+
+	return types.GetMacCopy(i.mac)
+}
+
 func (i *nwIface) Address() *net.IPNet {
 	i.Lock()
 	defer i.Unlock()
@@ -304,6 +312,7 @@ func configureInterface(iface netlink.Link, i *nwIface) error {
 		ErrMessage string
 	}{
 		{setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())},
+		{setInterfaceMAC, fmt.Sprintf("error setting interface %q MAC to %q", ifaceName, i.MacAddress())},
 		{setInterfaceIP, fmt.Sprintf("error setting interface %q IP to %q", ifaceName, i.Address())},
 		{setInterfaceIPv6, fmt.Sprintf("error setting interface %q IPv6 to %q", ifaceName, i.AddressIPv6())},
 		{setInterfaceMaster, fmt.Sprintf("error setting interface %q master to %q", ifaceName, i.DstMaster())},
@@ -326,6 +335,13 @@ func setInterfaceMaster(iface netlink.Link, i *nwIface) error {
 		LinkAttrs: netlink.LinkAttrs{Name: i.DstMaster()}})
 }
 
+func setInterfaceMAC(iface netlink.Link, i *nwIface) error {
+	if i.MacAddress() == nil {
+		return nil
+	}
+	return netlink.LinkSetHardwareAddr(iface, i.MacAddress())
+}
+
 func setInterfaceIP(iface netlink.Link, i *nwIface) error {
 	if i.Address() == nil {
 		return nil

+ 6 - 0
vendor/src/github.com/docker/libnetwork/osl/options_linux.go

@@ -42,6 +42,12 @@ func (n *networkNamespace) Master(name string) IfaceOption {
 	}
 }
 
+func (n *networkNamespace) MacAddress(mac net.HardwareAddr) IfaceOption {
+	return func(i *nwIface) {
+		i.mac = mac
+	}
+}
+
 func (n *networkNamespace) Address(addr *net.IPNet) IfaceOption {
 	return func(i *nwIface) {
 		i.address = addr

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

@@ -76,6 +76,9 @@ type IfaceOptionSetter interface {
 	// Bridge returns an option setter to set if the interface is a bridge.
 	Bridge(bool) IfaceOption
 
+	// MacAddress returns an option setter to set the MAC address.
+	MacAddress(net.HardwareAddr) IfaceOption
+
 	// Address returns an option setter to set IPv4 address.
 	Address(*net.IPNet) IfaceOption
 

+ 138 - 36
vendor/src/github.com/docker/libnetwork/resolver.go

@@ -2,8 +2,11 @@ package libnetwork
 
 import (
 	"fmt"
+	"math/rand"
 	"net"
 	"strings"
+	"sync"
+	"time"
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/iptables"
@@ -31,23 +34,35 @@ type Resolver interface {
 }
 
 const (
-	resolverIP    = "127.0.0.11"
-	dnsPort       = "53"
-	ptrIPv4domain = ".in-addr.arpa."
-	ptrIPv6domain = ".ip6.arpa."
-	respTTL       = 600
-	maxExtDNS     = 3 //max number of external servers to try
+	resolverIP      = "127.0.0.11"
+	dnsPort         = "53"
+	ptrIPv4domain   = ".in-addr.arpa."
+	ptrIPv6domain   = ".ip6.arpa."
+	respTTL         = 600
+	maxExtDNS       = 3 //max number of external servers to try
+	extIOTimeout    = 3 * time.Second
+	defaultRespSize = 512
 )
 
+type extDNSEntry struct {
+	ipStr   string
+	extConn net.Conn
+	extOnce sync.Once
+}
+
 // resolver implements the Resolver interface
 type resolver struct {
-	sb        *sandbox
-	extDNS    []string
-	server    *dns.Server
-	conn      *net.UDPConn
-	tcpServer *dns.Server
-	tcpListen *net.TCPListener
-	err       error
+	sb         *sandbox
+	extDNSList [maxExtDNS]extDNSEntry
+	server     *dns.Server
+	conn       *net.UDPConn
+	tcpServer  *dns.Server
+	tcpListen  *net.TCPListener
+	err        error
+}
+
+func init() {
+	rand.Seed(time.Now().Unix())
 }
 
 // NewResolver creates a new instance of the Resolver
@@ -136,7 +151,13 @@ func (r *resolver) Stop() {
 }
 
 func (r *resolver) SetExtServers(dns []string) {
-	r.extDNS = dns
+	l := len(dns)
+	if l > maxExtDNS {
+		l = maxExtDNS
+	}
+	for i := 0; i < l; i++ {
+		r.extDNSList[i].ipStr = dns[i]
+	}
 }
 
 func (r *resolver) NameServer() string {
@@ -151,22 +172,36 @@ func setCommonFlags(msg *dns.Msg) {
 	msg.RecursionAvailable = true
 }
 
+func shuffleAddr(addr []net.IP) []net.IP {
+	for i := len(addr) - 1; i > 0; i-- {
+		r := rand.Intn(i + 1)
+		addr[i], addr[r] = addr[r], addr[i]
+	}
+	return addr
+}
+
 func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) {
 	addr := r.sb.ResolveName(name)
 	if addr == nil {
 		return nil, nil
 	}
 
-	log.Debugf("Lookup for %s: IP %s", name, addr.String())
+	log.Debugf("Lookup for %s: IP %v", name, addr)
 
 	resp := new(dns.Msg)
 	resp.SetReply(query)
 	setCommonFlags(resp)
 
-	rr := new(dns.A)
-	rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
-	rr.A = addr
-	resp.Answer = append(resp.Answer, rr)
+	if len(addr) > 1 {
+		addr = shuffleAddr(addr)
+	}
+
+	for _, ip := range addr {
+		rr := new(dns.A)
+		rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
+		rr.A = ip
+		resp.Answer = append(resp.Answer, rr)
+	}
 	return resp, nil
 }
 
@@ -200,10 +235,23 @@ func (r *resolver) handlePTRQuery(ptr string, query *dns.Msg) (*dns.Msg, error)
 	return resp, nil
 }
 
+func truncateResp(resp *dns.Msg, maxSize int, isTCP bool) {
+	if !isTCP {
+		resp.Truncated = true
+	}
+
+	// trim the Answer RRs one by one till the whole message fits
+	// within the reply size
+	for resp.Len() > maxSize {
+		resp.Answer = resp.Answer[:len(resp.Answer)-1]
+	}
+}
+
 func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 	var (
-		resp *dns.Msg
-		err  error
+		extConn net.Conn
+		resp    *dns.Msg
+		err     error
 	)
 
 	if query == nil || len(query.Question) == 0 {
@@ -221,28 +269,82 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 		return
 	}
 
-	if resp == nil {
-		if len(r.extDNS) == 0 {
-			return
+	proto := w.LocalAddr().Network()
+	maxSize := 0
+	if proto == "tcp" {
+		maxSize = dns.MaxMsgSize - 1
+	} else if proto == "udp" {
+		optRR := query.IsEdns0()
+		if optRR != nil {
+			maxSize = int(optRR.UDPSize())
+		}
+		if maxSize < defaultRespSize {
+			maxSize = defaultRespSize
 		}
+	}
 
-		num := maxExtDNS
-		if len(r.extDNS) < maxExtDNS {
-			num = len(r.extDNS)
+	if resp != nil {
+		if resp.Len() > maxSize {
+			truncateResp(resp, maxSize, proto == "tcp")
 		}
-		for i := 0; i < num; i++ {
-			log.Debugf("Querying ext dns %s:%s for %s[%d]", w.LocalAddr().Network(), r.extDNS[i], name, query.Question[0].Qtype)
+	} else {
+		for i := 0; i < maxExtDNS; i++ {
+			extDNS := &r.extDNSList[i]
+			if extDNS.ipStr == "" {
+				break
+			}
+			log.Debugf("Querying ext dns %s:%s for %s[%d]", proto, extDNS.ipStr, name, query.Question[0].Qtype)
 
-			c := &dns.Client{Net: w.LocalAddr().Network()}
-			addr := fmt.Sprintf("%s:%d", r.extDNS[i], 53)
+			extConnect := func() {
+				addr := fmt.Sprintf("%s:%d", extDNS.ipStr, 53)
+				extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
+			}
 
-			resp, _, err = c.Exchange(query, addr)
-			if err == nil {
-				resp.Compress = true
-				break
+			// For udp clients connection is persisted to reuse for further queries.
+			// Accessing extDNS.extConn be a race here between go rouines. Hence the
+			// connection setup is done in a Once block and fetch the extConn again
+			extConn = extDNS.extConn
+			if extConn == nil || proto == "tcp" {
+				if proto == "udp" {
+					extDNS.extOnce.Do(func() {
+						r.sb.execFunc(extConnect)
+						extDNS.extConn = extConn
+					})
+					extConn = extDNS.extConn
+				} else {
+					r.sb.execFunc(extConnect)
+				}
+				if err != nil {
+					log.Debugf("Connect failed, %s", err)
+					continue
+				}
+			}
+
+			// Timeout has to be set for every IO operation.
+			extConn.SetDeadline(time.Now().Add(extIOTimeout))
+			co := &dns.Conn{Conn: extConn}
+
+			defer func() {
+				if proto == "tcp" {
+					co.Close()
+				}
+			}()
+			err = co.WriteMsg(query)
+			if err != nil {
+				log.Debugf("Send to DNS server failed, %s", err)
+				continue
 			}
-			log.Errorf("external resolution failed, %s", err)
+
+			resp, err = co.ReadMsg()
+			if err != nil {
+				log.Debugf("Read from DNS server failed, %s", err)
+				continue
+			}
+
+			resp.Compress = true
+			break
 		}
+
 		if resp == nil {
 			return
 		}

+ 86 - 19
vendor/src/github.com/docker/libnetwork/sandbox.go

@@ -10,6 +10,7 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/etchosts"
+	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/types"
 )
@@ -37,7 +38,7 @@ type Sandbox interface {
 	Delete() error
 	// ResolveName searches for the service name in the networks to which the sandbox
 	// is connected to.
-	ResolveName(name string) net.IP
+	ResolveName(name string) []net.IP
 	// ResolveIP returns the service name for the passed in IP. IP is in reverse dotted
 	// notation; the format used for DNS PTR records
 	ResolveIP(name string) string
@@ -118,6 +119,7 @@ type containerConfig struct {
 	useDefaultSandBox bool
 	useExternalKey    bool
 	prio              int // higher the value, more the priority
+	exposedPorts      []types.TransportPort
 }
 
 func (sb *sandbox) ID() string {
@@ -136,18 +138,27 @@ func (sb *sandbox) Key() string {
 }
 
 func (sb *sandbox) Labels() map[string]interface{} {
-	return sb.config.generic
+	sb.Lock()
+	sb.Unlock()
+	opts := make(map[string]interface{}, len(sb.config.generic))
+	for k, v := range sb.config.generic {
+		opts[k] = v
+	}
+	return opts
 }
 
 func (sb *sandbox) Statistics() (map[string]*types.InterfaceStatistics, error) {
 	m := make(map[string]*types.InterfaceStatistics)
 
-	if sb.osSbox == nil {
+	sb.Lock()
+	osb := sb.osSbox
+	sb.Unlock()
+	if osb == nil {
 		return m, nil
 	}
 
 	var err error
-	for _, i := range sb.osSbox.Info().Interfaces() {
+	for _, i := range osb.Info().Interfaces() {
 		if m[i.DstName()], err = i.Statistics(); err != nil {
 			return m, err
 		}
@@ -326,6 +337,18 @@ func (sb *sandbox) getConnectedEndpoints() []*endpoint {
 	return eps
 }
 
+func (sb *sandbox) removeEndpoint(ep *endpoint) {
+	sb.Lock()
+	defer sb.Unlock()
+
+	for i, e := range sb.endpoints {
+		if e == ep {
+			heap.Remove(&sb.endpoints, i)
+			return
+		}
+	}
+}
+
 func (sb *sandbox) getEndpoint(id string) *endpoint {
 	sb.Lock()
 	defer sb.Unlock()
@@ -391,8 +414,12 @@ func (sb *sandbox) ResolveIP(ip string) string {
 	return svc
 }
 
-func (sb *sandbox) ResolveName(name string) net.IP {
-	var ip net.IP
+func (sb *sandbox) execFunc(f func()) {
+	sb.osSbox.InvokeFunc(f)
+}
+
+func (sb *sandbox) ResolveName(name string) []net.IP {
+	var ip []net.IP
 
 	// Embedded server owns the docker network domain. Resolution should work
 	// for both container_name and container_name.network_name
@@ -440,7 +467,7 @@ func (sb *sandbox) ResolveName(name string) net.IP {
 	return nil
 }
 
-func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool) net.IP {
+func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool) []net.IP {
 	for _, ep := range epList {
 		name := req
 		n := ep.getNetwork()
@@ -463,7 +490,7 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin
 			}
 		} else {
 			// If it is a regular lookup and if the requested name is an alias
-			// dont perform a svc lookup for this endpoint.
+			// don't perform a svc lookup for this endpoint.
 			ep.Lock()
 			if _, ok := ep.aliases[req]; ok {
 				ep.Unlock()
@@ -481,7 +508,7 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin
 		ip, ok := sr.svcMap[name]
 		n.Unlock()
 		if ok {
-			return ip[0]
+			return ip
 		}
 	}
 	return nil
@@ -606,6 +633,9 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
 		if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
 			ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().AddressIPv6(i.addrv6))
 		}
+		if i.mac != nil {
+			ifaceOptions = append(ifaceOptions, sb.osSbox.InterfaceOptions().MacAddress(i.mac))
+		}
 
 		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)
@@ -621,14 +651,9 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
 		}
 	}
 
-	for _, gwep := range sb.getConnectedEndpoints() {
-		if len(gwep.Gateway()) > 0 {
-			if gwep != ep {
-				break
-			}
-			if err := sb.updateGateway(gwep); err != nil {
-				return err
-			}
+	if ep == sb.getGatewayEndpoint() {
+		if err := sb.updateGateway(ep); err != nil {
+			return err
 		}
 	}
 
@@ -647,7 +672,7 @@ func (sb *sandbox) clearNetworkResources(origEp *endpoint) error {
 	ep := sb.getEndpoint(origEp.id)
 	if ep == nil {
 		return fmt.Errorf("could not find the sandbox endpoint data for endpoint %s",
-			ep.name)
+			origEp.id)
 	}
 
 	sb.Lock()
@@ -739,6 +764,13 @@ func (sb *sandbox) joinLeaveEnd() {
 	}
 }
 
+func (sb *sandbox) hasPortConfigs() bool {
+	opts := sb.Labels()
+	_, hasExpPorts := opts[netlabel.ExposedPorts]
+	_, hasPortMaps := opts[netlabel.PortMap]
+	return hasExpPorts || hasPortMaps
+}
+
 // OptionHostname function returns an option setter for hostname option to
 // be passed to NewSandbox method.
 func OptionHostname(name string) SandboxOption {
@@ -848,7 +880,42 @@ func OptionUseExternalKey() SandboxOption {
 // 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
+		if sb.config.generic == nil {
+			sb.config.generic = make(map[string]interface{}, len(generic))
+		}
+		for k, v := range generic {
+			sb.config.generic[k] = v
+		}
+	}
+}
+
+// OptionExposedPorts function returns an option setter for the container exposed
+// ports option to be passed to container Create method.
+func OptionExposedPorts(exposedPorts []types.TransportPort) SandboxOption {
+	return func(sb *sandbox) {
+		if sb.config.generic == nil {
+			sb.config.generic = make(map[string]interface{})
+		}
+		// Defensive copy
+		eps := make([]types.TransportPort, len(exposedPorts))
+		copy(eps, exposedPorts)
+		// Store endpoint label and in generic because driver needs it
+		sb.config.exposedPorts = eps
+		sb.config.generic[netlabel.ExposedPorts] = eps
+	}
+}
+
+// OptionPortMapping function returns an option setter for the mapping
+// ports option to be passed to container Create method.
+func OptionPortMapping(portBindings []types.PortBinding) SandboxOption {
+	return func(sb *sandbox) {
+		if sb.config.generic == nil {
+			sb.config.generic = make(map[string]interface{})
+		}
+		// Store a copy of the bindings as generic data to pass to the driver
+		pbs := make([]types.PortBinding, len(portBindings))
+		copy(pbs, portBindings)
+		sb.config.generic[netlabel.PortMap] = pbs
 	}
 }
 

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

@@ -130,7 +130,7 @@ func (c *controller) acceptClientConnections(sock string, l net.Listener) {
 		conn, err := l.Accept()
 		if err != nil {
 			if _, err1 := os.Stat(sock); os.IsNotExist(err1) {
-				logrus.Debugf("Unix socket %s doesnt exist. cannot accept client connections", sock)
+				logrus.Debugf("Unix socket %s doesn't exist. cannot accept client connections", sock)
 				return
 			}
 			logrus.Errorf("Error accepting connection %v", err)

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

@@ -389,7 +389,7 @@ const (
 	// NEXTHOP indicates a StaticRoute with an IP next hop.
 	NEXTHOP = iota
 
-	// CONNECTED indicates a StaticRoute with a interface for directly connected peers.
+	// CONNECTED indicates a StaticRoute with an interface for directly connected peers.
 	CONNECTED
 )
 
@@ -458,25 +458,25 @@ type NotFoundError interface {
 	NotFound()
 }
 
-// ForbiddenError is an interface for errors which denote an valid request that cannot be honored
+// ForbiddenError is an interface for errors which denote a valid request that cannot be honored
 type ForbiddenError interface {
 	// Forbidden makes implementer into ForbiddenError type
 	Forbidden()
 }
 
-// NoServiceError  is an interface for errors returned when the required service is not available
+// NoServiceError is an interface for errors returned when the required service is not available
 type NoServiceError interface {
 	// NoService makes implementer into NoServiceError type
 	NoService()
 }
 
-// TimeoutError  is an interface for errors raised because of timeout
+// TimeoutError is an interface for errors raised because of timeout
 type TimeoutError interface {
 	// Timeout makes implementer into TimeoutError type
 	Timeout()
 }
 
-// NotImplementedError  is an interface for errors raised because of requested functionality is not yet implemented
+// NotImplementedError is an interface for errors raised because of requested functionality is not yet implemented
 type NotImplementedError interface {
 	// NotImplemented makes implementer into NotImplementedError type
 	NotImplemented()

+ 4 - 0
vendor/src/github.com/vishvananda/netlink/addr_linux.go

@@ -101,6 +101,10 @@ func AddrList(link Link, family int) ([]Addr, error) {
 			continue
 		}
 
+		if family != FAMILY_ALL && msg.Family != uint8(family) {
+			continue
+		}
+
 		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
 		if err != nil {
 			return nil, err

+ 1 - 0
vendor/src/github.com/vishvananda/netlink/class.go

@@ -56,6 +56,7 @@ func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass {
 	ceil := cattrs.Ceil / 8
 	buffer := cattrs.Buffer
 	cbuffer := cattrs.Cbuffer
+
 	if ceil == 0 {
 		ceil = rate
 	}

+ 20 - 2
vendor/src/github.com/vishvananda/netlink/class_linux.go

@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"errors"
 	"syscall"
 
 	"github.com/vishvananda/netlink/nl"
@@ -65,15 +66,32 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
 	options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
 	if htb, ok := class.(*HtbClass); ok {
 		opt := nl.TcHtbCopt{}
-		opt.Rate.Rate = uint32(htb.Rate)
-		opt.Ceil.Rate = uint32(htb.Ceil)
 		opt.Buffer = htb.Buffer
 		opt.Cbuffer = htb.Cbuffer
 		opt.Quantum = htb.Quantum
 		opt.Level = htb.Level
 		opt.Prio = htb.Prio
 		// TODO: Handle Debug properly. For now default to 0
+		/* Calculate {R,C}Tab and set Rate and Ceil */
+		cell_log := -1
+		ccell_log := -1
+		linklayer := nl.LINKLAYER_ETHERNET
+		mtu := 1600
+		var rtab [256]uint32
+		var ctab [256]uint32
+		tcrate := nl.TcRateSpec{Rate: uint32(htb.Rate)}
+		if CalcRtable(&tcrate, rtab, cell_log, uint32(mtu), linklayer) < 0 {
+			return errors.New("HTB: failed to calculate rate table.")
+		}
+		opt.Rate = tcrate
+		tcceil := nl.TcRateSpec{Rate: uint32(htb.Ceil)}
+		if CalcRtable(&tcceil, ctab, ccell_log, uint32(mtu), linklayer) < 0 {
+			return errors.New("HTB: failed to calculate ceil rate table.")
+		}
+		opt.Ceil = tcceil
 		nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize())
+		nl.NewRtAttrChild(options, nl.TCA_HTB_RTAB, SerializeRtab(rtab))
+		nl.NewRtAttrChild(options, nl.TCA_HTB_CTAB, SerializeRtab(ctab))
 	}
 	req.AddData(options)
 	return nil

+ 1 - 0
vendor/src/github.com/vishvananda/netlink/link.go

@@ -204,6 +204,7 @@ type Vxlan struct {
 	RSC          bool
 	L2miss       bool
 	L3miss       bool
+	UDPCSum      bool
 	NoAge        bool
 	GBP          bool
 	Age          int

+ 55 - 2
vendor/src/github.com/vishvananda/netlink/link_linux.go

@@ -142,6 +142,54 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
 	return err
 }
 
+// LinkSetVfHardwareAddr sets the hardware address of a vf for the link.
+// Equivalent to: `ip link set $link vf $vf mac $hwaddr`
+func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Index = int32(base.Index)
+	req.AddData(msg)
+
+	data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
+	info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
+	vfmsg := nl.VfMac{
+		Vf: uint32(vf),
+	}
+	copy(vfmsg.Mac[:], []byte(hwaddr))
+	nl.NewRtAttrChild(info, nl.IFLA_VF_MAC, vfmsg.Serialize())
+	req.AddData(data)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// LinkSetVfVlan sets the vlan of a vf for the link.
+// Equivalent to: `ip link set $link vf $vf vlan $vlan`
+func LinkSetVfVlan(link Link, vf, vlan int) error {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Index = int32(base.Index)
+	req.AddData(msg)
+
+	data := nl.NewRtAttr(nl.IFLA_VFINFO_LIST, nil)
+	info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil)
+	vfmsg := nl.VfVlan{
+		Vf:   uint32(vf),
+		Vlan: uint32(vlan),
+	}
+	nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize())
+	req.AddData(data)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
 // LinkSetMaster sets the master of the link device.
 // Equivalent to: `ip link set $link master $master`
 func LinkSetMaster(link Link, master *Bridge) error {
@@ -277,10 +325,12 @@ func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
 	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
 	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
 
+	if vxlan.UDPCSum {
+		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_CSUM, boolAttr(vxlan.UDPCSum))
+	}
 	if vxlan.GBP {
 		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GBP, boolAttr(vxlan.GBP))
 	}
-
 	if vxlan.NoAge {
 		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0))
 	} else if vxlan.Age > 0 {
@@ -815,6 +865,7 @@ func LinkList() ([]Link, error) {
 // LinkUpdate is used to pass information back from LinkSubscribe()
 type LinkUpdate struct {
 	nl.IfInfomsg
+	Header syscall.NlMsghdr
 	Link
 }
 
@@ -844,7 +895,7 @@ func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error {
 				if err != nil {
 					return
 				}
-				ch <- LinkUpdate{IfInfomsg: *ifmsg, Link: link}
+				ch <- LinkUpdate{IfInfomsg: *ifmsg, Header: m.Header, Link: link}
 			}
 		}
 	}()
@@ -935,6 +986,8 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
 			vxlan.L2miss = int8(datum.Value[0]) != 0
 		case nl.IFLA_VXLAN_L3MISS:
 			vxlan.L3miss = int8(datum.Value[0]) != 0
+		case nl.IFLA_VXLAN_UDP_CSUM:
+			vxlan.UDPCSum = int8(datum.Value[0]) != 0
 		case nl.IFLA_VXLAN_GBP:
 			vxlan.GBP = int8(datum.Value[0]) != 0
 		case nl.IFLA_VXLAN_AGEING:

+ 212 - 0
vendor/src/github.com/vishvananda/netlink/nl/link_linux.go

@@ -1,7 +1,13 @@
 package nl
 
+import (
+	"unsafe"
+)
+
 const (
 	DEFAULT_CHANGE = 0xFFFFFFFF
+	// doesn't exist in syscall
+	IFLA_VFINFO_LIST = 0x16
 )
 
 const (
@@ -182,3 +188,209 @@ const (
 	GRE_FLAGS   = 0x00F8
 	GRE_VERSION = 0x0007
 )
+
+const (
+	IFLA_VF_INFO_UNSPEC = iota
+	IFLA_VF_INFO
+	IFLA_VF_INFO_MAX = IFLA_VF_INFO
+)
+
+const (
+	IFLA_VF_UNSPEC = iota
+	IFLA_VF_MAC    /* Hardware queue specific attributes */
+	IFLA_VF_VLAN
+	IFLA_VF_TX_RATE      /* Max TX Bandwidth Allocation */
+	IFLA_VF_SPOOFCHK     /* Spoof Checking on/off switch */
+	IFLA_VF_LINK_STATE   /* link state enable/disable/auto switch */
+	IFLA_VF_RATE         /* Min and Max TX Bandwidth Allocation */
+	IFLA_VF_RSS_QUERY_EN /* RSS Redirection Table and Hash Key query
+	 * on/off switch
+	 */
+	IFLA_VF_STATS /* network device statistics */
+	IFLA_VF_MAX   = IFLA_VF_STATS
+)
+
+const (
+	IFLA_VF_LINK_STATE_AUTO    = iota /* link state of the uplink */
+	IFLA_VF_LINK_STATE_ENABLE         /* link always up */
+	IFLA_VF_LINK_STATE_DISABLE        /* link always down */
+	IFLA_VF_LINK_STATE_MAX     = IFLA_VF_LINK_STATE_DISABLE
+)
+
+const (
+	IFLA_VF_STATS_RX_PACKETS = iota
+	IFLA_VF_STATS_TX_PACKETS
+	IFLA_VF_STATS_RX_BYTES
+	IFLA_VF_STATS_TX_BYTES
+	IFLA_VF_STATS_BROADCAST
+	IFLA_VF_STATS_MULTICAST
+	IFLA_VF_STATS_MAX = IFLA_VF_STATS_MULTICAST
+)
+
+const (
+	SizeofVfMac        = 0x24
+	SizeofVfVlan       = 0x0c
+	SizeofVfTxRate     = 0x08
+	SizeofVfRate       = 0x0c
+	SizeofVfSpoofchk   = 0x08
+	SizeofVfLinkState  = 0x08
+	SizeofVfRssQueryEn = 0x08
+)
+
+// struct ifla_vf_mac {
+//   __u32 vf;
+//   __u8 mac[32]; /* MAX_ADDR_LEN */
+// };
+
+type VfMac struct {
+	Vf  uint32
+	Mac [32]byte
+}
+
+func (msg *VfMac) Len() int {
+	return SizeofVfMac
+}
+
+func DeserializeVfMac(b []byte) *VfMac {
+	return (*VfMac)(unsafe.Pointer(&b[0:SizeofVfMac][0]))
+}
+
+func (msg *VfMac) Serialize() []byte {
+	return (*(*[SizeofVfMac]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct ifla_vf_vlan {
+//   __u32 vf;
+//   __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
+//   __u32 qos;
+// };
+
+type VfVlan struct {
+	Vf   uint32
+	Vlan uint32
+	Qos  uint32
+}
+
+func (msg *VfVlan) Len() int {
+	return SizeofVfVlan
+}
+
+func DeserializeVfVlan(b []byte) *VfVlan {
+	return (*VfVlan)(unsafe.Pointer(&b[0:SizeofVfVlan][0]))
+}
+
+func (msg *VfVlan) Serialize() []byte {
+	return (*(*[SizeofVfVlan]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct ifla_vf_tx_rate {
+//   __u32 vf;
+//   __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
+// };
+
+type VfTxRate struct {
+	Vf   uint32
+	Rate uint32
+}
+
+func (msg *VfTxRate) Len() int {
+	return SizeofVfTxRate
+}
+
+func DeserializeVfTxRate(b []byte) *VfTxRate {
+	return (*VfTxRate)(unsafe.Pointer(&b[0:SizeofVfTxRate][0]))
+}
+
+func (msg *VfTxRate) Serialize() []byte {
+	return (*(*[SizeofVfTxRate]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct ifla_vf_rate {
+//   __u32 vf;
+//   __u32 min_tx_rate; /* Min Bandwidth in Mbps */
+//   __u32 max_tx_rate; /* Max Bandwidth in Mbps */
+// };
+
+type VfRate struct {
+	Vf        uint32
+	MinTxRate uint32
+	MaxTxRate uint32
+}
+
+func (msg *VfRate) Len() int {
+	return SizeofVfRate
+}
+
+func DeserializeVfRate(b []byte) *VfRate {
+	return (*VfRate)(unsafe.Pointer(&b[0:SizeofVfRate][0]))
+}
+
+func (msg *VfRate) Serialize() []byte {
+	return (*(*[SizeofVfRate]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct ifla_vf_spoofchk {
+//   __u32 vf;
+//   __u32 setting;
+// };
+
+type VfSpoofchk struct {
+	Vf      uint32
+	Setting uint32
+}
+
+func (msg *VfSpoofchk) Len() int {
+	return SizeofVfSpoofchk
+}
+
+func DeserializeVfSpoofchk(b []byte) *VfSpoofchk {
+	return (*VfSpoofchk)(unsafe.Pointer(&b[0:SizeofVfSpoofchk][0]))
+}
+
+func (msg *VfSpoofchk) Serialize() []byte {
+	return (*(*[SizeofVfSpoofchk]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct ifla_vf_link_state {
+//   __u32 vf;
+//   __u32 link_state;
+// };
+
+type VfLinkState struct {
+	Vf        uint32
+	LinkState uint32
+}
+
+func (msg *VfLinkState) Len() int {
+	return SizeofVfLinkState
+}
+
+func DeserializeVfLinkState(b []byte) *VfLinkState {
+	return (*VfLinkState)(unsafe.Pointer(&b[0:SizeofVfLinkState][0]))
+}
+
+func (msg *VfLinkState) Serialize() []byte {
+	return (*(*[SizeofVfLinkState]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct ifla_vf_rss_query_en {
+//   __u32 vf;
+//   __u32 setting;
+// };
+
+type VfRssQueryEn struct {
+	Vf      uint32
+	Setting uint32
+}
+
+func (msg *VfRssQueryEn) Len() int {
+	return SizeofVfRssQueryEn
+}
+
+func DeserializeVfRssQueryEn(b []byte) *VfRssQueryEn {
+	return (*VfRssQueryEn)(unsafe.Pointer(&b[0:SizeofVfRssQueryEn][0]))
+}
+
+func (msg *VfRssQueryEn) Serialize() []byte {
+	return (*(*[SizeofVfRssQueryEn]byte)(unsafe.Pointer(msg)))[:]
+}

+ 0 - 3
vendor/src/github.com/vishvananda/netlink/xfrm_state_linux.go

@@ -110,9 +110,6 @@ func XfrmStateDel(state *XfrmState) error {
 func XfrmStateList(family int) ([]XfrmState, error) {
 	req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP)
 
-	msg := nl.NewIfInfomsg(family)
-	req.AddData(msg)
-
 	msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
 	if err != nil {
 		return nil, err