Browse code

Libnetwork vendoring

Fixes in the Service Discovery areas

Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>

Flavio Crisciani authored on 2017/06/20 11:42:24
Showing 16 changed files
... ...
@@ -26,7 +26,7 @@ github.com/imdario/mergo 0.2.1
26 26
 golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0
27 27
 
28 28
 #get libnetwork packages
29
-github.com/docker/libnetwork f4a15a0890383619ad797b3bd2481cc6f46a978d
29
+github.com/docker/libnetwork 6426d1e66f33c0b0c8bb135b7ee547447f54d043
30 30
 github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
31 31
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
32 32
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
... ...
@@ -165,13 +165,13 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error {
165 165
 		a.networkDB.SetKey(added)
166 166
 	}
167 167
 
168
-	key, tag, err := c.getPrimaryKeyTag(subsysGossip)
168
+	key, _, err := c.getPrimaryKeyTag(subsysGossip)
169 169
 	if err != nil {
170 170
 		return err
171 171
 	}
172 172
 	a.networkDB.SetPrimaryKey(key)
173 173
 
174
-	key, tag, err = c.getPrimaryKeyTag(subsysIPSec)
174
+	key, tag, err := c.getPrimaryKeyTag(subsysIPSec)
175 175
 	if err != nil {
176 176
 		return err
177 177
 	}
... ...
@@ -648,13 +648,13 @@ func (ep *endpoint) addServiceInfoToCluster(sb *sandbox) error {
648 648
 		TaskAliases:  ep.myAliases,
649 649
 		EndpointIP:   ep.Iface().Address().IP.String(),
650 650
 	})
651
-
652 651
 	if err != nil {
653 652
 		return err
654 653
 	}
655 654
 
656 655
 	if agent != nil {
657 656
 		if err := agent.networkDB.CreateEntry(libnetworkEPTable, n.ID(), ep.ID(), buf); err != nil {
657
+			logrus.Warnf("addServiceInfoToCluster NetworkDB CreateEntry failed for %s %s err:%s", ep.id, n.id, err)
658 658
 			return err
659 659
 		}
660 660
 	}
... ...
@@ -686,6 +686,13 @@ func (ep *endpoint) deleteServiceInfoFromCluster(sb *sandbox, method string) err
686 686
 		name = ep.MyAliases()[0]
687 687
 	}
688 688
 
