diff --git a/pkg/proxy/service.go b/pkg/proxy/service.go index 1f84f0bcd1d..1ffa982f327 100644 --- a/pkg/proxy/service.go +++ b/pkg/proxy/service.go @@ -213,7 +213,19 @@ func (sct *ServiceChangeTracker) newBaseServiceInfo(port *v1.ServicePort, servic if ing.IP == "" { continue } - if ipFamily := proxyutil.GetIPFamilyFromIP(ing.IP); ipFamily == sct.ipFamily && proxyutil.IsVIPMode(ing) { + + // proxy mode load balancers do not need to track the IPs in the service cache + // and they can also implement IP family translation, so no need to check if + // the status ingress.IP and the ClusterIP belong to the same family. + if !proxyutil.IsVIPMode(ing) { + klog.V(4).InfoS("Service change tracker ignored the following load balancer ingress IP for given Service as it using Proxy mode", + "ipFamily", sct.ipFamily, "loadBalancerIngressIP", ing.IP, "service", klog.KObj(service)) + continue + } + + // kube-proxy does not implement IP family translation, skip addresses with + // different IP family + if ipFamily := proxyutil.GetIPFamilyFromIP(ing.IP); ipFamily == sct.ipFamily { info.loadBalancerVIPs = append(info.loadBalancerVIPs, ing.IP) } else { invalidIPs = append(invalidIPs, ing.IP) diff --git a/pkg/proxy/service_test.go b/pkg/proxy/service_test.go index f8bd9110f8b..e8d93f2b597 100644 --- a/pkg/proxy/service_test.go +++ b/pkg/proxy/service_test.go @@ -27,6 +27,9 @@ import ( "k8s.io/apimachinery/pkg/util/dump" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/sets" + utilfeature "k8s.io/apiserver/pkg/util/feature" + featuregatetesting "k8s.io/component-base/featuregate/testing" + "k8s.io/kubernetes/pkg/features" netutils "k8s.io/utils/net" ) @@ -91,12 +94,15 @@ func TestServiceToServiceMap(t *testing.T) { testClusterIPv6 := "2001:db8:85a3:0:0:8a2e:370:7334" testExternalIPv6 := "2001:db8:85a3:0:0:8a2e:370:7335" testSourceRangeIPv6 := "2001:db8::/32" + ipModeVIP := v1.LoadBalancerIPModeVIP + ipModeProxy := v1.LoadBalancerIPModeProxy testCases := []struct { - desc string - service *v1.Service - expected map[ServicePortName]*BaseServicePortInfo - ipFamily v1.IPFamily + desc string + service *v1.Service + expected map[ServicePortName]*BaseServicePortInfo + ipFamily v1.IPFamily + ipModeEnabled bool }{ { desc: "nothing", @@ -188,6 +194,90 @@ func TestServiceToServiceMap(t *testing.T) { }), }, }, + { + desc: "load balancer service ipMode VIP feature gate disable", + ipFamily: v1.IPv4Protocol, + + service: makeTestService("ns1", "load-balancer", func(svc *v1.Service) { + svc.Spec.Type = v1.ServiceTypeLoadBalancer + svc.Spec.ClusterIP = "172.16.55.11" + svc.Spec.LoadBalancerIP = "5.6.7.8" + svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000) + svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001) + svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.1.2.4", IPMode: &ipModeVIP}} + }), + expected: map[ServicePortName]*BaseServicePortInfo{ + makeServicePortName("ns1", "load-balancer", "port3", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) { + bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"} + }), + makeServicePortName("ns1", "load-balancer", "port4", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) { + bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"} + }), + }, + }, + { + desc: "load balancer service ipMode Proxy feature gate disable", + ipFamily: v1.IPv4Protocol, + + service: makeTestService("ns1", "load-balancer", func(svc *v1.Service) { + svc.Spec.Type = v1.ServiceTypeLoadBalancer + svc.Spec.ClusterIP = "172.16.55.11" + svc.Spec.LoadBalancerIP = "5.6.7.8" + svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000) + svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001) + svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.1.2.4", IPMode: &ipModeProxy}} + }), + expected: map[ServicePortName]*BaseServicePortInfo{ + makeServicePortName("ns1", "load-balancer", "port3", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) { + bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"} + }), + makeServicePortName("ns1", "load-balancer", "port4", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) { + bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"} + }), + }, + }, + { + desc: "load balancer service ipMode VIP feature gate enabled", + ipFamily: v1.IPv4Protocol, + ipModeEnabled: true, + + service: makeTestService("ns1", "load-balancer", func(svc *v1.Service) { + svc.Spec.Type = v1.ServiceTypeLoadBalancer + svc.Spec.ClusterIP = "172.16.55.11" + svc.Spec.LoadBalancerIP = "5.6.7.8" + svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000) + svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001) + svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.1.2.4", IPMode: &ipModeVIP}} + }), + expected: map[ServicePortName]*BaseServicePortInfo{ + makeServicePortName("ns1", "load-balancer", "port3", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) { + bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"} + }), + makeServicePortName("ns1", "load-balancer", "port4", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) { + bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"} + }), + }, + }, + { + desc: "load balancer service ipMode Proxy feature gate enabled", + ipFamily: v1.IPv4Protocol, + ipModeEnabled: true, + + service: makeTestService("ns1", "load-balancer", func(svc *v1.Service) { + svc.Spec.Type = v1.ServiceTypeLoadBalancer + svc.Spec.ClusterIP = "172.16.55.11" + svc.Spec.LoadBalancerIP = "5.6.7.8" + svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000) + svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001) + svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.1.2.4", IPMode: &ipModeProxy}} + }), + expected: map[ServicePortName]*BaseServicePortInfo{ + makeServicePortName("ns1", "load-balancer", "port3", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) { + }), + makeServicePortName("ns1", "load-balancer", "port4", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) { + }), + }, + }, { desc: "load balancer service with only local traffic policy", ipFamily: v1.IPv4Protocol, @@ -464,6 +554,7 @@ func TestServiceToServiceMap(t *testing.T) { for _, tc := range testCases { t.Run(tc.desc, func(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LoadBalancerIPMode, tc.ipModeEnabled)() svcTracker := NewServiceChangeTracker(nil, tc.ipFamily, nil, nil) // outputs newServices := svcTracker.serviceToServiceMap(tc.service)