Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 448c951

Browse files
committedApr 3, 2025·
Add EgressIP route advertisement test
1. Tests for both IPv4 and IPv6 EgressIP 2. Tests for advertising EgressIP for the default network and UDN to the default VRF.
1 parent d2d90c1 commit 448c951

File tree

5 files changed

+370
-31
lines changed

5 files changed

+370
-31
lines changed
 

Diff for: ‎test/extended/networking/egressip.go

+24-19
Original file line numberDiff line numberDiff line change
@@ -742,35 +742,40 @@ func applyEgressIPObject(oc *exutil.CLI, cloudNetworkClientset cloudnetwork.Inte
742742
_, err := runOcWithRetry(oc.AsAdmin(), "apply", "-f", egressIPYamlPath)
743743
o.Expect(err).NotTo(o.HaveOccurred())
744744

745-
framework.Logf(fmt.Sprintf("Waiting for CloudPrivateIPConfig creation for a maximum of %d seconds", timeout))
746-
var exists bool
747-
var isAssigned bool
748-
o.Eventually(func() bool {
749-
for eip := range egressIPSet {
750-
exists, isAssigned, err = cloudPrivateIpConfigExists(oc, cloudNetworkClientset, eip)
751-
o.Expect(err).NotTo(o.HaveOccurred())
752-
if !exists {
753-
framework.Logf("CloudPrivateIPConfig for %s not found.", eip)
754-
return false
755-
}
756-
if !isAssigned {
757-
framework.Logf("CloudPrivateIPConfig for %s not assigned.", eip)
758-
return false
745+
if cloudNetworkClientset != nil {
746+
framework.Logf(fmt.Sprintf("Waiting for CloudPrivateIPConfig creation for a maximum of %d seconds", timeout))
747+
var exists bool
748+
var isAssigned bool
749+
o.Eventually(func() bool {
750+
for eip := range egressIPSet {
751+
exists, isAssigned, err = cloudPrivateIpConfigExists(oc, cloudNetworkClientset, eip)
752+
o.Expect(err).NotTo(o.HaveOccurred())
753+
if !exists {
754+
framework.Logf("CloudPrivateIPConfig for %s not found.", eip)
755+
return false
756+
}
757+
if !isAssigned {
758+
framework.Logf("CloudPrivateIPConfig for %s not assigned.", eip)
759+
return false
760+
}
759761
}
760-
}
761-
framework.Logf("CloudPrivateIPConfigs for %v found.", egressIPSet)
762-
return true
763-
}, time.Duration(timeout)*time.Second, 5*time.Second).Should(o.BeTrue())
762+
framework.Logf("CloudPrivateIPConfigs for %v found.", egressIPSet)
763+
return true
764+
}, time.Duration(timeout)*time.Second, 5*time.Second).Should(o.BeTrue())
765+
}
764766

765767
framework.Logf(fmt.Sprintf("Waiting for EgressIP addresses inside status of EgressIP CR %s for a maximum of %d seconds", egressIPObjectName, timeout))
766768
var hasIP bool
769+
var nodeName string
767770
o.Eventually(func() bool {
768771
for eip := range egressIPSet {
769-
hasIP, err = egressIPStatusHasIP(oc, egressIPObjectName, eip)
772+
hasIP, nodeName, err = egressIPStatusHasIP(oc, egressIPObjectName, eip)
770773
o.Expect(err).NotTo(o.HaveOccurred())
771774
if !hasIP {
772775
framework.Logf("EgressIP object %s does not have IP %s in its status field.", egressIPObjectName, eip)
773776
return false
777+
} else {
778+
egressIPSet[eip] = nodeName
774779
}
775780
}
776781
framework.Logf("Egress IP object %s does have all IPs for %v.", egressIPObjectName, egressIPSet)

Diff for: ‎test/extended/networking/egressip_helpers.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -1729,21 +1729,21 @@ func cloudPrivateIpConfigExists(oc *exutil.CLI, cloudNetworkClientset cloudnetwo
17291729
}
17301730

17311731
// egressIPStatusHasIP returns if a given ip was found in a given EgressIP object's status field.
1732-
func egressIPStatusHasIP(oc *exutil.CLI, egressIPObjectName string, ip string) (bool, error) {
1732+
func egressIPStatusHasIP(oc *exutil.CLI, egressIPObjectName string, ip string) (bool, string, error) {
17331733
eip, err := getEgressIP(oc, egressIPObjectName)
17341734
if err != nil {
17351735
if errors.IsNotFound(err) {
1736-
return false, nil
1736+
return false, "", nil
17371737
}
1738-
return false, fmt.Errorf("Error looking up EgressIP %s, err: %v", egressIPObjectName, err)
1738+
return false, "", fmt.Errorf("Error looking up EgressIP %s, err: %v", egressIPObjectName, err)
17391739
}
17401740
for _, egressIPStatusItem := range eip.Status.Items {
17411741
if egressIPStatusItem.EgressIP == ip {
1742-
return true, nil
1742+
return true, egressIPStatusItem.Node, nil
17431743
}
17441744
}
17451745

1746-
return false, nil
1746+
return false, "", nil
17471747
}
17481748

17491749
// sdnNamespaceAddEgressIP adds EgressIP <egressip> to netnamespace <namespace>.

Diff for: ‎test/extended/networking/route_advertisements.go

+313-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net"
99
"os"
1010
"regexp"
11+
"slices"
1112
"strings"
1213
"time"
1314

@@ -71,6 +72,7 @@ var _ = g.Describe("[sig-network][OCPFeatureGate:RouteAdvertisements][Feature:Ro
7172
workerNodesOrdered []corev1.Node
7273
workerNodesOrderedNames []string
7374
advertisedPodsNodes []string
75+
egressIPNodes []string
7476
externalNodeName string
7577
targetNamespace string
7678
snifferNamespace string
@@ -153,6 +155,7 @@ var _ = g.Describe("[sig-network][OCPFeatureGate:RouteAdvertisements][Feature:Ro
153155
o.Expect(len(workerNodesOrderedNames)).Should(o.BeNumerically(">", 1))
154156
externalNodeName = workerNodesOrderedNames[0]
155157
advertisedPodsNodes = workerNodesOrderedNames[1:]
158+
egressIPNodes = workerNodesOrderedNames[1:]
156159

157160
g.By("Creating a project for the prober pod")
158161
// Create a target project and assign source and target namespace
@@ -208,9 +211,8 @@ var _ = g.Describe("[sig-network][OCPFeatureGate:RouteAdvertisements][Feature:Ro
208211
spawnProberSendEgressIPTrafficCheckLogs(oc, snifferNamespace, probePodName, routeName, targetProtocol, v4ExternalIP, serverPort, numberOfRequestsToSend, numberOfRequestsToSend, packetSnifferDaemonSet, v4PodIPSet)
209212
}
210213
if clusterIPFamily == DualStack || clusterIPFamily == IPv6 {
211-
// [TODO] enable IPv6 test once OCPBUGS-52194 is fixed
212-
// g.By("sending to IPv6 external host")
213-
// spawnProberSendEgressIPTrafficCheckLogs(oc, snifferNamespace, probePodName, routeName, targetProtocol, v6ExternalIP, serverPort, numberOfRequestsToSend, numberOfRequestsToSend, packetSnifferDaemonSet, v6PodIPSet)
214+
g.By("sending to IPv6 external host")
215+
spawnProberSendEgressIPTrafficCheckLogs(oc, snifferNamespace, probePodName, routeName, targetProtocol, v6ExternalIP, serverPort, numberOfRequestsToSend, numberOfRequestsToSend, packetSnifferDaemonSet, v6PodIPSet)
214216
}
215217
})
216218

@@ -229,10 +231,10 @@ var _ = g.Describe("[sig-network][OCPFeatureGate:RouteAdvertisements][Feature:Ro
229231

230232
if clusterIPFamily == DualStack || clusterIPFamily == IPv6 {
231233
// [TODO] enable IPv6 test once OCPBUGS-52194 is fixed
232-
// g.By("checking the external host to pod traffic works for IPv6")
233-
// for podIP := range v6PodIPSet {
234-
// checkExternalResponse(oc, proberPod, podIP, v6ExternalIP, serverPort, packetSnifferDaemonSet, targetProtocol)
235-
// }
234+
g.By("checking the external host to pod traffic works for IPv6")
235+
for podIP := range v6PodIPSet {
236+
checkExternalResponse(oc, proberPod, podIP, v6ExternalIP, serverPort, packetSnifferDaemonSet, targetProtocol)
237+
}
236238
}
237239
})
238240
})
@@ -349,9 +351,313 @@ var _ = g.Describe("[sig-network][OCPFeatureGate:RouteAdvertisements][Feature:Ro
349351
}
350352
})
351353
})
354+
355+
g.Context("[EgressIP][apigroup:user.openshift.io][apigroup:security.openshift.io]", func() {
356+
var err error
357+
var egressIPYamlPath, egressIPObjectName string
358+
359+
g.BeforeEach(func() {
360+
egressIPYamlPath = tmpDirBGP + "/" + egressIPYaml
361+
362+
g.By("Setup packet sniffer at nodes")
363+
packetSnifferDaemonSet, err = setupPacketSniffer(oc, clientset, snifferNamespace, egressIPNodes, networkPlugin)
364+
o.Expect(err).NotTo(o.HaveOccurred())
365+
366+
g.By("Setting the EgressIP nodes as EgressIP assignable")
367+
for _, node := range egressIPNodes {
368+
_, err = runOcWithRetry(oc.AsAdmin(), "label", "node", node, "k8s.ovn.org/egress-assignable=")
369+
o.Expect(err).NotTo(o.HaveOccurred())
370+
}
371+
})
372+
373+
g.AfterEach(func() {
374+
g.By("Deleting the EgressIP object if it exists for OVN Kubernetes")
375+
if _, err := os.Stat(egressIPYamlPath); err == nil {
376+
_, _ = runOcWithRetry(oc.AsAdmin(), "delete", "-f", tmpDirBGP+"/"+egressIPYaml)
377+
}
378+
379+
g.By("Removing the EgressIP assignable annotation for OVN Kubernetes")
380+
for _, nodeName := range egressIPNodes {
381+
_, _ = runOcWithRetry(oc.AsAdmin(), "label", "node", nodeName, "k8s.ovn.org/egress-assignable-")
382+
}
383+
})
384+
385+
g.Context("Advertising egressIP for default network", func() {
386+
g.BeforeEach(func() {
387+
egressIPObjectName = targetNamespace
388+
389+
g.By("Turn on the BGP advertisement of EgressIPs")
390+
_, err = runOcWithRetry(oc.AsAdmin(), "patch", "ra", "default", "--type=merge", `-p={"spec":{"advertisements":["EgressIP","PodNetwork"]}}`)
391+
o.Expect(err).NotTo(o.HaveOccurred())
392+
393+
g.By("Ensure the RouteAdvertisements is accepted")
394+
waitForRouteAdvertisements(oc, "default")
395+
396+
g.By("Makes sure the FRR configuration is generated for each node")
397+
for _, nodeName := range workerNodesOrderedNames {
398+
frr, err := getGeneratedFrrConfigurationForNode(oc, nodeName, "default")
399+
o.Expect(err).NotTo(o.HaveOccurred())
400+
o.Expect(frr).NotTo(o.BeNil())
401+
}
402+
})
403+
404+
g.AfterEach(func() {
405+
g.By("Turn off the BGP advertisement of EgressIPs")
406+
_, err := runOcWithRetry(oc.AsAdmin(), "patch", "ra", "default", "--type=merge", `-p={"spec":{"advertisements":["PodNetwork"]}}`)
407+
o.Expect(err).NotTo(o.HaveOccurred())
408+
})
409+
410+
g.DescribeTable("pods should have the assigned EgressIPs and EgressIPs can be created, updated and deleted [apigroup:route.openshift.io]",
411+
func(ipFamily IPFamily, externalIP string) {
412+
if clusterIPFamily != ipFamily && clusterIPFamily != DualStack {
413+
skipper.Skipf("Skipping test for IPFamily: %s", ipFamily)
414+
return
415+
}
416+
g.By("Selecte EgressIP set for the test")
417+
egressIPSet, newEgressIPSet := getEgressIPSet(ipFamily, egressIPNodes)
418+
419+
g.By("Deploy the test pods")
420+
deployName, routeName, podList, err = setupTestDeployment(oc, clientset, targetNamespace, advertisedPodsNodes)
421+
o.Expect(err).NotTo(o.HaveOccurred())
422+
o.Expect(len(podList.Items)).To(o.Equal(len(advertisedPodsNodes)))
423+
424+
numberOfRequestsToSend := 10
425+
// Run this twice to make sure that repeated EgressIP creation, update and deletion works.
426+
for i := 0; i < 2; i++ {
427+
g.By("Creating the EgressIP object")
428+
ovnKubernetesCreateEgressIPObject(oc, egressIPYamlPath, egressIPObjectName, targetNamespace, "", egressIPSet)
429+
430+
g.By("Applying the EgressIP object")
431+
applyEgressIPObject(oc, nil, egressIPYamlPath, targetNamespace, egressIPSet, egressUpdateTimeout)
432+
433+
g.By("Makes sure the EgressIP is advertised by FRR")
434+
for eip, nodeName := range egressIPSet {
435+
o.Expect(nodeName).ShouldNot(o.BeEmpty())
436+
o.Eventually(func() bool {
437+
return isRouteToEgressIPPresent(oc, eip, "default", nodeName)
438+
}).WithTimeout(timeOut).WithPolling(interval).Should(o.BeTrue())
439+
}
440+
441+
g.By(fmt.Sprintf("Sending requests from prober and making sure that %d requests with search string and EgressIPs %v were seen", numberOfRequestsToSend, egressIPSet))
442+
spawnProberSendEgressIPTrafficCheckLogs(oc, snifferNamespace, probePodName, routeName, targetProtocol, externalIP, serverPort, numberOfRequestsToSend, numberOfRequestsToSend, packetSnifferDaemonSet, egressIPSet)
443+
444+
g.By("Updating the EgressIP object")
445+
ovnKubernetesCreateEgressIPObject(oc, egressIPYamlPath, egressIPObjectName, targetNamespace, "", newEgressIPSet)
446+
447+
g.By("Applying the updated EgressIP object")
448+
applyEgressIPObject(oc, nil, egressIPYamlPath, targetNamespace, newEgressIPSet, egressUpdateTimeout)
449+
450+
g.By("Makes sure the updated EgressIP is advertised by FRR ")
451+
for eip, nodeName := range newEgressIPSet {
452+
o.Expect(nodeName).ShouldNot(o.BeEmpty())
453+
o.Eventually(func() bool {
454+
return isRouteToEgressIPPresent(oc, eip, "default", nodeName)
455+
}).WithTimeout(timeOut).WithPolling(interval).Should(o.BeTrue())
456+
}
457+
458+
g.By(fmt.Sprintf("Sending requests from prober and making sure that %d requests with search string and updated EgressIPs %v were seen", numberOfRequestsToSend, newEgressIPSet))
459+
spawnProberSendEgressIPTrafficCheckLogs(oc, snifferNamespace, probePodName, routeName, targetProtocol, externalIP, serverPort, numberOfRequestsToSend, numberOfRequestsToSend, packetSnifferDaemonSet, newEgressIPSet)
460+
461+
g.By("Deleting the EgressIP object")
462+
// Use cascading foreground deletion to make sure that the EgressIP object and its dependencies are gone.
463+
_, err = runOcWithRetry(oc.AsAdmin(), "delete", "egressip", egressIPObjectName, "--cascade=foreground")
464+
o.Expect(err).NotTo(o.HaveOccurred())
465+
466+
g.By("Makes sure the EgressIP is not advertised by FRR")
467+
for eip, nodeName := range newEgressIPSet {
468+
o.Eventually(func() bool {
469+
return isRouteToEgressIPPresent(oc, eip, "default", nodeName)
470+
}).WithTimeout(timeOut).WithPolling(interval).Should(o.BeFalse())
471+
}
472+
473+
g.By(fmt.Sprintf("Sending requests from prober and making sure that %d requests with search string and EgressIPs %v were seen", 0, newEgressIPSet))
474+
spawnProberSendEgressIPTrafficCheckLogs(oc, snifferNamespace, probePodName, routeName, targetProtocol, externalIP, serverPort, numberOfRequestsToSend, 0, packetSnifferDaemonSet, newEgressIPSet)
475+
}
476+
},
477+
g.Entry("IPv4", IPv4, v4ExternalIP),
478+
g.Entry("IPv6", IPv6, v6ExternalIP),
479+
)
480+
})
481+
482+
g.Context("Advertising egressIP for user defined network", func() {
483+
g.BeforeEach(func() {
484+
g.By("Create a namespace with UDPN")
485+
ns, err := f.CreateNamespace(context.TODO(), f.BaseName, map[string]string{
486+
"e2e-framework": f.BaseName,
487+
RequiredUDNNamespaceLabel: "",
488+
})
489+
o.Expect(err).NotTo(o.HaveOccurred())
490+
err = udnWaitForOpenShift(oc, ns.Name)
491+
o.Expect(err).NotTo(o.HaveOccurred())
492+
targetNamespace = ns.Name
493+
f.Namespace = ns
494+
egressIPObjectName = targetNamespace
495+
496+
g.By("Creating a cluster user defined network")
497+
nc := &networkAttachmentConfigParams{
498+
name: cudnName,
499+
topology: "layer3",
500+
role: "primary",
501+
namespace: targetNamespace,
502+
}
503+
nc.cidr = correctCIDRFamily(oc, userDefinedNetworkIPv4Subnet, userDefinedNetworkIPv6Subnet)
504+
cudnManifest := generateClusterUserDefinedNetworkManifest(nc)
505+
cleanup, err := createManifest(targetNamespace, cudnManifest)
506+
507+
o.Expect(err).NotTo(o.HaveOccurred())
508+
o.Eventually(clusterUserDefinedNetworkReadyFunc(oc.AdminDynamicClient(), cudnName), 60*time.Second, time.Second).Should(o.Succeed())
509+
g.By("Labeling the UDN for advertisement")
510+
_, err = runOcWithRetry(oc.AsAdmin(), "label", "clusteruserdefinednetworks", "-n", targetNamespace, cudnName, "advertise=true")
511+
o.Expect(err).NotTo(o.HaveOccurred())
512+
513+
g.By("Create the route advertisement for UDN")
514+
raManifest := newRouteAdvertisementsManifest(cudnName, true, true)
515+
err = applyManifest(targetNamespace, raManifest)
516+
o.Expect(err).NotTo(o.HaveOccurred())
517+
518+
g.By("Ensure the RouteAdvertisements is accepted")
519+
waitForRouteAdvertisements(oc, cudnName)
520+
521+
g.DeferCleanup(func() {
522+
runOcWithRetry(oc.AsAdmin(), "delete", "deploy", deployName)
523+
runOcWithRetry(oc.AsAdmin(), "delete", "ra", cudnName)
524+
runOcWithRetry(oc.AsAdmin(), "delete", "pod", "--all")
525+
runOcWithRetry(oc.AsAdmin(), "delete", "clusteruserdefinednetwork", cudnName)
526+
cleanup()
527+
})
528+
})
529+
530+
g.AfterEach(func() {
531+
})
532+
533+
g.DescribeTable("UDN pods should have the assigned EgressIPs and EgressIPs can be created, updated and deleted [apigroup:route.openshift.io]",
534+
func(ipFamily IPFamily, externalIP string) {
535+
if clusterIPFamily != ipFamily && clusterIPFamily != DualStack {
536+
skipper.Skipf("Skipping test for IPFamily: %s", ipFamily)
537+
return
538+
}
539+
540+
g.By("Selecte EgressIP set for the test")
541+
egressIPSet, newEgressIPSet := getEgressIPSet(ipFamily, egressIPNodes)
542+
543+
g.By("Deploy the test pods")
544+
deployName, routeName, podList, err = setupTestDeployment(oc, clientset, targetNamespace, advertisedPodsNodes)
545+
o.Expect(err).NotTo(o.HaveOccurred())
546+
o.Expect(len(podList.Items)).To(o.Equal(len(advertisedPodsNodes)))
547+
548+
numberOfRequestsToSend := 10
549+
// Run this twice to make sure that repeated EgressIP creation and deletion works.
550+
for i := 0; i < 2; i++ {
551+
g.By("Creating the EgressIP object")
552+
ovnKubernetesCreateEgressIPObject(oc, egressIPYamlPath, egressIPObjectName, targetNamespace, "", egressIPSet)
553+
554+
g.By("Applying the EgressIP object")
555+
applyEgressIPObject(oc, nil, egressIPYamlPath, targetNamespace, egressIPSet, egressUpdateTimeout)
556+
557+
g.By("Makes sure the EgressIP is advertised by FRR")
558+
for eip, nodeName := range egressIPSet {
559+
o.Expect(nodeName).ShouldNot(o.BeEmpty())
560+
o.Eventually(func() bool {
561+
return isRouteToEgressIPPresent(oc, eip, cudnName, nodeName)
562+
}).WithTimeout(timeOut).WithPolling(interval).Should(o.BeTrue())
563+
}
564+
565+
svcUrl := fmt.Sprintf("%s-0-service:%d", targetNamespace, serverPort)
566+
g.By(fmt.Sprintf("Sending requests from prober and making sure that %d requests with search string and EgressIPs %v were seen", numberOfRequestsToSend, egressIPSet))
567+
spawnProberSendEgressIPTrafficCheckLogs(oc, targetNamespace, probePodName, svcUrl, targetProtocol, externalIP, serverPort, numberOfRequestsToSend, numberOfRequestsToSend, packetSnifferDaemonSet, egressIPSet)
568+
569+
g.By("Updating the EgressIP object")
570+
ovnKubernetesCreateEgressIPObject(oc, egressIPYamlPath, egressIPObjectName, targetNamespace, "", newEgressIPSet)
571+
572+
g.By("Applying the updated EgressIP object")
573+
applyEgressIPObject(oc, nil, egressIPYamlPath, targetNamespace, newEgressIPSet, egressUpdateTimeout)
574+
575+
g.By("Makes sure the updated EgressIP is advertised by FRR ")
576+
for eip, nodeName := range newEgressIPSet {
577+
o.Expect(nodeName).ShouldNot(o.BeEmpty())
578+
o.Eventually(func() bool {
579+
return isRouteToEgressIPPresent(oc, eip, cudnName, nodeName)
580+
}).WithTimeout(timeOut).WithPolling(interval).Should(o.BeTrue())
581+
}
582+
583+
g.By(fmt.Sprintf("Sending requests from prober and making sure that %d requests with search string and updated EgressIPs %v were seen", numberOfRequestsToSend, newEgressIPSet))
584+
spawnProberSendEgressIPTrafficCheckLogs(oc, targetNamespace, probePodName, svcUrl, targetProtocol, externalIP, serverPort, numberOfRequestsToSend, numberOfRequestsToSend, packetSnifferDaemonSet, newEgressIPSet)
585+
586+
g.By("Deleting the EgressIP object")
587+
// Use cascading foreground deletion to make sure that the EgressIP object and its dependencies are gone.
588+
_, err = runOcWithRetry(oc.AsAdmin(), "delete", "egressip", egressIPObjectName, "--cascade=foreground")
589+
o.Expect(err).NotTo(o.HaveOccurred())
590+
591+
g.By("Makes sure the EgressIP is not advertised by FRR")
592+
for eip, nodeName := range newEgressIPSet {
593+
o.Eventually(func() bool {
594+
return isRouteToEgressIPPresent(oc, eip, cudnName, nodeName)
595+
}).WithTimeout(timeOut).WithPolling(interval).Should(o.BeFalse())
596+
}
597+
598+
g.By(fmt.Sprintf("Sending requests from prober and making sure that %d requests with search string and EgressIPs %v were seen", 0, newEgressIPSet))
599+
spawnProberSendEgressIPTrafficCheckLogs(oc, targetNamespace, probePodName, svcUrl, targetProtocol, externalIP, serverPort, numberOfRequestsToSend, 0, packetSnifferDaemonSet, newEgressIPSet)
600+
}
601+
},
602+
g.Entry("IPv4", IPv4, v4ExternalIP),
603+
g.Entry("IPv6", IPv6, v6ExternalIP),
604+
)
605+
})
606+
})
352607
})
353608
})
354609

