Browse code

bump libnetwork 9ff9b57c344df5cd47443ad9e65702ec85c5aeb0

full diff: https://github.com/docker/libnetwork/compare/48f846327bbe6a0dce0c556e8dc9f5bb939d5c16...9ff9b57c344df5cd47443ad9e65702ec85c5aeb0

- 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>

Sebastiaan van Stijn authored on 2019/04/24 01:35:28
Showing 12 changed files
... ...
@@ -3,7 +3,7 @@
3 3
 # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
4 4
 # updating the binary version, consider updating github.com/docker/libnetwork
5 5
 # in vendor.conf accordingly
6
-LIBNETWORK_COMMIT=48f846327bbe6a0dce0c556e8dc9f5bb939d5c16
6
+LIBNETWORK_COMMIT=9ff9b57c344df5cd47443ad9e65702ec85c5aeb0
7 7
 
8 8
 install_proxy() {
9 9
 	case "$1" in
... ...
@@ -39,7 +39,7 @@ github.com/gofrs/flock                              7f43ea2e6a643ad441fc12d0ecc0
39 39
 # libnetwork
40 40
 
41 41
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly
42
-github.com/docker/libnetwork                        48f846327bbe6a0dce0c556e8dc9f5bb939d5c16
42
+github.com/docker/libnetwork                        9ff9b57c344df5cd47443ad9e65702ec85c5aeb0
43 43
 github.com/docker/go-events                         9461782956ad83b30282bf90e31fa6a70c255ba9
44 44
 github.com/armon/go-radix                           e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
45 45
 github.com/armon/go-metrics                         eb0af217e5e9747e41dd5303755356b62d28e3ec
... ...
@@ -171,7 +171,19 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
171 171
 			return err
172 172
 		}
173 173
 
174
-		pbPolicy, err := windows.ConvertPortBindings(epConnectivity.PortBindings)
174
+		ep.portMapping = epConnectivity.PortBindings
175
+		ep.portMapping, err = windows.AllocatePorts(n.portMapper, ep.portMapping, ep.addr.IP)
176
+		if err != nil {
177
+			return err
178
+		}
179
+
180
+		defer func() {
181
+			if err != nil {
182
+				windows.ReleasePorts(n.portMapper, ep.portMapping)
183
+			}
184
+		}()
185
+
186
+		pbPolicy, err := windows.ConvertPortBindings(ep.portMapping)
175 187
 		if err != nil {
176 188
 			return err
177 189
 		}
... ...
@@ -229,6 +241,8 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
229 229
 		return fmt.Errorf("endpoint id %q not found", eid)
230 230
 	}
231 231
 
232
+	windows.ReleasePorts(n.portMapper, ep.portMapping)
233
+
232 234
 	n.deleteEndpoint(eid)
233 235
 
234 236
 	_, err := endpointRequest("DELETE", ep.profileID, "")
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"github.com/Microsoft/hcsshim"
12 12
 	"github.com/docker/libnetwork/driverapi"
13 13
 	"github.com/docker/libnetwork/netlabel"
14
+	"github.com/docker/libnetwork/portmapper"
14 15
 	"github.com/docker/libnetwork/types"
15 16
 	"github.com/sirupsen/logrus"
16 17
 )
... ...
@@ -46,6 +47,7 @@ type network struct {
46 46
 	initErr         error
47 47
 	subnets         []*subnet
48 48
 	secure          bool
49
+	portMapper      *portmapper.PortMapper
49 50
 	sync.Mutex
50 51
 }
51 52
 
... ...
@@ -89,10 +91,11 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
89 89
 	}
90 90
 
91 91
 	n := &network{
92
-		id:        id,
93
-		driver:    d,
94
-		endpoints: endpointTable{},
95
-		subnets:   []*subnet{},
92
+		id:         id,
93
+		driver:     d,
94
+		endpoints:  endpointTable{},
95
+		subnets:    []*subnet{},
96
+		portMapper: portmapper.New(""),
96 97
 	}
97 98
 
98 99
 	genData, ok := option[netlabel.GenericData].(map[string]string)
