Browse code

vendorin libnetwork @d2edad309cc874e865b5ba4d6bd6b276c93451d3

Signed-off-by: Santhosh Manohar <santhosh@docker.com>

Santhosh Manohar authored on 2017/01/05 04:42:48
Showing 27 changed files
... ...
@@ -23,7 +23,7 @@ github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
23 23
 github.com/imdario/mergo 0.2.1
24 24
 
25 25
 #get libnetwork packages
26
-github.com/docker/libnetwork 382be38ce860738d80b53d7875d83abd5970d9d6 https://github.com/aaronlehmann/libnetwork
26
+github.com/docker/libnetwork e8431956af5df6816e232d68376c012c2617edbd
27 27
 github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
28 28
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
29 29
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
... ...
@@ -6,6 +6,7 @@ package bitseq
6 6
 import (
7 7
 	"encoding/binary"
8 8
 	"encoding/json"
9
+	"errors"
9 10
 	"fmt"
10 11
 	"sync"
11 12
 
... ...
@@ -26,9 +27,9 @@ const (
26 26
 
27 27
 var (
28 28
 	// ErrNoBitAvailable is returned when no more bits are available to set
29
-	ErrNoBitAvailable = fmt.Errorf("no bit available")
29
+	ErrNoBitAvailable = errors.New("no bit available")
30 30
 	// ErrBitAllocated is returned when the specific bit requested is already set
31
-	ErrBitAllocated = fmt.Errorf("requested bit is already allocated")
31
+	ErrBitAllocated = errors.New("requested bit is already allocated")
32 32
 )
33 33
 
34 34
 // Handle contains the sequece representing the bitmask and its identifier
... ...
@@ -373,7 +374,7 @@ func (h *Handle) validateOrdinal(ordinal uint64) error {
373 373
 	h.Lock()
374 374
 	defer h.Unlock()
375 375
 	if ordinal >= h.bits {
376
-		return fmt.Errorf("bit does not belong to the sequence")
376
+		return errors.New("bit does not belong to the sequence")
377 377
 	}
378 378
 	return nil
379 379
 }
... ...
@@ -418,7 +419,7 @@ func (h *Handle) ToByteArray() ([]byte, error) {
418 418
 // FromByteArray reads his handle's data from a byte array
419 419
 func (h *Handle) FromByteArray(ba []byte) error {
420 420
 	if ba == nil {
421
-		return fmt.Errorf("nil byte array")
421
+		return errors.New("nil byte array")
422 422
 	}
423 423
 
424 424
 	nh := &sequence{}
... ...
@@ -273,7 +273,7 @@ func (c *controller) SetKeys(keys []*types.EncryptionKey) error {
273 273
 	}
274 274
 	for s, count := range subsysKeys {
275 275
 		if count != keyringSize {
276
-			return fmt.Errorf("incorrect number of keys for susbsystem %v", s)
276
+			return fmt.Errorf("incorrect number of keys for subsystem %v", s)
277 277
 		}
278 278
 	}
279 279
 
... ...
@@ -582,7 +582,7 @@ func (c *controller) pushNodeDiscovery(d driverapi.Driver, cap driverapi.Capabil
582 582
 			err = d.DiscoverDelete(discoverapi.NodeDiscovery, nodeData)
583 583
 		}
584 584
 		if err != nil {
585
-			logrus.Debugf("discovery notification error : %v", err)
585
+			logrus.Debugf("discovery notification error: %v", err)
586 586
 		}
587 587
 	}
588 588
 }
... ...
@@ -932,6 +932,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s
932 932
 			populatedEndpoints: map[string]struct{}{},
933 933
 			config:             containerConfig{},
934 934
 			controller:         c,
935
+			extDNS:             []extDNSEntry{},
935 936
 		}
936 937
 	}
937 938
 	sBox = sb
... ...
@@ -997,7 +998,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s
997 997
 
998 998
 	err = sb.storeUpdate()
999 999
 	if err != nil {
1000
-		return nil, fmt.Errorf("updating the store state of sandbox failed: %v", err)
1000
+		return nil, fmt.Errorf("failed to update the store state of sandbox: %v", err)
1001 1001
 	}
1002 1002
 
1003 1003
 	return sb, nil
... ...
@@ -1,6 +1,7 @@
1 1
 package datastore
2 2
 
