Browse code

Vendor in Libnetwork changes

Brings in https://github.com/moby/libnetwork/pull/2604

Signed-off-by: Arko Dasgupta <arko.dasgupta@docker.com>

Arko Dasgupta authored on 2020/12/16 03:22:03
Showing 6 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:=5c6a95bfb20c61571a00f913c6b91959ede84e8d}"
6
+: "${LIBNETWORK_COMMIT:=fa125a3512ee0f6187721c88582bf8c4378bd4d7}"
7 7
 
8 8
 install_proxy() {
9 9
 	case "$1" in
... ...
@@ -47,7 +47,7 @@ github.com/grpc-ecosystem/go-grpc-middleware        3c51f7f332123e8be5a157c0802a
47 47
 # libnetwork
48 48
 
49 49
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly
50
-github.com/docker/libnetwork                        5c6a95bfb20c61571a00f913c6b91959ede84e8d 
50
+github.com/docker/libnetwork                        fa125a3512ee0f6187721c88582bf8c4378bd4d7 
51 51
 github.com/docker/go-events                         e31b211e4f1cd09aa76fe4ac244571fab96ae47f
52 52
 github.com/armon/go-radix                           e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
53 53
 github.com/armon/go-metrics                         eb0af217e5e9747e41dd5303755356b62d28e3ec
... ...
@@ -11,71 +11,113 @@ import (
11 11
 	"github.com/sirupsen/logrus"
12 12
 )
13 13
 
14
-var (
15
-	defaultBindingIP   = net.IPv4(0, 0, 0, 0)
16
-	defaultBindingIPV6 = net.ParseIP("::")
17
-)
18
-
19 14
 func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
20 15
 	if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
21 16
 		return nil, nil
22 17
 	}
23 18
 
24
-	defHostIP := defaultBindingIP
19
+	defHostIP := net.IPv4zero // 0.0.0.0
25 20
 	if reqDefBindIP != nil {
26 21
 		defHostIP = reqDefBindIP
27 22
 	}
28 23
 
29
-	// IPv4 port binding including user land proxy
30
-	pb, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
31
-	if err != nil {
32
-		return nil, err
24
+	var containerIPv6 net.IP
25
+	if ep.addrv6 != nil {
26
+		containerIPv6 = ep.addrv6.IP
33 27
 	}
34 28
 
35
-	// IPv6 port binding excluding user land proxy
36
-	if n.driver.config.EnableIP6Tables && ep.addrv6 != nil {
37
-		// TODO IPv6 custom default binding IP
38
-		pbv6, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addrv6.IP, defaultBindingIPV6, false)
39
-		if err != nil {
40
-			// ensure we clear the previous allocated IPv4 ports
41
-			n.releasePortsInternal(pb)
42
-			return nil, err
43
-		}
44
-
45
-		pb = append(pb, pbv6...)
29
+	pb, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, containerIPv6, defHostIP, ulPxyEnabled)
30
+	if err != nil {
31
+		return nil, err
46 32
 	}
47 33
 	return pb, nil
48 34
 }
49 35
 
50
-func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
36
+func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIPv4, containerIPv6, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
51 37
 	bs := make([]types.PortBinding, 0, len(bindings))