99 100
new file mode 100644
... ...
@@ -0,0 +1,125 @@
0
+// +build windows
1
+
2
+package windows
3
+
4
+import (
5
+	"bytes"
6
+	"errors"
7
+	"fmt"
8
+	"net"
9
+
10
+	"github.com/docker/libnetwork/portmapper"
11
+	"github.com/docker/libnetwork/types"
12
+	"github.com/ishidawataru/sctp"
13
+	"github.com/sirupsen/logrus"
14
+)
15
+
16
+const (
17
+	maxAllocatePortAttempts = 10
18
+)
19
+
20
+// ErrUnsupportedAddressType is returned when the specified address type is not supported.
21
+type ErrUnsupportedAddressType string
22
+
23
+func (uat ErrUnsupportedAddressType) Error() string {
24
+	return fmt.Sprintf("unsupported address type: %s", string(uat))
25
+}
26
+
27
+// AllocatePorts allocates ports specified in bindings from the portMapper
28
+func AllocatePorts(portMapper *portmapper.PortMapper, bindings []types.PortBinding, containerIP net.IP) ([]types.PortBinding, error) {
29
+	bs := make([]types.PortBinding, 0, len(bindings))
30
+	for _, c := range bindings {
31
+		b := c.GetCopy()
32
+		if err := allocatePort(portMapper, &b, containerIP); err != nil {
33
+			// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
34
+			if cuErr := ReleasePorts(portMapper, bs); cuErr != nil {
35
+				logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
36
+			}
37
+			return nil, err
38
+		}
39
+		bs = append(bs, b)
40
+	}
41
+	return bs, nil
42
+}
43
+
44
+func allocatePort(portMapper *portmapper.PortMapper, bnd *types.PortBinding, containerIP net.IP) error {
45
+	var (
46
+		host net.Addr
47
+		err  error
48
+	)
49
+
50
+	// Store the container interface address in the operational binding
51
+	bnd.IP = containerIP
52
+
53
+	// Adjust HostPortEnd if this is not a range.
54
+	if bnd.HostPortEnd == 0 {
55
+		bnd.HostPortEnd = bnd.HostPort
56
+	}
57
+
58
+	// Construct the container side transport address
59
+	container, err := bnd.ContainerAddr()
60
+	if err != nil {
61
+		return err
62
+	}
63
+
64
+	// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
65
+	for i := 0; i < maxAllocatePortAttempts; i++ {
66
+		if host, err = portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), false); err == nil {
67
+			break
68
+		}
69
+		// There is no point in immediately retrying to map an explicitly chosen port.
70
+		if bnd.HostPort != 0 {
71
+			logrus.Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
72
+			break
73
+		}
74
+		logrus.Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
75
+	}
76
+	if err != nil {
77
+		return err
78
+	}
79
+
80
+	// Save the host port (regardless it was or not specified in the binding)
81
+	switch netAddr := host.(type) {
82
+	case *net.TCPAddr:
83
+		bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
84
+		break
85
+	case *net.UDPAddr:
86
+		bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
87
+		break
88
+	case *sctp.SCTPAddr:
89
+		bnd.HostPort = uint16(host.(*sctp.SCTPAddr).Port)
90
+		break
91
+	default:
92
+		// For completeness
93
+		return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
94
+	}
95
+	//Windows does not support host port ranges.
96
+	bnd.HostPortEnd = bnd.HostPort
97
+	return nil
98
+}
99
+
100
+// ReleasePorts releases ports specified in bindings from the portMapper
101
+func ReleasePorts(portMapper *portmapper.PortMapper, bindings []types.PortBinding) error {
102
+	var errorBuf bytes.Buffer
103
+
104
+	// Attempt to release all port bindings, do not stop on failure
105
+	for _, m := range bindings {
106
+		if err := releasePort(portMapper, m); err != nil {
107
+			errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
108
+		}
109
+	}
110
+
111
+	if errorBuf.Len() != 0 {
112
+		return errors.New(errorBuf.String())
113
+	}
114
+	return nil
115
+}
116
+
117
+func releasePort(portMapper *portmapper.PortMapper, bnd types.PortBinding) error {
118
+	// Construct the host side transport address
119
+	host, err := bnd.HostAddr()
120
+	if err != nil {
121
+		return err
122
+	}
123
+	return portMapper.Unmap(host)
124
+}
... ...
@@ -25,6 +25,7 @@ import (
25 25
 	"github.com/docker/libnetwork/discoverapi"
26 26
 	"github.com/docker/libnetwork/driverapi"
27 27
 	"github.com/docker/libnetwork/netlabel"
28
+	"github.com/docker/libnetwork/portmapper"
28 29
 	"github.com/docker/libnetwork/types"
29 30
 	"github.com/sirupsen/logrus"
30 31
 )
... ...
@@ -88,11 +89,12 @@ type hnsEndpoint struct {
88 88
 }
89 89
 
90 90
 type hnsNetwork struct {
91
-	id        string
92
-	created   bool
93
-	config    *networkConfiguration
94
-	endpoints map[string]*hnsEndpoint // key: endpoint id
95
-	driver    *driver                 // The network's driver
91
+	id         string
92
+	created    bool
93
+	config     *networkConfiguration
94
+	endpoints  map[string]*hnsEndpoint // key: endpoint id
95
+	driver     *driver                 // The network's driver
96
+	portMapper *portmapper.PortMapper
96 97
 	sync.Mutex
97 98
 }
98 99
 
