bump libnetwork 872f0a83c98add6cae255c8859e29532febc0039 (18.09 branch)

full diff: https://github.com/docker/libnetwork/compare/c9029898e32f7c89bbb81511fbb721df252ce61a...872f0a83c98add6cae255c8859e29532febc0039

- docker/libnetwork#2354 [18.09 backport] Cleanup the cluster provider when the agent is closed
  - backport of docker/libnetwork#2307 Fix for problem where agent is stopped and does not restart
  - fixes docker/for-linux#495 Docker swarm overlay networking not working after --force-new-cluster
- docker/libnetwork#2369 [18.09 BACKPORT] Pick a random host port if the user does not specify a host port
  - backport of docker/libnetwork#2368 (windows) Pick a random host port if the user does not specify a host port

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
diff --git a/hack/dockerfile/install/proxy.installer b/hack/dockerfile/install/proxy.installer
index 315b79e..82a90f6 100755
--- a/hack/dockerfile/install/proxy.installer
+++ b/hack/dockerfile/install/proxy.installer
@@ -3,7 +3,7 @@
 # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
 # updating the binary version, consider updating github.com/docker/libnetwork
 # in vendor.conf accordingly
-LIBNETWORK_COMMIT=4725f2163fb214a6312f3beae5991f838ec36326 # bump_18.09 branch
+LIBNETWORK_COMMIT=872f0a83c98add6cae255c8859e29532febc0039 # bump_18.09 branch
 
 install_proxy() {
 	case "$1" in
diff --git a/vendor.conf b/vendor.conf
index da39f03..43d78c9 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -37,7 +37,7 @@
 #get libnetwork packages
 
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy accordingly
-github.com/docker/libnetwork c9029898e32f7c89bbb81511fbb721df252ce61a # bump_18.09 branch
+github.com/docker/libnetwork 872f0a83c98add6cae255c8859e29532febc0039 # bump_18.09 branch
 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
diff --git a/vendor/github.com/docker/libnetwork/agent.go b/vendor/github.com/docker/libnetwork/agent.go
index a9d77e2..f7d57e2 100644
--- a/vendor/github.com/docker/libnetwork/agent.go
+++ b/vendor/github.com/docker/libnetwork/agent.go
@@ -378,6 +378,9 @@
 	c.agent = nil
 	c.Unlock()
 
+	// when the agent is closed the cluster provider should be cleaned up
+	c.SetClusterProvider(nil)
+
 	if agent == nil {
 		return
 	}
diff --git a/vendor/github.com/docker/libnetwork/drivers/windows/overlay/ov_endpoint_windows.go b/vendor/github.com/docker/libnetwork/drivers/windows/overlay/ov_endpoint_windows.go
index d1a4d9e..cc5679f 100644
--- a/vendor/github.com/docker/libnetwork/drivers/windows/overlay/ov_endpoint_windows.go
+++ b/vendor/github.com/docker/libnetwork/drivers/windows/overlay/ov_endpoint_windows.go
@@ -171,7 +171,19 @@
 			return err
 		}
 
-		pbPolicy, err := windows.ConvertPortBindings(epConnectivity.PortBindings)
+		ep.portMapping = epConnectivity.PortBindings
+		ep.portMapping, err = windows.AllocatePorts(n.portMapper, ep.portMapping, ep.addr.IP)
+		if err != nil {
+			return err
+		}
+
+		defer func() {
+			if err != nil {
+				windows.ReleasePorts(n.portMapper, ep.portMapping)
+			}
+		}()
+
+		pbPolicy, err := windows.ConvertPortBindings(ep.portMapping)
 		if err != nil {
 			return err
 		}
@@ -229,6 +241,8 @@
 		return fmt.Errorf("endpoint id %q not found", eid)
 	}
 
+	windows.ReleasePorts(n.portMapper, ep.portMapping)
+
 	n.deleteEndpoint(eid)
 
 	_, err := endpointRequest("DELETE", ep.profileID, "")
