diff --git a/go-controller/pkg/allocator/pod/pod_annotation_test.go b/go-controller/pkg/allocator/pod/pod_annotation_test.go index 8929cd1efd..5dfcd58e0f 100644 --- a/go-controller/pkg/allocator/pod/pod_annotation_test.go +++ b/go-controller/pkg/allocator/pod/pod_annotation_test.go @@ -183,6 +183,13 @@ func Test_allocatePodAnnotationWithRollback(t *testing.T) { MAC: util.IPAddrToHWAddr(ovntest.MustParseIPNets("192.168.0.3/24")[0].IP), Gateways: []net.IP{ovntest.MustParseIP("192.168.0.1").To4()}, Routes: []util.PodRoute{ + { + Dest: &net.IPNet{ + IP: ovntest.MustParseIP("169.254.169.5"), + Mask: net.CIDRMask(32, 32), + }, + NextHop: ovntest.MustParseIP("192.168.0.1").To4(), + }, { Dest: ovntest.MustParseIPNet("100.64.0.0/16"), NextHop: ovntest.MustParseIP("192.168.0.1").To4(), @@ -264,6 +271,13 @@ func Test_allocatePodAnnotationWithRollback(t *testing.T) { MAC: util.IPAddrToHWAddr(ovntest.MustParseIPNets("192.168.0.4/24")[0].IP), Gateways: []net.IP{ovntest.MustParseIP("192.168.0.1").To4()}, Routes: []util.PodRoute{ + { + Dest: &net.IPNet{ + IP: ovntest.MustParseIP("169.254.169.5"), + Mask: net.CIDRMask(32, 32), + }, + NextHop: ovntest.MustParseIP("192.168.0.1").To4(), + }, { Dest: ovntest.MustParseIPNet("100.64.0.0/16"), NextHop: ovntest.MustParseIP("192.168.0.1").To4(), @@ -293,6 +307,13 @@ func Test_allocatePodAnnotationWithRollback(t *testing.T) { MAC: util.IPAddrToHWAddr(ovntest.MustParseIPNets("192.168.0.4/24")[0].IP), Gateways: []net.IP{ovntest.MustParseIP("192.168.0.1").To4()}, Routes: []util.PodRoute{ + { + Dest: &net.IPNet{ + IP: ovntest.MustParseIP("169.254.169.5"), + Mask: net.CIDRMask(32, 32), + }, + NextHop: ovntest.MustParseIP("192.168.0.1").To4(), + }, { Dest: ovntest.MustParseIPNet("100.64.0.0/16"), NextHop: ovntest.MustParseIP("192.168.0.1").To4(), @@ -321,6 +342,13 @@ func Test_allocatePodAnnotationWithRollback(t *testing.T) { MAC: util.IPAddrToHWAddr(ovntest.MustParseIPNets("192.168.0.3/24")[0].IP), Gateways: []net.IP{ovntest.MustParseIP("192.168.0.1").To4()}, Routes: []util.PodRoute{ + { + Dest: &net.IPNet{ + IP: ovntest.MustParseIP("169.254.169.5"), + Mask: net.CIDRMask(32, 32), + }, + NextHop: ovntest.MustParseIP("192.168.0.1").To4(), + }, { Dest: ovntest.MustParseIPNet("100.64.0.0/16"), NextHop: ovntest.MustParseIP("192.168.0.1").To4(), @@ -377,6 +405,13 @@ func Test_allocatePodAnnotationWithRollback(t *testing.T) { MAC: requestedMACParsed, Gateways: []net.IP{ovntest.MustParseIP("192.168.0.1").To4()}, Routes: []util.PodRoute{ + { + Dest: &net.IPNet{ + IP: ovntest.MustParseIP("169.254.169.5"), + Mask: net.CIDRMask(32, 32), + }, + NextHop: ovntest.MustParseIP("192.168.0.1").To4(), + }, { Dest: ovntest.MustParseIPNet("100.64.0.0/16"), NextHop: ovntest.MustParseIP("192.168.0.1").To4(), diff --git a/go-controller/pkg/ovn/pods_test.go b/go-controller/pkg/ovn/pods_test.go index 6246bde376..2409d71cba 100644 --- a/go-controller/pkg/ovn/pods_test.go +++ b/go-controller/pkg/ovn/pods_test.go @@ -250,6 +250,13 @@ func newTPod(nodeName, nodeSubnet, nodeMgtIP, nodeGWIP, podName, podIPs, podMAC, routeSources = append(routeSources, sc) } } + hairpinMasqueradeIP := config.Gateway.MasqueradeIPs.V4OVNServiceHairpinMasqueradeIP.String() + mask := 32 + if isIPv6 { + hairpinMasqueradeIP = config.Gateway.MasqueradeIPs.V6OVNServiceHairpinMasqueradeIP.String() + mask = 128 + } + routeSources = append(routeSources, ovntest.MustParseIPNet(fmt.Sprintf("%s/%d", hairpinMasqueradeIP, mask))) joinNet := config.Gateway.V4JoinSubnet if isIPv6 { joinNet = config.Gateway.V6JoinSubnet diff --git a/go-controller/pkg/util/pod_annotation.go b/go-controller/pkg/util/pod_annotation.go index a396942645..91caa23070 100644 --- a/go-controller/pkg/util/pod_annotation.go +++ b/go-controller/pkg/util/pod_annotation.go @@ -441,6 +441,33 @@ func joinSubnetToRoute(isIPv6 bool, gatewayIP net.IP) PodRoute { } } +func serviceCIDRToRoute(isIPv6 bool, gatewayIP net.IP) []PodRoute { + var podRoutes []PodRoute + for _, serviceSubnet := range config.Kubernetes.ServiceCIDRs { + if isIPv6 == utilnet.IsIPv6CIDR(serviceSubnet) { + podRoutes = append(podRoutes, PodRoute{ + Dest: serviceSubnet, + NextHop: gatewayIP, + }) + } + } + return podRoutes +} + +func hairpinMasqueradeIPToRoute(isIPv6 bool, gatewayIP net.IP) PodRoute { + ip := config.Gateway.MasqueradeIPs.V4OVNServiceHairpinMasqueradeIP + if isIPv6 { + ip = config.Gateway.MasqueradeIPs.V6OVNServiceHairpinMasqueradeIP + } + return PodRoute{ + Dest: &net.IPNet{ + IP: ip, + Mask: GetIPFullMask(ip), + }, + NextHop: gatewayIP, + } +} + // addRoutesGatewayIP updates the provided pod annotation for the provided pod // with the gateways derived from the allocated IPs func AddRoutesGatewayIP( @@ -523,15 +550,9 @@ func AddRoutesGatewayIP( } // Ensure default service network traffic always goes to OVN - for _, serviceSubnet := range config.Kubernetes.ServiceCIDRs { - if isIPv6 == utilnet.IsIPv6CIDR(serviceSubnet) { - podAnnotation.Routes = append(podAnnotation.Routes, PodRoute{ - Dest: serviceSubnet, - NextHop: gatewayIPnet.IP, - }) - } - } - + podAnnotation.Routes = append(podAnnotation.Routes, serviceCIDRToRoute(isIPv6, gatewayIPnet.IP)...) + // Ensure service hairpin masquerade traffic always goes to OVN + podAnnotation.Routes = append(podAnnotation.Routes, hairpinMasqueradeIPToRoute(isIPv6, gatewayIPnet.IP)) otherDefaultRoute := otherDefaultRouteV4 if isIPv6 { otherDefaultRoute = otherDefaultRouteV6