52 38
 	for _, c := range bindings {
53
-		b := c.GetCopy()
54
-		if err := n.allocatePort(&b, containerIP, defHostIP, ulPxyEnabled); err != nil {
55
-			// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
56
-			if cuErr := n.releasePortsInternal(bs); cuErr != nil {
57
-				logrus.Warnf("Upon allocation failure for %v, failed to clear previously allocated port bindings: %v", b, cuErr)
39
+		bIPv4 := c.GetCopy()
40
+		bIPv6 := c.GetCopy()
41
+		// Allocate IPv4 Port mappings
42
+		if ok := n.validatePortBindingIPv4(&bIPv4, containerIPv4, defHostIP); ok {
43
+			if err := n.allocatePort(&bIPv4, ulPxyEnabled); err != nil {
44
+				// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
45
+				if cuErr := n.releasePortsInternal(bs); cuErr != nil {
46
+					logrus.Warnf("allocation failure for %v, failed to clear previously allocated ipv4 port bindings: %v", bIPv4, cuErr)
47
+				}
48
+				return nil, err
58 49
 			}
59
-			return nil, err
50
+			bs = append(bs, bIPv4)
51
+		}
52
+		// Allocate IPv6 Port mappings
53
+		if ok := n.validatePortBindingIPv6(&bIPv6, containerIPv6, defHostIP); ok {
54
+			if err := n.allocatePort(&bIPv6, ulPxyEnabled); err != nil {
55
+				// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
56
+				if cuErr := n.releasePortsInternal(bs); cuErr != nil {
57
+					logrus.Warnf("allocation failure for %v, failed to clear previously allocated ipv6 port bindings: %v", bIPv6, cuErr)
58
+				}
59
+				return nil, err
60
+			}
61
+			bs = append(bs, bIPv6)
60 62
 		}
61
-		bs = append(bs, b)
62 63
 	}
63 64
 	return bs, nil
64 65
 }
65 66
 
66
-func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) error {
67
-	var (
68
-		host net.Addr
69
-		err  error
70
-	)
71
-
72
-	// Store the container interface address in the operational binding
73
-	bnd.IP = containerIP
74
-
67
+// validatePortBindingIPv4 validates the port binding, populates the missing Host IP field and returns true
68
+// if this is a valid IPv4 binding, else returns false
69
+func (n *bridgeNetwork) validatePortBindingIPv4(bnd *types.PortBinding, containerIPv4, defHostIP net.IP) bool {
70
+	//Return early if there is a valid Host IP, but its not a IPv6 address
71
+	if len(bnd.HostIP) > 0 && bnd.HostIP.To4() == nil {
72
+		return false
73
+	}
75 74
 	// Adjust the host address in the operational binding
76 75
 	if len(bnd.HostIP) == 0 {
76
+		// Return early if the default binding address is an IPv6 address
77
+		if defHostIP.To4() == nil {
78
+			return false
79
+		}
77 80
 		bnd.HostIP = defHostIP
78 81
 	}
82
+	bnd.IP = containerIPv4
83
+	return true
84
+
85
+}
86
+
87
+// validatePortBindingIPv6 validates the port binding, populates the missing Host IP field and returns true
88
+// if this is a valid IP6v binding, else returns false
89
+func (n *bridgeNetwork) validatePortBindingIPv6(bnd *types.PortBinding, containerIPv6, defHostIP net.IP) bool {
90
+	// Return early if there is no IPv6 container endpoint
91
+	if containerIPv6 == nil {
92
+		return false
93
+	}
94
+	// Return early if there is a valid Host IP, which is a IPv4 address
95
+	if len(bnd.HostIP) > 0 && bnd.HostIP.To4() != nil {
96
+		return false
97
+	}
98
+
99
+	// Setup a binding to  "::" if Host IP is empty and the default binding IP is 0.0.0.0
100
+	if len(bnd.HostIP) == 0 {
101
+		if defHostIP.Equal(net.IPv4zero) {
102
+			bnd.HostIP = net.IPv6zero
103
+			// If the default binding IP is an IPv6 address, use it
104
+		} else if defHostIP.To4() == nil {
105
+			bnd.HostIP = defHostIP
106
+			// Return false if default binding ip is an IPv4 address
107
+		} else {
108
+			return false
109
+		}
110
+	}
111
+	bnd.IP = containerIPv6
112
+	return true
113
+
114
+}
115
+
116
+func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, ulPxyEnabled bool) error {
117
+	var (
118
+		host net.Addr
119
+		err  error
120
+	)
79 121
 
80 122
 	// Adjust HostPortEnd if this is not a range.
81 123
 	if bnd.HostPortEnd == 0 {
... ...
@@ -90,7 +132,7 @@ func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHos
90 90
 
91 91
 	portmapper := n.portMapper
92 92
 
93
-	if containerIP.To4() == nil {
93
+	if bnd.IP.To4() == nil {
94 94
 		portmapper = n.portMapperV6
95 95
 	}
96 96
 
... ...
@@ -151,20 +151,16 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
151 151
 	}
152 152
 
153 153
 	containerIP, containerPort := getIPAndPort(m.container)
154
-	if pm.checkIP(hostIP) {
155
-		if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
156
-			return nil, err
157
-		}
154
+	if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
155
+		return nil, err
158 156
 	}
159 157
 
160 158
 	cleanup := func() error {
161 159
 		// need to undo the iptables rules before we return
162 160
 		m.userlandProxy.Stop()
163
-		if pm.checkIP(hostIP) {
164
-			pm.DeleteForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
165
-			if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
166
-				return err
167
-			}
161
+		pm.DeleteForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
162
+		if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
163
+			return err
168 164
 		}
169 165
 
170 166
 		return nil
... ...
@@ -44,11 +44,3 @@ func (pm *PortMapper) forward(action iptables.Action, proto string, sourceIP net
44 44
 	}
45 45
 	return pm.chain.Forward(action, sourceIP, sourcePort, proto, containerIP, containerPort, pm.bridgeName)
46 46
 }