diff --git a/vendor/github.com/docker/libnetwork/drivers/windows/overlay/ov_network_windows.go b/vendor/github.com/docker/libnetwork/drivers/windows/overlay/ov_network_windows.go
index 9cc46f8..592cfc6 100644
--- a/vendor/github.com/docker/libnetwork/drivers/windows/overlay/ov_network_windows.go
+++ b/vendor/github.com/docker/libnetwork/drivers/windows/overlay/ov_network_windows.go
@@ -11,6 +11,7 @@
 	"github.com/Microsoft/hcsshim"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/portmapper"
 	"github.com/docker/libnetwork/types"
 	"github.com/sirupsen/logrus"
 )
@@ -46,6 +47,7 @@
 	initErr         error
 	subnets         []*subnet
 	secure          bool
+	portMapper      *portmapper.PortMapper
 	sync.Mutex
 }
 
@@ -89,10 +91,11 @@
 	}
 
 	n := &network{
-		id:        id,
-		driver:    d,
-		endpoints: endpointTable{},
-		subnets:   []*subnet{},
+		id:         id,
+		driver:     d,
+		endpoints:  endpointTable{},
+		subnets:    []*subnet{},
+		portMapper: portmapper.New(""),
 	}
 
 	genData, ok := option[netlabel.GenericData].(map[string]string)
diff --git a/vendor/github.com/docker/libnetwork/drivers/windows/port_mapping.go b/vendor/github.com/docker/libnetwork/drivers/windows/port_mapping.go
new file mode 100644
index 0000000..51791fd
--- /dev/null
+++ b/vendor/github.com/docker/libnetwork/drivers/windows/port_mapping.go
@@ -0,0 +1,125 @@
+// +build windows
+
+package windows
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"net"
+
+	"github.com/docker/libnetwork/portmapper"
+	"github.com/docker/libnetwork/types"
+	"github.com/ishidawataru/sctp"
+	"github.com/sirupsen/logrus"
+)
+
+const (
+	maxAllocatePortAttempts = 10
+)
+
+// ErrUnsupportedAddressType is returned when the specified address type is not supported.
+type ErrUnsupportedAddressType string
+
+func (uat ErrUnsupportedAddressType) Error() string {
+	return fmt.Sprintf("unsupported address type: %s", string(uat))
+}
+
+// AllocatePorts allocates ports specified in bindings from the portMapper
+func AllocatePorts(portMapper *portmapper.PortMapper, bindings []types.PortBinding, containerIP net.IP) ([]types.PortBinding, error) {
+	bs := make([]types.PortBinding, 0, len(bindings))
+	for _, c := range bindings {
+		b := c.GetCopy()
+		if err := allocatePort(portMapper, &b, containerIP); err != nil {
+			// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
+			if cuErr := ReleasePorts(portMapper, bs); cuErr != nil {
+				logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
+			}
+			return nil, err
+		}
+		bs = append(bs, b)
+	}
+	return bs, nil
+}
+
+func allocatePort(portMapper *portmapper.PortMapper, bnd *types.PortBinding, containerIP net.IP) error {
+	var (
+		host net.Addr
+		err  error
+	)
+
+	// Store the container interface address in the operational binding
+	bnd.IP = containerIP
+
+	// Adjust HostPortEnd if this is not a range.
+	if bnd.HostPortEnd == 0 {
+		bnd.HostPortEnd = bnd.HostPort
+	}
+
+	// Construct the container side transport address
+	container, err := bnd.ContainerAddr()
+	if err != nil {
+		return err
+	}
+
+	// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
+	for i := 0; i < maxAllocatePortAttempts; i++ {
+		if host, err = portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), false); err == nil {
+			break
+		}
+		// There is no point in immediately retrying to map an explicitly chosen port.
+		if bnd.HostPort != 0 {
+			logrus.Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
+			break
+		}
+		logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
+	}
+	if err != nil {
+		return err
+	}
+
+	// Save the host port (regardless it was or not specified in the binding)
+	switch netAddr := host.(type) {
+	case *net.TCPAddr:
+		bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
+		break
+	case *net.UDPAddr:
+		bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
+		break
+	case *sctp.SCTPAddr:
+		bnd.HostPort = uint16(host.(*sctp.SCTPAddr).Port)
+		break
+	default:
+		// For completeness
+		return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
+	}
+	//Windows does not support host port ranges.
+	bnd.HostPortEnd = bnd.HostPort
+	return nil
+}
+
+// ReleasePorts releases ports specified in bindings from the portMapper
+func ReleasePorts(portMapper *portmapper.PortMapper, bindings []types.PortBinding) error {
+	var errorBuf bytes.Buffer
+
+	// Attempt to release all port bindings, do not stop on failure
+	for _, m := range bindings {
+		if err := releasePort(portMapper, m); err != nil {
+			errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
+		}
+	}
+
+	if errorBuf.Len() != 0 {
+		return errors.New(errorBuf.String())
+	}
+	return nil
+}
+
+func releasePort(portMapper *portmapper.PortMapper, bnd types.PortBinding) error {
+	// Construct the host side transport address
+	host, err := bnd.HostAddr()
+	if err != nil {
+		return err
+	}
+	return portMapper.Unmap(host)
+}
diff --git a/vendor/github.com/docker/libnetwork/drivers/windows/windows.go b/vendor/github.com/docker/libnetwork/drivers/windows/windows.go
index c1cc61a..c8ab047 100644
--- a/vendor/github.com/docker/libnetwork/drivers/windows/windows.go
+++ b/vendor/github.com/docker/libnetwork/drivers/windows/windows.go
@@ -25,6 +25,7 @@
 	"github.com/docker/libnetwork/discoverapi"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/netlabel"