610+
func getEgressIPSet(ipFamily IPFamily, eipNodes []string) (map[string]string, map[string]string) {
611+
egressIPSet := make(map[string]string)
612+
newEgressIPSet := make(map[string]string)
613+
for i := range eipNodes {
614+
switch ipFamily {
615+
case IPv4:
616+
eip := fmt.Sprintf("192.168.111.%d", i+30)
617+
egressIPSet[eip] = ""
618+
neip := fmt.Sprintf("192.168.111.%d", i+40)
619+
newEgressIPSet[neip] = ""
620+
case IPv6:
621+
eip := fmt.Sprintf("fd2e:6f44:5dd8:c956::%d", i+30)
622+
egressIPSet[eip] = ""
623+
neip := fmt.Sprintf("fd2e:6f44:5dd8:c956::%d", i+40)
624+
newEgressIPSet[neip] = ""
625+
default:
626+
o.Expect(false).To(o.BeTrue())
627+
}
628+
}
629+
return egressIPSet, newEgressIPSet
630+
}
631+
632+
// isRouteToEgressIPPresent checks that routes to the egress IPs are being advertised by FRR.
633+
func isRouteToEgressIPPresent(oc *exutil.CLI, eip, netName, nodeName string) bool {
634+
advertised := false
635+
frr, err := getGeneratedFrrConfigurationForNode(oc, nodeName, netName)
636+
if err != nil && err.Error() == "FRR configuration for node "+nodeName+" not found" {
637+
return advertised
638+
}
639+
o.Expect(err).NotTo(o.HaveOccurred())
640+
if len(frr.Spec.BGP.Routers) == 0 {
641+
return advertised
642+
}
643+
644+
// Parse IP to determine if it's IPv4 or IPv6
645+
ip := net.ParseIP(eip)
646+
o.Expect(ip).NotTo(o.BeNil())
647+
648+
var prefix string
649+
if ip.To4() != nil {
650+
prefix = fmt.Sprintf("%s/32", eip)
651+
} else {
652+
prefix = fmt.Sprintf("%s/128", eip)
653+
}
654+
655+
if slices.Contains(frr.Spec.BGP.Routers[0].Prefixes, prefix) {
656+
advertised = true
657+
}
658+
return advertised
659+
}
660+
355661
// getRouteAdvertisements uses the dynamic admin client to return a pointer to
356662
// an existing RouteAdvertisements, or error.
357663
func getRouteAdvertisements(oc *exutil.CLI, name string) (*ratypes.RouteAdvertisements, error) {

Diff for: ‎test/extended/util/annotate/generated/zz_generated.annotations.go

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: ‎zz_generated.manifests/test-reporting.yaml

+20
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,26 @@ spec:
477477
when the VMI attached to a secondary UDN is migrated between nodes'
478478
- featureGate: RouteAdvertisements
479479
tests:
480+
- testName: '[sig-network][OCPFeatureGate:RouteAdvertisements][Feature:RouteAdvertisements][apigroup:operator.openshift.io]
481+
when using openshift ovn-kubernetes [EgressIP][apigroup:user.openshift.io][apigroup:security.openshift.io]
482+
Advertising egressIP for default network pods should have the assigned EgressIPs
483+
and EgressIPs can be created, updated and deleted [apigroup:route.openshift.io]
484+
IPv4'
485+
- testName: '[sig-network][OCPFeatureGate:RouteAdvertisements][Feature:RouteAdvertisements][apigroup:operator.openshift.io]
486+
when using openshift ovn-kubernetes [EgressIP][apigroup:user.openshift.io][apigroup:security.openshift.io]
487+
Advertising egressIP for default network pods should have the assigned EgressIPs
488+
and EgressIPs can be created, updated and deleted [apigroup:route.openshift.io]
489+
IPv6'
490+
- testName: '[sig-network][OCPFeatureGate:RouteAdvertisements][Feature:RouteAdvertisements][apigroup:operator.openshift.io]
491+
when using openshift ovn-kubernetes [EgressIP][apigroup:user.openshift.io][apigroup:security.openshift.io]
492+
Advertising egressIP for user defined network UDN pods should have the assigned
493+
EgressIPs and EgressIPs can be created, updated and deleted [apigroup:route.openshift.io]
494+
IPv4'
495+
- testName: '[sig-network][OCPFeatureGate:RouteAdvertisements][Feature:RouteAdvertisements][apigroup:operator.openshift.io]
496+
when using openshift ovn-kubernetes [EgressIP][apigroup:user.openshift.io][apigroup:security.openshift.io]
497+
Advertising egressIP for user defined network UDN pods should have the assigned
498+
EgressIPs and EgressIPs can be created, updated and deleted [apigroup:route.openshift.io]
499+
IPv6'
480500
- testName: '[sig-network][OCPFeatureGate:RouteAdvertisements][Feature:RouteAdvertisements][apigroup:operator.openshift.io]
481501
when using openshift ovn-kubernetes [PodNetwork] Advertising a cluster user
482502
defined network [apigroup:user.openshift.io][apigroup:security.openshift.io]

0 commit comments

Comments
 (0)
Please sign in to comment.