Browse code

Vendor libnetwork

- 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>

Flavio Crisciani authored on 2018/10/13 00:44:48
Showing 13 changed files
... ...
@@ -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)