Signed-off-by: Santhosh Manohar <santhosh@docker.com>
| ... | ... |
@@ -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) |