... ...
@@ -252,10 +254,11 @@ func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (s
252 252
 
253 253
 func (d *driver) createNetwork(config *networkConfiguration) error {
254 254
 	network := &hnsNetwork{
255
-		id:        config.ID,
256
-		endpoints: make(map[string]*hnsEndpoint),
257
-		config:    config,
258
-		driver:    d,
255
+		id:         config.ID,
256
+		endpoints:  make(map[string]*hnsEndpoint),
257
+		config:     config,
258
+		driver:     d,
259
+		portMapper: portmapper.New(""),
259 260
 	}
260 261
 
261 262
 	d.Lock()
... ...
@@ -610,7 +613,27 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
610 610
 		endpointStruct.MacAddress = strings.Replace(macAddress.String(), ":", "-", -1)
611 611
 	}
612 612
 
613
-	endpointStruct.Policies, err = ConvertPortBindings(epConnectivity.PortBindings)
613
+	portMapping := epConnectivity.PortBindings
614
+
615
+	if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" {
616
+		ip := net.IPv4(0, 0, 0, 0)
617
+		if ifInfo.Address() != nil {
618
+			ip = ifInfo.Address().IP
619
+		}
620
+
621
+		portMapping, err = AllocatePorts(n.portMapper, portMapping, ip)
622
+		if err != nil {
623
+			return err
624
+		}
625
+
626
+		defer func() {
627
+			if err != nil {
628
+				ReleasePorts(n.portMapper, portMapping)
629
+			}
630
+		}()
631
+	}
632
+
633
+	endpointStruct.Policies, err = ConvertPortBindings(portMapping)
614 634
 	if err != nil {
615 635
 		return err
616 636
 	}
... ...
@@ -721,6 +744,10 @@ func (d *driver) DeleteEndpoint(nid, eid string) error {
721 721
 		return err
722 722
 	}
723 723
 
724
+	if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" {
725
+		ReleasePorts(n.portMapper, ep.portMapping)
726
+	}
727
+
724 728
 	n.Lock()
725 729
 	delete(n.endpoints, eid)
726 730
 	n.Unlock()
... ...
@@ -1,5 +1,3 @@
1
-// +build !windows
2
-
3 1
 package portallocator
4 2
 
