From d527a09192756b70034555a66474a61aceb96aa0 Mon Sep 17 00:00:00 2001 From: Minhan Xia Date: Wed, 4 Mar 2020 11:29:36 -0800 Subject: [PATCH] add ExternalTrafficPolicy support for External IPs in ipvs kubeproxy --- pkg/proxy/ipvs/ipset.go | 3 ++ pkg/proxy/ipvs/proxier.go | 60 +++++++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/pkg/proxy/ipvs/ipset.go b/pkg/proxy/ipvs/ipset.go index 419b1a03598..7b75ec879c2 100644 --- a/pkg/proxy/ipvs/ipset.go +++ b/pkg/proxy/ipvs/ipset.go @@ -40,6 +40,9 @@ const ( kubeExternalIPSetComment = "Kubernetes service external ip + port for masquerade and filter purpose" kubeExternalIPSet = "KUBE-EXTERNAL-IP" + kubeExternalIPLocalSetComment = "Kubernetes service external ip + port with externalTrafficPolicy=local" + kubeExternalIPLocalSet = "KUBE-EXTERNAL-IP-LOCAL" + kubeLoadBalancerSetComment = "Kubernetes service lb portal" kubeLoadBalancerSet = "KUBE-LOAD-BALANCER" diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index 5b3eda42960..cbe0545d493 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -140,6 +140,7 @@ var ipsetInfo = []struct { {kubeLoopBackIPSet, utilipset.HashIPPortIP, kubeLoopBackIPSetComment}, {kubeClusterIPSet, utilipset.HashIPPort, kubeClusterIPSetComment}, {kubeExternalIPSet, utilipset.HashIPPort, kubeExternalIPSetComment}, + {kubeExternalIPLocalSet, utilipset.HashIPPort, kubeExternalIPLocalSetComment}, {kubeLoadBalancerSet, utilipset.HashIPPort, kubeLoadBalancerSetComment}, {kubeLoadbalancerFWSet, utilipset.HashIPPort, kubeLoadbalancerFWSetComment}, {kubeLoadBalancerLocalSet, utilipset.HashIPPort, kubeLoadBalancerLocalSetComment}, @@ -1236,12 +1237,21 @@ func (proxier *Proxier) syncProxyRules() { Protocol: protocol, SetType: utilipset.HashIPPort, } - // We have to SNAT packets to external IPs. - if valid := proxier.ipsetList[kubeExternalIPSet].validateEntry(entry); !valid { - klog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.ipsetList[kubeExternalIPSet].Name)) - continue + + if utilfeature.DefaultFeatureGate.Enabled(features.ExternalPolicyForExternalIP) && svcInfo.OnlyNodeLocalEndpoints() { + if valid := proxier.ipsetList[kubeExternalIPLocalSet].validateEntry(entry); !valid { + klog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.ipsetList[kubeExternalIPLocalSet].Name)) + continue + } + proxier.ipsetList[kubeExternalIPLocalSet].activeEntries.Insert(entry.String()) + } else { + // We have to SNAT packets to external IPs. + if valid := proxier.ipsetList[kubeExternalIPSet].validateEntry(entry); !valid { + klog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.ipsetList[kubeExternalIPSet].Name)) + continue + } + proxier.ipsetList[kubeExternalIPSet].activeEntries.Insert(entry.String()) } - proxier.ipsetList[kubeExternalIPSet].activeEntries.Insert(entry.String()) // ipvs call serv := &utilipvs.VirtualServer{ @@ -1257,7 +1267,12 @@ func (proxier *Proxier) syncProxyRules() { if err := proxier.syncService(svcNameString, serv, true); err == nil { activeIPVSServices[serv.String()] = true activeBindAddrs[serv.Address.String()] = true - if err := proxier.syncEndpoint(svcName, false, serv); err != nil { + + onlyNodeLocalEndpoints := false + if utilfeature.DefaultFeatureGate.Enabled(features.ExternalPolicyForExternalIP) { + onlyNodeLocalEndpoints = svcInfo.OnlyNodeLocalEndpoints() + } + if err := proxier.syncEndpoint(svcName, onlyNodeLocalEndpoints, serv); err != nil { klog.Errorf("Failed to sync endpoint for service: %v, err: %v", serv, err) } } else { @@ -1668,15 +1683,8 @@ func (proxier *Proxier) writeIptablesRules() { } } - if !proxier.ipsetList[kubeExternalIPSet].isEmpty() { - // Build masquerade rules for packets to external IPs. - args = append(args[:0], - "-A", string(kubeServicesChain), - "-m", "comment", "--comment", proxier.ipsetList[kubeExternalIPSet].getComment(), - "-m", "set", "--match-set", proxier.ipsetList[kubeExternalIPSet].Name, - "dst,dst", - ) - writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...) + // externalIPRules adds iptables rules applies to Service ExternalIPs + externalIPRules := func(args []string) { // Allow traffic for external IPs that does not come from a bridge (i.e. not from a container) // nor from a local process to be forwarded to the service. // This rule roughly translates to "all traffic from off-machine". @@ -1691,6 +1699,28 @@ func (proxier *Proxier) writeIptablesRules() { writeLine(proxier.natRules, append(dstLocalOnlyArgs, "-j", "ACCEPT")...) } + if !proxier.ipsetList[kubeExternalIPSet].isEmpty() { + // Build masquerade rules for packets to external IPs. + args = append(args[:0], + "-A", string(kubeServicesChain), + "-m", "comment", "--comment", proxier.ipsetList[kubeExternalIPSet].getComment(), + "-m", "set", "--match-set", proxier.ipsetList[kubeExternalIPSet].Name, + "dst,dst", + ) + writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...) + externalIPRules(args) + } + + if !proxier.ipsetList[kubeExternalIPLocalSet].isEmpty() { + args = append(args[:0], + "-A", string(kubeServicesChain), + "-m", "comment", "--comment", proxier.ipsetList[kubeExternalIPLocalSet].getComment(), + "-m", "set", "--match-set", proxier.ipsetList[kubeExternalIPLocalSet].Name, + "dst,dst", + ) + externalIPRules(args) + } + // -A KUBE-SERVICES -m addrtype --dst-type LOCAL -j KUBE-NODE-PORT args = append(args[:0], "-A", string(kubeServicesChain),