Browse code

Merge pull request #26659 from yongtang/26341-fixed-cidr-multiple-addresses-bridge

Fix issue for `--fixed-cidr` when bridge has multiple addresses

Michael Crosby authored on 2016/10/29 03:05:01
Showing 19 changed files
... ...
@@ -41,6 +41,7 @@ import (
41 41
 	rsystem "github.com/opencontainers/runc/libcontainer/system"
42 42
 	"github.com/opencontainers/runc/libcontainer/user"
43 43
 	specs "github.com/opencontainers/runtime-spec/specs-go"
44
+	"github.com/pkg/errors"
44 45
 	"github.com/vishvananda/netlink"
45 46
 )
46 47
 
... ...
@@ -710,13 +711,30 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
710 710
 
711 711
 	ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
712 712
 
713
-	nw, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName)
714
-	if err == nil {
715
-		ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String()
716
-		hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask)
717
-		if hip.IsGlobalUnicast() {
718
-			ipamV4Conf.Gateway = nw.IP.String()
713
+	nwList, nw6List, err := netutils.ElectInterfaceAddresses(bridgeName)
714
+	if err != nil {
715
+		return errors.Wrap(err, "list bridge addresses failed")
716
+	}
717
+
718
+	nw := nwList[0]
719
+	if len(nwList) > 1 && config.bridgeConfig.FixedCIDR != "" {
720
+		_, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR)
721
+		if err != nil {
722
+			return errors.Wrap(err, "parse CIDR failed")
719 723
 		}
724
+		// Iterate through in case there are multiple addresses for the bridge
725
+		for _, entry := range nwList {
726
+			if fCIDR.Contains(entry.IP) {
727
+				nw = entry
728
+				break
729
+			}
730
+		}
731
+	}
732
+
733
+	ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String()
734
+	hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask)
735
+	if hip.IsGlobalUnicast() {
736
+		ipamV4Conf.Gateway = nw.IP.String()
720 737
 	}
721 738
 