47
-
48
-// checkIP checks if IP is valid and matching to chain version
49
-func (pm *PortMapper) checkIP(ip net.IP) bool {
50
-	if pm.chain == nil || pm.chain.IPTable.Version == iptables.IPv4 {
51
-		return ip.To4() != nil
52
-	}
53
-	return ip.To16() != nil
54
-}
... ...
@@ -19,6 +19,16 @@ type userlandProxy interface {
19 19
 	Stop() error
20 20
 }
21 21
 
22
+// ipVersion refers to IP version - v4 or v6
23
+type ipVersion string
24
+
25
+const (
26
+	// IPv4 is version 4
27
+	ipv4 ipVersion = "4"
28
+	// IPv4 is version 6
29
+	ipv6 ipVersion = "6"
30
+)
31
+
22 32
 // proxyCommand wraps an exec.Cmd to run the userland TCP and UDP
23 33
 // proxies as separate processes.
24 34
 type proxyCommand struct {
... ...
@@ -77,21 +87,27 @@ func (p *proxyCommand) Stop() error {
77 77
 // port allocations on bound port, because without userland proxy we using
78 78
 // iptables rules and not net.Listen
79 79
 type dummyProxy struct {
80
-	listener io.Closer
81
-	addr     net.Addr
80
+	listener  io.Closer
81
+	addr      net.Addr
82
+	ipVersion ipVersion
82 83
 }
83 84
 
84 85
 func newDummyProxy(proto string, hostIP net.IP, hostPort int) (userlandProxy, error) {
86
+	// detect version of hostIP to bind only to correct version
87
+	version := ipv4
88
+	if hostIP.To4() == nil {
89
+		version = ipv6
90
+	}
85 91
 	switch proto {
86 92
 	case "tcp":
87 93
 		addr := &net.TCPAddr{IP: hostIP, Port: hostPort}
88
-		return &dummyProxy{addr: addr}, nil
94
+		return &dummyProxy{addr: addr, ipVersion: version}, nil
89 95
 	case "udp":
90 96
 		addr := &net.UDPAddr{IP: hostIP, Port: hostPort}
91
-		return &dummyProxy{addr: addr}, nil
97
+		return &dummyProxy{addr: addr, ipVersion: version}, nil
92 98
 	case "sctp":
93 99
 		addr := &sctp.SCTPAddr{IPAddrs: []net.IPAddr{{IP: hostIP}}, Port: hostPort}
94
-		return &dummyProxy{addr: addr}, nil
100
+		return &dummyProxy{addr: addr, ipVersion: version}, nil
95 101
 	default:
96 102
 		return nil, fmt.Errorf("Unknown addr type: %s", proto)
97 103
 	}
... ...
@@ -100,19 +116,19 @@ func newDummyProxy(proto string, hostIP net.IP, hostPort int) (userlandProxy, er
100 100
 func (p *dummyProxy) Start() error {
101 101
 	switch addr := p.addr.(type) {
102 102
 	case *net.TCPAddr:
103
-		l, err := net.ListenTCP("tcp", addr)
103
+		l, err := net.ListenTCP("tcp"+string(p.ipVersion), addr)
104 104
 		if err != nil {
105 105
 			return err
106 106
 		}
107 107
 		p.listener = l
108 108
 	case *net.UDPAddr:
109
-		l, err := net.ListenUDP("udp", addr)
109
+		l, err := net.ListenUDP("udp"+string(p.ipVersion), addr)
110 110
 		if err != nil {
111 111
 			return err
112 112
 		}
113 113
 		p.listener = l
114 114
 	case *sctp.SCTPAddr:
115
-		l, err := sctp.ListenSCTP("sctp", addr)
115
+		l, err := sctp.ListenSCTP("sctp"+string(p.ipVersion), addr)
116 116
 		if err != nil {
117 117
 			return err
118 118
 		}