+	"github.com/docker/libnetwork/portmapper"
 	"github.com/docker/libnetwork/types"
 	"github.com/sirupsen/logrus"
 )
@@ -88,11 +89,12 @@
 }
 
 type hnsNetwork struct {
-	id        string
-	created   bool
-	config    *networkConfiguration
-	endpoints map[string]*hnsEndpoint // key: endpoint id
-	driver    *driver                 // The network's driver
+	id         string
+	created    bool
+	config     *networkConfiguration
+	endpoints  map[string]*hnsEndpoint // key: endpoint id
+	driver     *driver                 // The network's driver
+	portMapper *portmapper.PortMapper
 	sync.Mutex
 }
 
@@ -252,10 +254,11 @@
 
 func (d *driver) createNetwork(config *networkConfiguration) error {
 	network := &hnsNetwork{
-		id:        config.ID,
-		endpoints: make(map[string]*hnsEndpoint),
-		config:    config,
-		driver:    d,
+		id:         config.ID,
+		endpoints:  make(map[string]*hnsEndpoint),
+		config:     config,
+		driver:     d,
+		portMapper: portmapper.New(""),
 	}
 
 	d.Lock()
@@ -610,7 +613,27 @@
 		endpointStruct.MacAddress = strings.Replace(macAddress.String(), ":", "-", -1)
 	}
 
-	endpointStruct.Policies, err = ConvertPortBindings(epConnectivity.PortBindings)
+	portMapping := epConnectivity.PortBindings
+
+	if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" {
+		ip := net.IPv4(0, 0, 0, 0)
+		if ifInfo.Address() != nil {
+			ip = ifInfo.Address().IP
+		}
+
+		portMapping, err = AllocatePorts(n.portMapper, portMapping, ip)
+		if err != nil {
+			return err
+		}
+
+		defer func() {
+			if err != nil {
+				ReleasePorts(n.portMapper, portMapping)
+			}
+		}()
+	}
+
+	endpointStruct.Policies, err = ConvertPortBindings(portMapping)
 	if err != nil {
 		return err
 	}
