Browse code

Vendoring libnetwork v0.7.0-dev.10

Signed-off-by: Alessandro Boch <aboch@docker.com>

Alessandro Boch authored on 2016/03/23 04:30:39
Showing 6 changed files
... ...
@@ -29,7 +29,7 @@ clone git github.com/RackSec/srslog 259aed10dfa74ea2961eddd1d9847619f6e98837
29 29
 clone git github.com/imdario/mergo 0.2.1
30 30
 
31 31
 #get libnetwork packages
32
-clone git github.com/docker/libnetwork v0.7.0-dev.9
32
+clone git github.com/docker/libnetwork v0.7.0-dev.10
33 33
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
34 34
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
35 35
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
... ...
@@ -1144,10 +1144,10 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContaine
1144 1144
 
1145 1145
 func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) {
1146 1146
 	// create two networks
1147
-	dockerCmd(c, "network", "create", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")
1147
+	dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")
1148 1148
 	assertNwIsAvailable(c, "n0")
1149 1149
 
1150
-	dockerCmd(c, "network", "create", "--subnet=172.30.0.0/16", "--ip-range=172.30.5.0/24", "--subnet=2001:db8:abcd::/64", "--ip-range=2001:db8:abcd::/80", "n1")
1150
+	dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--ip-range=172.30.5.0/24", "--subnet=2001:db8:abcd::/64", "--ip-range=2001:db8:abcd::/80", "n1")
1151 1151
 	assertNwIsAvailable(c, "n1")
1152 1152
 
1153 1153
 	// run a container on first network specifying the ip addresses
... ...
@@ -1183,7 +1183,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIPStoppedContainer
1183 1183
 	dockerCmd(c, "create", "--name", "c0", "busybox", "top")
1184 1184
 
1185 1185
 	// create a network
1186
-	dockerCmd(c, "network", "create", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0")
1186
+	dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0")
1187 1187
 	assertNwIsAvailable(c, "n0")
1188 1188
 
1189 1189
 	// connect the container to the network specifying an ip addresses
... ...
@@ -1,5 +1,10 @@
1 1
 # Changelog
2 2
 
3
+## 0.7.0-dev.10 (2016-03-21)
4
+- Add IPv6 service discovery (AAAA records) in embedded DNS server
5
+- Honor enableIPv6 flag in network create for the IP allocation
6
+- Avoid V6 queries in docker domain going to external nameservers
7
+
3 8
 ## 0.7.0-dev.9 (2016-03-18)
4 9
 - Support labels on networks
5 10
 
... ...
@@ -71,8 +71,9 @@ type NetworkInfo interface {
71 71
 type EndpointWalker func(ep Endpoint) bool
72 72
 
73 73
 type svcInfo struct {
74
-	svcMap map[string][]net.IP
75
-	ipMap  map[string]string
74
+	svcMap     map[string][]net.IP
75
+	svcIPv6Map map[string][]net.IP
76
+	ipMap      map[string]string
76 77
 }
77 78
 
78 79
 // IpamConf contains all the ipam related configurations for a network
... ...
@@ -489,6 +490,10 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
489 489
 	if v, ok := netMap["inDelete"]; ok {
490 490
 		n.inDelete = v.(bool)
491 491
 	}
492
+	// Reconcile old networks with the recently added `--ipv6` flag
493
+	if !n.enableIPv6 {
494
+		n.enableIPv6 = len(n.ipamV6Info) > 0
495
+	}
492 496
 	return nil
493 497
 }
494 498
 
... ...
@@ -779,7 +784,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
779 779
 		ep.ipamOptions[netlabel.MacAddress] = ep.iface.mac.String()
780 780
 	}
781 781
 
782
-	if err = ep.assignAddress(ipam.driver, true, !n.postIPv6); err != nil {
782
+	if err = ep.assignAddress(ipam.driver, true, n.enableIPv6 && !n.postIPv6); err != nil {
783 783
 		return nil, err
784 784
 	}
785 785
 	defer func() {
... ...
@@ -799,7 +804,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
799 799
 		}
800 800
 	}()
801 801
 
802
-	if err = ep.assignAddress(ipam.driver, false, n.postIPv6); err != nil {
802
+	if err = ep.assignAddress(ipam.driver, false, n.enableIPv6 && n.postIPv6); err != nil {
803 803
 		return nil, err
804 804
 	}
805 805
 
... ...
@@ -890,68 +895,103 @@ func (n *network) EndpointByID(id string) (Endpoint, error) {
890 890
 }
891 891
 
892 892
 func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool) {
893
+	var ipv6 net.IP
893 894
 	epName := ep.Name()
894 895
 	if iface := ep.Iface(); iface.Address() != nil {
895 896
 		myAliases := ep.MyAliases()
897
+		if iface.AddressIPv6() != nil {
898
+			ipv6 = iface.AddressIPv6().IP
899
+		}
900
+
896 901
 		if isAdd {
897 902
 			// If anonymous endpoint has an alias use the first alias
898 903
 			// for ip->name mapping. Not having the reverse mapping
899 904
 			// breaks some apps
900 905
 			if ep.isAnonymous() {
901 906
 				if len(myAliases) > 0 {
902
-					n.addSvcRecords(myAliases[0], iface.Address().IP, true)
907
+					n.addSvcRecords(myAliases[0], iface.Address().IP, ipv6, true)
903 908
 				}
904 909
 			} else {
905
-				n.addSvcRecords(epName, iface.Address().IP, true)
910
+				n.addSvcRecords(epName, iface.Address().IP, ipv6, true)
906 911
 			}
907 912
 			for _, alias := range myAliases {
908
-				n.addSvcRecords(alias, iface.Address().IP, false)
913
+				n.addSvcRecords(alias, iface.Address().IP, ipv6, false)
909 914
 			}
910 915
 		} else {
911 916
 			if ep.isAnonymous() {
912 917
 				if len(myAliases) > 0 {
913
-					n.deleteSvcRecords(myAliases[0], iface.Address().IP, true)
918
+					n.deleteSvcRecords(myAliases[0], iface.Address().IP, ipv6, true)
914 919
 				}
915 920
 			} else {
916
-				n.deleteSvcRecords(epName, iface.Address().IP, true)
921
+				n.deleteSvcRecords(epName, iface.Address().IP, ipv6, true)
917 922
 			}
918 923
 			for _, alias := range myAliases {
919
-				n.deleteSvcRecords(alias, iface.Address().IP, false)
924
+				n.deleteSvcRecords(alias, iface.Address().IP, ipv6, false)
920 925
 			}
921 926
 		}
922 927
 	}
923 928
 }
924 929
 
925
-func (n *network) addSvcRecords(name string, epIP net.IP, ipMapUpdate bool) {
930
+func addIPToName(ipMap map[string]string, name string, ip net.IP) {
931
+	reverseIP := netutils.ReverseIP(ip.String())
932
+	if _, ok := ipMap[reverseIP]; !ok {
933
+		ipMap[reverseIP] = name
934
+	}
935
+}
936
+
937
+func addNameToIP(svcMap map[string][]net.IP, name string, epIP net.IP) {
938
+	ipList := svcMap[name]
939
+	for _, ip := range ipList {
940
+		if ip.Equal(epIP) {
941
+			return
942
+		}
943
+	}
944
+	svcMap[name] = append(svcMap[name], epIP)
945
+}
946
+
947
+func delNameToIP(svcMap map[string][]net.IP, name string, epIP net.IP) {
948
+	ipList := svcMap[name]
949
+	for i, ip := range ipList {
950
+		if ip.Equal(epIP) {
951
+			ipList = append(ipList[:i], ipList[i+1:]...)
952
+			break
953
+		}
954
+	}
955
+	svcMap[name] = ipList
956
+
957
+	if len(ipList) == 0 {
958
+		delete(svcMap, name)
959
+	}
960
+}
961
+
962
+func (n *network) addSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool) {
926 963
 	c := n.getController()
927 964
 	c.Lock()
928 965
 	defer c.Unlock()
929 966
 	sr, ok := c.svcDb[n.ID()]
930 967
 	if !ok {
931 968
 		sr = svcInfo{
932
-			svcMap: make(map[string][]net.IP),
933
-			ipMap:  make(map[string]string),
969
+			svcMap:     make(map[string][]net.IP),
970
+			svcIPv6Map: make(map[string][]net.IP),
971
+			ipMap:      make(map[string]string),
934 972
 		}
935 973
 		c.svcDb[n.ID()] = sr
936 974
 	}
937 975
 
938 976
 	if ipMapUpdate {
939
-		reverseIP := netutils.ReverseIP(epIP.String())
940
-		if _, ok := sr.ipMap[reverseIP]; !ok {
941
-			sr.ipMap[reverseIP] = name
977
+		addIPToName(sr.ipMap, name, epIP)
978
+		if epIPv6 != nil {
979
+			addIPToName(sr.ipMap, name, epIPv6)
942 980
 		}
943 981
 	}
944 982
 
945
-	ipList := sr.svcMap[name]
946
-	for _, ip := range ipList {
947
-		if ip.Equal(epIP) {
948
-			return
949
-		}
983
+	addNameToIP(sr.svcMap, name, epIP)
984
+	if epIPv6 != nil {
985
+		addNameToIP(sr.svcIPv6Map, name, epIPv6)
950 986
 	}
951
-	sr.svcMap[name] = append(sr.svcMap[name], epIP)
952 987
 }
953 988
 
954
-func (n *network) deleteSvcRecords(name string, epIP net.IP, ipMapUpdate bool) {
989
+func (n *network) deleteSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUpdate bool) {
955 990
 	c := n.getController()
956 991
 	c.Lock()
957 992
 	defer c.Unlock()
... ...
@@ -962,19 +1002,16 @@ func (n *network) deleteSvcRecords(name string, epIP net.IP, ipMapUpdate bool) {
962 962
 
963 963
 	if ipMapUpdate {
964 964
 		delete(sr.ipMap, netutils.ReverseIP(epIP.String()))
965
-	}
966 965
 
967
-	ipList := sr.svcMap[name]
968
-	for i, ip := range ipList {
969
-		if ip.Equal(epIP) {
970
-			ipList = append(ipList[:i], ipList[i+1:]...)
971
-			break
966
+		if epIPv6 != nil {
967
+			delete(sr.ipMap, netutils.ReverseIP(epIPv6.String()))
972 968
 		}
973 969
 	}
974
-	sr.svcMap[name] = ipList
975 970
 
976
-	if len(ipList) == 0 {
977
-		delete(sr.svcMap, name)
971
+	delNameToIP(sr.svcMap, name, epIP)
972
+
973
+	if epIPv6 != nil {
974
+		delNameToIP(sr.svcIPv6Map, name, epIPv6)
978 975
 	}
979 976
 }
980 977
 
... ...
@@ -1033,6 +1070,10 @@ func (n *network) ipamAllocate() error {
1033 1033
 		}
1034 1034
 	}()
1035 1035
 
1036
+	if !n.enableIPv6 {
1037
+		return nil
1038
+	}
1039
+
1036 1040
 	return n.ipamAllocateVersion(6, ipam)
1037 1041
 }
1038 1042
 
... ...
@@ -1153,7 +1194,7 @@ func (n *network) ipamReleaseVersion(ipVer int, ipam ipamapi.Ipam) {
1153 1153
 		return
1154 1154
 	}
1155 1155
 
1156
-	if *infoList == nil {
1156
+	if len(*infoList) == 0 {
1157 1157
 		return
1158 1158
 	}
1159 1159
 
... ...
@@ -10,6 +10,7 @@ import (
10 10
 
11 11
 	log "github.com/Sirupsen/logrus"
12 12
 	"github.com/docker/libnetwork/iptables"
13
+	"github.com/docker/libnetwork/netutils"
13 14
 	"github.com/miekg/dns"
14 15
 )
15 16
 
... ...
@@ -185,27 +186,46 @@ func shuffleAddr(addr []net.IP) []net.IP {
185 185
 	return addr
186 186
 }
187 187
 
188
-func (r *resolver) handleIPv4Query(name string, query *dns.Msg) (*dns.Msg, error) {
189
-	addr := r.sb.ResolveName(name)
188
+func createRespMsg(query *dns.Msg) *dns.Msg {
189
+	resp := new(dns.Msg)
190
+	resp.SetReply(query)
191
+	setCommonFlags(resp)
192
+
193
+	return resp
194
+}
195
+
196
+func (r *resolver) handleIPQuery(name string, query *dns.Msg, ipType int) (*dns.Msg, error) {
197
+	addr, ipv6Miss := r.sb.ResolveName(name, ipType)
198
+	if addr == nil && ipv6Miss {
199
+		// Send a reply without any Answer sections
200
+		log.Debugf("Lookup name %s present without IPv6 address", name)
201
+		resp := createRespMsg(query)
202
+		return resp, nil
203
+	}
190 204
 	if addr == nil {
191 205
 		return nil, nil
192 206
 	}
193 207
 
194 208
 	log.Debugf("Lookup for %s: IP %v", name, addr)
195 209
 
196
-	resp := new(dns.Msg)
197
-	resp.SetReply(query)
198
-	setCommonFlags(resp)
199
-
210
+	resp := createRespMsg(query)
200 211
 	if len(addr) > 1 {
201 212
 		addr = shuffleAddr(addr)
202 213
 	}
203
-
204
-	for _, ip := range addr {
205
-		rr := new(dns.A)
206
-		rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
207
-		rr.A = ip
208
-		resp.Answer = append(resp.Answer, rr)
214
+	if ipType == netutils.IPv4 {
215
+		for _, ip := range addr {
216
+			rr := new(dns.A)
217
+			rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: respTTL}
218
+			rr.A = ip
219
+			resp.Answer = append(resp.Answer, rr)
220
+		}
221
+	} else {
222
+		for _, ip := range addr {
223
+			rr := new(dns.AAAA)
224
+			rr.Hdr = dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: respTTL}
225
+			rr.AAAA = ip
226
+			resp.Answer = append(resp.Answer, rr)
227
+		}
209 228
 	}
210 229
 	return resp, nil
211 230
 }
... ...
@@ -264,7 +284,9 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
264 264
 	}
265 265
 	name := query.Question[0].Name
266 266
 	if query.Question[0].Qtype == dns.TypeA {
267
-		resp, err = r.handleIPv4Query(name, query)
267
+		resp, err = r.handleIPQuery(name, query, netutils.IPv4)
268
+	} else if query.Question[0].Qtype == dns.TypeAAAA {
269
+		resp, err = r.handleIPQuery(name, query, netutils.IPv6)
268 270
 	} else if query.Question[0].Qtype == dns.TypePTR {
269 271
 		resp, err = r.handlePTRQuery(name, query)
270 272
 	}
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	log "github.com/Sirupsen/logrus"
12 12
 	"github.com/docker/libnetwork/etchosts"
13 13
 	"github.com/docker/libnetwork/netlabel"
14
+	"github.com/docker/libnetwork/netutils"
14 15
 	"github.com/docker/libnetwork/osl"
15 16
 	"github.com/docker/libnetwork/types"
16 17
 )
... ...
@@ -36,9 +37,11 @@ type Sandbox interface {
36 36
 	Rename(name string) error
37 37
 	// Delete destroys this container after detaching it from all connected endpoints.
38 38
 	Delete() error
39
-	// ResolveName searches for the service name in the networks to which the sandbox
40
-	// is connected to.
41
-	ResolveName(name string) []net.IP
39
+	// ResolveName resolves a service name to an IPv4 or IPv6 address by searching
40
+	// the networks the sandbox is connected to. For IPv6 queries, second  return
41
+	// value will be true if the name exists in docker domain but doesn't have an
42
+	// IPv6 address. Such queries shouldn't be forwarded  to external nameservers.
43
+	ResolveName(name string, iplen int) ([]net.IP, bool)
42 44
 	// ResolveIP returns the service name for the passed in IP. IP is in reverse dotted
43 45
 	// notation; the format used for DNS PTR records
44 46
 	ResolveIP(name string) string
... ...
@@ -418,9 +421,7 @@ func (sb *sandbox) execFunc(f func()) {
418 418
 	sb.osSbox.InvokeFunc(f)
419 419
 }
420 420
 
421
-func (sb *sandbox) ResolveName(name string) []net.IP {
422
-	var ip []net.IP
423
-
421
+func (sb *sandbox) ResolveName(name string, ipType int) ([]net.IP, bool) {
424 422
 	// Embedded server owns the docker network domain. Resolution should work
425 423
 	// for both container_name and container_name.network_name
426 424
 	// We allow '.' in service name and network name. For a name a.b.c.d the
... ...
@@ -453,21 +454,29 @@ func (sb *sandbox) ResolveName(name string) []net.IP {
453 453
 		log.Debugf("To resolve: %v in %v", reqName[i], networkName[i])
454 454
 
455 455
 		// First check for local container alias
456
-		ip = sb.resolveName(reqName[i], networkName[i], epList, true)
456
+		ip, ipv6Miss := sb.resolveName(reqName[i], networkName[i], epList, true, ipType)
457 457
 		if ip != nil {
458
-			return ip
458
+			return ip, false
459
+		}
460
+		if ipv6Miss {
461
+			return ip, ipv6Miss
459 462
 		}
460 463
 
461 464
 		// Resolve the actual container name
462
-		ip = sb.resolveName(reqName[i], networkName[i], epList, false)
465
+		ip, ipv6Miss = sb.resolveName(reqName[i], networkName[i], epList, false, ipType)
463 466
 		if ip != nil {
464
-			return ip
467
+			return ip, false
468
+		}
469
+		if ipv6Miss {
470
+			return ip, ipv6Miss
465 471
 		}
466 472
 	}
467
-	return nil
473
+	return nil, false
468 474
 }
469 475
 
470
-func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool) []net.IP {
476
+func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoint, alias bool, ipType int) ([]net.IP, bool) {
477
+	var ipv6Miss bool
478
+
471 479
 	for _, ep := range epList {
472 480
 		name := req
473 481
 		n := ep.getNetwork()
... ...
@@ -504,14 +513,26 @@ func (sb *sandbox) resolveName(req string, networkName string, epList []*endpoin
504 504
 			continue
505 505
 		}
506 506
 
507
+		var ip []net.IP
507 508
 		n.Lock()
508
-		ip, ok := sr.svcMap[name]
509
+		ip, ok = sr.svcMap[name]
510
+
511
+		if ipType == netutils.IPv6 {
512
+			// If the name resolved to v4 address then its a valid name in
513
+			// the docker network domain. If the network is not v6 enabled
514
+			// set ipv6Miss to filter the DNS query from going to external
515
+			// resolvers.
516
+			if ok && n.enableIPv6 == false {
517
+				ipv6Miss = true
518
+			}
519
+			ip = sr.svcIPv6Map[name]
520
+		}
509 521
 		n.Unlock()
510
-		if ok {
511
-			return ip
522
+		if ip != nil {
523
+			return ip, false
512 524
 		}
513 525
 	}
514
-	return nil
526
+	return nil, ipv6Miss
515 527
 }
516 528
 
517 529
 func (sb *sandbox) SetKey(basePath string) error {