Browse Source

vendorin libnetwork @d2edad309cc874e865b5ba4d6bd6b276c93451d3

Signed-off-by: Santhosh Manohar <santhosh@docker.com>
Santhosh Manohar 8 years ago
parent
commit
a0dcdcb95f
27 changed files with 301 additions and 91 deletions
  1. 1 1
      vendor.conf
  2. 5 4
      vendor/github.com/docker/libnetwork/bitseq/sequence.go
  3. 4 3
      vendor/github.com/docker/libnetwork/controller.go
  4. 3 2
      vendor/github.com/docker/libnetwork/datastore/cache.go
  5. 2 2
      vendor/github.com/docker/libnetwork/driverapi/driverapi.go
  6. 4 4
      vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go
  7. 2 1
      vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go
  8. 3 2
      vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go
  9. 2 1
      vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go
  10. 6 6
      vendor/github.com/docker/libnetwork/drivers/overlay/ov_network.go
  11. 2 1
      vendor/github.com/docker/libnetwork/drivers/remote/driver.go
  12. 1 1
      vendor/github.com/docker/libnetwork/drivers/windows/overlay/peerdb_windows.go
  13. 3 2
      vendor/github.com/docker/libnetwork/drvregistry/drvregistry.go
  14. 7 6
      vendor/github.com/docker/libnetwork/idm/idm.go
  15. 3 3
      vendor/github.com/docker/libnetwork/ipams/builtin/builtin_unix.go
  16. 3 3
      vendor/github.com/docker/libnetwork/ipams/builtin/builtin_windows.go
  17. 1 1
      vendor/github.com/docker/libnetwork/iptables/iptables.go
  18. 1 1
      vendor/github.com/docker/libnetwork/netutils/utils.go
  19. 42 19
      vendor/github.com/docker/libnetwork/network.go
  20. 2 2
      vendor/github.com/docker/libnetwork/networkdb/broadcast.go
  21. 7 0
      vendor/github.com/docker/libnetwork/osl/interface_linux.go
  22. 98 0
      vendor/github.com/docker/libnetwork/osl/namespace_linux.go
  23. 10 1
      vendor/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go
  24. 30 11
      vendor/github.com/docker/libnetwork/resolver.go
  25. 20 2
      vendor/github.com/docker/libnetwork/sandbox.go
  26. 38 11
      vendor/github.com/docker/libnetwork/sandbox_dns_unix.go
  27. 1 1
      vendor/github.com/docker/libnetwork/sandbox_store.go

+ 1 - 1
vendor.conf

@@ -23,7 +23,7 @@ github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
 github.com/imdario/mergo 0.2.1
 
 #get libnetwork packages
-github.com/docker/libnetwork 382be38ce860738d80b53d7875d83abd5970d9d6 https://github.com/aaronlehmann/libnetwork
+github.com/docker/libnetwork e8431956af5df6816e232d68376c012c2617edbd
 github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec

+ 5 - 4
vendor/github.com/docker/libnetwork/bitseq/sequence.go

@@ -6,6 +6,7 @@ package bitseq
 import (
 	"encoding/binary"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"sync"
 
@@ -26,9 +27,9 @@ const (
 
 var (
 	// ErrNoBitAvailable is returned when no more bits are available to set
-	ErrNoBitAvailable = fmt.Errorf("no bit available")
+	ErrNoBitAvailable = errors.New("no bit available")
 	// ErrBitAllocated is returned when the specific bit requested is already set
-	ErrBitAllocated = fmt.Errorf("requested bit is already allocated")
+	ErrBitAllocated = errors.New("requested bit is already allocated")
 )
 
 // Handle contains the sequece representing the bitmask and its identifier
@@ -373,7 +374,7 @@ func (h *Handle) validateOrdinal(ordinal uint64) error {
 	h.Lock()
 	defer h.Unlock()
 	if ordinal >= h.bits {
-		return fmt.Errorf("bit does not belong to the sequence")
+		return errors.New("bit does not belong to the sequence")
 	}
 	return nil
 }
@@ -418,7 +419,7 @@ func (h *Handle) ToByteArray() ([]byte, error) {
 // FromByteArray reads his handle's data from a byte array
 func (h *Handle) FromByteArray(ba []byte) error {
 	if ba == nil {
-		return fmt.Errorf("nil byte array")
+		return errors.New("nil byte array")
 	}
 
 	nh := &sequence{}

+ 4 - 3
vendor/github.com/docker/libnetwork/controller.go

@@ -273,7 +273,7 @@ func (c *controller) SetKeys(keys []*types.EncryptionKey) error {
 	}
 	for s, count := range subsysKeys {
 		if count != keyringSize {
-			return fmt.Errorf("incorrect number of keys for susbsystem %v", s)
+			return fmt.Errorf("incorrect number of keys for subsystem %v", s)
 		}
 	}
 
@@ -582,7 +582,7 @@ func (c *controller) pushNodeDiscovery(d driverapi.Driver, cap driverapi.Capabil
 			err = d.DiscoverDelete(discoverapi.NodeDiscovery, nodeData)
 		}
 		if err != nil {
-			logrus.Debugf("discovery notification error : %v", err)
+			logrus.Debugf("discovery notification error: %v", err)
 		}
 	}
 }
@@ -932,6 +932,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s
 			populatedEndpoints: map[string]struct{}{},
 			config:             containerConfig{},
 			controller:         c,
+			extDNS:             []extDNSEntry{},
 		}
 	}
 	sBox = sb