@@ -721,6 +744,10 @@
 		return err
 	}
 
+	if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" {
+		ReleasePorts(n.portMapper, ep.portMapping)
+	}
+
 	n.Lock()
 	delete(n.endpoints, eid)
 	n.Unlock()
diff --git a/vendor/github.com/docker/libnetwork/portallocator/portallocator_windows.go b/vendor/github.com/docker/libnetwork/portallocator/portallocator_windows.go
new file mode 100644
index 0000000..98cae14
--- /dev/null
+++ b/vendor/github.com/docker/libnetwork/portallocator/portallocator_windows.go
@@ -0,0 +1,10 @@
+package portallocator
+
+const (
+	StartPortRange = 60000
+	EndPortRange   = 65000
+)
+
+func getDynamicPortRange() (start int, end int, err error) {
+	return StartPortRange, EndPortRange, nil
+}
diff --git a/vendor/github.com/docker/libnetwork/portmapper/mapper.go b/vendor/github.com/docker/libnetwork/portmapper/mapper.go
index 7fa37b1..be4157b 100644
--- a/vendor/github.com/docker/libnetwork/portmapper/mapper.go
+++ b/vendor/github.com/docker/libnetwork/portmapper/mapper.go
@@ -4,9 +4,7 @@
 	"errors"
 	"fmt"
 	"net"
-	"sync"
 
-	"github.com/docker/libnetwork/iptables"
 	"github.com/docker/libnetwork/portallocator"
 	"github.com/ishidawataru/sctp"
 	"github.com/sirupsen/logrus"
@@ -32,20 +30,6 @@
 	ErrSCTPAddrNoIP = errors.New("sctp address does not contain any IP address")
 )
 
-// PortMapper manages the network address translation
-type PortMapper struct {
-	chain      *iptables.ChainInfo
-	bridgeName string
-
-	// udp:ip:port
-	currentMappings map[string]*mapping
-	lock            sync.Mutex
-
-	proxyPath string
-
-	Allocator *portallocator.PortAllocator
-}
-
 // New returns a new instance of PortMapper
 func New(proxyPath string) *PortMapper {
 	return NewWithPortAllocator(portallocator.Get(), proxyPath)
@@ -60,12 +44,6 @@
 	}
 }
 
-// SetIptablesChain sets the specified chain into portmapper
-func (pm *PortMapper) SetIptablesChain(c *iptables.ChainInfo, bridgeName string) {
-	pm.chain = c
-	pm.bridgeName = bridgeName
-}
-
 // Map maps the specified container transport address to the host's network address and transport port
 func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, useProxy bool) (host net.Addr, err error) {
 	return pm.MapRange(container, hostIP, hostPort, hostPort, useProxy)
@@ -174,7 +152,7 @@
 
 	containerIP, containerPort := getIPAndPort(m.container)
 	if hostIP.To4() != nil {
-		if err := pm.forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
+		if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
 			return nil, err
 		}
 	}
@@ -183,7 +161,7 @@
 		// need to undo the iptables rules before we return
 		m.userlandProxy.Stop()
 		if hostIP.To4() != nil {
-			pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
+			pm.DeleteForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
 			if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
 				return err
 			}
@@ -222,7 +200,7 @@
 
 	containerIP, containerPort := getIPAndPort(data.container)
 	hostIP, hostPort := getIPAndPort(data.host)
-	if err := pm.forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
+	if err := pm.DeleteForwardingTableEntry(data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
 		logrus.Errorf("Error on iptables delete: %s", err)
 	}
 
@@ -248,7 +226,7 @@
 	for _, data := range pm.currentMappings {
 		containerIP, containerPort := getIPAndPort(data.container)
 		hostIP, hostPort := getIPAndPort(data.host)
-		if err := pm.forward(iptables.Append, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
+		if err := pm.AppendForwardingTableEntry(data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
 			logrus.Errorf("Error on iptables add: %s", err)
 		}
 	}
@@ -285,10 +263,3 @@
 	}
 	return nil, 0
 }