3 3
 import (
4
+	"errors"
4 5
 	"fmt"
5 6
 	"sync"
6 7
 
... ...
@@ -36,7 +37,7 @@ func (c *cache) kmap(kvObject KVObject) (kvMap, error) {
36 36
 	// Bail out right away if the kvObject does not implement KVConstructor
37 37
 	ctor, ok := kvObject.(KVConstructor)
38 38
 	if !ok {
39
-		return nil, fmt.Errorf("error while populating kmap, object does not implement KVConstructor interface")
39
+		return nil, errors.New("error while populating kmap, object does not implement KVConstructor interface")
40 40
 	}
41 41
 
42 42
 	kvList, err := c.ds.store.List(keyPrefix)
... ...
@@ -153,7 +154,7 @@ func (c *cache) get(key string, kvObject KVObject) error {
153 153
 
154 154
 	ctor, ok := o.(KVConstructor)
155 155
 	if !ok {
156
-		return fmt.Errorf("kvobject does not implement KVConstructor interface. could not get object")
156
+		return errors.New("kvobject does not implement KVConstructor interface. could not get object")
157 157
 	}
158 158
 
159 159
 	return ctor.CopyTo(kvObject)
... ...
@@ -62,7 +62,7 @@ type Driver interface {
62 62
 	// programming to allow the external connectivity dictated by the passed options
63 63
 	ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error
64 64
 
65
-	// RevokeExternalConnectivity aks the driver to remove any external connectivity
65
+	// RevokeExternalConnectivity asks the driver to remove any external connectivity
66 66
 	// programming that was done so far
67 67
 	RevokeExternalConnectivity(nid, eid string) error
68 68
 
... ...
@@ -72,7 +72,7 @@ type Driver interface {
72 72
 	// only invoked for the global scope driver.
73 73
 	EventNotify(event EventType, nid string, tableName string, key string, value []byte)
74 74
 
75
-	// Type returns the the type of this driver, the network type this driver manages
75
+	// Type returns the type of this driver, the network type this driver manages
76 76
 	Type() string
77 77
 
78 78
 	// IsBuiltIn returns true if it is a built-in driver
... ...
@@ -186,24 +186,24 @@ func (c *networkConfiguration) Validate() error {
186 186
 // Conflicts check if two NetworkConfiguration objects overlap
187 187
 func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
188 188
 	if o == nil {
189
-		return fmt.Errorf("same configuration")
189
+		return errors.New("same configuration")
190 190
 	}
191 191
 
192 192
 	// Also empty, because only one network with empty name is allowed
193 193
 	if c.BridgeName == o.BridgeName {
194
-		return fmt.Errorf("networks have same bridge name")
194
+		return errors.New("networks have same bridge name")
195 195
 	}
196 196
 
197 197
 	// They must be in different subnets
198 198
 	if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) &&
199 199
 		(c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
200
-		return fmt.Errorf("networks have overlapping IPv4")
200
+		return errors.New("networks have overlapping IPv4")
201 201
 	}
202 202
 
203 203
 	// They must be in different v6 subnets
204 204
 	if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) &&
205 205
 		(c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) {
206
-		return fmt.Errorf("networks have overlapping IPv6")
206
+		return errors.New("networks have overlapping IPv6")
207 207
 	}
208 208
 
209 209
 	return nil
... ...
@@ -1,6 +1,7 @@
1 1
 package bridge
2 2
 
3 3
 import (
4
+	"errors"
4 5
 	"fmt"
5 6
 	"io/ioutil"
6 7
 	"os"
... ...
@@ -37,7 +38,7 @@ func setupBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) e
37 37
 					logrus.Warnf("running inside docker container, ignoring missing kernel params: %v", err)
38 38
 					err = nil
39 39
 				} else {
40
-					err = fmt.Errorf("please ensure that br_netfilter kernel module is loaded")
40
+					err = errors.New("please ensure that br_netfilter kernel module is loaded")
41 41
 				}
42 42
 			}
43 43
 		}
... ...
@@ -1,6 +1,7 @@
1 1
 package bridge
2 2
 
3 3
 import (
4
+	"errors"
4 5
 	"fmt"
5 6
 	"net"
6 7
 
... ...
@@ -17,7 +18,7 @@ const (
17 17
 func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
18 18
 	// Sanity check.
19 19
 	if config.EnableIPTables == false {
20
-		return nil, nil, nil, fmt.Errorf("cannot create new chains, EnableIPTable is disabled")
20
+		return nil, nil, nil, errors.New("cannot create new chains, EnableIPTable is disabled")
21 21
 	}
22 22
 
23 23
 	hairpinMode := !config.EnableUserlandProxy
... ...
@@ -68,7 +69,7 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt
68 68
 
69 69
 	// Sanity check.
70 70
 	if driverConfig.EnableIPTables == false {
71
-		return fmt.Errorf("Cannot program chains, EnableIPTable is disabled")
71
+		return errors.New("Cannot program chains, EnableIPTable is disabled")
72 72
 	}
73 73
 
74 74
 	// Pickup this configuration option from driver
... ...
@@ -1,6 +1,7 @@
1 1
 package bridge
2 2
 
3 3
 import (
4
+	"errors"
4 5
 	"fmt"
5 6
 	"io/ioutil"
6 7
 	"net"
... ...
@@ -13,7 +14,7 @@ import (
13 13
 
14 14
 func selectIPv4Address(addresses []netlink.Addr, selector *net.IPNet) (netlink.Addr, error) {
15 15
 	if len(addresses) == 0 {
16
-		return netlink.Addr{}, fmt.Errorf("unable to select an address as the address pool is empty")
16
+		return netlink.Addr{}, errors.New("unable to select an address as the address pool is empty")
17 17
 	}
18 18
 	if selector != nil {
19 19
 		for _, addr := range addresses {
... ...
@@ -402,7 +402,7 @@ func (n *network) getBridgeNamePrefix(s *subnet) string {
402 402
 	return "ov-" + fmt.Sprintf("%06x", n.vxlanID(s))
403 403
 }
404 404
 
405
-func isOverlap(nw *net.IPNet) bool {
405
+func checkOverlap(nw *net.IPNet) error {
406 406
 	var nameservers []string
407 407
 
408 408
 	if rc, err := resolvconf.Get(); err == nil {
... ...
@@ -410,14 +410,14 @@ func isOverlap(nw *net.IPNet) bool {
410 410
 	}
411 411
 
412 412
 	if err := netutils.CheckNameserverOverlaps(nameservers, nw); err != nil {
413
-		return true
413
+		return fmt.Errorf("overlay subnet %s failed check with nameserver: %v: %v", nw.String(), nameservers, err)
414 414
 	}
415 415
 
416 416
 	if err := netutils.CheckRouteOverlaps(nw); err != nil {
417
-		return true
417
+		return fmt.Errorf("overlay subnet %s failed check with host route table: %v", nw.String(), err)
418 418
 	}
419 419
 
420
-	return false
420
+	return nil
421 421
 }
422 422
 
423 423
 func (n *network) restoreSubnetSandbox(s *subnet, brName, vxlanName string) error {
... ...
@@ -456,8 +456,8 @@ func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error
456 456
 		// Try to delete the vxlan interface by vni if already present
457 457
 		deleteVxlanByVNI("", n.vxlanID(s))
458 458
 
459
-		if isOverlap(s.subnetIP) {
460
-			return fmt.Errorf("overlay subnet %s has conflicts in the host while running in host mode", s.subnetIP.String())
459
+		if err := checkOverlap(s.subnetIP); err != nil {
460
+			return err
461 461
 		}
462 462
 	}
463 463
 
... ...
@@ -1,6 +1,7 @@
1 1
 package remote
2 2
 
3 3
 import (
4
+	"errors"
4 5
 	"fmt"
5 6
 	"net"
6 7
 
... ...
@@ -132,7 +133,7 @@ func (d *driver) DeleteNetwork(nid string) error {
132 132
 
133 133
 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
134 134
 	if ifInfo == nil {
135
-		return fmt.Errorf("must not be called with nil InterfaceInfo")
135
+		return errors.New("must not be called with nil InterfaceInfo")
136 136
 	}
137 137
 
138 138
 	reqIface := &api.EndpointInterface{}
... ...
@@ -81,7 +81,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
81 81
 			return err
82 82
 		}
83 83
 
84
-		// Temp: We have to create a endpoint object to keep track of the HNS ID for
84
+		// Temp: We have to create an endpoint object to keep track of the HNS ID for
85 85
 		// this endpoint so that we can retrieve it later when the endpoint is deleted.
86 86
 		// This seems unnecessary when we already have dockers EID. See if we can pass
87 87
 		// the global EID to HNS to use as it's ID, rather than having each HNS assign
... ...
@@ -1,6 +1,7 @@
1 1
 package drvregistry
2 2
 
3 3
 import (
4
+	"errors"
4 5
 	"fmt"
5 6
 	"strings"
6 7
 	"sync"
... ...
@@ -160,7 +161,7 @@ func (r *DrvRegistry) GetPluginGetter() plugingetter.PluginGetter {
160 160
 // RegisterDriver registers the network driver when it gets discovered.
161 161
 func (r *DrvRegistry) RegisterDriver(ntype string, driver driverapi.Driver, capability driverapi.Capability) error {
162 162
 	if strings.TrimSpace(ntype) == "" {
163
-		return fmt.Errorf("network type string cannot be empty")
163
+		return errors.New("network type string cannot be empty")
164 164
 	}
165 165
 
166 166
 	r.Lock()
... ...
@@ -188,7 +189,7 @@ func (r *DrvRegistry) RegisterDriver(ntype string, driver driverapi.Driver, capa
188 188
 
189 189
 func (r *DrvRegistry) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
190 190
 	if strings.TrimSpace(name) == "" {
191
-		return fmt.Errorf("ipam driver name string cannot be empty")
191
+		return errors.New("ipam driver name string cannot be empty")
192 192
 	}
193 193
 
194 194
 	r.Lock()
... ...
@@ -2,6 +2,7 @@
2 2
 package idm
3 3
 
4 4
 import (
5
+	"errors"
5 6
 	"fmt"
6 7
 
7 8
 	"github.com/docker/libnetwork/bitseq"
... ...
@@ -18,7 +19,7 @@ type Idm struct {
18 18
 // New returns an instance of id manager for a [start,end] set of numerical ids
19 19
 func New(ds datastore.DataStore, id string, start, end uint64) (*Idm, error) {
20 20
 	if id == "" {
21
-		return nil, fmt.Errorf("Invalid id")
21
+		return nil, errors.New("Invalid id")
22 22
 	}
23 23
 	if end <= start {
24 24
 		return nil, fmt.Errorf("Invalid set range: [%d, %d]", start, end)
... ...
@@ -35,7 +36,7 @@ func New(ds datastore.DataStore, id string, start, end uint64) (*Idm, error) {
35 35
 // GetID returns the first available id in the set
36 36
 func (i *Idm) GetID() (uint64, error) {
37 37
 	if i.handle == nil {
38
-		return 0, fmt.Errorf("ID set is not initialized")
38
+		return 0, errors.New("ID set is not initialized")
39 39
 	}
40 40
 	ordinal, err := i.handle.SetAny()
41 41
 	return i.start + ordinal, err
... ...
@@ -44,11 +45,11 @@ func (i *Idm) GetID() (uint64, error) {
44 44
 // GetSpecificID tries to reserve the specified id
45 45
 func (i *Idm) GetSpecificID(id uint64) error {
46 46
 	if i.handle == nil {
47
-		return fmt.Errorf("ID set is not initialized")
47
+		return errors.New("ID set is not initialized")
48 48
 	}
49 49
 
50 50
 	if id < i.start || id > i.end {
51
-		return fmt.Errorf("Requested id does not belong to the set")
51
+		return errors.New("Requested id does not belong to the set")
52 52
 	}
53 53
 
54 54
 	return i.handle.Set(id - i.start)
... ...
@@ -57,11 +58,11 @@ func (i *Idm) GetSpecificID(id uint64) error {
57 57
 // GetIDInRange returns the first available id in the set within a [start,end] range
58 58
 func (i *Idm) GetIDInRange(start, end uint64) (uint64, error) {
59 59
 	if i.handle == nil {
60
-		return 0, fmt.Errorf("ID set is not initialized")
60
+		return 0, errors.New("ID set is not initialized")
61 61
 	}
62 62
 
63 63
 	if start < i.start || end > i.end {
64
-		return 0, fmt.Errorf("Requested range does not belong to the set")
64
+		return 0, errors.New("Requested range does not belong to the set")
65 65
 	}
66 66
 
67 67
 	ordinal, err := i.handle.SetAnyInRange(start-i.start, end-i.start)
... ...
@@ -3,7 +3,7 @@
3 3
 package builtin
4 4
 
5 5
 import (
6
-	"fmt"
6
+	"errors"
7 7
 
8 8
 	"github.com/docker/libnetwork/datastore"
9 9
 	"github.com/docker/libnetwork/ipam"
... ...
@@ -20,13 +20,13 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
20 20
 
21 21
 	if l != nil {
22 22
 		if localDs, ok = l.(datastore.DataStore); !ok {
23
-			return fmt.Errorf("incorrect local datastore passed to built-in ipam init")
23
+			return errors.New("incorrect local datastore passed to built-in ipam init")
24 24
 		}
25 25
 	}
26 26
 
27 27
 	if g != nil {
28 28
 		if globalDs, ok = g.(datastore.DataStore); !ok {
29
-			return fmt.Errorf("incorrect global datastore passed to built-in ipam init")
29
+			return errors.New("incorrect global datastore passed to built-in ipam init")
30 30
 		}
31 31
 	}
32 32
 
... ...
@@ -3,7 +3,7 @@
3 3
 package builtin
4 4
 
5 5
 import (
6
-	"fmt"
6
+	"errors"
7 7
 
8 8
 	"github.com/docker/libnetwork/datastore"
9 9
 	"github.com/docker/libnetwork/ipam"
... ...
@@ -22,13 +22,13 @@ func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error {
22 22
 
23 23
 	if l != nil {
24 24
 		if localDs, ok = l.(datastore.DataStore); !ok {
25
-			return fmt.Errorf("incorrect local datastore passed to built-in ipam init")
25
+			return errors.New("incorrect local datastore passed to built-in ipam init")
26 26
 		}
27 27
 	}
28 28
 
29 29
 	if g != nil {
30 30
 		if globalDs, ok = g.(datastore.DataStore); !ok {
31
-			return fmt.Errorf("incorrect global datastore passed to built-in ipam init")
31
+			return errors.New("incorrect global datastore passed to built-in ipam init")
32 32
 		}
33 33
 	}
34 34
 
... ...
@@ -131,7 +131,7 @@ func NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) {
131 131
 // ProgramChain is used to add rules to a chain
132 132
 func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) error {
133 133
 	if c.Name == "" {
134
-		return fmt.Errorf("Could not program chain, missing chain name")
134
+		return errors.New("Could not program chain, missing chain name")
135 135
 	}
136 136
 
137 137
 	switch c.Table {
... ...
@@ -173,7 +173,7 @@ func ReverseIP(IP string) string {
173 173
 // ParseAlias parses and validates the specified string as an alias format (name:alias)
174 174
 func ParseAlias(val string) (string, string, error) {
175 175
 	if val == "" {
176
-		return "", "", fmt.Errorf("empty string specified for alias")
176
+		return "", "", errors.New("empty string specified for alias")
177 177
 	}
178 178
 	arr := strings.Split(val, ":")
179 179
 	if len(arr) > 2 {
... ...
@@ -80,10 +80,18 @@ type NetworkInfo interface {
80 80
 // When the function returns true, the walk will stop.
81 81
 type EndpointWalker func(ep Endpoint) bool
82 82
 
83
+// ipInfo is the reverse mapping from IP to service name to serve the PTR query.
84
+// extResolver is set if an externl server resolves a service name to this IP.
85
+// Its an indication to defer PTR queries also to that external server.
86
+type ipInfo struct {
87
+	name        string
88
+	extResolver bool
89
+}
90
+
83 91
 type svcInfo struct {
84 92
 	svcMap     map[string][]net.IP
85 93
 	svcIPv6Map map[string][]net.IP
86
-	ipMap      map[string]string
94
+	ipMap      map[string]*ipInfo
87 95
 	service    map[string][]servicePorts
88 96
 }
89 97
 
... ...
@@ -877,7 +885,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
877 877
 	}
878 878
 
879 879
 	if _, err = n.EndpointByName(name); err == nil {
880
-		return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
880
+		return nil, types.ForbiddenErrorf("endpoint with name %s already exists in network %s", name, n.Name())
881 881
 	}
882 882
 
883 883
 	ep := &endpoint{name: name, generic: make(map[string]interface{}), iface: &endpointInterface{}}
... ...
@@ -1070,10 +1078,12 @@ func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool
1070 1070
 	}
1071 1071
 }
1072 1072
 
1073
-func addIPToName(ipMap map[string]string, name string, ip net.IP) {
1073
+func addIPToName(ipMap map[string]*ipInfo, name string, ip net.IP) {
1074 1074
 	reverseIP := netutils.ReverseIP(ip.String())
1075 1075
 	if _, ok := ipMap[reverseIP]; !ok {
1076
-		ipMap[reverseIP] = name
1076
+		ipMap[reverseIP] = &ipInfo{
1077
+			name: name,
1078
+		}
1077 1079
 	}
1078 1080
 }
1079 1081
 
... ...
@@ -1117,7 +1127,7 @@ func (n *network) addSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUp
1117 1117
 		sr = svcInfo{
1118 1118
 			svcMap:     make(map[string][]net.IP),
1119 1119
 			svcIPv6Map: make(map[string][]net.IP),
1120
-			ipMap:      make(map[string]string),
1120
+			ipMap:      make(map[string]*ipInfo),
1121 1121
 		}
1122 1122
 		c.svcRecords[n.ID()] = sr
1123 1123
 	}
... ...
@@ -1612,8 +1622,8 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
1612 1612
 
1613 1613
 	c := n.getController()
1614 1614
 	c.Lock()
1615
+	defer c.Unlock()
1615 1616
 	sr, ok := c.svcRecords[n.ID()]
1616
-	c.Unlock()
1617 1617
 
1618 1618
 	if !ok {
1619 1619
 		return nil, false
... ...
@@ -1621,7 +1631,6 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
1621 1621
 
1622 1622
 	req = strings.TrimSuffix(req, ".")
1623 1623
 	var ip []net.IP
1624
-	n.Lock()
1625 1624
 	ip, ok = sr.svcMap[req]
1626 1625
 
1627 1626
 	if ipType == types.IPv6 {
... ...
@@ -1634,22 +1643,38 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
1634 1634
 		}
1635 1635
 		ip = sr.svcIPv6Map[req]
1636 1636
 	}
1637
-	n.Unlock()
1638 1637
 
1639 1638
 	if ip != nil {
1640
-		return ip, false
1639
+		ipLocal := make([]net.IP, len(ip))
1640
+		copy(ipLocal, ip)
1641
+		return ipLocal, false
1641 1642
 	}
1642 1643
 
1643 1644
 	return nil, ipv6Miss
1644 1645
 }
1645 1646
 
1646
-func (n *network) ResolveIP(ip string) string {
1647
-	var svc string
1647
+func (n *network) HandleQueryResp(name string, ip net.IP) {
1648
+	c := n.getController()
1649
+	c.Lock()
1650
+	defer c.Unlock()
1651
+	sr, ok := c.svcRecords[n.ID()]
1648 1652
 
1653
+	if !ok {
1654
+		return
1655
+	}
1656
+
1657
+	ipStr := netutils.ReverseIP(ip.String())
1658
+
1659
+	if ipInfo, ok := sr.ipMap[ipStr]; ok {
1660
+		ipInfo.extResolver = true
1661
+	}
1662
+}
1663
+
1664
+func (n *network) ResolveIP(ip string) string {
1649 1665
 	c := n.getController()
1650 1666
 	c.Lock()
1667
+	defer c.Unlock()
1651 1668
 	sr, ok := c.svcRecords[n.ID()]
1652
-	c.Unlock()
1653 1669
 
1654 1670
 	if !ok {
1655 1671
 		return ""
... ...
@@ -1657,15 +1682,13 @@ func (n *network) ResolveIP(ip string) string {
1657 1657
 
1658 1658
 	nwName := n.Name()
1659 1659
 
1660
-	n.Lock()
1661
-	defer n.Unlock()
1662
-	svc, ok = sr.ipMap[ip]
1660
+	ipInfo, ok := sr.ipMap[ip]
1663 1661
 
1664
-	if ok {
1665
-		return svc + "." + nwName
1662
+	if !ok || ipInfo.extResolver {
1663
+		return ""
1666 1664
 	}
1667 1665
 
1668
-	return svc
1666
+	return ipInfo.name + "." + nwName
1669 1667
 }
1670 1668
 
1671 1669
 func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) {
... ...
@@ -1689,8 +1712,8 @@ func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) {
1689 1689
 	svcName := strings.Join(parts[2:], ".")
1690 1690
 
1691 1691
 	c.Lock()
1692
+	defer c.Unlock()
1692 1693
 	sr, ok := c.svcRecords[n.ID()]
1693
-	c.Unlock()
1694 1694
 
1695 1695
 	if !ok {
1696 1696
 		return nil, nil
... ...
@@ -1,7 +1,7 @@
1 1
 package networkdb
2 2
 
3 3
 import (
4
-	"fmt"
4
+	"errors"
5 5
 	"time"
6 6
 
7 7
 	"github.com/hashicorp/memberlist"
... ...
@@ -90,7 +90,7 @@ func (nDB *NetworkDB) sendNodeEvent(event NodeEvent_Type) error {
90 90
 	select {
91 91
 	case <-notifyCh:
92 92
 	case <-time.After(broadcastTimeout):
93
-		return fmt.Errorf("timed out broadcasting node event")
93
+		return errors.New("timed out broadcasting node event")
94 94
 	}
95 95
 
96 96
 	return nil
... ...
@@ -179,6 +179,8 @@ func (i *nwIface) Remove() error {
179 179
 	}
180 180
 	n.Unlock()
181 181
 
182
+	n.checkLoV6()
183
+
182 184
 	return nil
183 185
 }
184 186
 
... ...
@@ -318,6 +320,8 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
318 318
 	n.iFaces = append(n.iFaces, i)
319 319
 	n.Unlock()
320 320
 
321
+	n.checkLoV6()
322
+
321 323
 	return nil
322 324
 }
323 325
 
... ...
@@ -378,6 +382,9 @@ func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error
378 378
 	if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil {
379 379
 		return err
380 380
 	}
381
+	if err := setIPv6(i.ns.path, i.DstName(), true); err != nil {
382
+		return fmt.Errorf("failed to enable ipv6: %v", err)
383
+	}
381 384
 	ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
382 385
 	return nlh.AddrAdd(iface, ipAddr)
383 386
 }
... ...
@@ -24,6 +24,10 @@ import (
24 24
 
25 25
 const defaultPrefix = "/var/run/docker"
26 26
 
27
+func init() {
28
+	reexec.Register("set-ipv6", reexecSetIPv6)
29
+}
30
+
27 31
 var (
28 32
 	once             sync.Once
29 33
 	garbagePathMap   = make(map[string]bool)
... ...
@@ -47,6 +51,7 @@ type networkNamespace struct {
47 47
 	nextIfIndex  int
48 48
 	isDefault    bool
49 49
 	nlHandle     *netlink.Handle
50
+	loV6Enabled  bool
50 51
 	sync.Mutex
51 52
 }
52 53
 
... ...
@@ -216,6 +221,12 @@ func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
216 216
 		logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err)
217 217
 	}
218 218
 
219
+	// As starting point, disable IPv6 on all interfaces
220
+	err = setIPv6(n.path, "all", false)
221
+	if err != nil {
222
+		logrus.Warnf("Failed to disable IPv6 on all interfaces on network namespace %q: %v", n.path, err)
223
+	}
224
+
219 225
 	if err = n.loopbackUp(); err != nil {
220 226
 		n.nlHandle.Delete()
221 227
 		return nil, err
... ...
@@ -263,6 +274,12 @@ func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) {
263 263
 		logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err)
264 264
 	}
265 265
 
266
+	// As starting point, disable IPv6 on all interfaces
267
+	err = setIPv6(n.path, "all", false)
268
+	if err != nil {
269
+		logrus.Warnf("Failed to disable IPv6 on all interfaces on network namespace %q: %v", n.path, err)
270
+	}
271
+
266 272
 	if err = n.loopbackUp(); err != nil {
267 273
 		n.nlHandle.Delete()
268 274
 		return nil, err
... ...
@@ -508,3 +525,84 @@ func (n *networkNamespace) Restore(ifsopt map[string][]IfaceOption, routes []*ty
508 508
 
509 509
 	return nil
510 510
 }
511
+
512
+// Checks whether IPv6 needs to be enabled/disabled on the loopback interface
513
+func (n *networkNamespace) checkLoV6() {
514
+	var (
515
+		enable = false
516
+		action = "disable"
517
+	)
518
+
519
+	n.Lock()
520
+	for _, iface := range n.iFaces {
521
+		if iface.AddressIPv6() != nil {
522
+			enable = true
523
+			action = "enable"
524
+			break
525
+		}
526
+	}
527
+	n.Unlock()
528
+
529
+	if n.loV6Enabled == enable {
530
+		return
531
+	}
532
+
533
+	if err := setIPv6(n.path, "lo", enable); err != nil {
534
+		logrus.Warnf("Failed to %s IPv6 on loopback interface on network namespace %q: %v", action, n.path, err)
535
+	}
536
+
537
+	n.loV6Enabled = enable
538
+}
539
+
540
+func reexecSetIPv6() {
541
+	runtime.LockOSThread()
542
+	defer runtime.UnlockOSThread()
543
+
544
+	if len(os.Args) < 3 {
545
+		logrus.Errorf("invalid number of arguments for %s", os.Args[0])
546
+		os.Exit(1)
547
+	}
548
+
549
+	ns, err := netns.GetFromPath(os.Args[1])
550
+	if err != nil {
551
+		logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err)
552
+		os.Exit(2)
553
+	}
554
+	defer ns.Close()
555
+
556
+	if err = netns.Set(ns); err != nil {
557
+		logrus.Errorf("setting into container netns %q failed: %v", os.Args[1], err)
558
+		os.Exit(3)
559
+	}
560
+
561
+	var (
562
+		action = "disable"
563
+		value  = byte('1')
564
+		path   = fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", os.Args[2])
565
+	)
566
+
567
+	if os.Args[3] == "true" {
568
+		action = "enable"
569
+		value = byte('0')
570
+	}
571
+
572
+	if err = ioutil.WriteFile(path, []byte{value, '\n'}, 0644); err != nil {
573
+		logrus.Errorf("failed to %s IPv6 forwarding for container's interface %s: %v", action, os.Args[2], err)
574
+		os.Exit(4)
575
+	}
576
+
577
+	os.Exit(0)
578
+}
579
+
580
+func setIPv6(path, iface string, enable bool) error {
581
+	cmd := &exec.Cmd{
582
+		Path:   reexec.Self(),
583
+		Args:   append([]string{"set-ipv6"}, path, iface, strconv.FormatBool(enable)),
584
+		Stdout: os.Stdout,
585
+		Stderr: os.Stderr,
586
+	}
587
+	if err := cmd.Run(); err != nil {
588
+		return fmt.Errorf("reexec to set IPv6 failed: %v", err)
589
+	}
590
+	return nil
591
+}
... ...
@@ -4,10 +4,14 @@ import (
4 4
 	"regexp"
5 5
 )
6 6
 
7
-// IPLocalhost is a regex patter for localhost IP address range.
7
+// IPLocalhost is a regex pattern for IPv4 or IPv6 loopback range.
8 8
 const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)`
9 9
 
10
+// IPv4Localhost is a regex pattern for IPv4 localhost address range.
11
+const IPv4Localhost = `(127\.([0-9]{1,3}\.){2}[0-9]{1,3})`
12
+
10 13
 var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
14
+var localhostIPv4Regexp = regexp.MustCompile(IPv4Localhost)
11 15
 
12 16
 // IsLocalhost returns true if ip matches the localhost IP regular expression.
13 17
 // Used for determining if nameserver settings are being passed which are
... ...
@@ -15,3 +19,8 @@ var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
15 15
 func IsLocalhost(ip string) bool {
16 16
 	return localhostIPRegexp.MatchString(ip)
17 17
 }
18
+
19
+// IsIPv4Localhost returns true if ip matches the IPv4 localhost regular expression.
20
+func IsIPv4Localhost(ip string) bool {
21
+	return localhostIPv4Regexp.MatchString(ip)
22
+}
... ...
@@ -29,7 +29,7 @@ type Resolver interface {
29 29
 	NameServer() string
30 30
 	// SetExtServers configures the external nameservers the resolver
31 31
 	// should use to forward queries
32
-	SetExtServers([]string)
32
+	SetExtServers([]extDNSEntry)
33 33
 	// ResolverOptions returns resolv.conf options that should be set
34 34
 	ResolverOptions() []string
35 35
 }
... ...
@@ -54,6 +54,9 @@ type DNSBackend interface {
54 54
 	ExecFunc(f func()) error
55 55
 	//NdotsSet queries the backends ndots dns option settings
56 56
 	NdotsSet() bool
57
+	// HandleQueryResp passes the name & IP from a response to the backend. backend
58
+	// can use it to maintain any required state about the resolution
59
+	HandleQueryResp(name string, ip net.IP)
57 60
 }
58 61
 
59 62
 const (
... ...
@@ -69,7 +72,8 @@ const (
69 69
 )
70 70
 
71 71
 type extDNSEntry struct {
72
-	ipStr string
72
+	ipStr        string
73
+	hostLoopback bool
73 74
 }
74 75
 
75 76
 // resolver implements the Resolver interface
... ...
@@ -182,13 +186,13 @@ func (r *resolver) Stop() {
182 182
 	r.queryLock = sync.Mutex{}
183 183
 }
184 184
 
185
-func (r *resolver) SetExtServers(dns []string) {
186
-	l := len(dns)
185
+func (r *resolver) SetExtServers(extDNS []extDNSEntry) {
186
+	l := len(extDNS)
187 187
 	if l > maxExtDNS {
188 188
 		l = maxExtDNS
189 189
 	}
190 190
 	for i := 0; i < l; i++ {
191
-		r.extDNSList[i].ipStr = dns[i]
191
+		r.extDNSList[i] = extDNS[i]
192 192
 	}
193 193
 }
194 194
 
... ...
@@ -417,10 +421,14 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
417 417
 				extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
418 418
 			}
419 419
 
420
-			execErr := r.backend.ExecFunc(extConnect)
421
-			if execErr != nil {
422
-				logrus.Warn(execErr)
423
-				continue
420
+			if extDNS.hostLoopback {
421
+				extConnect()
422
+			} else {
423
+				execErr := r.backend.ExecFunc(extConnect)
424
+				if execErr != nil {
425
+					logrus.Warn(execErr)
426
+					continue
427
+				}
424 428
 			}
425 429
 			if err != nil {
426 430
 				logrus.Warnf("Connect failed: %s", err)
... ...
@@ -462,9 +470,20 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
462 462
 				logrus.Debugf("Read from DNS server failed, %s", err)
463 463
 				continue
464 464
 			}
465
-
466 465
 			r.forwardQueryEnd()
467
-
466
+			if resp != nil {
467
+				for _, rr := range resp.Answer {
468
+					h := rr.Header()
469
+					switch h.Rrtype {
470
+					case dns.TypeA:
471
+						ip := rr.(*dns.A).A
472
+						r.backend.HandleQueryResp(h.Name, ip)
473
+					case dns.TypeAAAA:
474
+						ip := rr.(*dns.AAAA).AAAA
475
+						r.backend.HandleQueryResp(h.Name, ip)
476
+					}
477
+				}
478
+			}
468 479
 			resp.Compress = true
469 480
 			break
470 481
 		}
... ...
@@ -45,7 +45,7 @@ type Sandbox interface {
45 45
 	// EnableService  makes a managed container's service available by adding the
46 46
 	// endpoint to the service load balancer and service discovery
47 47
 	EnableService() error
48
-	// DisableService removes a managed contianer's endpoints from the load balancer
48
+	// DisableService removes a managed container's endpoints from the load balancer
49 49
 	// and service discovery
50 50
 	DisableService() error
51 51
 }
... ...
@@ -69,7 +69,7 @@ type sandbox struct {
69 69
 	id                 string
70 70
 	containerID        string
71 71
 	config             containerConfig
72
-	extDNS             []string
72
+	extDNS             []extDNSEntry
73 73
 	osSbox             osl.Sandbox
74 74
 	controller         *controller
75 75
 	resolver           Resolver
... ...
@@ -411,6 +411,13 @@ func (sb *sandbox) updateGateway(ep *endpoint) error {
411 411
 	return nil
412 412
 }
413 413
 
414
+func (sb *sandbox) HandleQueryResp(name string, ip net.IP) {
415
+	for _, ep := range sb.getConnectedEndpoints() {
416
+		n := ep.getNetwork()
417
+		n.HandleQueryResp(name, ip)
418
+	}
419
+}
420
+
414 421
 func (sb *sandbox) ResolveIP(ip string) string {
415 422
 	var svc string
416 423
 	logrus.Debugf("IP To resolve %v", ip)
... ...
@@ -1167,6 +1174,17 @@ func (eh epHeap) Less(i, j int) bool {
1167 1167
 		return true
1168 1168
 	}
1169 1169
 
1170
+	if epi.joinInfo != nil && epj.joinInfo != nil {
1171
+		if (epi.joinInfo.gw != nil && epi.joinInfo.gw6 != nil) &&
1172
+			(epj.joinInfo.gw == nil || epj.joinInfo.gw6 == nil) {
1173
+			return true
1174
+		}
1175
+		if (epj.joinInfo.gw != nil && epj.joinInfo.gw6 != nil) &&
1176
+			(epi.joinInfo.gw == nil || epi.joinInfo.gw6 == nil) {
1177
+			return false
1178
+		}
1179
+	}
1180
+
1170 1181
 	if ci != nil {
1171 1182
 		cip, ok = ci.epPriority[eh[i].ID()]
1172 1183
 		if !ok {
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/Sirupsen/logrus"
15 15
 	"github.com/docker/libnetwork/etchosts"
16 16
 	"github.com/docker/libnetwork/resolvconf"
17
+	"github.com/docker/libnetwork/resolvconf/dns"
17 18
 	"github.com/docker/libnetwork/types"
18 19
 )
19 20
 
... ...
@@ -100,8 +101,6 @@ func (sb *sandbox) buildHostsFile() error {
100 100
 }
101 101
 
102 102
 func (sb *sandbox) updateHostsFile(ifaceIP string) error {
103
-	var mhost string
104
-
105 103
 	if ifaceIP == "" {
106 104
 		return nil
107 105
 	}
... ...
@@ -110,11 +109,17 @@ func (sb *sandbox) updateHostsFile(ifaceIP string) error {
110 110
 		return nil
111 111
 	}
112 112
 
113
+	// User might have provided a FQDN in hostname or split it across hostname
114
+	// and domainname.  We want the FQDN and the bare hostname.
115
+	fqdn := sb.config.hostName
116
+	mhost := sb.config.hostName
113 117
 	if sb.config.domainName != "" {
114
-		mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName,
115
-			sb.config.hostName)
116
-	} else {
117
-		mhost = sb.config.hostName
118
+		fqdn = fmt.Sprintf("%s.%s", fqdn, sb.config.domainName)
119
+	}
120
+
121
+	parts := strings.SplitN(fqdn, ".", 2)
122
+	if len(parts) == 2 {
123
+		mhost = fmt.Sprintf("%s %s", fqdn, parts[0])
118 124
 	}
119 125
 
120 126
 	extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}}
... ...
@@ -161,6 +166,20 @@ func (sb *sandbox) restorePath() {
161 161
 	}
162 162
 }
163 163
 
164
+func (sb *sandbox) setExternalResolvers(content []byte, addrType int, checkLoopback bool) {
165
+	servers := resolvconf.GetNameservers(content, addrType)
166
+	for _, ip := range servers {
167
+		hostLoopback := false
168
+		if checkLoopback {
169
+			hostLoopback = dns.IsIPv4Localhost(ip)
170
+		}
171
+		sb.extDNS = append(sb.extDNS, extDNSEntry{
172
+			ipStr:        ip,
173
+			hostLoopback: hostLoopback,
174
+		})
175
+	}
176
+}
177
+
164 178
 func (sb *sandbox) setupDNS() error {
165 179
 	var newRC *resolvconf.File
166 180
 
... ...
@@ -208,7 +227,17 @@ func (sb *sandbox) setupDNS() error {
208 208
 		if err != nil {
209 209
 			return err
210 210
 		}
211
+		// After building the resolv.conf from the user config save the
212
+		// external resolvers in the sandbox. Note that --dns 127.0.0.x
213
+		// config refers to the loopback in the container namespace
214
+		sb.setExternalResolvers(newRC.Content, types.IPv4, false)
211 215
 	} else {
216
+		// If the host resolv.conf file has 127.0.0.x container should
217
+		// use the host restolver for queries. This is supported by the
218
+		// docker embedded DNS server. Hence save the external resolvers
219
+		// before filtering it out.
220
+		sb.setExternalResolvers(currRC.Content, types.IPv4, true)
221
+
212 222
 		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
213 223
 		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
214 224
 			return err
... ...
@@ -297,7 +326,6 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
297 297
 
298 298
 // Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
299 299
 // resolv.conf by doing the following
300
-// - Save the external name servers in resolv.conf in the sandbox
301 300
 // - Add only the embedded server's IP to container's resolv.conf
302 301
 // - If the embedded server needs any resolv.conf options add it to the current list
303 302
 func (sb *sandbox) rebuildDNS() error {
... ...
@@ -306,10 +334,9 @@ func (sb *sandbox) rebuildDNS() error {
306 306
 		return err
307 307
 	}
308 308
 
309
-	// localhost entries have already been filtered out from the list
310
-	// retain only the v4 servers in sb for forwarding the DNS queries
311
-	sb.extDNS = resolvconf.GetNameservers(currRC.Content, types.IPv4)
312
-
309
+	if len(sb.extDNS) == 0 {
310
+		sb.setExternalResolvers(currRC.Content, types.IPv4, false)
311
+	}
313 312
 	var (
314 313
 		dnsList        = []string{sb.resolver.NameServer()}
315 314
 		dnsOptionsList = resolvconf.GetOptions(currRC.Content)
... ...
@@ -27,7 +27,7 @@ type sbState struct {
27 27
 	dbExists   bool
28 28
 	Eps        []epState
29 29
 	EpPriority map[string]int
30
-	ExtDNS     []string
30
+	ExtDNS     []extDNSEntry
31 31
 }
32 32
 
33 33
 func (sbs *sbState) Key() []string {