5 3
 import (
... ...
@@ -1 +1,10 @@
1 1
 package portallocator
2
+
3
+const (
4
+	StartPortRange = 60000
5
+	EndPortRange   = 65000
6
+)
7
+
8
+func getDynamicPortRange() (start int, end int, err error) {
9
+	return StartPortRange, EndPortRange, nil
10
+}
... ...
@@ -4,9 +4,7 @@ import (
4 4
 	"errors"
5 5
 	"fmt"
6 6
 	"net"
7
-	"sync"
8 7
 
9
-	"github.com/docker/libnetwork/iptables"
10 8
 	"github.com/docker/libnetwork/portallocator"
11 9
 	"github.com/ishidawataru/sctp"
12 10
 	"github.com/sirupsen/logrus"
... ...
@@ -32,20 +30,6 @@ var (
32 32
 	ErrSCTPAddrNoIP = errors.New("sctp address does not contain any IP address")
33 33
 )
34 34
 
35
-// PortMapper manages the network address translation
36
-type PortMapper struct {
37
-	chain      *iptables.ChainInfo
38
-	bridgeName string
39
-
40
-	// udp:ip:port
41
-	currentMappings map[string]*mapping
42
-	lock            sync.Mutex
43
-
44
-	proxyPath string
45
-
46
-	Allocator *portallocator.PortAllocator
47
-}
48
-
49 35
 // New returns a new instance of PortMapper
50 36
 func New(proxyPath string) *PortMapper {
51 37
 	return NewWithPortAllocator(portallocator.Get(), proxyPath)
... ...
@@ -60,12 +44,6 @@ func NewWithPortAllocator(allocator *portallocator.PortAllocator, proxyPath stri
60 60
 	}
61 61
 }
62 62
 
63
-// SetIptablesChain sets the specified chain into portmapper
64
-func (pm *PortMapper) SetIptablesChain(c *iptables.ChainInfo, bridgeName string) {
65
-	pm.chain = c
66
-	pm.bridgeName = bridgeName
67
-}
68
-
69 63
 // Map maps the specified container transport address to the host's network address and transport port
70 64
 func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, useProxy bool) (host net.Addr, err error) {
71 65
 	return pm.MapRange(container, hostIP, hostPort, hostPort, useProxy)
... ...
@@ -174,7 +152,7 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
174 174
 
175 175
 	containerIP, containerPort := getIPAndPort(m.container)
176 176
 	if hostIP.To4() != nil {
177
-		if err := pm.forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
177
+		if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
178 178
 			return nil, err
179 179
 		}
180 180
 	}
... ...
@@ -183,7 +161,7 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
183 183
 		// need to undo the iptables rules before we return
184 184
 		m.userlandProxy.Stop()
185 185
 		if hostIP.To4() != nil {
186
-			pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
186
+			pm.DeleteForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
187 187
 			if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
188 188
 				return err
189 189
 			}
... ...
@@ -222,7 +200,7 @@ func (pm *PortMapper) Unmap(host net.Addr) error {
222 222
 
223 223
 	containerIP, containerPort := getIPAndPort(data.container)
224 224
 	hostIP, hostPort := getIPAndPort(data.host)
225
-	if err := pm.forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
225
+	if err := pm.DeleteForwardingTableEntry(data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
226 226
 		logrus.Errorf("Error on iptables delete: %s", err)
227 227
 	}
228 228
 
... ...
@@ -248,7 +226,7 @@ func (pm *PortMapper) ReMapAll() {
248 248
 	for _, data := range pm.currentMappings {
249 249
 		containerIP, containerPort := getIPAndPort(data.container)
250 250
 		hostIP, hostPort := getIPAndPort(data.host)
251
-		if err := pm.forward(iptables.Append, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
251
+		if err := pm.AppendForwardingTableEntry(data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil {
252 252
 			logrus.Errorf("Error on iptables add: %s", err)
253 253
 		}
254 254
 	}
... ...
@@ -285,10 +263,3 @@ func getIPAndPort(a net.Addr) (net.IP, int) {
285 285
 	}
286 286
 	return nil, 0
287 287
 }
288
-
289
-func (pm *PortMapper) forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
290
-	if pm.chain == nil {
291
-		return nil
292
-	}
293
-	return pm.chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort, pm.bridgeName)
294
-}
295 288
new file mode 100644
... ...
@@ -0,0 +1,46 @@
0
+package portmapper
1
+
2
+import (
3
+	"net"
4
+	"sync"
5
+
6
+	"github.com/docker/libnetwork/iptables"
7
+	"github.com/docker/libnetwork/portallocator"
8
+)
9
+
10
+// PortMapper manages the network address translation
11
+type PortMapper struct {
12
+	bridgeName string
13
+
14
+	// udp:ip:port
15
+	currentMappings map[string]*mapping
16
+	lock            sync.Mutex
17
+
18
+	proxyPath string
19
+
20
+	Allocator *portallocator.PortAllocator
21
+	chain     *iptables.ChainInfo
22
+}
23
+
24
+// SetIptablesChain sets the specified chain into portmapper
25
+func (pm *PortMapper) SetIptablesChain(c *iptables.ChainInfo, bridgeName string) {
26
+	pm.chain = c
27
+	pm.bridgeName = bridgeName
28
+}
29
+
30
+// AppendForwardingTableEntry adds a port mapping to the forwarding table
31
+func (pm *PortMapper) AppendForwardingTableEntry(proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
32
+	return pm.forward(iptables.Append, proto, sourceIP, sourcePort, containerIP, containerPort)
33
+}
34
+
35
+// DeleteForwardingTableEntry removes a port mapping from the forwarding table
36
+func (pm *PortMapper) DeleteForwardingTableEntry(proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
37
+	return pm.forward(iptables.Delete, proto, sourceIP, sourcePort, containerIP, containerPort)
38
+}
39
+
40
+func (pm *PortMapper) forward(action iptables.Action, proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
41
+	if pm.chain == nil {
42
+		return nil
43
+	}
44
+	return pm.chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort, pm.bridgeName)
45
+}
0 46
new file mode 100644
... ...
@@ -0,0 +1,31 @@
0
+package portmapper
1
+
2
+import (
3
+	"net"
4
+	"sync"
5
+
6
+	"github.com/docker/libnetwork/portallocator"
7
+)
8
+
9
+// PortMapper manages the network address translation
10
+type PortMapper struct {
11
+	bridgeName string
12
+
13
+	// udp:ip:port
14
+	currentMappings map[string]*mapping
15
+	lock            sync.Mutex
16
+
17
+	proxyPath string
18
+
19
+	Allocator *portallocator.PortAllocator
20
+}
21
+
22
+// AppendForwardingTableEntry adds a port mapping to the forwarding table
23
+func (pm *PortMapper) AppendForwardingTableEntry(proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
24
+	return nil
25
+}
26
+
27
+// DeleteForwardingTableEntry removes a port mapping from the forwarding table
28
+func (pm *PortMapper) DeleteForwardingTableEntry(proto string, sourceIP net.IP, sourcePort int, containerIP string, containerPort int) error {
29
+	return nil
30
+}
0 31
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+package portmapper
1
+
2
+import (
3
+	"errors"
4
+	"net"
5
+)
6
+
7
+func newProxyCommand(proto string, hostIP net.IP, hostPort int, containerIP net.IP, containerPort int, proxyPath string) (userlandProxy, error) {
8
+	return nil, errors.New("proxy is unsupported on windows")
9
+}