-
-func (pm *PortMapper) forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
-	if pm.chain == nil {
-		return nil
-	}
-	return pm.chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort, pm.bridgeName)
-}
diff --git a/vendor/github.com/docker/libnetwork/portmapper/mapper_linux.go b/vendor/github.com/docker/libnetwork/portmapper/mapper_linux.go
new file mode 100644
index 0000000..0e76c54
--- /dev/null
+++ b/vendor/github.com/docker/libnetwork/portmapper/mapper_linux.go
@@ -0,0 +1,46 @@
+package portmapper
+
+import (
+	"net"
+	"sync"
+
+	"github.com/docker/libnetwork/iptables"
+	"github.com/docker/libnetwork/portallocator"
+)
+
+// PortMapper manages the network address translation
+type PortMapper struct {
+	bridgeName string
+
+	// udp:ip:port
+	currentMappings map[string]*mapping
+	lock            sync.Mutex
+
+	proxyPath string
+
+	Allocator *portallocator.PortAllocator
+	chain     *iptables.ChainInfo
+}
+
+// SetIptablesChain sets the specified chain into portmapper
+func (pm *PortMapper) SetIptablesChain(c *iptables.ChainInfo, bridgeName string) {
+	pm.chain = c
+	pm.bridgeName = bridgeName
+}
+
+// AppendForwardingTableEntry adds a port mapping to the forwarding table
+func (pm *PortMapper) AppendForwardingTableEntry(proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
+	return pm.forward(iptables.Append, proto, sourceIP, sourcePort, containerIP, containerPort)
+}
+
+// DeleteForwardingTableEntry removes a port mapping from the forwarding table
+func (pm *PortMapper) DeleteForwardingTableEntry(proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
+	return pm.forward(iptables.Delete, proto, sourceIP, sourcePort, containerIP, containerPort)
+}
+
+func (pm *PortMapper) forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
+	if pm.chain == nil {
+		return nil
+	}
+	return pm.chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort, pm.bridgeName)
+}
diff --git a/vendor/github.com/docker/libnetwork/portmapper/mapper_windows.go b/vendor/github.com/docker/libnetwork/portmapper/mapper_windows.go
new file mode 100644
index 0000000..89651e5
--- /dev/null
+++ b/vendor/github.com/docker/libnetwork/portmapper/mapper_windows.go
@@ -0,0 +1,31 @@
+package portmapper
+
+import (
+	"net"
+	"sync"
+
+	"github.com/docker/libnetwork/portallocator"
+)
+
+// PortMapper manages the network address translation
+type PortMapper struct {
+	bridgeName string
+
+	// udp:ip:port
+	currentMappings map[string]*mapping
+	lock            sync.Mutex
+
+	proxyPath string
+
+	Allocator *portallocator.PortAllocator
+}
+
+// AppendForwardingTableEntry adds a port mapping to the forwarding table
+func (pm *PortMapper) AppendForwardingTableEntry(proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
+	return nil
+}
+
+// DeleteForwardingTableEntry removes a port mapping from the forwarding table
+func (pm *PortMapper) DeleteForwardingTableEntry(proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
+	return nil
+}
diff --git a/vendor/github.com/docker/libnetwork/portmapper/proxy_windows.go b/vendor/github.com/docker/libnetwork/portmapper/proxy_windows.go
new file mode 100644
index 0000000..06a9e24
--- /dev/null
+++ b/vendor/github.com/docker/libnetwork/portmapper/proxy_windows.go
@@ -0,0 +1,10 @@
+package portmapper
+
+import (
+	"errors"
+	"net"
+)
+
+func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
+	return nil, errors.New("proxy is unsupported on windows")
+}