689
+	if agent != nil {
690
+		// First delete from networkDB then locally
691
+		if err := agent.networkDB.DeleteEntry(libnetworkEPTable, n.ID(), ep.ID()); err != nil {
692
+			logrus.Warnf("deleteServiceInfoFromCluster NetworkDB DeleteEntry failed for %s %s err:%s", ep.id, n.id, err)
693
+		}
694
+	}
695
+
689 696
 	if ep.Iface().Address() != nil {
690 697
 		if ep.svcID != "" {
691 698
 			// This is a task part of a service
... ...
@@ -693,7 +700,7 @@ func (ep *endpoint) deleteServiceInfoFromCluster(sb *sandbox, method string) err
693 693
 			if n.ingress {
694 694
 				ingressPorts = ep.ingressPorts
695 695
 			}
696
-			if err := c.rmServiceBinding(ep.svcName, ep.svcID, n.ID(), ep.ID(), name, ep.virtualIP, ingressPorts, ep.svcAliases, ep.myAliases, ep.Iface().Address().IP, "deleteServiceInfoFromCluster"); err != nil {
696
+			if err := c.rmServiceBinding(ep.svcName, ep.svcID, n.ID(), ep.ID(), name, ep.virtualIP, ingressPorts, ep.svcAliases, ep.myAliases, ep.Iface().Address().IP, "deleteServiceInfoFromCluster", true); err != nil {
697 697
 				return err
698 698
 			}
699 699
 		} else {
... ...
@@ -704,12 +711,6 @@ func (ep *endpoint) deleteServiceInfoFromCluster(sb *sandbox, method string) err
704 704
 		}
705 705
 	}
706 706
 
707
-	if agent != nil {
708
-		if err := agent.networkDB.DeleteEntry(libnetworkEPTable, n.ID(), ep.ID()); err != nil {
709
-			return err
710
-		}
711
-	}
712
-
713 707
 	logrus.Debugf("deleteServiceInfoFromCluster from %s END for %s %s", method, ep.svcName, ep.ID())
714 708
 
715 709
 	return nil
... ...
@@ -883,7 +884,7 @@ func (c *controller) handleEpTableEvent(ev events.Event) {
883 883
 	}
884 884
 
885 885
 	if isAdd {
886
-		logrus.Debugf("handleEpTableEvent ADD %s R:%v", isAdd, eid, epRec)
886
+		logrus.Debugf("handleEpTableEvent ADD %s R:%v", eid, epRec)
887 887
 		if svcID != "" {
888 888
 			// This is a remote task part of a service
889 889
 			if err := c.addServiceBinding(svcName, svcID, nid, eid, containerName, vip, ingressPorts, serviceAliases, taskAliases, ip, "handleEpTableEvent"); err != nil {
... ...
@@ -897,10 +898,10 @@ func (c *controller) handleEpTableEvent(ev events.Event) {
897 897
 			}
898 898
 		}
899 899
 	} else {
900
-		logrus.Debugf("handleEpTableEvent DEL %s R:%v", isAdd, eid, epRec)
900
+		logrus.Debugf("handleEpTableEvent DEL %s R:%v", eid, epRec)
901 901
 		if svcID != "" {
902 902
 			// This is a remote task part of a service
903
-			if err := c.rmServiceBinding(svcName, svcID, nid, eid, containerName, vip, ingressPorts, serviceAliases, taskAliases, ip, "handleEpTableEvent"); err != nil {
903
+			if err := c.rmServiceBinding(svcName, svcID, nid, eid, containerName, vip, ingressPorts, serviceAliases, taskAliases, ip, "handleEpTableEvent", true); err != nil {
904 904
 				logrus.Errorf("failed removing service binding for %s epRec:%v err:%s", eid, epRec, err)
905 905
 				return
906 906
 			}
... ...
@@ -10,24 +10,26 @@ import (
10 10
 type SetMatrix interface {
11 11
 	// Get returns the members of the set for a specific key as a slice.
12 12
 	Get(key string) ([]interface{}, bool)
13
-	// Contains is used to verify is an element is in a set for a specific key
13
+	// Contains is used to verify if an element is in a set for a specific key
14 14
 	// returns true if the element is in the set
15 15
 	// returns true if there is a set for the key
16 16
 	Contains(key string, value interface{}) (bool, bool)
17
-	// Insert inserts the mapping between the IP and the endpoint identifier
18
-	// returns true if the mapping was not present, false otherwise
19
-	// returns also the number of endpoints associated to the IP
17
+	// Insert inserts the value in the set of a key
18
+	// returns true if the value is inserted (was not already in the set), false otherwise
19
+	// returns also the length of the set for the key
20 20
 	Insert(key string, value interface{}) (bool, int)
21
-	// Remove removes the mapping between the IP and the endpoint identifier
22
-	// returns true if the mapping was deleted, false otherwise
23
-	// returns also the number of endpoints associated to the IP
21
+	// Remove removes the value in the set for a specific key
22
+	// returns true if the value is deleted, false otherwise
23
+	// returns also the length of the set for the key
24 24
 	Remove(key string, value interface{}) (bool, int)
25
-	// Cardinality returns the number of elements in the set of a specfic key
26
-	// returns false if the key is not in the map
25
+	// Cardinality returns the number of elements in the set for a key
26
+	// returns false if the set is not present
27 27
 	Cardinality(key string) (int, bool)
28 28
 	// String returns the string version of the set, empty otherwise
29
-	// returns false if the key is not in the map
29
+	// returns false if the set is not present
30 30
 	String(key string) (string, bool)
31
+	// Returns all the keys in the map
32
+	Keys() []string
31 33
 }
32 34
 
33 35
 type setMatrix struct {
... ...
@@ -121,3 +123,13 @@ func (s *setMatrix) String(key string) (string, bool) {
121 121
 	}
122 122
 	return set.String(), ok
123 123
 }
124
+
125
+func (s *setMatrix) Keys() []string {
126
+	s.Lock()
127
+	defer s.Unlock()
128
+	keys := make([]string, 0, len(s.matrix))
129
+	for k := range s.matrix {
130
+		keys = append(keys, k)
131
+	}
132
+	return keys
133
+}
... ...
@@ -1014,7 +1014,7 @@ func (c *controller) NetworkByID(id string) (Network, error) {
1014 1014
 }
1015 1015
 
1016 1016
 // NewSandbox creates a new sandbox for the passed container id
1017
-func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (sBox Sandbox, err error) {
1017
+func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (Sandbox, error) {
1018 1018
 	if containerID == "" {
1019 1019
 		return nil, types.BadRequestErrorf("invalid container ID")
1020 1020
 	}
... ...
@@ -1054,7 +1054,6 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s
1054 1054
 			extDNS:             []extDNSEntry{},
1055 1055
 		}
1056 1056
 	}
1057
-	sBox = sb
1058 1057
 
1059 1058
 	heap.Init(&sb.endpoints)
1060 1059
 
... ...
@@ -1073,6 +1072,8 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s
1073 1073
 		sb.id = "ingress_sbox"
1074 1074
 	}
1075 1075
 	c.Unlock()
1076
+
1077
+	var err error
1076 1078
 	defer func() {
1077 1079
 		if err != nil {
1078 1080
 			c.Lock()
... ...
@@ -670,7 +670,7 @@ func (n *network) initSandbox(restore bool) error {
670 670
 	// In the restore case network sandbox already exist; but we don't know
671 671
 	// what epoch number it was created with. It has to be retrieved by
672 672
 	// searching the net namespaces.
673
-	key := ""
673
+	var key string
674 674
 	if restore {
675 675
 		key = osl.GenerateKey("-" + n.id)
676 676
 	} else {
... ...
@@ -872,15 +872,10 @@ func (n *network) Value() []byte {
872 872
 		netJSON = append(netJSON, sj)
873 873
 	}
874 874
 
875
-	b, err := json.Marshal(netJSON)
876
-	if err != nil {
877
-		return []byte{}
878
-	}
879
-
880 875
 	m["secure"] = n.secure
881 876
 	m["subnets"] = netJSON
882 877
 	m["mtu"] = n.mtu
883
-	b, err = json.Marshal(m)
878
+	b, err := json.Marshal(m)
884 879
 	if err != nil {
885 880
 		return []byte{}
886 881
 	}
... ...
@@ -457,7 +457,7 @@ func (n *network) initSandbox(restore bool) error {
457 457
 	// In the restore case network sandbox already exist; but we don't know
458 458
 	// what epoch number it was created with. It has to be retrieved by
459 459
 	// searching the net namespaces.
460
-	key := ""
460
+	var key string
461 461
 	if restore {
462 462
 		key = osl.GenerateKey("-" + n.id)
463 463
 	} else {
... ...
@@ -570,15 +570,10 @@ func (n *network) Value() []byte {
570 570
 		netJSON = append(netJSON, sj)
571 571
 	}
572 572
 
573
-	b, err := json.Marshal(netJSON)
574
-	if err != nil {
575
-		return []byte{}
576
-	}
577
-
578 573
 	m["secure"] = n.secure
579 574
 	m["subnets"] = netJSON
580 575
 	m["mtu"] = n.mtu
581
-	b, err = json.Marshal(m)
576
+	b, err := json.Marshal(m)
582 577
 	if err != nil {
583 578
 		return []byte{}
584 579
 	}
... ...
@@ -324,6 +324,9 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
324 324
 	}
325 325
 
326 326
 	n, err := d.getNetwork(id)
327
+	if err != nil {
328
+		return err
329
+	}
327 330
 	n.created = true
328 331
 	return d.storeUpdate(config)
329 332
 }
... ...
@@ -530,7 +533,13 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
530 530
 	}
531 531
 
532 532
 	epOption, err := parseEndpointOptions(epOptions)
533
+	if err != nil {
534
+		return err
535
+	}
533 536
 	epConnectivity, err := parseEndpointConnectivity(epOptions)
537
+	if err != nil {
538
+		return err
539
+	}
534 540
 
535 541
 	macAddress := ifInfo.MacAddress()
536 542
 	// Use the macaddress if it was provided
... ...
@@ -232,9 +232,12 @@ func (ep *hnsEndpoint) MarshalJSON() ([]byte, error) {
232 232
 	epMap["Type"] = ep.Type
233 233
 	epMap["profileID"] = ep.profileID
234 234
 	epMap["MacAddress"] = ep.macAddress.String()
235
-	epMap["Addr"] = ep.addr.String()
236
-	epMap["gateway"] = ep.gateway.String()
237
-
235
+	if ep.addr.IP != nil {
236
+		epMap["Addr"] = ep.addr.String()
237
+	}
238
+	if ep.gateway != nil {
239
+		epMap["gateway"] = ep.gateway.String()
240
+	}
238 241
 	epMap["epOption"] = ep.epOption
239 242
 	epMap["epConnectivity"] = ep.epConnectivity
240 243
 	epMap["PortMapping"] = ep.portMapping
... ...
@@ -251,7 +254,6 @@ func (ep *hnsEndpoint) UnmarshalJSON(b []byte) error {
251 251
 	if err = json.Unmarshal(b, &epMap); err != nil {
252 252
 		return fmt.Errorf("Failed to unmarshal to endpoint: %v", err)
253 253
 	}
254
-
255 254
 	if v, ok := epMap["MacAddress"]; ok {
256 255
 		if ep.macAddress, err = net.ParseMAC(v.(string)); err != nil {
257 256
 			return types.InternalErrorf("failed to decode endpoint MAC address (%s) after json unmarshal: %v", v.(string), err)
... ...
@@ -262,7 +264,9 @@ func (ep *hnsEndpoint) UnmarshalJSON(b []byte) error {
262 262
 			return types.InternalErrorf("failed to decode endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err)
263 263
 		}
264 264
 	}
265
-
265
+	if v, ok := epMap["gateway"]; ok {
266
+		ep.gateway = net.ParseIP(v.(string))
267
+	}
266 268
 	ep.id = epMap["id"].(string)
267 269
 	ep.Type = epMap["Type"].(string)
268 270
 	ep.nid = epMap["nid"].(string)
... ...
@@ -448,7 +448,7 @@ func (a *Allocator) RequestAddress(poolID string, prefAddress net.IP, opts map[s
448 448
 	c := p
449 449
 	for c.Range != nil {
450 450
 		k = c.ParentKey
451
-		c, ok = aSpace.subnets[k]
451
+		c = aSpace.subnets[k]
452 452
 	}
453 453
 	aSpace.Unlock()
454 454
 
... ...
@@ -9,7 +9,7 @@ type Response struct {
9 9
 	Error string
10 10
 }
11 11
 
12
-// IsSuccess returns wheter the plugin response is successful
12
+// IsSuccess returns whether the plugin response is successful
13 13
 func (r *Response) IsSuccess() bool {
14 14
 	return r.Error == ""
15 15
 }
... ...
@@ -92,12 +92,20 @@ type EndpointWalker func(ep Endpoint) bool
92 92
 // Its an indication to defer PTR queries also to that external server.
93 93
 type ipInfo struct {
94 94
 	name        string
95
+	serviceID   string
95 96
 	extResolver bool
96 97
 }
97 98
 
99
+// svcMapEntry is the body of the element into the svcMap
100
+// The ip is a string because the SetMatrix does not accept non hashable values
101
+type svcMapEntry struct {
102
+	ip        string
103
+	serviceID string
104
+}
105
+
98 106
 type svcInfo struct {
99
-	svcMap     map[string][]net.IP
100
-	svcIPv6Map map[string][]net.IP
107
+	svcMap     common.SetMatrix
108
+	svcIPv6Map common.SetMatrix
101 109
 	ipMap      common.SetMatrix
102 110
 	service    map[string][]servicePorts
103 111
 }
... ...
@@ -933,6 +941,9 @@ func (n *network) delete(force bool) error {
933 933
 	id := n.id
934 934
 	n.Unlock()
935 935
 
936
+	c.networkLocker.Lock(id)
937
+	defer c.networkLocker.Unlock(id)
938
+
936 939
 	n, err := c.getNetworkFromStore(id)
937 940
 	if err != nil {
938 941
 		return &UnknownNetworkError{name: name, id: id}
... ...
@@ -991,12 +1002,6 @@ func (n *network) delete(force bool) error {
991 991
 
992 992
 	c.cleanupServiceBindings(n.ID())
993 993
 
994
-	// The network had been left, the service discovery can be cleaned up
995
-	c.Lock()
996
-	logrus.Debugf("network %s delete, clean svcRecords", n.id)
997
-	delete(c.svcRecords, n.id)
998
-	c.Unlock()
999
-
1000 994
 removeFromStore:
1001 995
 	// deleteFromStore performs an atomic delete operation and the
1002 996
 	// network.epCnt will help prevent any possible
... ...
@@ -1070,6 +1075,9 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
1070 1070
 	ep := &endpoint{name: name, generic: make(map[string]interface{}), iface: &endpointInterface{}}
1071 1071
 	ep.id = stringid.GenerateRandomID()
1072 1072
 
1073
+	n.ctrlr.networkLocker.Lock(n.id)
1074
+	defer n.ctrlr.networkLocker.Unlock(n.id)
1075
+
1073 1076
 	// Initialize ep.network with a possibly stale copy of n. We need this to get network from
1074 1077
 	// store. But once we get it from store we will have the most uptodate copy possibly.
1075 1078
 	ep.network = n
... ...
@@ -1228,75 +1236,77 @@ func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool
1228 1228
 			ipv6 = iface.AddressIPv6().IP
1229 1229
 		}
1230 1230
 
1231
+		serviceID := ep.svcID
1232
+		if serviceID == "" {
1233
+			serviceID = ep.ID()
1234
+		}
1231 1235
 		if isAdd {
1232 1236
 			// If anonymous endpoint has an alias use the first alias
1233 1237
 			// for ip->name mapping. Not having the reverse mapping
1234 1238
 			// breaks some apps
1235 1239
 			if ep.isAnonymous() {
1236 1240
 				if len(myAliases) > 0 {
1237
-					n.addSvcRecords(ep.ID(), myAliases[0], iface.Address().IP, ipv6, true, "updateSvcRecord")
1241
+					n.addSvcRecords(ep.ID(), myAliases[0], serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord")
1238 1242
 				}
1239 1243
 			} else {
1240
-				n.addSvcRecords(ep.ID(), epName, iface.Address().IP, ipv6, true, "updateSvcRecord")
1244
+				n.addSvcRecords(ep.ID(), epName, serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord")
1241 1245
 			}
1242 1246
 			for _, alias := range myAliases {
1243
-				n.addSvcRecords(ep.ID(), alias, iface.Address().IP, ipv6, false, "updateSvcRecord")
1247
+				n.addSvcRecords(ep.ID(), alias, serviceID, iface.Address().IP, ipv6, false, "updateSvcRecord")
1244 1248
 			}
1245 1249
 		} else {
1246 1250
 			if ep.isAnonymous() {
1247 1251
 				if len(myAliases) > 0 {
1248
-					n.deleteSvcRecords(ep.ID(), myAliases[0], iface.Address().IP, ipv6, true, "updateSvcRecord")
1252
+					n.deleteSvcRecords(ep.ID(), myAliases[0], serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord")
1249 1253
 				}
1250 1254
 			} else {
1251
-				n.deleteSvcRecords(ep.ID(), epName, iface.Address().IP, ipv6, true, "updateSvcRecord")
1255
+				n.deleteSvcRecords(ep.ID(), epName, serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord")
1252 1256
 			}
1253 1257
 			for _, alias := range myAliases {
1254
-				n.deleteSvcRecords(ep.ID(), alias, iface.Address().IP, ipv6, false, "updateSvcRecord")
1258
+				n.deleteSvcRecords(ep.ID(), alias, serviceID, iface.Address().IP, ipv6, false, "updateSvcRecord")
1255 1259
 			}
1256 1260
 		}
1257 1261
 	}
1258 1262
 }
1259 1263
 
1260
-func addIPToName(ipMap common.SetMatrix, name string, ip net.IP) {
1264
+func addIPToName(ipMap common.SetMatrix, name, serviceID string, ip net.IP) {
1261 1265
 	reverseIP := netutils.ReverseIP(ip.String())
1262 1266
 	ipMap.Insert(reverseIP, ipInfo{
1263
-		name: name,
1267
+		name:      name,
1268
+		serviceID: serviceID,
1264 1269
 	})
1265 1270
 }
1266 1271
 
1267
-func addNameToIP(svcMap map[string][]net.IP, name string, epIP net.IP) {
1268
-	ipList := svcMap[name]
1269
-	for _, ip := range ipList {
1270
-		if ip.Equal(epIP) {
1271
-			return
1272
-		}
1273
-	}
1274
-	svcMap[name] = append(svcMap[name], epIP)
1272
+func delIPToName(ipMap common.SetMatrix, name, serviceID string, ip net.IP) {
1273
+	reverseIP := netutils.ReverseIP(ip.String())
1274
+	ipMap.Remove(reverseIP, ipInfo{
1275
+		name:      name,
1276
+		serviceID: serviceID,
1277
+	})
1275 1278
 }
1276 1279
 
1277
-func delNameToIP(svcMap map[string][]net.IP, name string, epIP net.IP) {
1278
-	ipList := svcMap[name]
1279
-	for i, ip := range ipList {
1280
-		if ip.Equal(epIP) {
1281
-			ipList = append(ipList[:i], ipList[i+1:]...)
1282
-			break
1283
-		}
1284
-	}
1285
-	svcMap[name] = ipList
1280
+func addNameToIP(svcMap common.SetMatrix, name, serviceID string, epIP net.IP) {
1281
+	svcMap.Insert(name, svcMapEntry{
1282
+		ip:        epIP.String(),
1283
+		serviceID: serviceID,
1284
+	})
1285
+}
1286 1286
 
1287
-	if len(ipList) == 0 {
1288
-		delete(svcMap, name)
1289
-	}
1287
+func delNameToIP(svcMap common.SetMatrix, name, serviceID string, epIP net.IP) {
1288
+	svcMap.Remove(name, svcMapEntry{
1289
+		ip:        epIP.String(),
1290
+		serviceID: serviceID,
1291
+	})
1290 1292
 }
1291 1293
 
1292
-func (n *network) addSvcRecords(eID, name string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool, method string) {
1294
+func (n *network) addSvcRecords(eID, name, serviceID string, epIP, epIPv6 net.IP, ipMapUpdate bool, method string) {
1293 1295
 	// Do not add service names for ingress network as this is a
1294 1296
 	// routing only network
1295 1297
 	if n.ingress {
1296 1298
 		return
1297 1299
 	}
1298 1300
 
1299
-	logrus.Debugf("%s (%s).addSvcRecords(%s, %s, %s, %t) %s", eID, n.ID()[0:7], name, epIP, epIPv6, ipMapUpdate, method)
1301
+	logrus.Debugf("%s (%s).addSvcRecords(%s, %s, %s, %t) %s sid:%s", eID, n.ID()[0:7], name, epIP, epIPv6, ipMapUpdate, method, serviceID)
1300 1302
 
1301 1303
 	c := n.getController()
1302 1304
 	c.Lock()
... ...
@@ -1305,34 +1315,34 @@ func (n *network) addSvcRecords(eID, name string, epIP net.IP, epIPv6 net.IP, ip
1305 1305
 	sr, ok := c.svcRecords[n.ID()]
1306 1306
 	if !ok {
1307 1307
 		sr = svcInfo{
1308
-			svcMap:     make(map[string][]net.IP),
1309
-			svcIPv6Map: make(map[string][]net.IP),
1308
+			svcMap:     common.NewSetMatrix(),
1309
+			svcIPv6Map: common.NewSetMatrix(),
1310 1310
 			ipMap:      common.NewSetMatrix(),
1311 1311
 		}
1312 1312
 		c.svcRecords[n.ID()] = sr
1313 1313
 	}
1314 1314
 
1315 1315
 	if ipMapUpdate {
1316
-		addIPToName(sr.ipMap, name, epIP)
1316
+		addIPToName(sr.ipMap, name, serviceID, epIP)
1317 1317
 		if epIPv6 != nil {
1318
-			addIPToName(sr.ipMap, name, epIPv6)
1318
+			addIPToName(sr.ipMap, name, serviceID, epIPv6)
1319 1319
 		}
1320 1320
 	}
1321 1321
 
1322
-	addNameToIP(sr.svcMap, name, epIP)
1322
+	addNameToIP(sr.svcMap, name, serviceID, epIP)
1323 1323
 	if epIPv6 != nil {
1324
-		addNameToIP(sr.svcIPv6Map, name, epIPv6)
1324
+		addNameToIP(sr.svcIPv6Map, name, serviceID, epIPv6)
1325 1325
 	}
1326 1326
 }
1327 1327
 
1328
-func (n *network) deleteSvcRecords(eID, name string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool, method string) {
1328
+func (n *network) deleteSvcRecords(eID, name, serviceID string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool, method string) {
1329 1329
 	// Do not delete service names from ingress network as this is a
1330 1330
 	// routing only network
1331 1331
 	if n.ingress {
1332 1332
 		return
1333 1333
 	}
1334 1334
 
1335
-	logrus.Debugf("%s (%s).deleteSvcRecords(%s, %s, %s, %t) %s", eID, n.ID()[0:7], name, epIP, epIPv6, ipMapUpdate, method)
1335
+	logrus.Debugf("%s (%s).deleteSvcRecords(%s, %s, %s, %t) %s sid:%s ", eID, n.ID()[0:7], name, epIP, epIPv6, ipMapUpdate, method, serviceID)
1336 1336
 
1337 1337
 	c := n.getController()
1338 1338
 	c.Lock()
... ...
@@ -1344,21 +1354,17 @@ func (n *network) deleteSvcRecords(eID, name string, epIP net.IP, epIPv6 net.IP,
1344 1344
 	}
1345 1345
 
1346 1346
 	if ipMapUpdate {
1347
-		sr.ipMap.Remove(netutils.ReverseIP(epIP.String()), ipInfo{
1348
-			name: name,
1349
-		})
1347
+		delIPToName(sr.ipMap, name, serviceID, epIP)
1350 1348
 
1351 1349
 		if epIPv6 != nil {
1352
-			sr.ipMap.Remove(netutils.ReverseIP(epIPv6.String()), ipInfo{
1353
-				name: name,
1354
-			})
1350
+			delIPToName(sr.ipMap, name, serviceID, epIPv6)
1355 1351
 		}
1356 1352
 	}
1357 1353
 
1358
-	delNameToIP(sr.svcMap, name, epIP)
1354
+	delNameToIP(sr.svcMap, name, serviceID, epIP)
1359 1355
 
1360 1356
 	if epIPv6 != nil {
1361
-		delNameToIP(sr.svcIPv6Map, name, epIPv6)
1357
+		delNameToIP(sr.svcIPv6Map, name, serviceID, epIPv6)
1362 1358
 	}
1363 1359
 }
1364 1360
 
... ...
@@ -1376,19 +1382,31 @@ func (n *network) getSvcRecords(ep *endpoint) []etchosts.Record {
1376 1376
 
1377 1377
 	n.ctrlr.Lock()
1378 1378
 	defer n.ctrlr.Unlock()
1379
-	sr, _ := n.ctrlr.svcRecords[n.id]
1379
+	sr, ok := n.ctrlr.svcRecords[n.id]
1380
+	if !ok || sr.svcMap == nil {
1381
+		return nil
1382
+	}
1380 1383
 
1381
-	for h, ip := range sr.svcMap {
1382
-		if strings.Split(h, ".")[0] == epName {
1384
+	svcMapKeys := sr.svcMap.Keys()
1385
+	// Loop on service names on this network
1386
+	for _, k := range svcMapKeys {
1387
+		if strings.Split(k, ".")[0] == epName {
1388
+			continue
1389
+		}
1390
+		// Get all the IPs associated to this service
1391
+		mapEntryList, ok := sr.svcMap.Get(k)
1392
+		if !ok {
1393
+			// The key got deleted
1383 1394
 			continue
1384 1395
 		}
1385
-		if len(ip) == 0 {
1386
-			logrus.Warnf("Found empty list of IP addresses for service %s on network %s (%s)", h, n.name, n.id)
1396
+		if len(mapEntryList) == 0 {
1397
+			logrus.Warnf("Found empty list of IP addresses for service %s on network %s (%s)", k, n.name, n.id)
1387 1398
 			continue
1388 1399
 		}
1400
+
1389 1401
 		recs = append(recs, etchosts.Record{
1390
-			Hosts: h,
1391
-			IP:    ip[0].String(),
1402
+			Hosts: k,
1403
+			IP:    mapEntryList[0].(svcMapEntry).ip,
1392 1404
 		})
1393 1405
 	}
1394 1406
 
... ...
@@ -1845,8 +1863,7 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
1845 1845
 	}
1846 1846
 
1847 1847
 	req = strings.TrimSuffix(req, ".")
1848
-	var ip []net.IP
1849
-	ip, ok = sr.svcMap[req]
1848
+	ipSet, ok := sr.svcMap.Get(req)
1850 1849
 
1851 1850
 	if ipType == types.IPv6 {
1852 1851
 		// If the name resolved to v4 address then its a valid name in
... ...
@@ -1856,13 +1873,20 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
1856 1856
 		if ok && n.enableIPv6 == false {
1857 1857
 			ipv6Miss = true
1858 1858
 		}
1859
-		ip = sr.svcIPv6Map[req]
1859
+		ipSet, ok = sr.svcIPv6Map.Get(req)
1860 1860
 	}
1861 1861
 
1862
-	if ip != nil {
1863
-		ipLocal := make([]net.IP, len(ip))
1864
-		copy(ipLocal, ip)
1865
-		return ipLocal, false
1862
+	if ok && len(ipSet) > 0 {
1863
+		// this map is to avoid IP duplicates, this can happen during a transition period where 2 services are using the same IP
1864
+		noDup := make(map[string]bool)
1865
+		var ipLocal []net.IP
1866
+		for _, ip := range ipSet {
1867
+			if _, dup := noDup[ip.(svcMapEntry).ip]; !dup {
1868
+				noDup[ip.(svcMapEntry).ip] = true
1869
+				ipLocal = append(ipLocal, net.ParseIP(ip.(svcMapEntry).ip))
1870
+			}
1871
+		}
1872
+		return ipLocal, ok
1866 1873
 	}
1867 1874
 
1868 1875
 	return nil, ipv6Miss
... ...
@@ -1904,7 +1928,7 @@ func (n *network) ResolveIP(ip string) string {
1904 1904
 		return ""
1905 1905
 	}
1906 1906
 	// NOTE it is possible to have more than one element in the Set, this will happen
1907
-	// because of interleave of diffent events from differnt sources (local container create vs
1907
+	// because of interleave of different events from different sources (local container create vs
1908 1908
 	// network db notifications)
1909 1909
 	// In such cases the resolution will be based on the first element of the set, and can vary
1910 1910
 	// during the system stabilitation
... ...
@@ -7,6 +7,7 @@ package osl
7 7
 func GC() {
8 8
 }
9 9
 
10
+// GetSandboxForExternalKey returns sandbox object for the supplied path
10 11
 func GetSandboxForExternalKey(path string, key string) (Sandbox, error) {
11 12
 	return nil, nil
12 13
 }
... ...
@@ -629,6 +629,10 @@ func (sb *sandbox) SetKey(basePath string) error {
629 629
 	}
630 630
 
631 631
 	sb.Lock()
632
+	if sb.inDelete {
633
+		sb.Unlock()
634
+		return types.ForbiddenErrorf("failed to SetKey: sandbox %q delete in progress", sb.id)
635
+	}
632 636
 	oldosSbox := sb.osSbox
633 637
 	sb.Unlock()
634 638
 
... ...
@@ -85,14 +85,8 @@ type loadBalancer struct {
85 85
 
86 86
 	// Map of backend IPs backing this loadbalancer on this
87 87
 	// network. It is keyed with endpoint ID.
88
-	backEnds map[string]loadBalancerBackend
88
+	backEnds map[string]net.IP
89 89
 
90 90
 	// Back pointer to service to which the loadbalancer belongs.
91 91
 	service *service
92 92
 }
93
-
94
-type loadBalancerBackend struct {
95
-	ip            net.IP
96
-	containerName string
97
-	taskAliases   []string
98
-}
... ...
@@ -15,29 +15,35 @@ func (c *controller) addEndpointNameResolution(svcName, svcID, nID, eID, contain
15 15
 		return err
16 16
 	}
17 17
 
18
-	logrus.Debugf("addEndpointNameResolution %s %s add_service:%t", eID, svcName, addService)
18
+	logrus.Debugf("addEndpointNameResolution %s %s add_service:%t sAliases:%v tAliases:%v", eID, svcName, addService, serviceAliases, taskAliases)
19 19
 
20 20
 	// Add container resolution mappings
21 21
 	c.addContainerNameResolution(nID, eID, containerName, taskAliases, ip, method)
22 22
 
23
+	serviceID := svcID
24
+	if serviceID == "" {
25
+		// This is the case of a normal container not part of a service
26
+		serviceID = eID
27
+	}
28
+
23 29
 	// Add endpoint IP to special "tasks.svc_name" so that the applications have access to DNS RR.
24
-	n.(*network).addSvcRecords(eID, "tasks."+svcName, ip, nil, false, method)
30
+	n.(*network).addSvcRecords(eID, "tasks."+svcName, serviceID, ip, nil, false, method)
25 31
 	for _, alias := range serviceAliases {
26
-		n.(*network).addSvcRecords(eID, "tasks."+alias, ip, nil, false, method)
32
+		n.(*network).addSvcRecords(eID, "tasks."+alias, serviceID, ip, nil, false, method)
27 33
 	}
28 34
 
29 35
 	// Add service name to vip in DNS, if vip is valid. Otherwise resort to DNS RR
30 36
 	if len(vip) == 0 {
31
-		n.(*network).addSvcRecords(eID, svcName, ip, nil, false, method)
37
+		n.(*network).addSvcRecords(eID, svcName, serviceID, ip, nil, false, method)
32 38
 		for _, alias := range serviceAliases {
33
-			n.(*network).addSvcRecords(eID, alias, ip, nil, false, method)
39
+			n.(*network).addSvcRecords(eID, alias, serviceID, ip, nil, false, method)
34 40
 		}
35 41
 	}
36 42
 
37 43
 	if addService && len(vip) != 0 {
38
-		n.(*network).addSvcRecords(eID, svcName, vip, nil, false, method)
44
+		n.(*network).addSvcRecords(eID, svcName, serviceID, vip, nil, false, method)
39 45
 		for _, alias := range serviceAliases {
40
-			n.(*network).addSvcRecords(eID, alias, vip, nil, false, method)
46
+			n.(*network).addSvcRecords(eID, alias, serviceID, vip, nil, false, method)
41 47
 		}
42 48
 	}
43 49
 
... ...
@@ -52,11 +58,11 @@ func (c *controller) addContainerNameResolution(nID, eID, containerName string,
52 52
 	logrus.Debugf("addContainerNameResolution %s %s", eID, containerName)
53 53
 
54 54
 	// Add resolution for container name
55
-	n.(*network).addSvcRecords(eID, containerName, ip, nil, true, method)
55
+	n.(*network).addSvcRecords(eID, containerName, eID, ip, nil, true, method)
56 56
 
57 57
 	// Add resolution for taskaliases
58 58
 	for _, alias := range taskAliases {
59
-		n.(*network).addSvcRecords(eID, alias, ip, nil, true, method)
59
+		n.(*network).addSvcRecords(eID, alias, eID, ip, nil, true, method)
60 60
 	}
61 61
 
62 62
 	return nil
... ...
@@ -68,32 +74,38 @@ func (c *controller) deleteEndpointNameResolution(svcName, svcID, nID, eID, cont
68 68
 		return err
69 69
 	}
70 70
 
71
-	logrus.Debugf("deleteEndpointNameResolution %s %s rm_service:%t suppress:%t", eID, svcName, rmService, multipleEntries)
71
+	logrus.Debugf("deleteEndpointNameResolution %s %s rm_service:%t suppress:%t sAliases:%v tAliases:%v", eID, svcName, rmService, multipleEntries, serviceAliases, taskAliases)
72 72
 
73 73
 	// Delete container resolution mappings
74 74
 	c.delContainerNameResolution(nID, eID, containerName, taskAliases, ip, method)
75 75
 
76
+	serviceID := svcID
77
+	if serviceID == "" {
78
+		// This is the case of a normal container not part of a service
79
+		serviceID = eID
80
+	}
81
+
76 82
 	// Delete the special "tasks.svc_name" backend record.
77 83
 	if !multipleEntries {
78
-		n.(*network).deleteSvcRecords(eID, "tasks."+svcName, ip, nil, false, method)
84
+		n.(*network).deleteSvcRecords(eID, "tasks."+svcName, serviceID, ip, nil, false, method)
79 85
 		for _, alias := range serviceAliases {
80
-			n.(*network).deleteSvcRecords(eID, "tasks."+alias, ip, nil, false, method)
86
+			n.(*network).deleteSvcRecords(eID, "tasks."+alias, serviceID, ip, nil, false, method)
81 87
 		}
82 88
 	}
83 89
 
84 90
 	// If we are doing DNS RR delete the endpoint IP from DNS record right away.
85 91
 	if !multipleEntries && len(vip) == 0 {
86
-		n.(*network).deleteSvcRecords(eID, svcName, ip, nil, false, method)
92
+		n.(*network).deleteSvcRecords(eID, svcName, serviceID, ip, nil, false, method)
87 93
 		for _, alias := range serviceAliases {
88
-			n.(*network).deleteSvcRecords(eID, alias, ip, nil, false, method)
94
+			n.(*network).deleteSvcRecords(eID, alias, serviceID, ip, nil, false, method)
89 95
 		}
90 96
 	}
91 97
 
92 98
 	// Remove the DNS record for VIP only if we are removing the service
93 99
 	if rmService && len(vip) != 0 && !multipleEntries {
94
-		n.(*network).deleteSvcRecords(eID, svcName, vip, nil, false, method)
100
+		n.(*network).deleteSvcRecords(eID, svcName, serviceID, vip, nil, false, method)
95 101
 		for _, alias := range serviceAliases {
96
-			n.(*network).deleteSvcRecords(eID, alias, vip, nil, false, method)
102
+			n.(*network).deleteSvcRecords(eID, alias, serviceID, vip, nil, false, method)
97 103
 		}
98 104
 	}
99 105
 
... ...
@@ -108,11 +120,11 @@ func (c *controller) delContainerNameResolution(nID, eID, containerName string,
108 108
 	logrus.Debugf("delContainerNameResolution %s %s", eID, containerName)
109 109
 
110 110
 	// Delete resolution for container name
111
-	n.(*network).deleteSvcRecords(eID, containerName, ip, nil, true, method)
111
+	n.(*network).deleteSvcRecords(eID, containerName, eID, ip, nil, true, method)
112 112
 
113 113
 	// Delete resolution for taskaliases
114 114
 	for _, alias := range taskAliases {
115
-		n.(*network).deleteSvcRecords(eID, alias, ip, nil, true, method)
115
+		n.(*network).deleteSvcRecords(eID, alias, eID, ip, nil, true, method)
116 116
 	}
117 117
 
118 118
 	return nil
... ...
@@ -152,6 +164,7 @@ func (c *controller) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int
152 152
 func (c *controller) cleanupServiceBindings(cleanupNID string) {
153 153
 	var cleanupFuncs []func()
154 154
 
155
+	logrus.Debugf("cleanupServiceBindings for %s", cleanupNID)
155 156
 	c.Lock()
156 157
 	services := make([]*service, 0, len(c.serviceBindings))
157 158
 	for _, s := range c.serviceBindings {
... ...
@@ -171,16 +184,27 @@ func (c *controller) cleanupServiceBindings(cleanupNID string) {
171 171
 				continue
172 172
 			}
173 173
 
174
-			for eid, be := range lb.backEnds {
174
+			// The network is being deleted, erase all the associated service discovery records
175
+			// TODO(fcrisciani) separate the Load Balancer from the Service discovery, this operation
176
+			// can be done safely here, but the rmServiceBinding is still keeping consistency in the
177
+			// data structures that are tracking the endpoint to IP mapping.
178
+			c.Lock()
179
+			logrus.Debugf("cleanupServiceBindings erasing the svcRecords for %s", nid)
180
+			delete(c.svcRecords, nid)
181
+			c.Unlock()
182
+
183
+			for eid, ip := range lb.backEnds {
184
+				epID := eid
185
+				epIP := ip
175 186
 				service := s
176 187
 				loadBalancer := lb
177 188
 				networkID := nid
178
-				epID := eid
179
-				epIP := be.ip
180
-
181 189
 				cleanupFuncs = append(cleanupFuncs, func() {
182
-					if err := c.rmServiceBinding(service.name, service.id, networkID, epID, be.containerName, loadBalancer.vip,
183
-						service.ingressPorts, service.aliases, be.taskAliases, epIP, "cleanupServiceBindings"); err != nil {
190
+					// ContainerName and taskAliases are not available here, this is still fine because the Service discovery
191
+					// cleanup already happened before. The only thing that rmServiceBinding is still doing here a part from the Load
192
+					// Balancer bookeeping, is to keep consistent the mapping of endpoint to IP.
193
+					if err := c.rmServiceBinding(service.name, service.id, networkID, epID, "", loadBalancer.vip,
194
+						service.ingressPorts, service.aliases, []string{}, epIP, "cleanupServiceBindings", false); err != nil {
184 195
 						logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v",
185 196
 							service.id, networkID, epID, err)
186 197
 					}
... ...
@@ -228,8 +252,7 @@ func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName s
228 228
 		}
229 229
 		s.Unlock()
230 230
 	}
231
-	logrus.Debugf("addServiceBinding from %s START for %s %s", method, svcName, eID)
232
-
231
+	logrus.Debugf("addServiceBinding from %s START for %s %s p:%p nid:%s skey:%v", method, svcName, eID, s, nID, skey)
233 232
 	defer s.Unlock()
234 233
 
235 234
 	lb, ok := s.loadBalancers[nID]
... ...
@@ -242,7 +265,7 @@ func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName s
242 242
 		lb = &loadBalancer{
243 243
 			vip:      vip,
244 244
 			fwMark:   fwMarkCtr,
245
-			backEnds: make(map[string]loadBalancerBackend),
245
+			backEnds: make(map[string]net.IP),
246 246
 			service:  s,
247 247
 		}
248 248
 
... ...
@@ -253,9 +276,7 @@ func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName s
253 253
 		addService = true
254 254
 	}
255 255
 
256
-	lb.backEnds[eID] = loadBalancerBackend{ip: ip,
257
-		containerName: containerName,
258
-		taskAliases:   taskAliases}
256
+	lb.backEnds[eID] = ip
259 257
 
260 258
 	ok, entries := s.assignIPToEndpoint(ip.String(), eID)
261 259
 	if !ok || entries > 1 {
... ...
@@ -277,7 +298,7 @@ func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName s
277 277
 	return nil
278 278
 }
279 279
 
280
-func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases []string, taskAliases []string, ip net.IP, method string) error {
280
+func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases []string, taskAliases []string, ip net.IP, method string, deleteSvcRecords bool) error {
281 281
 
282 282
 	var rmService bool
283 283
 
... ...
@@ -294,7 +315,6 @@ func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName st
294 294
 	c.Lock()
295 295
 	s, ok := c.serviceBindings[skey]
296 296
 	c.Unlock()
297
-	logrus.Debugf("rmServiceBinding from %s START for %s %s", method, svcName, eID)
298 297
 	if !ok {
299 298
 		logrus.Warnf("rmServiceBinding %s %s %s aborted c.serviceBindings[skey] !ok", method, svcName, eID)
300 299
 		return nil
... ...
@@ -302,6 +322,7 @@ func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName st
302 302
 
303 303
 	s.Lock()
304 304
 	defer s.Unlock()
305
+	logrus.Debugf("rmServiceBinding from %s START for %s %s p:%p nid:%s sKey:%v deleteSvc:%t", method, svcName, eID, s, nID, skey, deleteSvcRecords)
305 306
 	lb, ok := s.loadBalancers[nID]
306 307
 	if !ok {
307 308
 		logrus.Warnf("rmServiceBinding %s %s %s aborted s.loadBalancers[nid] !ok", method, svcName, eID)
... ...
@@ -322,17 +343,7 @@ func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName st
322 322
 		rmService = true
323 323
 
324 324
 		delete(s.loadBalancers, nID)
325
-	}
326
-
327
-	if len(s.loadBalancers) == 0 {
328
-		// All loadbalancers for the service removed. Time to
329
-		// remove the service itself.
330
-		c.Lock()
331
-
332
-		// Mark the object as deleted so that the add won't use it wrongly
333
-		s.deleted = true
334
-		delete(c.serviceBindings, skey)
335
-		c.Unlock()
325
+		logrus.Debugf("rmServiceBinding %s delete %s, p:%p in loadbalancers len:%d", eID, nID, lb, len(s.loadBalancers))
336 326
 	}
337 327
 
338 328
 	ok, entries := s.removeIPToEndpoint(ip.String(), eID)
... ...
@@ -348,7 +359,22 @@ func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName st
348 348
 	}
349 349
 
350 350
 	// Delete the name resolutions
351
-	c.deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, rmService, entries > 0, "rmServiceBinding")
351
+	if deleteSvcRecords {
352
+		c.deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, rmService, entries > 0, "rmServiceBinding")
353
+	}
354
+
355
+	if len(s.loadBalancers) == 0 {
356
+		// All loadbalancers for the service removed. Time to
357
+		// remove the service itself.
358
+		c.Lock()
359
+
360
+		// Mark the object as deleted so that the add won't use it wrongly
361
+		s.deleted = true
362
+		// NOTE The delete from the serviceBindings map has to be the last operation else we are allowing a race between this service
363
+		// that is getting deleted and a new service that will be created if the entry is not anymore there
364
+		delete(c.serviceBindings, skey)
365
+		c.Unlock()
366
+	}
352 367
 
353 368
 	logrus.Debugf("rmServiceBinding from %s END for %s %s", method, svcName, eID)
354 369
 	return nil
... ...
@@ -102,8 +102,8 @@ func (sb *sandbox) populateLoadbalancers(ep *endpoint) {
102 102
 		}
103 103
 
104 104
 		lb.service.Lock()
105
-		for _, l := range lb.backEnds {
106
-			sb.addLBBackend(l.ip, lb.vip, lb.fwMark, lb.service.ingressPorts, eIP, gwIP, n.ingress)
105
+		for _, ip := range lb.backEnds {
106
+			sb.addLBBackend(ip, lb.vip, lb.fwMark, lb.service.ingressPorts, eIP, gwIP, n.ingress)
107 107
 		}
108 108
 		lb.service.Unlock()
109 109
 	}
... ...
@@ -520,7 +520,7 @@ func writePortsToFile(ports []*PortConfig) (string, error) {
520 520
 	}
521 521
 	defer f.Close()
522 522
 
523
-	buf, err := proto.Marshal(&EndpointRecord{
523
+	buf, _ := proto.Marshal(&EndpointRecord{
524 524
 		IngressPorts: ports,
525 525
 	})
526 526