From bef49026e29040f0c197b3f267c4db991d09ba03 Mon Sep 17 00:00:00 2001 From: Alex O'Regan Date: Mon, 9 Feb 2026 12:39:46 +0000 Subject: [PATCH 1/5] splits maglev test into v4 and v6 runs --- e2e/pkg/tests/networking/maglev.go | 189 +++++++++++++++++------------ 1 file changed, 111 insertions(+), 78 deletions(-) diff --git a/e2e/pkg/tests/networking/maglev.go b/e2e/pkg/tests/networking/maglev.go index 3407410cfb1..97d321cbd86 100644 --- a/e2e/pkg/tests/networking/maglev.go +++ b/e2e/pkg/tests/networking/maglev.go @@ -54,6 +54,8 @@ var _ = describe.CalicoDescribe( describe.WithFeature("Maglev"), describe.WithCategory(describe.Networking), describe.WithExternalNode(), + describe.WithDataplane(describe.BPF), + describe.WithAWS(), "Maglev load balancing tests", func() { var ( @@ -104,82 +106,97 @@ var _ = describe.CalicoDescribe( framework.Logf("Node name to IPv6 mapping: %v", maglevTests.nodeNameToIPv6) }) - It("test service ip load balancing behavior before and after maglev annotation", func() { - // Ensure we have at least 3 nodes for the test - Expect(len(nodeNames)).Should(BeNumerically(">=", 3), "Need at least 3 nodes for this test") - - // Deploy 20 backend pods on node 1 (first node) - maglevTests.DeployBackendPods(20, []string{nodeNames[0]}) - // Deploy service "netexec" backed by the 20 pods - maglevTests.DeployService() - // Add route to external node where packets to service cluster IP go to node 2 - maglevTests.SetupExternalNodeClientRoutingToSpecificNode(extNode, nodeNames[1]) // node 2 (second node) - - // Test random backend selection without Maglev annotation for both IPv4 and IPv6 - maglevTests.TestRandomBackendSelection(extNode, false) // IPv4 test - maglevTests.TestRandomBackendSelection(extNode, true) // IPv6 test - - // Enable Maglev on the same service by adding annotation - maglevTests.EnableMaglev() - - // Set a fixed source port for consistent hashing tests - maglevTests.SetSourcePort(12345) - - // Test Maglev consistent hashing with the annotation for both IPv4 and IPv6 using first source port - backendViaNode2IPv4Port1 := maglevTests.TestMaglevConsistentHashing(extNode, false) // IPv4 test with port 12345 - backendViaNode2IPv6Port1 := maglevTests.TestMaglevConsistentHashing(extNode, true) // IPv6 test with port 12345 - - // Test Maglev consistent hashing with a different source port to verify different flows can hash to different backends - maglevTests.SetSourcePort(23456) // Change source port - backendViaNode2IPv4Port2 := maglevTests.TestMaglevConsistentHashing(extNode, false) // IPv4 test with port 23456 - backendViaNode2IPv6Port2 := maglevTests.TestMaglevConsistentHashing(extNode, true) // IPv6 test with port 23456 - framework.Logf("Maglev hashing with different source ports: IPv4 port 12345->%s, port 23456->%s; IPv6 port 12345->%s, port 23456->%s", - backendViaNode2IPv4Port1, backendViaNode2IPv4Port2, backendViaNode2IPv6Port1, backendViaNode2IPv6Port2) - - // Reset source port for next tests - maglevTests.SetSourcePort(12345) - - // Then: Remove the routes from external node to service cluster IPs via node 2 - maglevTests.RemoveExternalNodeClientRoutes(extNode, nodeNames[1]) - - // Add route to external node where packets to service cluster IP go to node 3 - maglevTests.SetupExternalNodeClientRoutingToSpecificNode(extNode, nodeNames[2]) // node 3 (third node) - - // Test Maglev consistent hashing again for both IPv4 and IPv6 via node 3 with first source port - backendViaNode3IPv4Port1 := maglevTests.TestMaglevConsistentHashing(extNode, false) // IPv4 test via node 3 with port 12345 - backendViaNode3IPv6Port1 := maglevTests.TestMaglevConsistentHashing(extNode, true) // IPv6 test via node 3 with port 12345 - - // Test Maglev consistent hashing via node 3 with a different source port - maglevTests.SetSourcePort(23456) // Change source port - backendViaNode3IPv4Port2 := maglevTests.TestMaglevConsistentHashing(extNode, false) // IPv4 test via node 3 with port 23456 - backendViaNode3IPv6Port2 := maglevTests.TestMaglevConsistentHashing(extNode, true) // IPv6 test via node 3 with port 23456 - framework.Logf("Maglev hashing via node 3 with different source ports: IPv4 port 12345->%s, port 23456->%s; IPv6 port 12345->%s, port 23456->%s", - backendViaNode3IPv4Port1, backendViaNode3IPv4Port2, backendViaNode3IPv6Port1, backendViaNode3IPv6Port2) - - // Reset source port - maglevTests.SetSourcePort(12345) - - // Assert that the backend selected via node 3 is the same as that selected via node 2 (for same source port) - Expect(backendViaNode3IPv4Port1).Should(Equal(backendViaNode2IPv4Port1), - fmt.Sprintf("Expected IPv4 backend selection to be consistent across nodes: node 2 selected %s, node 3 selected %s", - backendViaNode2IPv4Port1, backendViaNode3IPv4Port1)) - - Expect(backendViaNode3IPv6Port1).Should(Equal(backendViaNode2IPv6Port1), - fmt.Sprintf("Expected IPv6 backend selection to be consistent across nodes: node 2 selected %s, node 3 selected %s", - backendViaNode2IPv6Port1, backendViaNode3IPv6Port1)) - - // Also verify that the second source port routes to the same backend across nodes - Expect(backendViaNode3IPv4Port2).Should(Equal(backendViaNode2IPv4Port2), - fmt.Sprintf("Expected IPv4 backend selection (port 23456) to be consistent across nodes: node 2 selected %s, node 3 selected %s", - backendViaNode2IPv4Port2, backendViaNode3IPv4Port2)) - - Expect(backendViaNode3IPv6Port2).Should(Equal(backendViaNode2IPv6Port2), - fmt.Sprintf("Expected IPv6 backend selection (port 23456) to be consistent across nodes: node 2 selected %s, node 3 selected %s", - backendViaNode2IPv6Port2, backendViaNode3IPv6Port2)) - - framework.Logf("Maglev cross-node consistency verified for both source ports: IPv4 port 12345->%s, port 23456->%s; IPv6 port 12345->%s, port 23456->%s", - backendViaNode2IPv4Port1, backendViaNode2IPv4Port2, backendViaNode2IPv6Port1, backendViaNode2IPv6Port2) - }) + makeMaglevTest := func(isIPv6 bool) func() { + + ipVer := "IPv4" + if isIPv6 { + ipVer = "IPv6" + } + return func() { + if isIPv6 { + if len(maglevTests.nodeNameToIPv6) == 0 { + Skip("IPv6 is not configured, skipping IPv6 Maglev test") + } + } else { + if len(maglevTests.nodeNameToIPv4) == 0 { + Skip("IPv4 is not configured, skipping IPv4 Maglev test") + } + } + // Ensure we have at least 3 nodes for the test + Expect(len(nodeNames)).Should(BeNumerically(">=", 3), "Need at least 3 nodes for this test") + + // Deploy 20 backend pods on node 1 (first node) + maglevTests.DeployBackendPods(20, []string{nodeNames[0]}) + // Deploy service "netexec" backed by the 20 pods + maglevTests.DeployService() + // Add route to external node where packets to service cluster IP go to node 2 + maglevTests.SetupExternalNodeClientRoutingToSpecificNode(extNode, nodeNames[1]) // node 2 (second node) + + // Test random backend selection without Maglev annotation for both IPv4 and IPv6 + maglevTests.TestRandomBackendSelection(extNode, isIPv6) // IPv4 test + + // Enable Maglev on the same service by adding annotation + maglevTests.EnableMaglev() + + // Set a fixed source port for consistent hashing tests + maglevTests.SetSourcePort(12345) + + // Test Maglev consistent hashing with the annotation for both IPv4 and IPv6 using first source port + backendViaNode2Port1 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // IPv4 test with port 12345 + + // Test Maglev consistent hashing with a different source port to verify different flows can hash to different backends + maglevTests.SetSourcePort(23456) // Change source port + backendViaNode2Port2 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // IPv4 test with port 23456 + framework.Logf("Maglev hashing with different source ports: %s port 12345->%s, port 23456->%s", + ipVer, backendViaNode2Port1, backendViaNode2Port2) + + // Reset source port for next tests + maglevTests.SetSourcePort(12345) + + // Then: Remove the routes from external node to service cluster IPs via node 2 + maglevTests.RemoveExternalNodeClientRoutes(extNode, nodeNames[1]) + + // Add route to external node where packets to service cluster IP go to node 3 + maglevTests.SetupExternalNodeClientRoutingToSpecificNode(extNode, nodeNames[2]) // node 3 (third node) + + // Test Maglev consistent hashing again for both IPv4 and IPv6 via node 3 with first source port + backendViaNode3Port1 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // IPv4 test via node 3 with port 12345 + + // Test Maglev consistent hashing via node 3 with a different source port + maglevTests.SetSourcePort(23456) // Change source port + backendViaNode3Port2 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // IPv4 test via node 3 with port 23456 + framework.Logf("Maglev hashing via node 3 with different source ports: %s port 12345->%s, port 23456->%s", + ipVer, backendViaNode3Port1, backendViaNode3Port2) + + // Reset source port + maglevTests.SetSourcePort(12345) + + // Assert that the backend selected via node 3 is the same as that selected via node 2 (for same source port) + Expect(backendViaNode3Port1).Should(Equal(backendViaNode2Port1), + fmt.Sprintf("Expected IPv4 backend selection to be consistent across nodes: node 2 selected %s, node 3 selected %s", + backendViaNode2Port1, backendViaNode3Port1)) + + Expect(backendViaNode3Port1).Should(Equal(backendViaNode2Port1), + fmt.Sprintf("Expected IPv6 backend selection to be consistent across nodes: node 2 selected %s, node 3 selected %s", + backendViaNode2Port1, backendViaNode3Port1)) + + // Also verify that the second source port routes to the same backend across nodes + Expect(backendViaNode3Port2).Should(Equal(backendViaNode2Port2), + fmt.Sprintf("Expected IPv4 backend selection (port 23456) to be consistent across nodes: node 2 selected %s, node 3 selected %s", + backendViaNode2Port2, backendViaNode3Port2)) + + Expect(backendViaNode3Port2).Should(Equal(backendViaNode2Port2), + fmt.Sprintf("Expected IPv6 backend selection (port 23456) to be consistent across nodes: node 2 selected %s, node 3 selected %s", + backendViaNode2Port2, backendViaNode3Port2)) + + framework.Logf("Maglev cross-node consistency verified for both source ports: %s port 12345->%s, port 23456->%s", + ipVer, backendViaNode2Port1, backendViaNode2Port2) + } + } + + It("test service ip load balancing behavior before and after maglev annotation", makeMaglevTest(false)) + It("test service ip load balancing behavior before and after maglev annotation", makeMaglevTest(true)) + }) type MaglevTests struct { @@ -215,6 +232,22 @@ func NewMaglevTests(f *framework.Framework) *MaglevTests { } } +// IPFamilies returns a list of families compatible with this cluster's configuration - for use in service creation. +func (m *MaglevTests) IPFamilies() []v1.IPFamily { + families := make([]v1.IPFamily, 0) + if len(m.nodeNameToIPv4) > 0 { + framework.Logf("Found IPv4 node IPs; Adding IPv4Protocol to IPFamily list") + families = append(families, v1.IPv4Protocol) + } + + if len(m.nodeNameToIPv6) > 0 { + framework.Logf("Found IPv6 node IPs; Adding IPv6Protocol to IPFamily list") + families = append(families, v1.IPv6Protocol) + } + + return families +} + // parseBackendResponse parses the JSON response from netexec and returns the backend pod name func (m *MaglevTests) parseBackendResponse(output string) (string, error) { // NetexecResponse represents the JSON response from the netexec service @@ -304,7 +337,7 @@ func (m *MaglevTests) DeployBackendPods(numPods int, nodes []string) { } func (m *MaglevTests) DeployService() { - By("deploying dual-stack service") + By("deploying service") service := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ @@ -313,7 +346,7 @@ func (m *MaglevTests) DeployService() { }, Spec: v1.ServiceSpec{ Type: v1.ServiceTypeClusterIP, - IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}, + IPFamilies: m.IPFamilies(), IPFamilyPolicy: ptr.To(v1.IPFamilyPolicyPreferDualStack), Selector: map[string]string{ "app": "netexec", From 685bc73a370fa9eab2588f417cce5b50df435441 Mon Sep 17 00:00:00 2001 From: Alex O'Regan Date: Mon, 9 Feb 2026 13:20:24 +0000 Subject: [PATCH 2/5] update Maglev e2e comments to be ip-version-agnostic --- e2e/pkg/tests/networking/maglev.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/e2e/pkg/tests/networking/maglev.go b/e2e/pkg/tests/networking/maglev.go index 97d321cbd86..25484f8c57a 100644 --- a/e2e/pkg/tests/networking/maglev.go +++ b/e2e/pkg/tests/networking/maglev.go @@ -132,8 +132,8 @@ var _ = describe.CalicoDescribe( // Add route to external node where packets to service cluster IP go to node 2 maglevTests.SetupExternalNodeClientRoutingToSpecificNode(extNode, nodeNames[1]) // node 2 (second node) - // Test random backend selection without Maglev annotation for both IPv4 and IPv6 - maglevTests.TestRandomBackendSelection(extNode, isIPv6) // IPv4 test + // Test random backend selection without Maglev annotation + maglevTests.TestRandomBackendSelection(extNode, isIPv6) // Enable Maglev on the same service by adding annotation maglevTests.EnableMaglev() @@ -141,12 +141,12 @@ var _ = describe.CalicoDescribe( // Set a fixed source port for consistent hashing tests maglevTests.SetSourcePort(12345) - // Test Maglev consistent hashing with the annotation for both IPv4 and IPv6 using first source port - backendViaNode2Port1 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // IPv4 test with port 12345 + // Test Maglev consistent hashing with the annotation using first source port + backendViaNode2Port1 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // test with port 12345 // Test Maglev consistent hashing with a different source port to verify different flows can hash to different backends maglevTests.SetSourcePort(23456) // Change source port - backendViaNode2Port2 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // IPv4 test with port 23456 + backendViaNode2Port2 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // test with port 23456 framework.Logf("Maglev hashing with different source ports: %s port 12345->%s, port 23456->%s", ipVer, backendViaNode2Port1, backendViaNode2Port2) @@ -159,12 +159,12 @@ var _ = describe.CalicoDescribe( // Add route to external node where packets to service cluster IP go to node 3 maglevTests.SetupExternalNodeClientRoutingToSpecificNode(extNode, nodeNames[2]) // node 3 (third node) - // Test Maglev consistent hashing again for both IPv4 and IPv6 via node 3 with first source port - backendViaNode3Port1 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // IPv4 test via node 3 with port 12345 + // Test Maglev consistent hashing again via node 3 with first source port + backendViaNode3Port1 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // test via node 3 with port 12345 // Test Maglev consistent hashing via node 3 with a different source port maglevTests.SetSourcePort(23456) // Change source port - backendViaNode3Port2 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // IPv4 test via node 3 with port 23456 + backendViaNode3Port2 := maglevTests.TestMaglevConsistentHashing(extNode, isIPv6) // test via node 3 with port 23456 framework.Logf("Maglev hashing via node 3 with different source ports: %s port 12345->%s, port 23456->%s", ipVer, backendViaNode3Port1, backendViaNode3Port2) From 48343f6044834c3965994a96b9a52682744ff829 Mon Sep 17 00:00:00 2001 From: Alex O'Regan Date: Mon, 9 Feb 2026 13:20:49 +0000 Subject: [PATCH 3/5] update an e2e-describe method comment --- e2e/pkg/describe/describe.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/pkg/describe/describe.go b/e2e/pkg/describe/describe.go index bd4179140a0..84fee03c65a 100644 --- a/e2e/pkg/describe/describe.go +++ b/e2e/pkg/describe/describe.go @@ -97,7 +97,7 @@ func WithAzure() any { return framework.WithLabel("RunsOnAzure") } -// WithAzure marks tests that must run on AWS. +// WithAWS marks tests that must run on AWS. func WithAWS() any { return framework.WithLabel("RunsOnAWS") } From 05c53cd90839e9c1437963c18afbc3517aa1989b Mon Sep 17 00:00:00 2001 From: Alex O Regan Date: Mon, 9 Feb 2026 13:21:22 +0000 Subject: [PATCH 4/5] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- e2e/pkg/tests/networking/maglev.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/pkg/tests/networking/maglev.go b/e2e/pkg/tests/networking/maglev.go index 25484f8c57a..9bc45aa21bc 100644 --- a/e2e/pkg/tests/networking/maglev.go +++ b/e2e/pkg/tests/networking/maglev.go @@ -194,8 +194,8 @@ var _ = describe.CalicoDescribe( } } - It("test service ip load balancing behavior before and after maglev annotation", makeMaglevTest(false)) - It("test service ip load balancing behavior before and after maglev annotation", makeMaglevTest(true)) + It("test service ip load balancing behavior before and after maglev annotation (IPv4)", makeMaglevTest(false)) + It("test service ip load balancing behavior before and after maglev annotation (IPv6)", makeMaglevTest(true)) }) From e20c8f30484a81469cae8c9bbcab4e470a834db0 Mon Sep 17 00:00:00 2001 From: Alex O'Regan Date: Mon, 9 Feb 2026 13:25:23 +0000 Subject: [PATCH 5/5] de-dupe checks after removing ip-version --- e2e/pkg/tests/networking/maglev.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/e2e/pkg/tests/networking/maglev.go b/e2e/pkg/tests/networking/maglev.go index 9bc45aa21bc..691616c6346 100644 --- a/e2e/pkg/tests/networking/maglev.go +++ b/e2e/pkg/tests/networking/maglev.go @@ -173,20 +173,12 @@ var _ = describe.CalicoDescribe( // Assert that the backend selected via node 3 is the same as that selected via node 2 (for same source port) Expect(backendViaNode3Port1).Should(Equal(backendViaNode2Port1), - fmt.Sprintf("Expected IPv4 backend selection to be consistent across nodes: node 2 selected %s, node 3 selected %s", - backendViaNode2Port1, backendViaNode3Port1)) - - Expect(backendViaNode3Port1).Should(Equal(backendViaNode2Port1), - fmt.Sprintf("Expected IPv6 backend selection to be consistent across nodes: node 2 selected %s, node 3 selected %s", + fmt.Sprintf("Expected backend selection to be consistent across nodes: node 2 selected %s, node 3 selected %s", backendViaNode2Port1, backendViaNode3Port1)) // Also verify that the second source port routes to the same backend across nodes Expect(backendViaNode3Port2).Should(Equal(backendViaNode2Port2), - fmt.Sprintf("Expected IPv4 backend selection (port 23456) to be consistent across nodes: node 2 selected %s, node 3 selected %s", - backendViaNode2Port2, backendViaNode3Port2)) - - Expect(backendViaNode3Port2).Should(Equal(backendViaNode2Port2), - fmt.Sprintf("Expected IPv6 backend selection (port 23456) to be consistent across nodes: node 2 selected %s, node 3 selected %s", + fmt.Sprintf("Expected backend selection (port 23456) to be consistent across nodes: node 2 selected %s, node 3 selected %s", backendViaNode2Port2, backendViaNode3Port2)) framework.Logf("Maglev cross-node consistency verified for both source ports: %s port 12345->%s, port 23456->%s",