diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index 16776973386..6f2f71e5fe6 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -148,12 +148,39 @@ type serviceInfo struct { loadBalancerSourceRanges []string onlyNodeLocalEndpoints bool healthCheckNodePort int + // The following fields are computed and stored for performance reasons. + serviceNameString string + servicePortChainName utiliptables.Chain + serviceFirewallChainName utiliptables.Chain + serviceLBChainName utiliptables.Chain } // internal struct for endpoints information type endpointsInfo struct { endpoint string // TODO: should be an endpointString type isLocal bool + // The following fields we lazily compute and store here for performance + // reasons. If the protocol is the same as you expect it to be, then the + // chainName can be reused, otherwise it should be recomputed. + protocol string + chainName utiliptables.Chain +} + +// Returns just the IP part of the endpoint. +func (e *endpointsInfo) IPPart() string { + if index := strings.Index(e.endpoint, ":"); index != -1 { + return e.endpoint[0:index] + } + return e.endpoint +} + +// Returns the endpoint chain name for a given endpointsInfo. +func (e *endpointsInfo) endpointChain(svcNameString, protocol string) utiliptables.Chain { + if e.protocol != protocol { + e.protocol = protocol + e.chainName = servicePortEndpointChainName(svcNameString, protocol, e.endpoint) + } + return e.chainName } func (e *endpointsInfo) String() string { @@ -192,6 +219,13 @@ func newServiceInfo(svcPortName proxy.ServicePortName, port *api.ServicePort, se } } + // Store the following for performance reasons. + protocol := strings.ToLower(string(info.protocol)) + info.serviceNameString = svcPortName.String() + info.servicePortChainName = servicePortChainName(info.serviceNameString, protocol) + info.serviceFirewallChainName = serviceFirewallChainName(info.serviceNameString, protocol) + info.serviceLBChainName = serviceLBChainName(info.serviceNameString, protocol) + return info } @@ -346,6 +380,11 @@ type Proxier struct { healthChecker healthcheck.Server healthzServer healthcheck.HealthzUpdater + // Since converting probabilities (floats) to strings is expensive + // and we are using only probabilities in the format of 1/n, we are + // precomputing some number of those and cache for future reuse. + precomputedProbabilities []string + // The following buffers are used to reuse memory and avoid allocations // that are significantly impacting performance. iptablesData *bytes.Buffer @@ -441,27 +480,28 @@ func NewProxier(ipt utiliptables.Interface, healthChecker := healthcheck.NewServer(hostname, recorder, nil, nil) // use default implementations of deps proxier := &Proxier{ - portsMap: make(map[localPort]closeable), - serviceMap: make(proxyServiceMap), - serviceChanges: newServiceChangeMap(), - endpointsMap: make(proxyEndpointsMap), - endpointsChanges: newEndpointsChangeMap(hostname), - iptables: ipt, - masqueradeAll: masqueradeAll, - masqueradeMark: masqueradeMark, - exec: exec, - clusterCIDR: clusterCIDR, - hostname: hostname, - nodeIP: nodeIP, - portMapper: &listenPortOpener{}, - recorder: recorder, - healthChecker: healthChecker, - healthzServer: healthzServer, - iptablesData: bytes.NewBuffer(nil), - filterChains: bytes.NewBuffer(nil), - filterRules: bytes.NewBuffer(nil), - natChains: bytes.NewBuffer(nil), - natRules: bytes.NewBuffer(nil), + portsMap: make(map[localPort]closeable), + serviceMap: make(proxyServiceMap), + serviceChanges: newServiceChangeMap(), + endpointsMap: make(proxyEndpointsMap), + endpointsChanges: newEndpointsChangeMap(hostname), + iptables: ipt, + masqueradeAll: masqueradeAll, + masqueradeMark: masqueradeMark, + exec: exec, + clusterCIDR: clusterCIDR, + hostname: hostname, + nodeIP: nodeIP, + portMapper: &listenPortOpener{}, + recorder: recorder, + healthChecker: healthChecker, + healthzServer: healthzServer, + precomputedProbabilities: make([]string, 0, 1001), + iptablesData: bytes.NewBuffer(nil), + filterChains: bytes.NewBuffer(nil), + filterRules: bytes.NewBuffer(nil), + natChains: bytes.NewBuffer(nil), + natRules: bytes.NewBuffer(nil), } burstSyncs := 2 glog.V(3).Infof("minSyncPeriod: %v, syncPeriod: %v, burstSyncs: %d", minSyncPeriod, syncPeriod, burstSyncs) @@ -557,6 +597,28 @@ func CleanupLeftovers(ipt utiliptables.Interface) (encounteredError bool) { return encounteredError } +func computeProbability(n int) string { + return fmt.Sprintf("%0.5f", 1.0/float64(n)) +} + +// This assumes proxier.mu is held +func (proxier *Proxier) precomputeProbabilities(numberOfPrecomputed int) { + if len(proxier.precomputedProbabilities) == 0 { + proxier.precomputedProbabilities = append(proxier.precomputedProbabilities, "") + } + for i := len(proxier.precomputedProbabilities); i <= numberOfPrecomputed; i++ { + proxier.precomputedProbabilities = append(proxier.precomputedProbabilities, computeProbability(i)) + } +} + +// This assumes proxier.mu is held +func (proxier *Proxier) probability(n int) string { + if n >= len(proxier.precomputedProbabilities) { + proxier.precomputeProbabilities(n) + } + return proxier.precomputedProbabilities[n] +} + // Sync is called to synchronize the proxier state to iptables as soon as possible. func (proxier *Proxier) Sync() { proxier.syncRunner.Run() @@ -751,8 +813,7 @@ func getLocalIPs(endpointsMap proxyEndpointsMap) map[types.NamespacedName]sets.S if localIPs[nsn] == nil { localIPs[nsn] = sets.NewString() } - ip := strings.Split(ep.endpoint, ":")[0] // just the IP part - localIPs[nsn].Insert(ip) + localIPs[nsn].Insert(ep.IPPart()) // just the IP part } } } @@ -873,6 +934,13 @@ type endpointServicePair struct { servicePortName proxy.ServicePortName } +func (esp *endpointServicePair) IPPart() string { + if index := strings.Index(esp.endpoint, ":"); index != -1 { + return esp.endpoint[0:index] + } + return esp.endpoint +} + const noConnectionToDelete = "0 flow entries have been deleted" // After a UDP endpoint has been removed, we must flush any pending conntrack entries to it, or else we @@ -881,7 +949,7 @@ const noConnectionToDelete = "0 flow entries have been deleted" func (proxier *Proxier) deleteEndpointConnections(connectionMap map[endpointServicePair]bool) { for epSvcPair := range connectionMap { if svcInfo, ok := proxier.serviceMap[epSvcPair.servicePortName]; ok && svcInfo.protocol == api.ProtocolUDP { - endpointIP := strings.Split(epSvcPair.endpoint, ":")[0] + endpointIP := epSvcPair.endpoint[0:strings.Index(epSvcPair.endpoint, ":")] glog.V(2).Infof("Deleting connection tracking state for service IP %s, endpoint IP %s", svcInfo.clusterIP.String(), endpointIP) err := utilproxy.ExecConntrackTool(proxier.exec, "-D", "--orig-dst", svcInfo.clusterIP.String(), "--dst-nat", endpointIP, "-p", "udp") if err != nil && !strings.Contains(err.Error(), noConnectionToDelete) { @@ -1053,15 +1121,28 @@ func (proxier *Proxier) syncProxyRules() { // Accumulate the set of local ports that we will be holding open once this update is complete replacementPortsMap := map[localPort]closeable{} + // We are creating those slices ones here to avoid memory reallocations + // in every loop. Note that reuse the memory, instead of doing: + // slice = + // you should always do one of the below: + // slice = slice[:0] // and then append to it + // slice = append(slice[:0], ...) + endpoints := make([]*endpointsInfo, 0) + endpointChains := make([]utiliptables.Chain, 0) + // To avoid growing this slice, we arbitrarily set its size to 64, + // there is never more than that many arguments for a single line. + // Note that even if we go over 64, it will still be correct - it + // is just for efficiency, not correctness. + args := make([]string, 64) + // Build rules for each service. + var svcNameString string for svcName, svcInfo := range proxier.serviceMap { protocol := strings.ToLower(string(svcInfo.protocol)) - // Precompute svcNameString; with many services the many calls - // to ServicePortName.String() show up in CPU profiles. - svcNameString := svcName.String() + svcNameString = svcInfo.serviceNameString // Create the per-service chain, retaining counters if possible. - svcChain := servicePortChainName(svcNameString, protocol) + svcChain := svcInfo.servicePortChainName if chain, ok := existingNATChains[svcChain]; ok { writeLine(proxier.natChains, chain) } else { @@ -1069,7 +1150,7 @@ func (proxier *Proxier) syncProxyRules() { } activeNATChains[svcChain] = true - svcXlbChain := serviceLBChainName(svcNameString, protocol) + svcXlbChain := svcInfo.serviceLBChainName if svcInfo.onlyNodeLocalEndpoints { // Only for services request OnlyLocal traffic // create the per-service LB chain, retaining counters if possible. @@ -1085,13 +1166,13 @@ func (proxier *Proxier) syncProxyRules() { } // Capture the clusterIP. - args := []string{ + args = append(args[:0], "-A", string(kubeServicesChain), "-m", "comment", "--comment", fmt.Sprintf(`"%s cluster IP"`, svcNameString), "-m", protocol, "-p", protocol, "-d", fmt.Sprintf("%s/32", svcInfo.clusterIP.String()), - "--dport", fmt.Sprintf("%d", svcInfo.port), - } + "--dport", strconv.Itoa(svcInfo.port), + ) if proxier.masqueradeAll { writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...) } @@ -1135,13 +1216,13 @@ func (proxier *Proxier) syncProxyRules() { replacementPortsMap[lp] = socket } } // We're holding the port, so it's OK to install iptables rules. - args := []string{ + args = append(args[:0], "-A", string(kubeServicesChain), "-m", "comment", "--comment", fmt.Sprintf(`"%s external IP"`, svcNameString), "-m", protocol, "-p", protocol, "-d", fmt.Sprintf("%s/32", externalIP), - "--dport", fmt.Sprintf("%d", svcInfo.port), - } + "--dport", strconv.Itoa(svcInfo.port), + ) // We have to SNAT packets to external IPs. writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...) @@ -1166,17 +1247,17 @@ func (proxier *Proxier) syncProxyRules() { "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString), "-m", protocol, "-p", protocol, "-d", fmt.Sprintf("%s/32", externalIP), - "--dport", fmt.Sprintf("%d", svcInfo.port), + "--dport", strconv.Itoa(svcInfo.port), "-j", "REJECT", ) } } // Capture load-balancer ingress. + fwChain := svcInfo.serviceFirewallChainName for _, ingress := range svcInfo.loadBalancerStatus.Ingress { if ingress.IP != "" { // create service firewall chain - fwChain := serviceFirewallChainName(svcNameString, protocol) if chain, ok := existingNATChains[fwChain]; ok { writeLine(proxier.natChains, chain) } else { @@ -1187,20 +1268,20 @@ func (proxier *Proxier) syncProxyRules() { // This currently works for loadbalancers that preserves source ips. // For loadbalancers which direct traffic to service NodePort, the firewall rules will not apply. - args := []string{ + args = append(args[:0], "-A", string(kubeServicesChain), "-m", "comment", "--comment", fmt.Sprintf(`"%s loadbalancer IP"`, svcNameString), "-m", protocol, "-p", protocol, "-d", fmt.Sprintf("%s/32", ingress.IP), - "--dport", fmt.Sprintf("%d", svcInfo.port), - } + "--dport", strconv.Itoa(svcInfo.port), + ) // jump to service firewall chain writeLine(proxier.natRules, append(args, "-j", string(fwChain))...) - args = []string{ + args = append(args[:0], "-A", string(fwChain), "-m", "comment", "--comment", fmt.Sprintf(`"%s loadbalancer IP"`, svcNameString), - } + ) // Each source match rule in the FW chain may jump to either the SVC or the XLB chain chosenChain := svcXlbChain @@ -1266,12 +1347,12 @@ func (proxier *Proxier) syncProxyRules() { replacementPortsMap[lp] = socket } // We're holding the port, so it's OK to install iptables rules. - args := []string{ + args = append(args[:0], "-A", string(kubeNodePortsChain), "-m", "comment", "--comment", svcNameString, "-m", protocol, "-p", protocol, - "--dport", fmt.Sprintf("%d", svcInfo.nodePort), - } + "--dport", strconv.Itoa(svcInfo.nodePort), + ) if !svcInfo.onlyNodeLocalEndpoints { // Nodeports need SNAT, unless they're local. writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...) @@ -1293,7 +1374,7 @@ func (proxier *Proxier) syncProxyRules() { "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString), "-m", "addrtype", "--dst-type", "LOCAL", "-m", protocol, "-p", protocol, - "--dport", fmt.Sprintf("%d", svcInfo.nodePort), + "--dport", strconv.Itoa(svcInfo.nodePort), "-j", "REJECT", ) } @@ -1306,7 +1387,7 @@ func (proxier *Proxier) syncProxyRules() { "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString), "-m", protocol, "-p", protocol, "-d", fmt.Sprintf("%s/32", svcInfo.clusterIP.String()), - "--dport", fmt.Sprintf("%d", svcInfo.port), + "--dport", strconv.Itoa(svcInfo.port), "-j", "REJECT", ) continue @@ -1317,11 +1398,12 @@ func (proxier *Proxier) syncProxyRules() { // Generate the per-endpoint chains. We do this in multiple passes so we // can group rules together. // These two slices parallel each other - keep in sync - endpoints := make([]*endpointsInfo, 0) - endpointChains := make([]utiliptables.Chain, 0) + endpoints = endpoints[:0] + endpointChains = endpointChains[:0] + var endpointChain utiliptables.Chain for _, ep := range proxier.endpointsMap[svcName] { endpoints = append(endpoints, ep) - endpointChain := servicePortEndpointChainName(svcNameString, protocol, ep.endpoint) + endpointChain = ep.endpointChain(svcNameString, protocol) endpointChains = append(endpointChains, endpointChain) // Create the endpoint chain, retaining counters if possible. @@ -1340,7 +1422,7 @@ func (proxier *Proxier) syncProxyRules() { "-A", string(svcChain), "-m", "comment", "--comment", svcNameString, "-m", "recent", "--name", string(endpointChain), - "--rcheck", "--seconds", fmt.Sprintf("%d", svcInfo.stickyMaxAgeMinutes*60), "--reap", + "--rcheck", "--seconds", strconv.Itoa(svcInfo.stickyMaxAgeMinutes*60), "--reap", "-j", string(endpointChain)) } } @@ -1349,29 +1431,29 @@ func (proxier *Proxier) syncProxyRules() { n := len(endpointChains) for i, endpointChain := range endpointChains { // Balancing rules in the per-service chain. - args := []string{ + args = append(args[:0], []string{ "-A", string(svcChain), "-m", "comment", "--comment", svcNameString, - } + }...) if i < (n - 1) { // Each rule is a probabilistic match. args = append(args, "-m", "statistic", "--mode", "random", - "--probability", fmt.Sprintf("%0.5f", 1.0/float64(n-i))) + "--probability", proxier.probability(n-i)) } // The final (or only if n == 1) rule is a guaranteed match. args = append(args, "-j", string(endpointChain)) writeLine(proxier.natRules, args...) // Rules in the per-endpoint chain. - args = []string{ + args = append(args[:0], "-A", string(endpointChain), "-m", "comment", "--comment", svcNameString, - } + ) // Handle traffic that loops back to the originator with SNAT. writeLine(proxier.natRules, append(args, - "-s", fmt.Sprintf("%s/32", strings.Split(endpoints[i].endpoint, ":")[0]), + "-s", fmt.Sprintf("%s/32", endpoints[i].IPPart()), "-j", string(KubeMarkMasqChain))...) // Update client-affinity lists. if svcInfo.sessionAffinityType == api.ServiceAffinityClientIP { @@ -1402,42 +1484,42 @@ func (proxier *Proxier) syncProxyRules() { // Service's ClusterIP instead. This happens whether or not we have local // endpoints; only if clusterCIDR is specified if len(proxier.clusterCIDR) > 0 { - args = []string{ + args = append(args[:0], "-A", string(svcXlbChain), "-m", "comment", "--comment", - fmt.Sprintf(`"Redirect pods trying to reach external loadbalancer VIP to clusterIP"`), + `"Redirect pods trying to reach external loadbalancer VIP to clusterIP"`, "-s", proxier.clusterCIDR, "-j", string(svcChain), - } + ) writeLine(proxier.natRules, args...) } numLocalEndpoints := len(localEndpointChains) if numLocalEndpoints == 0 { // Blackhole all traffic since there are no local endpoints - args := []string{ + args = append(args[:0], "-A", string(svcXlbChain), "-m", "comment", "--comment", fmt.Sprintf(`"%s has no local endpoints"`, svcNameString), "-j", string(KubeMarkDropChain), - } + ) writeLine(proxier.natRules, args...) } else { // Setup probability filter rules only over local endpoints for i, endpointChain := range localEndpointChains { // Balancing rules in the per-service chain. - args := []string{ + args = append(args[:0], "-A", string(svcXlbChain), "-m", "comment", "--comment", fmt.Sprintf(`"Balancing rule %d for %s"`, i, svcNameString), - } + ) if i < (numLocalEndpoints - 1) { // Each rule is a probabilistic match. args = append(args, "-m", "statistic", "--mode", "random", - "--probability", fmt.Sprintf("%0.5f", 1.0/float64(numLocalEndpoints-i))) + "--probability", proxier.probability(numLocalEndpoints-i)) } // The final (or only if n == 1) rule is a guaranteed match. args = append(args, "-j", string(endpointChain)) diff --git a/pkg/proxy/iptables/proxier_test.go b/pkg/proxy/iptables/proxier_test.go index 33f2386c467..989c244776e 100644 --- a/pkg/proxy/iptables/proxier_test.go +++ b/pkg/proxy/iptables/proxier_test.go @@ -386,22 +386,23 @@ func NewFakeProxier(ipt utiliptables.Interface) *Proxier { // TODO: Call NewProxier after refactoring out the goroutine // invocation into a Run() method. p := &Proxier{ - exec: &exec.FakeExec{}, - serviceMap: make(proxyServiceMap), - serviceChanges: newServiceChangeMap(), - endpointsMap: make(proxyEndpointsMap), - endpointsChanges: newEndpointsChangeMap(testHostname), - iptables: ipt, - clusterCIDR: "10.0.0.0/24", - hostname: testHostname, - portsMap: make(map[localPort]closeable), - portMapper: &fakePortOpener{[]*localPort{}}, - healthChecker: newFakeHealthChecker(), - iptablesData: bytes.NewBuffer(nil), - filterChains: bytes.NewBuffer(nil), - filterRules: bytes.NewBuffer(nil), - natChains: bytes.NewBuffer(nil), - natRules: bytes.NewBuffer(nil), + exec: &exec.FakeExec{}, + serviceMap: make(proxyServiceMap), + serviceChanges: newServiceChangeMap(), + endpointsMap: make(proxyEndpointsMap), + endpointsChanges: newEndpointsChangeMap(testHostname), + iptables: ipt, + clusterCIDR: "10.0.0.0/24", + hostname: testHostname, + portsMap: make(map[localPort]closeable), + portMapper: &fakePortOpener{[]*localPort{}}, + healthChecker: newFakeHealthChecker(), + precomputedProbabilities: make([]string, 0, 1001), + iptablesData: bytes.NewBuffer(nil), + filterChains: bytes.NewBuffer(nil), + filterRules: bytes.NewBuffer(nil), + natChains: bytes.NewBuffer(nil), + natRules: bytes.NewBuffer(nil), } p.syncRunner = async.NewBoundedFrequencyRunner("test-sync-runner", p.syncProxyRules, 0, time.Minute, 1) return p @@ -1292,7 +1293,7 @@ func Test_getLocalIPs(t *testing.T) { // Case[1]: unnamed port endpointsMap: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, expected: map[types.NamespacedName]sets.String{}, @@ -1300,7 +1301,7 @@ func Test_getLocalIPs(t *testing.T) { // Case[2]: unnamed port local endpointsMap: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {"1.1.1.1:11", true}, + {endpoint: "1.1.1.1:11", isLocal: true}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -1310,12 +1311,12 @@ func Test_getLocalIPs(t *testing.T) { // Case[3]: named local and non-local ports for the same IP. endpointsMap: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, - {"1.1.1.2:11", true}, + {endpoint: "1.1.1.1:11", isLocal: false}, + {endpoint: "1.1.1.2:11", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.1:12", false}, - {"1.1.1.2:12", true}, + {endpoint: "1.1.1.1:12", isLocal: false}, + {endpoint: "1.1.1.2:12", isLocal: true}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -1325,21 +1326,21 @@ func Test_getLocalIPs(t *testing.T) { // Case[4]: named local and non-local ports for different IPs. endpointsMap: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, makeServicePortName("ns2", "ep2", "p22"): { - {"2.2.2.2:22", true}, - {"2.2.2.22:22", true}, + {endpoint: "2.2.2.2:22", isLocal: true}, + {endpoint: "2.2.2.22:22", isLocal: true}, }, makeServicePortName("ns2", "ep2", "p23"): { - {"2.2.2.3:23", true}, + {endpoint: "2.2.2.3:23", isLocal: true}, }, makeServicePortName("ns4", "ep4", "p44"): { - {"4.4.4.4:44", true}, - {"4.4.4.5:44", false}, + {endpoint: "4.4.4.4:44", isLocal: true}, + {endpoint: "4.4.4.5:44", isLocal: false}, }, makeServicePortName("ns4", "ep4", "p45"): { - {"4.4.4.6:45", true}, + {endpoint: "4.4.4.6:45", isLocal: true}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -1384,7 +1385,7 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }), expected: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, }, { @@ -1404,7 +1405,7 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }), expected: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "port"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, }, { @@ -1423,7 +1424,7 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }), expected: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, }, { @@ -1452,12 +1453,12 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }), expected: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p1"): { - {"1.1.1.1:11", false}, - {"2.2.2.2:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, + {endpoint: "2.2.2.2:11", isLocal: false}, }, makeServicePortName("ns1", "ep1", "p2"): { - {"1.1.1.1:22", false}, - {"2.2.2.2:22", false}, + {endpoint: "1.1.1.1:22", isLocal: false}, + {endpoint: "2.2.2.2:22", isLocal: false}, }, }, }, { @@ -1477,7 +1478,7 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }), expected: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p1"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, }, { @@ -1497,7 +1498,7 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }), expected: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p2"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, }, { @@ -1517,7 +1518,7 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }), expected: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p1"): { - {"1.1.1.1:22", false}, + {endpoint: "1.1.1.1:22", isLocal: false}, }, }, }} @@ -1931,12 +1932,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, expectedStale: []endpointServicePair{}, @@ -1951,12 +1952,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", true}, + {endpoint: "1.1.1.1:11", isLocal: true}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", true}, + {endpoint: "1.1.1.1:11", isLocal: true}, }, }, expectedStale: []endpointServicePair{}, @@ -1973,18 +1974,18 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.2:12", false}, + {endpoint: "1.1.1.2:12", isLocal: false}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.2:12", false}, + {endpoint: "1.1.1.2:12", isLocal: false}, }, }, expectedStale: []endpointServicePair{}, @@ -1999,24 +2000,24 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", true}, + {endpoint: "1.1.1.1:11", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.1:12", true}, + {endpoint: "1.1.1.1:12", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {"1.1.1.3:13", false}, + {endpoint: "1.1.1.3:13", isLocal: false}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", true}, + {endpoint: "1.1.1.1:11", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.1:12", true}, + {endpoint: "1.1.1.1:12", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {"1.1.1.3:13", false}, + {endpoint: "1.1.1.3:13", isLocal: false}, }, }, expectedStale: []endpointServicePair{}, @@ -2035,54 +2036,54 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, - {"1.1.1.2:11", true}, + {endpoint: "1.1.1.1:11", isLocal: false}, + {endpoint: "1.1.1.2:11", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.1:12", false}, - {"1.1.1.2:12", true}, + {endpoint: "1.1.1.1:12", isLocal: false}, + {endpoint: "1.1.1.2:12", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {"1.1.1.3:13", false}, - {"1.1.1.4:13", true}, + {endpoint: "1.1.1.3:13", isLocal: false}, + {endpoint: "1.1.1.4:13", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p14"): { - {"1.1.1.3:14", false}, - {"1.1.1.4:14", true}, + {endpoint: "1.1.1.3:14", isLocal: false}, + {endpoint: "1.1.1.4:14", isLocal: true}, }, makeServicePortName("ns2", "ep2", "p21"): { - {"2.2.2.1:21", false}, - {"2.2.2.2:21", true}, + {endpoint: "2.2.2.1:21", isLocal: false}, + {endpoint: "2.2.2.2:21", isLocal: true}, }, makeServicePortName("ns2", "ep2", "p22"): { - {"2.2.2.1:22", false}, - {"2.2.2.2:22", true}, + {endpoint: "2.2.2.1:22", isLocal: false}, + {endpoint: "2.2.2.2:22", isLocal: true}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, - {"1.1.1.2:11", true}, + {endpoint: "1.1.1.1:11", isLocal: false}, + {endpoint: "1.1.1.2:11", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.1:12", false}, - {"1.1.1.2:12", true}, + {endpoint: "1.1.1.1:12", isLocal: false}, + {endpoint: "1.1.1.2:12", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {"1.1.1.3:13", false}, - {"1.1.1.4:13", true}, + {endpoint: "1.1.1.3:13", isLocal: false}, + {endpoint: "1.1.1.4:13", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p14"): { - {"1.1.1.3:14", false}, - {"1.1.1.4:14", true}, + {endpoint: "1.1.1.3:14", isLocal: false}, + {endpoint: "1.1.1.4:14", isLocal: true}, }, makeServicePortName("ns2", "ep2", "p21"): { - {"2.2.2.1:21", false}, - {"2.2.2.2:21", true}, + {endpoint: "2.2.2.1:21", isLocal: false}, + {endpoint: "2.2.2.2:21", isLocal: true}, }, makeServicePortName("ns2", "ep2", "p22"): { - {"2.2.2.1:22", false}, - {"2.2.2.2:22", true}, + {endpoint: "2.2.2.1:22", isLocal: false}, + {endpoint: "2.2.2.2:22", isLocal: true}, }, }, expectedStale: []endpointServicePair{}, @@ -2101,7 +2102,7 @@ func Test_updateEndpointsMap(t *testing.T) { oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {"1.1.1.1:11", true}, + {endpoint: "1.1.1.1:11", isLocal: true}, }, }, expectedStale: []endpointServicePair{}, @@ -2118,7 +2119,7 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {"1.1.1.1:11", true}, + {endpoint: "1.1.1.1:11", isLocal: true}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, @@ -2137,17 +2138,17 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, - {"1.1.1.2:11", true}, + {endpoint: "1.1.1.1:11", isLocal: false}, + {endpoint: "1.1.1.2:11", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.1:12", false}, - {"1.1.1.2:12", true}, + {endpoint: "1.1.1.1:12", isLocal: false}, + {endpoint: "1.1.1.2:12", isLocal: true}, }, }, expectedStale: []endpointServicePair{}, @@ -2164,17 +2165,17 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, - {"1.1.1.2:11", true}, + {endpoint: "1.1.1.1:11", isLocal: false}, + {endpoint: "1.1.1.2:11", isLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.1:12", false}, - {"1.1.1.2:12", true}, + {endpoint: "1.1.1.1:12", isLocal: false}, + {endpoint: "1.1.1.2:12", isLocal: true}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, expectedStale: []endpointServicePair{{ @@ -2198,15 +2199,15 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.2:12", true}, + {endpoint: "1.1.1.2:12", isLocal: true}, }, }, expectedStale: []endpointServicePair{}, @@ -2223,15 +2224,15 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.2:12", false}, + {endpoint: "1.1.1.2:12", isLocal: false}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, expectedStale: []endpointServicePair{{ @@ -2249,12 +2250,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11-2"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, expectedStale: []endpointServicePair{{ @@ -2272,12 +2273,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:22", false}, + {endpoint: "1.1.1.1:22", isLocal: false}, }, }, expectedStale: []endpointServicePair{{ @@ -2301,39 +2302,39 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, }, makeServicePortName("ns2", "ep2", "p22"): { - {"2.2.2.2:22", true}, - {"2.2.2.22:22", true}, + {endpoint: "2.2.2.2:22", isLocal: true}, + {endpoint: "2.2.2.22:22", isLocal: true}, }, makeServicePortName("ns2", "ep2", "p23"): { - {"2.2.2.3:23", true}, + {endpoint: "2.2.2.3:23", isLocal: true}, }, makeServicePortName("ns4", "ep4", "p44"): { - {"4.4.4.4:44", true}, - {"4.4.4.5:44", true}, + {endpoint: "4.4.4.4:44", isLocal: true}, + {endpoint: "4.4.4.5:44", isLocal: true}, }, makeServicePortName("ns4", "ep4", "p45"): { - {"4.4.4.6:45", true}, + {endpoint: "4.4.4.6:45", isLocal: true}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {"1.1.1.1:11", false}, - {"1.1.1.11:11", false}, + {endpoint: "1.1.1.1:11", isLocal: false}, + {endpoint: "1.1.1.11:11", isLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {"1.1.1.2:12", false}, + {endpoint: "1.1.1.2:12", isLocal: false}, }, makeServicePortName("ns1", "ep1", "p122"): { - {"1.1.1.2:122", false}, + {endpoint: "1.1.1.2:122", isLocal: false}, }, makeServicePortName("ns3", "ep3", "p33"): { - {"3.3.3.3:33", false}, + {endpoint: "3.3.3.3:33", isLocal: false}, }, makeServicePortName("ns4", "ep4", "p44"): { - {"4.4.4.4:44", true}, + {endpoint: "4.4.4.4:44", isLocal: true}, }, }, expectedStale: []endpointServicePair{{ diff --git a/pkg/util/iptables/save_restore.go b/pkg/util/iptables/save_restore.go index 435a54bebd4..6f4eacacab0 100644 --- a/pkg/util/iptables/save_restore.go +++ b/pkg/util/iptables/save_restore.go @@ -52,7 +52,9 @@ func GetChainLines(table Table, save []byte) map[Chain]string { } else if strings.HasPrefix(line, "#") { continue } else if strings.HasPrefix(line, ":") && len(line) > 1 { - chain := Chain(strings.SplitN(line[1:], " ", 2)[0]) + // We assume that the contains space - chain lines have 3 fields, + // space delimited. If there is no space, this line will panic. + chain := Chain(line[1:strings.Index(line, " ")]) chainsMap[chain] = line } }