@@ -997,7 +998,7 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (s
 
 	err = sb.storeUpdate()
 	if err != nil {
-		return nil, fmt.Errorf("updating the store state of sandbox failed: %v", err)
+		return nil, fmt.Errorf("failed to update the store state of sandbox: %v", err)
 	}
 
 	return sb, nil

+ 3 - 2
vendor/github.com/docker/libnetwork/datastore/cache.go

@@ -1,6 +1,7 @@
 package datastore
 
 import (
+	"errors"
 	"fmt"
 	"sync"
 
@@ -36,7 +37,7 @@ func (c *cache) kmap(kvObject KVObject) (kvMap, error) {
 	// Bail out right away if the kvObject does not implement KVConstructor
 	ctor, ok := kvObject.(KVConstructor)
 	if !ok {
-		return nil, fmt.Errorf("error while populating kmap, object does not implement KVConstructor interface")
+		return nil, errors.New("error while populating kmap, object does not implement KVConstructor interface")
 	}
 
 	kvList, err := c.ds.store.List(keyPrefix)
@@ -153,7 +154,7 @@ func (c *cache) get(key string, kvObject KVObject) error {
 
 	ctor, ok := o.(KVConstructor)
 	if !ok {
-		return fmt.Errorf("kvobject does not implement KVConstructor interface. could not get object")
+		return errors.New("kvobject does not implement KVConstructor interface. could not get object")
 	}
 
 	return ctor.CopyTo(kvObject)

+ 2 - 2
vendor/github.com/docker/libnetwork/driverapi/driverapi.go

@@ -62,7 +62,7 @@ type Driver interface {
 	// programming to allow the external connectivity dictated by the passed options
 	ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error
 
-	// RevokeExternalConnectivity aks the driver to remove any external connectivity
+	// RevokeExternalConnectivity asks the driver to remove any external connectivity
 	// programming that was done so far
 	RevokeExternalConnectivity(nid, eid string) error
 
@@ -72,7 +72,7 @@ type Driver interface {
 	// only invoked for the global scope driver.
 	EventNotify(event EventType, nid string, tableName string, key string, value []byte)
 
-	// Type returns the the type of this driver, the network type this driver manages
+	// Type returns the type of this driver, the network type this driver manages
 	Type() string
 
 	// IsBuiltIn returns true if it is a built-in driver

+ 4 - 4
vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go

@@ -186,24 +186,24 @@ func (c *networkConfiguration) Validate() error {
 // Conflicts check if two NetworkConfiguration objects overlap
 func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
 	if o == nil {
-		return fmt.Errorf("same configuration")
+		return errors.New("same configuration")
 	}
 
 	// Also empty, because only one network with empty name is allowed
 	if c.BridgeName == o.BridgeName {
-		return fmt.Errorf("networks have same bridge name")
+		return errors.New("networks have same bridge name")
 	}
 
 	// They must be in different subnets
 	if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) &&
 		(c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
-		return fmt.Errorf("networks have overlapping IPv4")
+		return errors.New("networks have overlapping IPv4")
 	}
 
 	// They must be in different v6 subnets
 	if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) &&
 		(c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) {
-		return fmt.Errorf("networks have overlapping IPv6")
+		return errors.New("networks have overlapping IPv6")
 	}
 
 	return nil

+ 2 - 1
vendor/github.com/docker/libnetwork/drivers/bridge/setup_bridgenetfiltering.go

@@ -1,6 +1,7 @@
 package bridge
 
 import (
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -37,7 +38,7 @@ func setupBridgeNetFiltering(config *networkConfiguration, i *bridgeInterface) e
 					logrus.Warnf("running inside docker container, ignoring missing kernel params: %v", err)
 					err = nil
 				} else {
-					err = fmt.Errorf("please ensure that br_netfilter kernel module is loaded")
+					err = errors.New("please ensure that br_netfilter kernel module is loaded")
 				}
 			}
 		}

+ 3 - 2
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go

@@ -1,6 +1,7 @@
 package bridge
 
 import (
+	"errors"
 	"fmt"
 	"net"
 
@@ -17,7 +18,7 @@ const (
 func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
 	// Sanity check.
 	if config.EnableIPTables == false {
-		return nil, nil, nil, fmt.Errorf("cannot create new chains, EnableIPTable is disabled")
+		return nil, nil, nil, errors.New("cannot create new chains, EnableIPTable is disabled")
 	}
 
 	hairpinMode := !config.EnableUserlandProxy
@@ -68,7 +69,7 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt
 
 	// Sanity check.
 	if driverConfig.EnableIPTables == false {
-		return fmt.Errorf("Cannot program chains, EnableIPTable is disabled")
+		return errors.New("Cannot program chains, EnableIPTable is disabled")
 	}
 
 	// Pickup this configuration option from driver

+ 2 - 1
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ipv4.go

@@ -1,6 +1,7 @@
 package bridge
 
 import (
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"net"
@@ -13,7 +14,7 @@ import (
 
 func selectIPv4Address(addresses []netlink.Addr, selector *net.IPNet) (netlink.Addr, error) {
 	if len(addresses) == 0 {
-		return netlink.Addr{}, fmt.Errorf("unable to select an address as the address pool is empty")
+		return netlink.Addr{}, errors.New("unable to select an address as the address pool is empty")
 	}
 	if selector != nil {
 		for _, addr := range addresses {

+ 6 - 6
vendor/github.com/docker/libnetwork/drivers/overlay/ov_network.go

@@ -402,7 +402,7 @@ func (n *network) getBridgeNamePrefix(s *subnet) string {
 	return "ov-" + fmt.Sprintf("%06x", n.vxlanID(s))
 }
 
-func isOverlap(nw *net.IPNet) bool {
+func checkOverlap(nw *net.IPNet) error {
 	var nameservers []string
 
 	if rc, err := resolvconf.Get(); err == nil {
@@ -410,14 +410,14 @@ func isOverlap(nw *net.IPNet) bool {
 	}
 
 	if err := netutils.CheckNameserverOverlaps(nameservers, nw); err != nil {
-		return true
+		return fmt.Errorf("overlay subnet %s failed check with nameserver: %v: %v", nw.String(), nameservers, err)
 	}
 
 	if err := netutils.CheckRouteOverlaps(nw); err != nil {
-		return true
+		return fmt.Errorf("overlay subnet %s failed check with host route table: %v", nw.String(), err)
 	}
 
-	return false
+	return nil
 }
 
 func (n *network) restoreSubnetSandbox(s *subnet, brName, vxlanName string) error {
@@ -456,8 +456,8 @@ func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error
 		// Try to delete the vxlan interface by vni if already present
 		deleteVxlanByVNI("", n.vxlanID(s))
 
-		if isOverlap(s.subnetIP) {
-			return fmt.Errorf("overlay subnet %s has conflicts in the host while running in host mode", s.subnetIP.String())
+		if err := checkOverlap(s.subnetIP); err != nil {
+			return err
 		}
 	}
 

+ 2 - 1
vendor/github.com/docker/libnetwork/drivers/remote/driver.go

@@ -1,6 +1,7 @@
 package remote
 
 import (
+	"errors"
 	"fmt"
 	"net"
 
@@ -132,7 +133,7 @@ func (d *driver) DeleteNetwork(nid string) error {
 
 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
 	if ifInfo == nil {
-		return fmt.Errorf("must not be called with nil InterfaceInfo")
+		return errors.New("must not be called with nil InterfaceInfo")
 	}
 
 	reqIface := &api.EndpointInterface{}

+ 1 - 1
vendor/github.com/docker/libnetwork/drivers/windows/overlay/peerdb_windows.go

@@ -81,7 +81,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
 			return err
 		}
 
-		// Temp: We have to create a endpoint object to keep track of the HNS ID for
+		// Temp: We have to create an endpoint object to keep track of the HNS ID for
 		// this endpoint so that we can retrieve it later when the endpoint is deleted.
 		// This seems unnecessary when we already have dockers EID. See if we can pass
 		// the global EID to HNS to use as it's ID, rather than having each HNS assign

+ 3 - 2
vendor/github.com/docker/libnetwork/drvregistry/drvregistry.go

@@ -1,6 +1,7 @@
 package drvregistry
 
 import (
+	"errors"
 	"fmt"
 	"strings"
 	"sync"
@@ -160,7 +161,7 @@ func (r *DrvRegistry) GetPluginGetter() plugingetter.PluginGetter {
 // RegisterDriver registers the network driver when it gets discovered.
 func (r *DrvRegistry) RegisterDriver(ntype string, driver driverapi.Driver, capability driverapi.Capability) error {
 	if strings.TrimSpace(ntype) == "" {
-		return fmt.Errorf("network type string cannot be empty")
+		return errors.New("network type string cannot be empty")
 	}
 
 	r.Lock()
@@ -188,7 +189,7 @@ func (r *DrvRegistry) RegisterDriver(ntype string, driver driverapi.Driver, capa
 
 func (r *DrvRegistry) registerIpamDriver(name string, driver ipamapi.Ipam, caps *ipamapi.Capability) error {
 	if strings.TrimSpace(name) == "" {
-		return fmt.Errorf("ipam driver name string cannot be empty")
+		return errors.New("ipam driver name string cannot be empty")
 	}
 
 	r.Lock()

+ 7 - 6
vendor/github.com/docker/libnetwork/idm/idm.go

@@ -2,6 +2,7 @@
 package idm
 
 import (
+	"errors"
 	"fmt"
 
 	"github.com/docker/libnetwork/bitseq"
@@ -18,7 +19,7 @@ type Idm struct {
 // New returns an instance of id manager for a [start,end] set of numerical ids
 func New(ds datastore.DataStore, id string, start, end uint64) (*Idm, error) {
 	if id == "" {
-		return nil, fmt.Errorf("Invalid id")
+		return nil, errors.New("Invalid id")
 	}
 	if end <= start {
 		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) {
 // GetID returns the first available id in the set
 func (i *Idm) GetID() (uint64, error) {
 	if i.handle == nil {
-		return 0, fmt.Errorf("ID set is not initialized")
+		return 0, errors.New("ID set is not initialized")
 	}
 	ordinal, err := i.handle.SetAny()
 	return i.start + ordinal, err
@@ -44,11 +45,11 @@ func (i *Idm) GetID() (uint64, error) {
 // GetSpecificID tries to reserve the specified id
 func (i *Idm) GetSpecificID(id uint64) error {
 	if i.handle == nil {
-		return fmt.Errorf("ID set is not initialized")
+		return errors.New("ID set is not initialized")
 	}
 
 	if id < i.start || id > i.end {
-		return fmt.Errorf("Requested id does not belong to the set")
+		return errors.New("Requested id does not belong to the set")
 	}
 
 	return i.handle.Set(id - i.start)
@@ -57,11 +58,11 @@ func (i *Idm) GetSpecificID(id uint64) error {
 // GetIDInRange returns the first available id in the set within a [start,end] range
 func (i *Idm) GetIDInRange(start, end uint64) (uint64, error) {
 	if i.handle == nil {
-		return 0, fmt.Errorf("ID set is not initialized")
+		return 0, errors.New("ID set is not initialized")
 	}
 
 	if start < i.start || end > i.end {
-		return 0, fmt.Errorf("Requested range does not belong to the set")
+		return 0, errors.New("Requested range does not belong to the set")
 	}
 
 	ordinal, err := i.handle.SetAnyInRange(start-i.start, end-i.start)

+ 3 - 3
vendor/github.com/docker/libnetwork/ipams/builtin/builtin_unix.go

@@ -3,7 +3,7 @@
 package builtin
 
 import (
-	"fmt"
+	"errors"
 
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/ipam"
@@ -20,13 +20,13 @@ func Init(ic ipamapi.Callback, l, g interface{}) error {
 
 	if l != nil {
 		if localDs, ok = l.(datastore.DataStore); !ok {
-			return fmt.Errorf("incorrect local datastore passed to built-in ipam init")
+			return errors.New("incorrect local datastore passed to built-in ipam init")
 		}
 	}
 
 	if g != nil {
 		if globalDs, ok = g.(datastore.DataStore); !ok {
-			return fmt.Errorf("incorrect global datastore passed to built-in ipam init")
+			return errors.New("incorrect global datastore passed to built-in ipam init")
 		}
 	}
 

+ 3 - 3
vendor/github.com/docker/libnetwork/ipams/builtin/builtin_windows.go

@@ -3,7 +3,7 @@
 package builtin
 
 import (
-	"fmt"
+	"errors"
 
 	"github.com/docker/libnetwork/datastore"
 	"github.com/docker/libnetwork/ipam"
@@ -22,13 +22,13 @@ func InitDockerDefault(ic ipamapi.Callback, l, g interface{}) error {
 
 	if l != nil {
 		if localDs, ok = l.(datastore.DataStore); !ok {
-			return fmt.Errorf("incorrect local datastore passed to built-in ipam init")
+			return errors.New("incorrect local datastore passed to built-in ipam init")
 		}
 	}
 
 	if g != nil {
 		if globalDs, ok = g.(datastore.DataStore); !ok {
-			return fmt.Errorf("incorrect global datastore passed to built-in ipam init")
+			return errors.New("incorrect global datastore passed to built-in ipam init")
 		}
 	}
 

+ 1 - 1
vendor/github.com/docker/libnetwork/iptables/iptables.go

@@ -131,7 +131,7 @@ func NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) {
 // ProgramChain is used to add rules to a chain
 func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) error {
 	if c.Name == "" {
-		return fmt.Errorf("Could not program chain, missing chain name")
+		return errors.New("Could not program chain, missing chain name")
 	}
 
 	switch c.Table {

+ 1 - 1
vendor/github.com/docker/libnetwork/netutils/utils.go

@@ -173,7 +173,7 @@ func ReverseIP(IP string) string {
 // ParseAlias parses and validates the specified string as an alias format (name:alias)
 func ParseAlias(val string) (string, string, error) {
 	if val == "" {
-		return "", "", fmt.Errorf("empty string specified for alias")
+		return "", "", errors.New("empty string specified for alias")
 	}
 	arr := strings.Split(val, ":")
 	if len(arr) > 2 {

+ 42 - 19
vendor/github.com/docker/libnetwork/network.go

@@ -80,10 +80,18 @@ type NetworkInfo interface {
 // When the function returns true, the walk will stop.
 type EndpointWalker func(ep Endpoint) bool
 
+// ipInfo is the reverse mapping from IP to service name to serve the PTR query.
+// extResolver is set if an externl server resolves a service name to this IP.
+// Its an indication to defer PTR queries also to that external server.
+type ipInfo struct {
+	name        string
+	extResolver bool
+}
+
 type svcInfo struct {
 	svcMap     map[string][]net.IP
 	svcIPv6Map map[string][]net.IP
-	ipMap      map[string]string
+	ipMap      map[string]*ipInfo
 	service    map[string][]servicePorts
 }
 
@@ -877,7 +885,7 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
 	}
 
 	if _, err = n.EndpointByName(name); err == nil {
-		return nil, types.ForbiddenErrorf("service endpoint with name %s already exists", name)
+		return nil, types.ForbiddenErrorf("endpoint with name %s already exists in network %s", name, n.Name())
 	}
 
 	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
 	}
 }
 
-func addIPToName(ipMap map[string]string, name string, ip net.IP) {
+func addIPToName(ipMap map[string]*ipInfo, name string, ip net.IP) {
 	reverseIP := netutils.ReverseIP(ip.String())
 	if _, ok := ipMap[reverseIP]; !ok {
-		ipMap[reverseIP] = name
+		ipMap[reverseIP] = &ipInfo{
+			name: name,
+		}
 	}
 }
 
@@ -1117,7 +1127,7 @@ func (n *network) addSvcRecords(name string, epIP net.IP, epIPv6 net.IP, ipMapUp
 		sr = svcInfo{
 			svcMap:     make(map[string][]net.IP),
 			svcIPv6Map: make(map[string][]net.IP),
-			ipMap:      make(map[string]string),
+			ipMap:      make(map[string]*ipInfo),
 		}
 		c.svcRecords[n.ID()] = sr
 	}
@@ -1612,8 +1622,8 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
 
 	c := n.getController()
 	c.Lock()
+	defer c.Unlock()
 	sr, ok := c.svcRecords[n.ID()]
-	c.Unlock()
 
 	if !ok {
 		return nil, false
@@ -1621,7 +1631,6 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
 
 	req = strings.TrimSuffix(req, ".")
 	var ip []net.IP
-	n.Lock()
 	ip, ok = sr.svcMap[req]
 
 	if ipType == types.IPv6 {
@@ -1634,22 +1643,38 @@ func (n *network) ResolveName(req string, ipType int) ([]net.IP, bool) {
 		}
 		ip = sr.svcIPv6Map[req]
 	}
-	n.Unlock()
 
 	if ip != nil {
-		return ip, false
+		ipLocal := make([]net.IP, len(ip))
+		copy(ipLocal, ip)
+		return ipLocal, false
 	}
 
 	return nil, ipv6Miss
 }
 
-func (n *network) ResolveIP(ip string) string {
-	var svc string
+func (n *network) HandleQueryResp(name string, ip net.IP) {
+	c := n.getController()
+	c.Lock()
+	defer c.Unlock()
+	sr, ok := c.svcRecords[n.ID()]
 
+	if !ok {
+		return
+	}
+
+	ipStr := netutils.ReverseIP(ip.String())
+
+	if ipInfo, ok := sr.ipMap[ipStr]; ok {
+		ipInfo.extResolver = true
+	}
+}
+
+func (n *network) ResolveIP(ip string) string {
 	c := n.getController()
 	c.Lock()
+	defer c.Unlock()
 	sr, ok := c.svcRecords[n.ID()]
-	c.Unlock()
 
 	if !ok {
 		return ""
@@ -1657,15 +1682,13 @@ func (n *network) ResolveIP(ip string) string {
 
 	nwName := n.Name()
 
-	n.Lock()
-	defer n.Unlock()
-	svc, ok = sr.ipMap[ip]
+	ipInfo, ok := sr.ipMap[ip]
 
-	if ok {
-		return svc + "." + nwName
+	if !ok || ipInfo.extResolver {
+		return ""
 	}
 
-	return svc
+	return ipInfo.name + "." + nwName
 }
 
 func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) {
@@ -1689,8 +1712,8 @@ func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) {
 	svcName := strings.Join(parts[2:], ".")
 
 	c.Lock()
+	defer c.Unlock()
 	sr, ok := c.svcRecords[n.ID()]
-	c.Unlock()
 
 	if !ok {
 		return nil, nil

+ 2 - 2
vendor/github.com/docker/libnetwork/networkdb/broadcast.go

@@ -1,7 +1,7 @@
 package networkdb
 
 import (
-	"fmt"
+	"errors"
 	"time"
 
 	"github.com/hashicorp/memberlist"
@@ -90,7 +90,7 @@ func (nDB *NetworkDB) sendNodeEvent(event NodeEvent_Type) error {
 	select {
 	case <-notifyCh:
 	case <-time.After(broadcastTimeout):
-		return fmt.Errorf("timed out broadcasting node event")
+		return errors.New("timed out broadcasting node event")
 	}
 
 	return nil

+ 7 - 0
vendor/github.com/docker/libnetwork/osl/interface_linux.go

@@ -179,6 +179,8 @@ func (i *nwIface) Remove() error {
 	}
 	n.Unlock()
 
+	n.checkLoV6()
+
 	return nil
 }
 
@@ -318,6 +320,8 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
 	n.iFaces = append(n.iFaces, i)
 	n.Unlock()
 
+	n.checkLoV6()
+
 	return nil
 }
 
@@ -378,6 +382,9 @@ func setInterfaceIPv6(nlh *netlink.Handle, iface netlink.Link, i *nwIface) error
 	if err := checkRouteConflict(nlh, i.AddressIPv6(), netlink.FAMILY_V6); err != nil {
 		return err
 	}
+	if err := setIPv6(i.ns.path, i.DstName(), true); err != nil {
+		return fmt.Errorf("failed to enable ipv6: %v", err)
+	}
 	ipAddr := &netlink.Addr{IPNet: i.AddressIPv6(), Label: "", Flags: syscall.IFA_F_NODAD}
 	return nlh.AddrAdd(iface, ipAddr)
 }

+ 98 - 0
vendor/github.com/docker/libnetwork/osl/namespace_linux.go

@@ -24,6 +24,10 @@ import (
 
 const defaultPrefix = "/var/run/docker"
 
+func init() {
+	reexec.Register("set-ipv6", reexecSetIPv6)
+}
+
 var (
 	once             sync.Once
 	garbagePathMap   = make(map[string]bool)
@@ -47,6 +51,7 @@ type networkNamespace struct {
 	nextIfIndex  int
 	isDefault    bool
 	nlHandle     *netlink.Handle
+	loV6Enabled  bool
 	sync.Mutex
 }
 
@@ -216,6 +221,12 @@ func NewSandbox(key string, osCreate, isRestore bool) (Sandbox, error) {
 		logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err)
 	}
 
+	// As starting point, disable IPv6 on all interfaces
+	err = setIPv6(n.path, "all", false)
+	if err != nil {
+		logrus.Warnf("Failed to disable IPv6 on all interfaces on network namespace %q: %v", n.path, err)
+	}
+
 	if err = n.loopbackUp(); err != nil {
 		n.nlHandle.Delete()
 		return nil, err
@@ -263,6 +274,12 @@ func GetSandboxForExternalKey(basePath string, key string) (Sandbox, error) {
 		logrus.Warnf("Failed to set the timeout on the sandbox netlink handle sockets: %v", err)
 	}
 
+	// As starting point, disable IPv6 on all interfaces
+	err = setIPv6(n.path, "all", false)
+	if err != nil {
+		logrus.Warnf("Failed to disable IPv6 on all interfaces on network namespace %q: %v", n.path, err)
+	}
+
 	if err = n.loopbackUp(); err != nil {
 		n.nlHandle.Delete()
 		return nil, err
@@ -508,3 +525,84 @@ func (n *networkNamespace) Restore(ifsopt map[string][]IfaceOption, routes []*ty
 
 	return nil
 }
+
+// Checks whether IPv6 needs to be enabled/disabled on the loopback interface
+func (n *networkNamespace) checkLoV6() {
+	var (
+		enable = false
+		action = "disable"
+	)
+
+	n.Lock()
+	for _, iface := range n.iFaces {
+		if iface.AddressIPv6() != nil {
+			enable = true
+			action = "enable"
+			break
+		}
+	}
+	n.Unlock()
+
+	if n.loV6Enabled == enable {
+		return
+	}
+
+	if err := setIPv6(n.path, "lo", enable); err != nil {
+		logrus.Warnf("Failed to %s IPv6 on loopback interface on network namespace %q: %v", action, n.path, err)
+	}
+
+	n.loV6Enabled = enable
+}
+
+func reexecSetIPv6() {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	if len(os.Args) < 3 {
+		logrus.Errorf("invalid number of arguments for %s", os.Args[0])
+		os.Exit(1)
+	}
+
+	ns, err := netns.GetFromPath(os.Args[1])
+	if err != nil {
+		logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err)
+		os.Exit(2)
+	}
+	defer ns.Close()
+
+	if err = netns.Set(ns); err != nil {
+		logrus.Errorf("setting into container netns %q failed: %v", os.Args[1], err)
+		os.Exit(3)
+	}
+
+	var (
+		action = "disable"
+		value  = byte('1')
+		path   = fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", os.Args[2])
+	)
+
+	if os.Args[3] == "true" {
+		action = "enable"
+		value = byte('0')
+	}
+
+	if err = ioutil.WriteFile(path, []byte{value, '\n'}, 0644); err != nil {
+		logrus.Errorf("failed to %s IPv6 forwarding for container's interface %s: %v", action, os.Args[2], err)
+		os.Exit(4)
+	}
+
+	os.Exit(0)
+}
+
+func setIPv6(path, iface string, enable bool) error {
+	cmd := &exec.Cmd{
+		Path:   reexec.Self(),
+		Args:   append([]string{"set-ipv6"}, path, iface, strconv.FormatBool(enable)),
+		Stdout: os.Stdout,
+		Stderr: os.Stderr,
+	}
+	if err := cmd.Run(); err != nil {
+		return fmt.Errorf("reexec to set IPv6 failed: %v", err)
+	}
+	return nil
+}

+ 10 - 1
vendor/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go

@@ -4,10 +4,14 @@ import (
 	"regexp"
 )
 
-// IPLocalhost is a regex patter for localhost IP address range.
+// IPLocalhost is a regex pattern for IPv4 or IPv6 loopback range.
 const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)`
 
+// IPv4Localhost is a regex pattern for IPv4 localhost address range.
+const IPv4Localhost = `(127\.([0-9]{1,3}\.){2}[0-9]{1,3})`
+
 var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
+var localhostIPv4Regexp = regexp.MustCompile(IPv4Localhost)
 
 // IsLocalhost returns true if ip matches the localhost IP regular expression.
 // Used for determining if nameserver settings are being passed which are
@@ -15,3 +19,8 @@ var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
 func IsLocalhost(ip string) bool {
 	return localhostIPRegexp.MatchString(ip)
 }
+
+// IsIPv4Localhost returns true if ip matches the IPv4 localhost regular expression.
+func IsIPv4Localhost(ip string) bool {
+	return localhostIPv4Regexp.MatchString(ip)
+}

+ 30 - 11
vendor/github.com/docker/libnetwork/resolver.go

@@ -29,7 +29,7 @@ type Resolver interface {
 	NameServer() string
 	// SetExtServers configures the external nameservers the resolver
 	// should use to forward queries
-	SetExtServers([]string)
+	SetExtServers([]extDNSEntry)
 	// ResolverOptions returns resolv.conf options that should be set
 	ResolverOptions() []string
 }
@@ -54,6 +54,9 @@ type DNSBackend interface {
 	ExecFunc(f func()) error
 	//NdotsSet queries the backends ndots dns option settings
 	NdotsSet() bool
+	// HandleQueryResp passes the name & IP from a response to the backend. backend
+	// can use it to maintain any required state about the resolution
+	HandleQueryResp(name string, ip net.IP)
 }
 
 const (
@@ -69,7 +72,8 @@ const (
 )
 
 type extDNSEntry struct {
-	ipStr string
+	ipStr        string
+	hostLoopback bool
 }
 
 // resolver implements the Resolver interface
@@ -182,13 +186,13 @@ func (r *resolver) Stop() {
 	r.queryLock = sync.Mutex{}
 }
 
-func (r *resolver) SetExtServers(dns []string) {
-	l := len(dns)
+func (r *resolver) SetExtServers(extDNS []extDNSEntry) {
+	l := len(extDNS)
 	if l > maxExtDNS {
 		l = maxExtDNS
 	}
 	for i := 0; i < l; i++ {
-		r.extDNSList[i].ipStr = dns[i]
+		r.extDNSList[i] = extDNS[i]
 	}
 }
 
@@ -417,10 +421,14 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 				extConn, err = net.DialTimeout(proto, addr, extIOTimeout)
 			}
 
-			execErr := r.backend.ExecFunc(extConnect)
-			if execErr != nil {
-				logrus.Warn(execErr)
-				continue
+			if extDNS.hostLoopback {
+				extConnect()
+			} else {
+				execErr := r.backend.ExecFunc(extConnect)
+				if execErr != nil {
+					logrus.Warn(execErr)
+					continue
+				}
 			}
 			if err != nil {
 				logrus.Warnf("Connect failed: %s", err)
@@ -462,9 +470,20 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
 				logrus.Debugf("Read from DNS server failed, %s", err)
 				continue
 			}
-
 			r.forwardQueryEnd()
-
+			if resp != nil {
+				for _, rr := range resp.Answer {
+					h := rr.Header()
+					switch h.Rrtype {
+					case dns.TypeA:
+						ip := rr.(*dns.A).A
+						r.backend.HandleQueryResp(h.Name, ip)
+					case dns.TypeAAAA:
+						ip := rr.(*dns.AAAA).AAAA
+						r.backend.HandleQueryResp(h.Name, ip)
+					}
+				}
+			}
 			resp.Compress = true
 			break
 		}

+ 20 - 2
vendor/github.com/docker/libnetwork/sandbox.go

@@ -45,7 +45,7 @@ type Sandbox interface {
 	// EnableService  makes a managed container's service available by adding the
 	// endpoint to the service load balancer and service discovery
 	EnableService() error
-	// DisableService removes a managed contianer's endpoints from the load balancer
+	// DisableService removes a managed container's endpoints from the load balancer
 	// and service discovery
 	DisableService() error
 }
@@ -69,7 +69,7 @@ type sandbox struct {
 	id                 string
 	containerID        string
 	config             containerConfig
-	extDNS             []string
+	extDNS             []extDNSEntry
 	osSbox             osl.Sandbox
 	controller         *controller
 	resolver           Resolver
@@ -411,6 +411,13 @@ func (sb *sandbox) updateGateway(ep *endpoint) error {
 	return nil
 }
 
+func (sb *sandbox) HandleQueryResp(name string, ip net.IP) {
+	for _, ep := range sb.getConnectedEndpoints() {
+		n := ep.getNetwork()
+		n.HandleQueryResp(name, ip)
+	}
+}
+
 func (sb *sandbox) ResolveIP(ip string) string {
 	var svc string
 	logrus.Debugf("IP To resolve %v", ip)
@@ -1167,6 +1174,17 @@ func (eh epHeap) Less(i, j int) bool {
 		return true
 	}
 
+	if epi.joinInfo != nil && epj.joinInfo != nil {
+		if (epi.joinInfo.gw != nil && epi.joinInfo.gw6 != nil) &&
+			(epj.joinInfo.gw == nil || epj.joinInfo.gw6 == nil) {
+			return true
+		}
+		if (epj.joinInfo.gw != nil && epj.joinInfo.gw6 != nil) &&
+			(epi.joinInfo.gw == nil || epi.joinInfo.gw6 == nil) {
+			return false
+		}
+	}
+
 	if ci != nil {
 		cip, ok = ci.epPriority[eh[i].ID()]
 		if !ok {

+ 38 - 11
vendor/github.com/docker/libnetwork/sandbox_dns_unix.go

@@ -14,6 +14,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/libnetwork/etchosts"
 	"github.com/docker/libnetwork/resolvconf"
+	"github.com/docker/libnetwork/resolvconf/dns"
 	"github.com/docker/libnetwork/types"
 )
 
@@ -100,8 +101,6 @@ func (sb *sandbox) buildHostsFile() error {
 }
 
 func (sb *sandbox) updateHostsFile(ifaceIP string) error {
-	var mhost string
-
 	if ifaceIP == "" {
 		return nil
 	}
@@ -110,11 +109,17 @@ func (sb *sandbox) updateHostsFile(ifaceIP string) error {
 		return nil
 	}
 
+	// User might have provided a FQDN in hostname or split it across hostname
+	// and domainname.  We want the FQDN and the bare hostname.
+	fqdn := sb.config.hostName
+	mhost := sb.config.hostName
 	if sb.config.domainName != "" {
-		mhost = fmt.Sprintf("%s.%s %s", sb.config.hostName, sb.config.domainName,
-			sb.config.hostName)
-	} else {
-		mhost = sb.config.hostName
+		fqdn = fmt.Sprintf("%s.%s", fqdn, sb.config.domainName)
+	}
+
+	parts := strings.SplitN(fqdn, ".", 2)
+	if len(parts) == 2 {
+		mhost = fmt.Sprintf("%s %s", fqdn, parts[0])
 	}
 
 	extraContent := []etchosts.Record{{Hosts: mhost, IP: ifaceIP}}
@@ -161,6 +166,20 @@ func (sb *sandbox) restorePath() {
 	}
 }
 
+func (sb *sandbox) setExternalResolvers(content []byte, addrType int, checkLoopback bool) {
+	servers := resolvconf.GetNameservers(content, addrType)
+	for _, ip := range servers {
+		hostLoopback := false
+		if checkLoopback {
+			hostLoopback = dns.IsIPv4Localhost(ip)
+		}
+		sb.extDNS = append(sb.extDNS, extDNSEntry{
+			ipStr:        ip,
+			hostLoopback: hostLoopback,
+		})
+	}
+}
+
 func (sb *sandbox) setupDNS() error {
 	var newRC *resolvconf.File
 
@@ -208,7 +227,17 @@ func (sb *sandbox) setupDNS() error {
 		if err != nil {
 			return err
 		}
+		// After building the resolv.conf from the user config save the
+		// external resolvers in the sandbox. Note that --dns 127.0.0.x
+		// config refers to the loopback in the container namespace
+		sb.setExternalResolvers(newRC.Content, types.IPv4, false)
 	} else {
+		// If the host resolv.conf file has 127.0.0.x container should
+		// use the host restolver for queries. This is supported by the
+		// docker embedded DNS server. Hence save the external resolvers
+		// before filtering it out.
+		sb.setExternalResolvers(currRC.Content, types.IPv4, true)
+
 		// Replace any localhost/127.* (at this point we have no info about ipv6, pass it as true)
 		if newRC, err = resolvconf.FilterResolvDNS(currRC.Content, true); err != nil {
 			return err
@@ -297,7 +326,6 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
 
 // Embedded DNS server has to be enabled for this sandbox. Rebuild the container's
 // resolv.conf by doing the following
-// - Save the external name servers in resolv.conf in the sandbox
 // - Add only the embedded server's IP to container's resolv.conf
 // - If the embedded server needs any resolv.conf options add it to the current list
 func (sb *sandbox) rebuildDNS() error {
@@ -306,10 +334,9 @@ func (sb *sandbox) rebuildDNS() error {
 		return err
 	}
 
-	// localhost entries have already been filtered out from the list
-	// retain only the v4 servers in sb for forwarding the DNS queries
-	sb.extDNS = resolvconf.GetNameservers(currRC.Content, types.IPv4)
-
+	if len(sb.extDNS) == 0 {
+		sb.setExternalResolvers(currRC.Content, types.IPv4, false)
+	}
 	var (
 		dnsList        = []string{sb.resolver.NameServer()}
 		dnsOptionsList = resolvconf.GetOptions(currRC.Content)

+ 1 - 1
vendor/github.com/docker/libnetwork/sandbox_store.go

@@ -27,7 +27,7 @@ type sbState struct {
 	dbExists   bool
 	Eps        []epState
 	EpPriority map[string]int
-	ExtDNS     []string
+	ExtDNS     []extDNSEntry
 }
 
 func (sbs *sbState) Key() []string {