722 739
 	if config.bridgeConfig.IP != "" {
... ...
@@ -70,7 +70,7 @@ clone git github.com/RackSec/srslog 365bf33cd9acc21ae1c355209865f17228ca534e
70 70
 clone git github.com/imdario/mergo 0.2.1
71 71
 
72 72
 #get libnetwork packages
73
-clone git github.com/docker/libnetwork 9fbb4ecbb45af655c4ac3c2f3a849b2294cb447a
73
+clone git github.com/docker/libnetwork f4338b6f1085ccfe5972e655cca8a1d15d73439d
74 74
 clone git github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
75 75
 clone git github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
76 76
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
... ...
@@ -1062,9 +1062,14 @@ func SandboxKeyWalker(out *Sandbox, key string) SandboxWalker {
1062 1062
 }
1063 1063
 
1064 1064
 func (c *controller) loadDriver(networkType string) error {
1065
-	// Plugins pkg performs lazy loading of plugins that acts as remote drivers.
1066
-	// As per the design, this Get call will result in remote driver discovery if there is a corresponding plugin available.
1067
-	_, err := plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
1065
+	var err error
1066
+
1067
+	if pg := c.GetPluginGetter(); pg != nil {
1068
+		_, err = pg.Get(networkType, driverapi.NetworkPluginEndpointType, plugingetter.LOOKUP)
1069
+	} else {
1070
+		_, err = plugins.Get(networkType, driverapi.NetworkPluginEndpointType)
1071
+	}
1072
+
1068 1073
 	if err != nil {
1069 1074
 		if err == plugins.ErrNotFound {
1070 1075
 			return types.NotFoundErrorf(err.Error())
... ...
@@ -1076,7 +1081,15 @@ func (c *controller) loadDriver(networkType string) error {
1076 1076
 }
1077 1077
 
1078 1078
 func (c *controller) loadIPAMDriver(name string) error {
1079
-	if _, err := c.GetPluginGetter().Get(name, ipamapi.PluginEndpointType, plugingetter.LOOKUP); err != nil {
1079
+	var err error
1080
+
1081
+	if pg := c.GetPluginGetter(); pg != nil {
1082
+		_, err = pg.Get(name, ipamapi.PluginEndpointType, plugingetter.LOOKUP)
1083
+	} else {
1084
+		_, err = plugins.Get(name, ipamapi.PluginEndpointType)
1085
+	}
1086
+
1087
+	if err != nil {
1080 1088
 		if err == plugins.ErrNotFound {
1081 1089
 			return types.NotFoundErrorf(err.Error())
1082 1090
 		}
... ...
@@ -779,6 +779,20 @@ func (d *driver) DeleteNetwork(nid string) error {
779 779
 	config := n.config
780 780
 	n.Unlock()
781 781
 
782
+	// delele endpoints belong to this network
783
+	for _, ep := range n.endpoints {
784
+		if err := n.releasePorts(ep); err != nil {
785
+			logrus.Warn(err)
786
+		}
787
+		if link, err := d.nlh.LinkByName(ep.srcName); err == nil {
788
+			d.nlh.LinkDel(link)
789
+		}
790
+
791
+		if err := d.storeDelete(ep); err != nil {
792
+			logrus.Warnf("Failed to remove bridge endpoint %s from store: %v", ep.id[0:7], err)
793
+		}
794
+	}
795
+
782 796
 	d.Lock()
783 797
 	delete(d.networks, nid)
784 798
 	d.Unlock()
... ...
@@ -52,23 +52,22 @@ func (i *bridgeInterface) exists() bool {
52 52
 	return i.Link != nil
53 53
 }
54 54
 
55
-// addresses returns a single IPv4 address and all IPv6 addresses for the
56
-// bridge interface.
57
-func (i *bridgeInterface) addresses() (netlink.Addr, []netlink.Addr, error) {
55
+// addresses returns all IPv4 addresses and all IPv6 addresses for the bridge interface.
56
+func (i *bridgeInterface) addresses() ([]netlink.Addr, []netlink.Addr, error) {
58 57
 	v4addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V4)
59 58
 	if err != nil {
60
-		return netlink.Addr{}, nil, fmt.Errorf("Failed to retrieve V4 addresses: %v", err)
59
+		return nil, nil, fmt.Errorf("Failed to retrieve V4 addresses: %v", err)
61 60
 	}
62 61
 
63 62
 	v6addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V6)
64 63
 	if err != nil {
65
-		return netlink.Addr{}, nil, fmt.Errorf("Failed to retrieve V6 addresses: %v", err)
64
+		return nil, nil, fmt.Errorf("Failed to retrieve V6 addresses: %v", err)
66 65
 	}
67 66
 
68 67
 	if len(v4addr) == 0 {
69
-		return netlink.Addr{}, v6addr, nil
68
+		return nil, v6addr, nil
70 69
 	}
71
-	return v4addr[0], v6addr, nil
70
+	return v4addr, v6addr, nil
72 71
 }
73 72
 
74 73
 func (i *bridgeInterface) programIPv6Address() error {
... ...
@@ -3,6 +3,7 @@ package bridge
3 3
 import (
4 4
 	"fmt"
5 5
 	"io/ioutil"
6
+	"net"
6 7
 	"path/filepath"
7 8
 
8 9
 	log "github.com/Sirupsen/logrus"
... ...
@@ -10,12 +11,28 @@ import (
10 10
 	"github.com/vishvananda/netlink"
11 11
 )
12 12
 
13
+func selectIPv4Address(addresses []netlink.Addr, selector *net.IPNet) (netlink.Addr, error) {
14
+	if len(addresses) == 0 {
15
+		return netlink.Addr{}, fmt.Errorf("unable to select an address as the address pool is empty")
16
+	}
17
+	if selector != nil {
18
+		for _, addr := range addresses {
19
+			if selector.Contains(addr.IP) {
20
+				return addr, nil
21
+			}
22
+		}
23
+	}
24
+	return addresses[0], nil
25
+}
26
+
13 27
 func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error {
14
-	addrv4, _, err := i.addresses()
28
+	addrv4List, _, err := i.addresses()
15 29
 	if err != nil {
16 30
 		return fmt.Errorf("failed to retrieve bridge interface addresses: %v", err)
17 31
 	}
18 32
 
33
+	addrv4, _ := selectIPv4Address(addrv4List, config.AddressIPv4)
34
+
19 35
 	if !types.CompareIPNet(addrv4.IPNet, config.AddressIPv4) {
20 36
 		if addrv4.IPNet != nil {
21 37
 			if err := i.nlh.AddrDel(i.Link, &addrv4); err != nil {
... ...
@@ -11,12 +11,14 @@ import (
11 11
 )
12 12
 
13 13
 func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) error {
14
-	// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
15
-	addrv4, addrsv6, err := i.addresses()
14
+	// Fetch a slice of IPv4 addresses and a slice of IPv6 addresses from the bridge.
15
+	addrsv4, addrsv6, err := i.addresses()
16 16
 	if err != nil {
17 17
 		return fmt.Errorf("Failed to verify ip addresses: %v", err)
18 18
 	}
19 19
 
20
+	addrv4, _ := selectIPv4Address(addrsv4, config.AddressIPv4)
21
+
20 22
 	// Verify that the bridge does have an IPv4 address.
21 23
 	if addrv4.IPNet == nil {
22 24
 		return &ErrNoIPAddr{}
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"github.com/docker/docker/pkg/stringid"
9 9
 	"github.com/docker/libnetwork/driverapi"
10 10
 	"github.com/docker/libnetwork/netlabel"
11
+	"github.com/docker/libnetwork/ns"
11 12
 	"github.com/docker/libnetwork/options"
12 13
 	"github.com/docker/libnetwork/osl"
13 14
 	"github.com/docker/libnetwork/types"
... ...
@@ -147,6 +148,15 @@ func (d *driver) DeleteNetwork(nid string) error {
147 147
 			}
148 148
 		}
149 149
 	}
150
+	for _, ep := range n.endpoints {
151
+		if link, err := ns.NlHandle().LinkByName(ep.srcName); err == nil {
152
+			ns.NlHandle().LinkDel(link)
153
+		}
154
+
155
+		if err := d.storeDelete(ep); err != nil {
156
+			logrus.Warnf("Failed to remove ipvlan endpoint %s from store: %v", ep.id[0:7], err)
157
+		}
158
+	}
150 159
 	// delete the *network
151 160
 	d.deleteNetwork(nid)
152 161
 	// delete the network record from persistent cache
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"github.com/docker/docker/pkg/stringid"
9 9
 	"github.com/docker/libnetwork/driverapi"
10 10
 	"github.com/docker/libnetwork/netlabel"
11
+	"github.com/docker/libnetwork/ns"
11 12
 	"github.com/docker/libnetwork/options"
12 13
 	"github.com/docker/libnetwork/osl"
13 14
 	"github.com/docker/libnetwork/types"
... ...
@@ -151,6 +152,15 @@ func (d *driver) DeleteNetwork(nid string) error {
151 151
 			}
152 152
 		}
153 153
 	}
154
+	for _, ep := range n.endpoints {
155
+		if link, err := ns.NlHandle().LinkByName(ep.srcName); err == nil {
156
+			ns.NlHandle().LinkDel(link)
157
+		}
158
+
159
+		if err := d.storeDelete(ep); err != nil {
160
+			logrus.Warnf("Failed to remove macvlan endpoint %s from store: %v", ep.id[0:7], err)
161
+		}
162
+	}
154 163
 	// delete the *network
155 164
 	d.deleteNetwork(nid)
156 165
 	// delete the network record from persistent cache
... ...
@@ -182,6 +182,18 @@ func (d *driver) DeleteNetwork(nid string) error {
182 182
 		return fmt.Errorf("could not find network with id %s", nid)
183 183
 	}
184 184
 
185
+	for _, ep := range n.endpoints {
186
+		if ep.ifName != "" {
187
+			if link, err := ns.NlHandle().LinkByName(ep.ifName); err != nil {
188
+				ns.NlHandle().LinkDel(link)
189
+			}
190
+		}
191
+
192
+		if err := d.deleteEndpointFromStore(ep); err != nil {
193
+			logrus.Warnf("Failed to delete overlay endpoint %s from local store: %v", ep.id[0:7], err)
194
+		}
195
+
196
+	}
185 197
 	d.deleteNetwork(nid)
186 198
 
187 199
 	vnis, err := n.releaseVxlanID()
... ...
@@ -513,14 +513,22 @@ func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {
513 513
 	if moveExtConn {
514 514
 		if extEp != nil {
515 515
 			log.Debugf("Revoking external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
516
-			if err = d.RevokeExternalConnectivity(extEp.network.ID(), extEp.ID()); err != nil {
516
+			extN, err := extEp.getNetworkFromStore()
517
+			if err != nil {
518
+				return fmt.Errorf("failed to get network from store during join: %v", err)
519
+			}
520
+			extD, err := extN.driver(true)
521
+			if err != nil {
522
+				return fmt.Errorf("failed to join endpoint: %v", err)
523
+			}
524
+			if err = extD.RevokeExternalConnectivity(extEp.network.ID(), extEp.ID()); err != nil {
517 525
 				return types.InternalErrorf(
518 526
 					"driver failed revoking external connectivity on endpoint %s (%s): %v",
519 527
 					extEp.Name(), extEp.ID(), err)
520 528
 			}
521 529
 			defer func() {
522 530
 				if err != nil {
523
-					if e := d.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); e != nil {
531
+					if e := extD.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); e != nil {
524 532
 						log.Warnf("Failed to roll-back external connectivity on endpoint %s (%s): %v",
525 533
 							extEp.Name(), extEp.ID(), e)
526 534
 					}
... ...
@@ -699,7 +707,15 @@ func (ep *endpoint) sbLeave(sb *sandbox, force bool, options ...EndpointOption)
699 699
 	extEp = sb.getGatewayEndpoint()
700 700
 	if moveExtConn && extEp != nil {
701 701
 		log.Debugf("Programming external connectivity on endpoint %s (%s)", extEp.Name(), extEp.ID())
702
-		if err := d.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); err != nil {
702
+		extN, err := extEp.getNetworkFromStore()
703
+		if err != nil {
704
+			return fmt.Errorf("failed to get network from store during leave: %v", err)
705
+		}
706
+		extD, err := extN.driver(true)
707
+		if err != nil {
708
+			return fmt.Errorf("failed to leave endpoint: %v", err)
709
+		}
710
+		if err := extD.ProgramExternalConnectivity(extEp.network.ID(), extEp.ID(), sb.Labels()); err != nil {
703 711
 			log.Warnf("driver failed programming external connectivity on endpoint %s: (%s) %v",
704 712
 				extEp.Name(), extEp.ID(), err)
705 713
 		}
... ...
@@ -199,12 +199,22 @@ func (a *Allocator) GetDefaultAddressSpaces() (string, string, error) {
199 199
 // RequestPool returns an address pool along with its unique id.
200 200
 func (a *Allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
201 201
 	log.Debugf("RequestPool(%s, %s, %s, %v, %t)", addressSpace, pool, subPool, options, v6)
202
-retry:
203
-	k, nw, ipr, pdf, err := a.parsePoolRequest(addressSpace, pool, subPool, v6)
202
+
203
+	k, nw, ipr, err := a.parsePoolRequest(addressSpace, pool, subPool, v6)
204 204
 	if err != nil {
205 205
 		return "", nil, nil, types.InternalErrorf("failed to parse pool request for address space %q pool %q subpool %q: %v", addressSpace, pool, subPool, err)
206 206
 	}
207 207
 
208
+	pdf := k == nil
209
+
210
+retry:
211
+	if pdf {
212
+		if nw, err = a.getPredefinedPool(addressSpace, v6); err != nil {
213
+			return "", nil, nil, err
214
+		}
215
+		k = &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String()}
216
+	}
217
+
208 218
 	if err := a.refresh(addressSpace); err != nil {
209 219
 		return "", nil, nil, err
210 220
 	}
... ...
@@ -279,39 +289,36 @@ func (a *Allocator) getAddrSpace(as string) (*addrSpace, error) {
279 279
 	return aSpace, nil
280 280
 }
281 281
 
282
-func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool) (*SubnetKey, *net.IPNet, *AddressRange, bool, error) {
282
+func (a *Allocator) parsePoolRequest(addressSpace, pool, subPool string, v6 bool) (*SubnetKey, *net.IPNet, *AddressRange, error) {
283 283
 	var (
284 284
 		nw  *net.IPNet
285 285
 		ipr *AddressRange
286 286
 		err error
287
-		pdf = false
288 287
 	)
289 288
 
290 289
 	if addressSpace == "" {
291
-		return nil, nil, nil, false, ipamapi.ErrInvalidAddressSpace
290
+		return nil, nil, nil, ipamapi.ErrInvalidAddressSpace
292 291
 	}
293 292
 
294 293
 	if pool == "" && subPool != "" {
295
-		return nil, nil, nil, false, ipamapi.ErrInvalidSubPool
294
+		return nil, nil, nil, ipamapi.ErrInvalidSubPool
296 295
 	}
297 296
 
298
-	if pool != "" {
299
-		if _, nw, err = net.ParseCIDR(pool); err != nil {
300
-			return nil, nil, nil, false, ipamapi.ErrInvalidPool
301
-		}
302
-		if subPool != "" {
303
-			if ipr, err = getAddressRange(subPool, nw); err != nil {
304
-				return nil, nil, nil, false, err
305
-			}
306
-		}
307
-	} else {
308
-		if nw, err = a.getPredefinedPool(addressSpace, v6); err != nil {
309
-			return nil, nil, nil, false, err
297
+	if pool == "" {
298
+		return nil, nil, nil, nil
299
+	}
300
+
301
+	if _, nw, err = net.ParseCIDR(pool); err != nil {
302
+		return nil, nil, nil, ipamapi.ErrInvalidPool
303
+	}
304
+
305
+	if subPool != "" {
306
+		if ipr, err = getAddressRange(subPool, nw); err != nil {
307
+			return nil, nil, nil, err
310 308
 		}
311
-		pdf = true
312 309
 	}
313 310
 
314
-	return &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String(), ChildSubnet: subPool}, nw, ipr, pdf, nil
311
+	return &SubnetKey{AddressSpace: addressSpace, Subnet: nw.String(), ChildSubnet: subPool}, nw, ipr, nil
315 312
 }
316 313
 
317 314
 func (a *Allocator) insertBitMask(key SubnetKey, pool *net.IPNet) error {
... ...
@@ -406,7 +413,7 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error)
406 406
 		}
407 407
 	}
408 408
 
409
-	return nil, types.NotFoundErrorf("could not find an available predefined network")
409
+	return nil, types.NotFoundErrorf("could not find an available non-overlapping address pool among the defaults to auto assign to the network")
410 410
 }
411 411
 
412 412
 // RequestAddress returns an address from the specified pool ID
... ...
@@ -7,10 +7,12 @@ import (
7 7
 )
8 8
 
9 9
 // ElectInterfaceAddresses looks for an interface on the OS with the specified name
10
-// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist,
11
-// it chooses from a predifined list the first IPv4 address which does not conflict
12
-// with other interfaces on the system.
13
-func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
10
+// and returns returns all its IPv4 and IPv6 addresses in CIDR notation.
11
+// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned.
12
+// If the interface does not exist, it chooses from a predefined
13
+// list the first IPv4 address which does not conflict with other
14
+// interfaces on the system.
15
+func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) {
14 16
 	return nil, nil, types.NotImplementedErrorf("not supported on freebsd")
15 17
 }
16 18
 
... ...
@@ -62,15 +62,15 @@ func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, err
62 62
 }
63 63
 
64 64
 // ElectInterfaceAddresses looks for an interface on the OS with the
65
-// specified name and returns its IPv4 and IPv6 addresses in CIDR
66
-// form. If the interface does not exist, it chooses from a predefined
65
+// specified name and returns returns all its IPv4 and IPv6 addresses in CIDR notation.
66
+// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned.
67
+// If the interface does not exist, it chooses from a predefined
67 68
 // list the first IPv4 address which does not conflict with other
68 69
 // interfaces on the system.
69
-func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
70
+func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) {
70 71
 	var (
71
-		v4Net  *net.IPNet
72
+		v4Nets []*net.IPNet
72 73
 		v6Nets []*net.IPNet
73
-		err    error
74 74
 	)
75 75
 
76 76
 	defer osl.InitOSContext()()
... ...
@@ -85,23 +85,24 @@ func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
85 85
 		if err != nil {
86 86
 			return nil, nil, err
87 87
 		}
88
-		if len(v4addr) > 0 {
89
-			v4Net = v4addr[0].IPNet
88
+		for _, nlAddr := range v4addr {
89
+			v4Nets = append(v4Nets, nlAddr.IPNet)
90 90
 		}
91 91
 		for _, nlAddr := range v6addr {
92 92
 			v6Nets = append(v6Nets, nlAddr.IPNet)
93 93
 		}
94 94
 	}
95 95
 
96
-	if link == nil || v4Net == nil {
96
+	if link == nil || len(v4Nets) == 0 {
97 97
 		// Choose from predefined broad networks
98
-		v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
98
+		v4Net, err := FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
99 99
 		if err != nil {
100 100
 			return nil, nil, err
101 101
 		}
102
+		v4Nets = append(v4Nets, v4Net)
102 103
 	}
103 104
 
104
-	return v4Net, v6Nets, nil
105
+	return v4Nets, v6Nets, nil
105 106
 }
106 107
 
107 108
 // FindAvailableNetwork returns a network from the passed list which does not
... ...
@@ -22,10 +22,12 @@ func CheckRouteOverlaps(toCheck *net.IPNet) error {
22 22
 }
23 23
 
24 24
 // ElectInterfaceAddresses looks for an interface on the OS with the specified name
25
-// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist,
26
-// it chooses from a predifined list the first IPv4 address which does not conflict
27
-// with other interfaces on the system.
28
-func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
25
+// and returns returns all its IPv4 and IPv6 addresses in CIDR notation.
26
+// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned.
27
+// If the interface does not exist, it chooses from a predefined
28
+// list the first IPv4 address which does not conflict with other
29
+// interfaces on the system.
30
+func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) {
29 31
 	var (
30 32
 		v4Net *net.IPNet
31 33
 	)
... ...
@@ -63,7 +65,7 @@ func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
63 63
 			return nil, nil, err
64 64
 		}
65 65
 	}
66
-	return v4Net, nil, nil
66
+	return []*net.IPNet{v4Net}, nil, nil
67 67
 }
68 68
 
69 69
 // FindAvailableNetwork returns a network from the passed list which does not
... ...
@@ -7,10 +7,12 @@ import (
7 7
 )
8 8
 
9 9
 // ElectInterfaceAddresses looks for an interface on the OS with the specified name
10
-// and returns its IPv4 and IPv6 addresses in CIDR form. If the interface does not exist,
11
-// it chooses from a predifined list the first IPv4 address which does not conflict
12
-// with other interfaces on the system.
13
-func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
10
+// and returns returns all its IPv4 and IPv6 addresses in CIDR notation.
11
+// If a failure in retrieving the addresses or no IPv4 address is found, an error is returned.
12
+// If the interface does not exist, it chooses from a predefined
13
+// list the first IPv4 address which does not conflict with other
14
+// interfaces on the system.
15
+func ElectInterfaceAddresses(name string) ([]*net.IPNet, []*net.IPNet, error) {
14 16
 	return nil, nil, types.NotImplementedErrorf("not supported on windows")
15 17
 }
16 18
 
... ...
@@ -16,9 +16,11 @@ import (
16 16
 )
17 17
 
18 18
 const (
19
-	reapInterval  = 60 * time.Second
20
-	reapPeriod    = 5 * time.Second
21
-	retryInterval = 1 * time.Second
19
+	reapInterval     = 60 * time.Second
20
+	reapPeriod       = 5 * time.Second
21
+	retryInterval    = 1 * time.Second
22
+	nodeReapInterval = 24 * time.Hour
23
+	nodeReapPeriod   = 2 * time.Hour
22 24
 )
23 25
 
24 26
 type logWriter struct{}
... ...
@@ -147,6 +149,7 @@ func (nDB *NetworkDB) clusterInit() error {
147 147
 		{config.GossipInterval, nDB.gossip},
148 148
 		{config.PushPullInterval, nDB.bulkSyncTables},
149 149
 		{retryInterval, nDB.reconnectNode},
150
+		{nodeReapPeriod, nDB.reapDeadNode},
150 151
 	} {
151 152
 		t := time.NewTicker(trigger.interval)
152 153
 		go nDB.triggerFunc(trigger.interval, t.C, nDB.stopCh, trigger.fn)
... ...
@@ -234,6 +237,19 @@ func (nDB *NetworkDB) triggerFunc(stagger time.Duration, C <-chan time.Time, sto
234 234
 	}
235 235
 }
236 236
 
237
+func (nDB *NetworkDB) reapDeadNode() {
238
+	nDB.Lock()
239
+	defer nDB.Unlock()
240
+	for id, n := range nDB.failedNodes {
241
+		if n.reapTime > 0 {
242
+			n.reapTime -= reapPeriod
243
+			continue
244
+		}
245
+		logrus.Debugf("Removing failed node %v from gossip cluster", n.Name)
246
+		delete(nDB.failedNodes, id)
247
+	}
248
+}
249
+
237 250
 func (nDB *NetworkDB) reconnectNode() {
238 251
 	nDB.RLock()
239 252
 	if len(nDB.failedNodes) == 0 {
... ...
@@ -29,6 +29,8 @@ func (e *eventDelegate) NotifyLeave(mn *memberlist.Node) {
29 29
 	e.nDB.Lock()
30 30
 	if n, ok := e.nDB.nodes[mn.Name]; ok {
31 31
 		delete(e.nDB.nodes, mn.Name)
32
+
33
+		n.reapTime = reapInterval
32 34
 		e.nDB.failedNodes[mn.Name] = n
33 35
 	}
34 36
 	e.nDB.Unlock()
... ...
@@ -94,6 +94,8 @@ type NetworkDB struct {
94 94
 type node struct {
95 95
 	memberlist.Node
96 96
 	ltime serf.LamportTime
97
+	// Number of hours left before the reaper removes the node
98
+	reapTime time.Duration
97 99
 }
98 100
 
99 101
 // network describes the node/network attachment.