Browse code

Service discovery race on serviceBindings delete. Bug on IP reuse (#1808)

* Correct SetMatrix documentation

The SetMatrix is a generic data structure, so the description
should not be tight to any specific use

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

* Service Discovery reuse name and serviceBindings deletion

- Added logic to handle name reuse from different services
- Moved the deletion from the serviceBindings map at the end
of the rmServiceBindings body to avoid race with new services

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

* Avoid race on network cleanup

Use the locker to avoid the race between the network
deletion and new endpoints being created

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

* CleanupServiceBindings to clean the SD records

Allow the cleanupServicebindings to take care of the service discovery
cleanup. Also avoid to trigger the cleanup for each endpoint from an SD
point of view
LB and SD will be separated in the future

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

* Addressed comments

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

* NetworkDB deleteEntry has to happen

If there is an error locally guarantee that the delete entry
on network DB is still honored

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

Flavio Crisciani authored on 2017/06/18 21:25:58
Showing 7 changed files
... ...
@@ -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
... ...
@@ -900,7 +901,7 @@ func (c *controller) handleEpTableEvent(ev events.Event) {
900 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 specific 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
+}
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/docker/libnetwork/driverapi"
14 14
 	"github.com/docker/libnetwork/ipamapi"
15 15
 	"github.com/docker/libnetwork/netlabel"
16
+	"github.com/docker/libnetwork/netutils"
16 17
 	"github.com/docker/libnetwork/testutils"
17 18
 	"github.com/docker/libnetwork/types"
18 19
 )
... ...
@@ -382,8 +383,8 @@ func TestSRVServiceQuery(t *testing.T) {
382 382
 	}
383 383
 
384 384
 	sr := svcInfo{
385
-		svcMap:     make(map[string][]net.IP),
386
-		svcIPv6Map: make(map[string][]net.IP),
385
+		svcMap:     common.NewSetMatrix(),
386
+		svcIPv6Map: common.NewSetMatrix(),
387 387
 		ipMap:      common.NewSetMatrix(),
388 388
 		service:    make(map[string][]servicePorts),
389 389
 	}
... ...
@@ -440,6 +441,119 @@ func TestSRVServiceQuery(t *testing.T) {
440 440
 	}
441 441
 }
442 442
 
443
+func TestServiceVIPReuse(t *testing.T) {
444
+	c, err := New()
445
+	if err != nil {
446
+		t.Fatal(err)
447
+	}
448
+	defer c.Stop()
449
+
450
+	n, err := c.NewNetwork("bridge", "net1", "", nil)
451
+	if err != nil {
452
+		t.Fatal(err)
453
+	}
454
+	defer func() {
455
+		if err := n.Delete(); err != nil {
456
+			t.Fatal(err)
457
+		}
458
+	}()
459
+
460
+	ep, err := n.CreateEndpoint("testep")
461
+	if err != nil {
462
+		t.Fatal(err)
463
+	}
464
+
465
+	sb, err := c.NewSandbox("c1")
466
+	if err != nil {
467
+		t.Fatal(err)
468
+	}
469
+	defer func() {
470
+		if err := sb.Delete(); err != nil {
471
+			t.Fatal(err)
472
+		}
473
+	}()
474
+
475
+	err = ep.Join(sb)
476
+	if err != nil {
477
+		t.Fatal(err)
478
+	}
479
+
480
+	// Add 2 services with same name but different service ID to share the same VIP
481
+	n.(*network).addSvcRecords("ep1", "service_test", "serviceID1", net.ParseIP("192.168.0.1"), net.IP{}, true, "test")
482
+	n.(*network).addSvcRecords("ep2", "service_test", "serviceID2", net.ParseIP("192.168.0.1"), net.IP{}, true, "test")
483
+
484
+	ipToResolve := netutils.ReverseIP("192.168.0.1")
485
+
486
+	ipList, _ := n.(*network).ResolveName("service_test", types.IPv4)
487
+	if len(ipList) == 0 {
488
+		t.Fatal("There must be the VIP")
489
+	}
490
+	if len(ipList) != 1 {
491
+		t.Fatal("It must return only 1 VIP")
492
+	}
493
+	if ipList[0].String() != "192.168.0.1" {
494
+		t.Fatal("The service VIP is 192.168.0.1")
495
+	}
496
+	name := n.(*network).ResolveIP(ipToResolve)
497
+	if name == "" {
498
+		t.Fatal("It must return a name")
499
+	}
500
+	if name != "service_test.net1" {
501
+		t.Fatalf("It must return the service_test.net1 != %s", name)
502
+	}
503
+
504
+	// Delete service record for one of the services, the IP should remain because one service is still associated with it
505
+	n.(*network).deleteSvcRecords("ep1", "service_test", "serviceID1", net.ParseIP("192.168.0.1"), net.IP{}, true, "test")
506
+	ipList, _ = n.(*network).ResolveName("service_test", types.IPv4)
507
+	if len(ipList) == 0 {
508
+		t.Fatal("There must be the VIP")
509
+	}
510
+	if len(ipList) != 1 {
511
+		t.Fatal("It must return only 1 VIP")
512
+	}
513
+	if ipList[0].String() != "192.168.0.1" {
514
+		t.Fatal("The service VIP is 192.168.0.1")
515
+	}
516
+	name = n.(*network).ResolveIP(ipToResolve)
517
+	if name == "" {
518
+		t.Fatal("It must return a name")
519
+	}
520
+	if name != "service_test.net1" {
521
+		t.Fatalf("It must return the service_test.net1 != %s", name)
522
+	}
523
+
524
+	// Delete again the service using the previous service ID, nothing should happen
525
+	n.(*network).deleteSvcRecords("ep2", "service_test", "serviceID1", net.ParseIP("192.168.0.1"), net.IP{}, true, "test")
526
+	ipList, _ = n.(*network).ResolveName("service_test", types.IPv4)
527
+	if len(ipList) == 0 {
528
+		t.Fatal("There must be the VIP")
529
+	}
530
+	if len(ipList) != 1 {
531
+		t.Fatal("It must return only 1 VIP")
532
+	}
533
+	if ipList[0].String() != "192.168.0.1" {
534
+		t.Fatal("The service VIP is 192.168.0.1")
535
+	}
536
+	name = n.(*network).ResolveIP(ipToResolve)
537
+	if name == "" {
538
+		t.Fatal("It must return a name")
539
+	}
540
+	if name != "service_test.net1" {
541
+		t.Fatalf("It must return the service_test.net1 != %s", name)
542
+	}
543
+
544
+	// Delete now using the second service ID, now all the entries should be gone
545
+	n.(*network).deleteSvcRecords("ep2", "service_test", "serviceID2", net.ParseIP("192.168.0.1"), net.IP{}, true, "test")
546
+	ipList, _ = n.(*network).ResolveName("service_test", types.IPv4)
547
+	if len(ipList) != 0 {
548
+		t.Fatal("All the VIPs should be gone now")
549
+	}
550
+	name = n.(*network).ResolveIP(ipToResolve)
551
+	if name != "" {
552
+		t.Fatalf("It must return empty no more services associated, instead:%s", name)
553
+	}
554
+}
555
+
443 556
 func TestIpamReleaseOnNetDriverFailures(t *testing.T) {
444 557
 	if !testutils.IsRunningInContainer() {
445 558
 		defer testutils.SetupTestOSContext(t)()
... ...
@@ -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
... ...
@@ -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
 	}