- DSR support for linux
- increase max DNS pending query from 100->1024
- DNs to handle NXDOMAIN, REFUSED
diff:
https://github.com/docker/libnetwork/compare/20461b8539336a4b5fcf551a86dd24ebae211984...d7b61745d16675c9f548b19f06fda80d422a74f0
Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>
| ... | ... |
@@ -3,7 +3,7 @@ |
| 3 | 3 |
# LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When |
| 4 | 4 |
# updating the binary version, consider updating github.com/docker/libnetwork |
| 5 | 5 |
# in vendor.conf accordingly |
| 6 |
-LIBNETWORK_COMMIT=20461b8539336a4b5fcf551a86dd24ebae211984 |
|
| 6 |
+LIBNETWORK_COMMIT=d7b61745d16675c9f548b19f06fda80d422a74f0 |
|
| 7 | 7 |
|
| 8 | 8 |
install_proxy() {
|
| 9 | 9 |
case "$1" in |
| ... | ... |
@@ -37,7 +37,7 @@ github.com/mitchellh/hashstructure 2bca23e0e452137f789efbc8610126fd8b94f73b |
| 37 | 37 |
#get libnetwork packages |
| 38 | 38 |
|
| 39 | 39 |
# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy accordingly |
| 40 |
-github.com/docker/libnetwork 20461b8539336a4b5fcf551a86dd24ebae211984 |
|
| 40 |
+github.com/docker/libnetwork d7b61745d16675c9f548b19f06fda80d422a74f0 |
|
| 41 | 41 |
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 |
| 42 | 42 |
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 |
| 43 | 43 |
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec |
| ... | ... |
@@ -700,6 +700,9 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, |
| 700 | 700 |
return nil |
| 701 | 701 |
} |
| 702 | 702 |
|
| 703 |
+// XXX This should be made driver agnostic. See comment below. |
|
| 704 |
+const overlayDSROptionString = "dsr" |
|
| 705 |
+ |
|
| 703 | 706 |
// NewNetwork creates a new network of the specified network type. The options |
| 704 | 707 |
// are network specific and modeled in a generic way. |
| 705 | 708 |
func (c *controller) NewNetwork(networkType, name string, id string, options ...NetworkOption) (Network, error) {
|
| ... | ... |
@@ -723,15 +726,16 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... |
| 723 | 723 |
defaultIpam := defaultIpamForNetworkType(networkType) |
| 724 | 724 |
// Construct the network object |
| 725 | 725 |
network := &network{
|
| 726 |
- name: name, |
|
| 727 |
- networkType: networkType, |
|
| 728 |
- generic: map[string]interface{}{netlabel.GenericData: make(map[string]string)},
|
|
| 729 |
- ipamType: defaultIpam, |
|
| 730 |
- id: id, |
|
| 731 |
- created: time.Now(), |
|
| 732 |
- ctrlr: c, |
|
| 733 |
- persist: true, |
|
| 734 |
- drvOnce: &sync.Once{},
|
|
| 726 |
+ name: name, |
|
| 727 |
+ networkType: networkType, |
|
| 728 |
+ generic: map[string]interface{}{netlabel.GenericData: make(map[string]string)},
|
|
| 729 |
+ ipamType: defaultIpam, |
|
| 730 |
+ id: id, |
|
| 731 |
+ created: time.Now(), |
|
| 732 |
+ ctrlr: c, |
|
| 733 |
+ persist: true, |
|
| 734 |
+ drvOnce: &sync.Once{},
|
|
| 735 |
+ loadBalancerMode: loadBalancerModeDefault, |
|
| 735 | 736 |
} |
| 736 | 737 |
|
| 737 | 738 |
network.processOptions(options...) |
| ... | ... |
@@ -829,6 +833,21 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... |
| 829 | 829 |
} |
| 830 | 830 |
}() |
| 831 | 831 |
|
| 832 |
+ // XXX If the driver type is "overlay" check the options for DSR |
|
| 833 |
+ // being set. If so, set the network's load balancing mode to DSR. |
|
| 834 |
+ // This should really be done in a network option, but due to |
|
| 835 |
+ // time pressure to get this in without adding changes to moby, |
|
| 836 |
+ // swarm and CLI, it is being implemented as a driver-specific |
|
| 837 |
+ // option. Unfortunately, drivers can't influence the core |
|
| 838 |
+ // "libnetwork.network" data type. Hence we need this hack code |
|
| 839 |
+ // to implement in this manner. |
|
| 840 |
+ if gval, ok := network.generic[netlabel.GenericData]; ok && network.networkType == "overlay" {
|
|
| 841 |
+ optMap := gval.(map[string]string) |
|
| 842 |
+ if _, ok := optMap[overlayDSROptionString]; ok {
|
|
| 843 |
+ network.loadBalancerMode = loadBalancerModeDSR |
|
| 844 |
+ } |
|
| 845 |
+ } |
|
| 846 |
+ |
|
| 832 | 847 |
addToStore: |
| 833 | 848 |
// First store the endpoint count, then the network. To avoid to |
| 834 | 849 |
// end up with a datastore containing a network and not an epCnt, |
| ... | ... |
@@ -261,7 +261,7 @@ func (ep *hnsEndpoint) UnmarshalJSON(b []byte) error {
|
| 261 | 261 |
} |
| 262 | 262 |
if v, ok := epMap["Addr"]; ok {
|
| 263 | 263 |
if ep.addr, err = types.ParseCIDR(v.(string)); err != nil {
|
| 264 |
- return types.InternalErrorf("failed to decode endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 264 |
+ logrus.Warnf("failed to decode endpoint IPv4 address (%s) after json unmarshal: %v", v.(string), err)
|
|
| 265 | 265 |
} |
| 266 | 266 |
} |
| 267 | 267 |
if v, ok := epMap["gateway"]; ok {
|
| ... | ... |
@@ -145,3 +145,23 @@ const ( |
| 145 | 145 |
// addresses. |
| 146 | 146 |
SourceHashing = "sh" |
| 147 | 147 |
) |
| 148 |
+ |
|
| 149 |
+const ( |
|
| 150 |
+ // ConnFwdMask is a mask for the fwd methods |
|
| 151 |
+ ConnFwdMask = 0x0007 |
|
| 152 |
+ |
|
| 153 |
+ // ConnFwdMasq denotes forwarding via masquerading/NAT |
|
| 154 |
+ ConnFwdMasq = 0x0000 |
|
| 155 |
+ |
|
| 156 |
+ // ConnFwdLocalNode denotes forwarding to a local node |
|
| 157 |
+ ConnFwdLocalNode = 0x0001 |
|
| 158 |
+ |
|
| 159 |
+ // ConnFwdTunnel denotes forwarding via a tunnel |
|
| 160 |
+ ConnFwdTunnel = 0x0002 |
|
| 161 |
+ |
|
| 162 |
+ // ConnFwdDirectRoute denotes forwarding via direct routing |
|
| 163 |
+ ConnFwdDirectRoute = 0x0003 |
|
| 164 |
+ |
|
| 165 |
+ // ConnFwdBypass denotes forwarding while bypassing the cache |
|
| 166 |
+ ConnFwdBypass = 0x0004 |
|
| 167 |
+) |
| ... | ... |
@@ -62,8 +62,12 @@ type Destination struct {
|
| 62 | 62 |
LowerThreshold uint32 |
| 63 | 63 |
ActiveConnections int |
| 64 | 64 |
InactiveConnections int |
| 65 |
+ Stats DstStats |
|
| 65 | 66 |
} |
| 66 | 67 |
|
| 68 |
+// DstStats defines IPVS destination (real server) statistics |
|
| 69 |
+type DstStats SvcStats |
|
| 70 |
+ |
|
| 67 | 71 |
// Handle provides a namespace specific ipvs handle to program ipvs |
| 68 | 72 |
// rules. |
| 69 | 73 |
type Handle struct {
|
| ... | ... |
@@ -443,6 +443,12 @@ func assembleDestination(attrs []syscall.NetlinkRouteAttr) (*Destination, error) |
| 443 | 443 |
d.ActiveConnections = int(native.Uint16(attr.Value)) |
| 444 | 444 |
case ipvsDestAttrInactiveConnections: |
| 445 | 445 |
d.InactiveConnections = int(native.Uint16(attr.Value)) |
| 446 |
+ case ipvsSvcAttrStats: |
|
| 447 |
+ stats, err := assembleStats(attr.Value) |
|
| 448 |
+ if err != nil {
|
|
| 449 |
+ return nil, err |
|
| 450 |
+ } |
|
| 451 |
+ d.Stats = DstStats(stats) |
|
| 446 | 452 |
} |
| 447 | 453 |
} |
| 448 | 454 |
return &d, nil |
| ... | ... |
@@ -199,43 +199,50 @@ func (i *IpamInfo) UnmarshalJSON(data []byte) error {
|
| 199 | 199 |
} |
| 200 | 200 |
|
| 201 | 201 |
type network struct {
|
| 202 |
- ctrlr *controller |
|
| 203 |
- name string |
|
| 204 |
- networkType string |
|
| 205 |
- id string |
|
| 206 |
- created time.Time |
|
| 207 |
- scope string // network data scope |
|
| 208 |
- labels map[string]string |
|
| 209 |
- ipamType string |
|
| 210 |
- ipamOptions map[string]string |
|
| 211 |
- addrSpace string |
|
| 212 |
- ipamV4Config []*IpamConf |
|
| 213 |
- ipamV6Config []*IpamConf |
|
| 214 |
- ipamV4Info []*IpamInfo |
|
| 215 |
- ipamV6Info []*IpamInfo |
|
| 216 |
- enableIPv6 bool |
|
| 217 |
- postIPv6 bool |
|
| 218 |
- epCnt *endpointCnt |
|
| 219 |
- generic options.Generic |
|
| 220 |
- dbIndex uint64 |
|
| 221 |
- dbExists bool |
|
| 222 |
- persist bool |
|
| 223 |
- stopWatchCh chan struct{}
|
|
| 224 |
- drvOnce *sync.Once |
|
| 225 |
- resolverOnce sync.Once |
|
| 226 |
- resolver []Resolver |
|
| 227 |
- internal bool |
|
| 228 |
- attachable bool |
|
| 229 |
- inDelete bool |
|
| 230 |
- ingress bool |
|
| 231 |
- driverTables []networkDBTable |
|
| 232 |
- dynamic bool |
|
| 233 |
- configOnly bool |
|
| 234 |
- configFrom string |
|
| 235 |
- loadBalancerIP net.IP |
|
| 202 |
+ ctrlr *controller |
|
| 203 |
+ name string |
|
| 204 |
+ networkType string |
|
| 205 |
+ id string |
|
| 206 |
+ created time.Time |
|
| 207 |
+ scope string // network data scope |
|
| 208 |
+ labels map[string]string |
|
| 209 |
+ ipamType string |
|
| 210 |
+ ipamOptions map[string]string |
|
| 211 |
+ addrSpace string |
|
| 212 |
+ ipamV4Config []*IpamConf |
|
| 213 |
+ ipamV6Config []*IpamConf |
|
| 214 |
+ ipamV4Info []*IpamInfo |
|
| 215 |
+ ipamV6Info []*IpamInfo |
|
| 216 |
+ enableIPv6 bool |
|
| 217 |
+ postIPv6 bool |
|
| 218 |
+ epCnt *endpointCnt |
|
| 219 |
+ generic options.Generic |
|
| 220 |
+ dbIndex uint64 |
|
| 221 |
+ dbExists bool |
|
| 222 |
+ persist bool |
|
| 223 |
+ stopWatchCh chan struct{}
|
|
| 224 |
+ drvOnce *sync.Once |
|
| 225 |
+ resolverOnce sync.Once |
|
| 226 |
+ resolver []Resolver |
|
| 227 |
+ internal bool |
|
| 228 |
+ attachable bool |
|
| 229 |
+ inDelete bool |
|
| 230 |
+ ingress bool |
|
| 231 |
+ driverTables []networkDBTable |
|
| 232 |
+ dynamic bool |
|
| 233 |
+ configOnly bool |
|
| 234 |
+ configFrom string |
|
| 235 |
+ loadBalancerIP net.IP |
|
| 236 |
+ loadBalancerMode string |
|
| 236 | 237 |
sync.Mutex |
| 237 | 238 |
} |
| 238 | 239 |
|
| 240 |
+const ( |
|
| 241 |
+ loadBalancerModeNAT = "NAT" |
|
| 242 |
+ loadBalancerModeDSR = "DSR" |
|
| 243 |
+ loadBalancerModeDefault = loadBalancerModeNAT |
|
| 244 |
+) |
|
| 245 |
+ |
|
| 239 | 246 |
func (n *network) Name() string {
|
| 240 | 247 |
n.Lock() |
| 241 | 248 |
defer n.Unlock() |
| ... | ... |
@@ -475,6 +482,7 @@ func (n *network) CopyTo(o datastore.KVObject) error {
|
| 475 | 475 |
dstN.configOnly = n.configOnly |
| 476 | 476 |
dstN.configFrom = n.configFrom |
| 477 | 477 |
dstN.loadBalancerIP = n.loadBalancerIP |
| 478 |
+ dstN.loadBalancerMode = n.loadBalancerMode |
|
| 478 | 479 |
|
| 479 | 480 |
// copy labels |
| 480 | 481 |
if dstN.labels == nil {
|
| ... | ... |
@@ -592,6 +600,7 @@ func (n *network) MarshalJSON() ([]byte, error) {
|
| 592 | 592 |
netMap["configOnly"] = n.configOnly |
| 593 | 593 |
netMap["configFrom"] = n.configFrom |
| 594 | 594 |
netMap["loadBalancerIP"] = n.loadBalancerIP |
| 595 |
+ netMap["loadBalancerMode"] = n.loadBalancerMode |
|
| 595 | 596 |
return json.Marshal(netMap) |
| 596 | 597 |
} |
| 597 | 598 |
|
| ... | ... |
@@ -705,6 +714,10 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
|
| 705 | 705 |
if v, ok := netMap["loadBalancerIP"]; ok {
|
| 706 | 706 |
n.loadBalancerIP = net.ParseIP(v.(string)) |
| 707 | 707 |
} |
| 708 |
+ n.loadBalancerMode = loadBalancerModeDefault |
|
| 709 |
+ if v, ok := netMap["loadBalancerMode"]; ok {
|
|
| 710 |
+ n.loadBalancerMode = v.(string) |
|
| 711 |
+ } |
|
| 708 | 712 |
// Reconcile old networks with the recently added `--ipv6` flag |
| 709 | 713 |
if !n.enableIPv6 {
|
| 710 | 714 |
n.enableIPv6 = len(n.ipamV6Info) > 0 |
| ... | ... |
@@ -384,6 +384,36 @@ func (n *networkNamespace) RemoveAliasIP(ifName string, ip *net.IPNet) error {
|
| 384 | 384 |
return n.nlHandle.AddrDel(iface, &netlink.Addr{IPNet: ip})
|
| 385 | 385 |
} |
| 386 | 386 |
|
| 387 |
+func (n *networkNamespace) DisableARPForVIP(srcName string) (Err error) {
|
|
| 388 |
+ dstName := "" |
|
| 389 |
+ for _, i := range n.Interfaces() {
|
|
| 390 |
+ if i.SrcName() == srcName {
|
|
| 391 |
+ dstName = i.DstName() |
|
| 392 |
+ break |
|
| 393 |
+ } |
|
| 394 |
+ } |
|
| 395 |
+ if dstName == "" {
|
|
| 396 |
+ return fmt.Errorf("failed to find interface %s in sandbox", srcName)
|
|
| 397 |
+ } |
|
| 398 |
+ |
|
| 399 |
+ err := n.InvokeFunc(func() {
|
|
| 400 |
+ path := filepath.Join("/proc/sys/net/ipv4/conf", dstName, "arp_ignore")
|
|
| 401 |
+ if err := ioutil.WriteFile(path, []byte{'1', '\n'}, 0644); err != nil {
|
|
| 402 |
+ Err = fmt.Errorf("Failed to set %s to 1: %v", path, err)
|
|
| 403 |
+ return |
|
| 404 |
+ } |
|
| 405 |
+ path = filepath.Join("/proc/sys/net/ipv4/conf", dstName, "arp_announce")
|
|
| 406 |
+ if err := ioutil.WriteFile(path, []byte{'2', '\n'}, 0644); err != nil {
|
|
| 407 |
+ Err = fmt.Errorf("Failed to set %s to 2: %v", path, err)
|
|
| 408 |
+ return |
|
| 409 |
+ } |
|
| 410 |
+ }) |
|
| 411 |
+ if err != nil {
|
|
| 412 |
+ return err |
|
| 413 |
+ } |
|
| 414 |
+ return |
|
| 415 |
+} |
|
| 416 |
+ |
|
| 387 | 417 |
func (n *networkNamespace) InvokeFunc(f func()) error {
|
| 388 | 418 |
return nsInvoke(n.nsPath(), func(nsFD int) error { return nil }, func(callerFD int) error {
|
| 389 | 419 |
f() |
| ... | ... |
@@ -51,6 +51,10 @@ type Sandbox interface {
|
| 51 | 51 |
// RemoveAliasIP removes the passed IP address from the named interface |
| 52 | 52 |
RemoveAliasIP(ifName string, ip *net.IPNet) error |
| 53 | 53 |
|
| 54 |
+ // DisableARPForVIP disables ARP replies and requests for VIP addresses |
|
| 55 |
+ // on a particular interface |
|
| 56 |
+ DisableARPForVIP(ifName string) error |
|
| 57 |
+ |
|
| 54 | 58 |
// Add a static route to the sandbox. |
| 55 | 59 |
AddStaticRoute(*types.StaticRoute) error |
| 56 | 60 |
|
| ... | ... |
@@ -67,7 +67,7 @@ const ( |
| 67 | 67 |
maxExtDNS = 3 //max number of external servers to try |
| 68 | 68 |
extIOTimeout = 4 * time.Second |
| 69 | 69 |
defaultRespSize = 512 |
| 70 |
- maxConcurrent = 100 |
|
| 70 |
+ maxConcurrent = 1024 |
|
| 71 | 71 |
logInterval = 2 * time.Second |
| 72 | 72 |
) |
| 73 | 73 |
|
| ... | ... |
@@ -111,7 +111,7 @@ func NewResolver(address string, proxyDNS bool, resolverKey string, backend DNSB |
| 111 | 111 |
} |
| 112 | 112 |
|
| 113 | 113 |
func (r *resolver) SetupFunc(port int) func() {
|
| 114 |
- return (func() {
|
|
| 114 |
+ return func() {
|
|
| 115 | 115 |
var err error |
| 116 | 116 |
|
| 117 | 117 |
// DNS operates primarily on UDP |
| ... | ... |
@@ -138,7 +138,7 @@ func (r *resolver) SetupFunc(port int) func() {
|
| 138 | 138 |
return |
| 139 | 139 |
} |
| 140 | 140 |
r.err = nil |
| 141 |
- }) |
|
| 141 |
+ } |
|
| 142 | 142 |
} |
| 143 | 143 |
|
| 144 | 144 |
func (r *resolver) Start() error {
|
| ... | ... |
@@ -490,35 +490,51 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
|
| 490 | 490 |
continue |
| 491 | 491 |
} |
| 492 | 492 |
r.forwardQueryEnd() |
| 493 |
- if resp != nil {
|
|
| 494 |
- if resp.Rcode == dns.RcodeServerFailure {
|
|
| 495 |
- // for Server Failure response, continue to the next external DNS server |
|
| 496 |
- logrus.Debugf("[resolver] external DNS %s:%s responded with ServFail for %q", proto, extDNS.IPStr, name)
|
|
| 497 |
- continue |
|
| 498 |
- } |
|
| 499 |
- answers := 0 |
|
| 500 |
- for _, rr := range resp.Answer {
|
|
| 501 |
- h := rr.Header() |
|
| 502 |
- switch h.Rrtype {
|
|
| 503 |
- case dns.TypeA: |
|
| 504 |
- answers++ |
|
| 505 |
- ip := rr.(*dns.A).A |
|
| 506 |
- logrus.Debugf("[resolver] received A record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr)
|
|
| 507 |
- r.backend.HandleQueryResp(h.Name, ip) |
|
| 508 |
- case dns.TypeAAAA: |
|
| 509 |
- answers++ |
|
| 510 |
- ip := rr.(*dns.AAAA).AAAA |
|
| 511 |
- logrus.Debugf("[resolver] received AAAA record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr)
|
|
| 512 |
- r.backend.HandleQueryResp(h.Name, ip) |
|
| 513 |
- } |
|
| 493 |
+ |
|
| 494 |
+ if resp == nil {
|
|
| 495 |
+ logrus.Debugf("[resolver] external DNS %s:%s returned empty response for %q", proto, extDNS.IPStr, name)
|
|
| 496 |
+ break |
|
| 497 |
+ } |
|
| 498 |
+ switch resp.Rcode {
|
|
| 499 |
+ case dns.RcodeServerFailure, dns.RcodeRefused: |
|
| 500 |
+ // Server returned FAILURE: continue with the next external DNS server |
|
| 501 |
+ // Server returned REFUSED: this can be a transitional status, so continue with the next external DNS server |
|
| 502 |
+ logrus.Debugf("[resolver] external DNS %s:%s responded with %s for %q", proto, extDNS.IPStr, statusString(resp.Rcode), name)
|
|
| 503 |
+ continue |
|
| 504 |
+ case dns.RcodeNameError: |
|
| 505 |
+ // Server returned NXDOMAIN. Stop resolution if it's an authoritative answer (see RFC 8020: https://tools.ietf.org/html/rfc8020#section-2) |
|
| 506 |
+ logrus.Debugf("[resolver] external DNS %s:%s responded with %s for %q", proto, extDNS.IPStr, statusString(resp.Rcode), name)
|
|
| 507 |
+ if resp.Authoritative {
|
|
| 508 |
+ break |
|
| 514 | 509 |
} |
| 515 |
- if resp.Answer == nil || answers == 0 {
|
|
| 516 |
- logrus.Debugf("[resolver] external DNS %s:%s did not return any %s records for %q", proto, extDNS.IPStr, queryType, name)
|
|
| 510 |
+ continue |
|
| 511 |
+ case dns.RcodeSuccess: |
|
| 512 |
+ // All is well |
|
| 513 |
+ default: |
|
| 514 |
+ // Server gave some error. Log the error, and continue with the next external DNS server |
|
| 515 |
+ logrus.Debugf("[resolver] external DNS %s:%s responded with %s (code %d) for %q", proto, extDNS.IPStr, statusString(resp.Rcode), resp.Rcode, name)
|
|
| 516 |
+ continue |
|
| 517 |
+ } |
|
| 518 |
+ answers := 0 |
|
| 519 |
+ for _, rr := range resp.Answer {
|
|
| 520 |
+ h := rr.Header() |
|
| 521 |
+ switch h.Rrtype {
|
|
| 522 |
+ case dns.TypeA: |
|
| 523 |
+ answers++ |
|
| 524 |
+ ip := rr.(*dns.A).A |
|
| 525 |
+ logrus.Debugf("[resolver] received A record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr)
|
|
| 526 |
+ r.backend.HandleQueryResp(h.Name, ip) |
|
| 527 |
+ case dns.TypeAAAA: |
|
| 528 |
+ answers++ |
|
| 529 |
+ ip := rr.(*dns.AAAA).AAAA |
|
| 530 |
+ logrus.Debugf("[resolver] received AAAA record %q for %q from %s:%s", ip, h.Name, proto, extDNS.IPStr)
|
|
| 531 |
+ r.backend.HandleQueryResp(h.Name, ip) |
|
| 517 | 532 |
} |
| 518 |
- resp.Compress = true |
|
| 519 |
- } else {
|
|
| 520 |
- logrus.Debugf("[resolver] external DNS %s:%s returned empty response for %q", proto, extDNS.IPStr, name)
|
|
| 521 | 533 |
} |
| 534 |
+ if resp.Answer == nil || answers == 0 {
|
|
| 535 |
+ logrus.Debugf("[resolver] external DNS %s:%s did not return any %s records for %q", proto, extDNS.IPStr, queryType, name)
|
|
| 536 |
+ } |
|
| 537 |
+ resp.Compress = true |
|
| 522 | 538 |
break |
| 523 | 539 |
} |
| 524 | 540 |
if resp == nil {
|
| ... | ... |
@@ -531,6 +547,13 @@ func (r *resolver) ServeDNS(w dns.ResponseWriter, query *dns.Msg) {
|
| 531 | 531 |
} |
| 532 | 532 |
} |
| 533 | 533 |
|
| 534 |
+func statusString(responseCode int) string {
|
|
| 535 |
+ if s, ok := dns.RcodeToString[responseCode]; ok {
|
|
| 536 |
+ return s |
|
| 537 |
+ } |
|
| 538 |
+ return "UNKNOWN" |
|
| 539 |
+} |
|
| 540 |
+ |
|
| 534 | 541 |
func (r *resolver) forwardQueryStart() bool {
|
| 535 | 542 |
r.queryLock.Lock() |
| 536 | 543 |
defer r.queryLock.Unlock() |
| ... | ... |
@@ -742,8 +742,17 @@ func releaseOSSboxResources(osSbox osl.Sandbox, ep *endpoint) {
|
| 742 | 742 |
|
| 743 | 743 |
ep.Lock() |
| 744 | 744 |
joinInfo := ep.joinInfo |
| 745 |
+ vip := ep.virtualIP |
|
| 746 |
+ lbModeIsDSR := ep.network.loadBalancerMode == loadBalancerModeDSR |
|
| 745 | 747 |
ep.Unlock() |
| 746 | 748 |
|
| 749 |
+ if len(vip) > 0 && lbModeIsDSR {
|
|
| 750 |
+ ipNet := &net.IPNet{IP: vip, Mask: net.CIDRMask(32, 32)}
|
|
| 751 |
+ if err := osSbox.RemoveAliasIP(osSbox.GetLoopbackIfaceName(), ipNet); err != nil {
|
|
| 752 |
+ logrus.WithError(err).Debugf("failed to remove virtual ip %v to loopback", ipNet)
|
|
| 753 |
+ } |
|
| 754 |
+ } |
|
| 755 |
+ |
|
| 747 | 756 |
if joinInfo == nil {
|
| 748 | 757 |
return |
| 749 | 758 |
} |
| ... | ... |
@@ -831,6 +840,7 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
|
| 831 | 831 |
ep.Lock() |
| 832 | 832 |
joinInfo := ep.joinInfo |
| 833 | 833 |
i := ep.iface |
| 834 |
+ lbModeIsDSR := ep.network.loadBalancerMode == loadBalancerModeDSR |
|
| 834 | 835 |
ep.Unlock() |
| 835 | 836 |
|
| 836 | 837 |
if ep.needResolver() {
|
| ... | ... |
@@ -854,6 +864,18 @@ func (sb *sandbox) populateNetworkResources(ep *endpoint) error {
|
| 854 | 854 |
if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
|
| 855 | 855 |
return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)
|
| 856 | 856 |
} |
| 857 |
+ |
|
| 858 |
+ if len(ep.virtualIP) > 0 && lbModeIsDSR {
|
|
| 859 |
+ if sb.loadBalancerNID == "" {
|
|
| 860 |
+ if err := sb.osSbox.DisableARPForVIP(i.srcName); err != nil {
|
|
| 861 |
+ return fmt.Errorf("failed disable ARP for VIP: %v", err)
|
|
| 862 |
+ } |
|
| 863 |
+ } |
|
| 864 |
+ ipNet := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)}
|
|
| 865 |
+ if err := sb.osSbox.AddAliasIP(sb.osSbox.GetLoopbackIfaceName(), ipNet); err != nil {
|
|
| 866 |
+ return fmt.Errorf("failed to add virtual ip %v to loopback: %v", ipNet, err)
|
|
| 867 |
+ } |
|
| 868 |
+ } |
|
| 857 | 869 |
} |
| 858 | 870 |
|
| 859 | 871 |
if joinInfo != nil {
|
| ... | ... |
@@ -142,7 +142,7 @@ func (n *network) addLBBackend(ip net.IP, lb *loadBalancer) {
|
| 142 | 142 |
} |
| 143 | 143 |
|
| 144 | 144 |
logrus.Debugf("Creating service for vip %s fwMark %d ingressPorts %#v in sbox %.7s (%.7s)", lb.vip, lb.fwMark, lb.service.ingressPorts, sb.ID(), sb.ContainerID())
|
| 145 |
- if err := invokeFWMarker(sb.Key(), lb.vip, lb.fwMark, lb.service.ingressPorts, eIP, false); err != nil {
|
|
| 145 |
+ if err := invokeFWMarker(sb.Key(), lb.vip, lb.fwMark, lb.service.ingressPorts, eIP, false, n.loadBalancerMode); err != nil {
|
|
| 146 | 146 |
logrus.Errorf("Failed to add firewall mark rule in sbox %.7s (%.7s): %v", sb.ID(), sb.ContainerID(), err)
|
| 147 | 147 |
return |
| 148 | 148 |
} |
| ... | ... |
@@ -158,6 +158,9 @@ func (n *network) addLBBackend(ip net.IP, lb *loadBalancer) {
|
| 158 | 158 |
Address: ip, |
| 159 | 159 |
Weight: 1, |
| 160 | 160 |
} |
| 161 |
+ if n.loadBalancerMode == loadBalancerModeDSR {
|
|
| 162 |
+ d.ConnectionFlags = ipvs.ConnFwdDirectRoute |
|
| 163 |
+ } |
|
| 161 | 164 |
|
| 162 | 165 |
// Remove the sched name before using the service to add |
| 163 | 166 |
// destination. |
| ... | ... |
@@ -203,6 +206,9 @@ func (n *network) rmLBBackend(ip net.IP, lb *loadBalancer, rmService bool, fullR |
| 203 | 203 |
Address: ip, |
| 204 | 204 |
Weight: 1, |
| 205 | 205 |
} |
| 206 |
+ if n.loadBalancerMode == loadBalancerModeDSR {
|
|
| 207 |
+ d.ConnectionFlags = ipvs.ConnFwdDirectRoute |
|
| 208 |
+ } |
|
| 206 | 209 |
|
| 207 | 210 |
if fullRemove {
|
| 208 | 211 |
if err := i.DelDestination(s, d); err != nil && err != syscall.ENOENT {
|
| ... | ... |
@@ -231,7 +237,7 @@ func (n *network) rmLBBackend(ip net.IP, lb *loadBalancer, rmService bool, fullR |
| 231 | 231 |
} |
| 232 | 232 |
} |
| 233 | 233 |
|
| 234 |
- if err := invokeFWMarker(sb.Key(), lb.vip, lb.fwMark, lb.service.ingressPorts, eIP, true); err != nil {
|
|
| 234 |
+ if err := invokeFWMarker(sb.Key(), lb.vip, lb.fwMark, lb.service.ingressPorts, eIP, true, n.loadBalancerMode); err != nil {
|
|
| 235 | 235 |
logrus.Errorf("Failed to delete firewall mark rule in sbox %.7s (%.7s): %v", sb.ID(), sb.ContainerID(), err)
|
| 236 | 236 |
} |
| 237 | 237 |
|
| ... | ... |
@@ -566,7 +572,7 @@ func readPortsFromFile(fileName string) ([]*PortConfig, error) {
|
| 566 | 566 |
|
| 567 | 567 |
// Invoke fwmarker reexec routine to mark vip destined packets with |
| 568 | 568 |
// the passed firewall mark. |
| 569 |
-func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, isDelete bool) error {
|
|
| 569 |
+func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*PortConfig, eIP *net.IPNet, isDelete bool, lbMode string) error {
|
|
| 570 | 570 |
var ingressPortsFile string |
| 571 | 571 |
|
| 572 | 572 |
if len(ingressPorts) != 0 {
|
| ... | ... |
@@ -586,7 +592,7 @@ func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*Port |
| 586 | 586 |
|
| 587 | 587 |
cmd := &exec.Cmd{
|
| 588 | 588 |
Path: reexec.Self(), |
| 589 |
- Args: append([]string{"fwmarker"}, path, vip.String(), fmt.Sprintf("%d", fwMark), addDelOpt, ingressPortsFile, eIP.String()),
|
|
| 589 |
+ Args: append([]string{"fwmarker"}, path, vip.String(), fmt.Sprintf("%d", fwMark), addDelOpt, ingressPortsFile, eIP.String(), lbMode),
|
|
| 590 | 590 |
Stdout: os.Stdout, |
| 591 | 591 |
Stderr: os.Stderr, |
| 592 | 592 |
} |
| ... | ... |
@@ -603,7 +609,7 @@ func fwMarker() {
|
| 603 | 603 |
runtime.LockOSThread() |
| 604 | 604 |
defer runtime.UnlockOSThread() |
| 605 | 605 |
|
| 606 |
- if len(os.Args) < 7 {
|
|
| 606 |
+ if len(os.Args) < 8 {
|
|
| 607 | 607 |
logrus.Error("invalid number of arguments..")
|
| 608 | 608 |
os.Exit(1) |
| 609 | 609 |
} |
| ... | ... |
@@ -645,7 +651,8 @@ func fwMarker() {
|
| 645 | 645 |
os.Exit(5) |
| 646 | 646 |
} |
| 647 | 647 |
|
| 648 |
- if addDelOpt == "-A" {
|
|
| 648 |
+ lbMode := os.Args[7] |
|
| 649 |
+ if addDelOpt == "-A" && lbMode == loadBalancerModeNAT {
|
|
| 649 | 650 |
eIP, subnet, err := net.ParseCIDR(os.Args[6]) |
| 650 | 651 |
if err != nil {
|
| 651 | 652 |
logrus.Errorf("Failed to parse endpoint IP %s: %v", os.Args[6], err)
|