Skip to content

Commit

Permalink
Merge pull request #4106 from tssurya/run-ipv6-lanes-cp-take-2
Browse files Browse the repository at this point in the history
Run ipv6 lane in control plane jobs
  • Loading branch information
trozet authored Feb 27, 2024
2 parents cc3e580 + 8cf27a9 commit b4388c5
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 111 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,12 @@ jobs:
- {"target": "shard-conformance", "ha": "noHA", "gateway-mode": "local", "ipfamily": "dualstack", "disable-snat-multiple-gws": "snatGW", "second-bridge": "1br", "ic": "ic-single-node-zones"}
- {"target": "shard-conformance", "ha": "noHA", "gateway-mode": "shared", "ipfamily": "ipv6", "disable-snat-multiple-gws": "snatGW", "second-bridge": "1br", "ic": "ic-single-node-zones"}
- {"target": "shard-conformance", "ha": "noHA", "gateway-mode": "shared", "ipfamily": "ipv4", "disable-snat-multiple-gws": "snatGW", "second-bridge": "1br", "ic": "ic-single-node-zones"}
- {"target": "control-plane", "ha": "HA", "gateway-mode": "shared", "ipfamily": "ipv4", "disable-snat-multiple-gws": "noSnatGW", "second-bridge": "1br", "ic": "ic-disabled"}
- {"target": "control-plane", "ha": "HA", "gateway-mode": "shared", "ipfamily": "ipv6", "disable-snat-multiple-gws": "noSnatGW", "second-bridge": "1br", "ic": "ic-disabled"}
- {"target": "control-plane", "ha": "HA", "gateway-mode": "shared", "ipfamily": "ipv4", "disable-snat-multiple-gws": "snatGW", "second-bridge": "1br", "ic": "ic-disabled"}
- {"target": "control-plane", "ha": "noHA", "gateway-mode": "local", "ipfamily": "ipv4", "disable-snat-multiple-gws": "noSnatGW", "second-bridge": "1br", "ic": "ic-single-node-zones"}
- {"target": "control-plane", "ha": "noHA", "gateway-mode": "local", "ipfamily": "ipv6", "disable-snat-multiple-gws": "noSnatGW", "second-bridge": "1br", "ic": "ic-single-node-zones"}
- {"target": "control-plane", "ha": "noHA", "gateway-mode": "shared", "ipfamily": "ipv4", "disable-snat-multiple-gws": "noSnatGW", "second-bridge": "2br", "ic": "ic-single-node-zones"}
- {"target": "control-plane", "ha": "noHA", "gateway-mode": "shared", "ipfamily": "ipv6", "disable-snat-multiple-gws": "noSnatGW", "second-bridge": "2br", "ic": "ic-single-node-zones"}
- {"target": "multi-homing", "ha": "noHA", "gateway-mode": "local", "ipfamily": "ipv4", "disable-snat-multiple-gws": "SnatGW", "second-bridge": "1br", "ic": "ic-disabled"}
- {"target": "node-ip-mac-migration", "ha": "noHA", "gateway-mode": "shared", "ipfamily": "ipv6", "disable-snat-multiple-gws": "SnatGW", "second-bridge": "1br", "ic": "ic-disabled"}
- {"target": "node-ip-mac-migration", "ha": "noHA", "gateway-mode": "shared", "ipfamily": "ipv4", "disable-snat-multiple-gws": "SnatGW", "second-bridge": "1br", "ic": "ic-single-node-zones"}
Expand Down Expand Up @@ -506,7 +508,9 @@ jobs:
make -C test control-plane WHAT="Kubevirt Virtual Machines"
else
make -C test ${{ matrix.target }}
make -C test conformance
if [ "${{ matrix.ipfamily }}" != "ipv6" ]; then
make -C test conformance
fi
fi
- name: Export kind logs
Expand Down
39 changes: 24 additions & 15 deletions test/e2e/acl_logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,7 @@ var _ = Describe("ACL Logging for EgressFirewall", func() {
allowACLVerdict = "allow"
namespacePrefix = "acl-log-egressfw"
secondaryNamespacePrefix = "acl-log-egressfw-sec"

// These targets must be off cluster - traffic to the cluster should always be
// allowed: https://docs.openshift.com/container-platform/4.10/networking/openshift_sdn/configuring-egress-firewall.html
// "As a cluster administrator, you can create an egress firewall for a project that restricts egress traffic leaving
// your OpenShift Container Platform cluster."
// Because the egress firewall feature only affects traffic leaving the cluster, we will not log for on-cluster targets.
allowedDstIP = "172.18.0.1"
deniedDstIP = "172.19.0.10"
dstPort = 8080
dstPort = 8080
)

fr := wrappedTestFramework(namespacePrefix)
Expand All @@ -192,15 +184,32 @@ var _ = Describe("ACL Logging for EgressFirewall", func() {
nsNameSecondary string
pokePod *v1.Pod
pokePodSecondary *v1.Pod
allowedDstIP string
deniedDstIP string
)

BeforeEach(func() {
// These targets must be off cluster - traffic to the cluster should always be
// allowed: https://docs.openshift.com/container-platform/4.10/networking/openshift_sdn/configuring-egress-firewall.html
// "As a cluster administrator, you can create an egress firewall for a project that restricts egress traffic leaving
// your OpenShift Container Platform cluster."
// Because the egress firewall feature only affects traffic leaving the cluster, we will not log for on-cluster targets.
allowedDstIP = "172.18.0.1"
deniedDstIP = "172.19.0.10"
mask := "32"
denyCIDR := "0.0.0.0/0"
if IsIPv6Cluster(fr.ClientSet) {
allowedDstIP = "2001:4860:4860::8888"
deniedDstIP = "2001:4860:4860::8844"
mask = "128"
denyCIDR = "::/0"
}
By("configuring the ACL logging level within the namespace")
nsName = fr.Namespace.Name
Expect(setNamespaceACLLogSeverity(fr, nsName, initialDenyACLSeverity, initialAllowACLSeverity, aclRemoveOptionDelete)).To(Succeed())

By("creating a \"default deny\" Egress Firewall")
err := makeEgressFirewall(nsName)
err := makeEgressFirewall(nsName, allowedDstIP, mask, denyCIDR)
Expect(err).NotTo(HaveOccurred())

By("creating a pod running agnhost netexec")
Expand All @@ -221,7 +230,7 @@ var _ = Describe("ACL Logging for EgressFirewall", func() {
Expect(setNamespaceACLLogSeverity(fr, nsNameSecondary, initialDenyACLSeverity, initialAllowACLSeverity, aclRemoveOptionDelete)).To(Succeed())

By("creating a \"default deny\" Egress Firewall inside the secondary namespace")
err = makeEgressFirewall(nsNameSecondary)
err = makeEgressFirewall(nsNameSecondary, allowedDstIP, mask, denyCIDR)
Expect(err).NotTo(HaveOccurred())

By("creating a pod running agnhost netexec inside the secondary namespace")
Expand Down Expand Up @@ -621,7 +630,7 @@ func makeDenyAllPolicy(f *framework.Framework, ns string, policyName string) (*k
return f.ClientSet.NetworkingV1().NetworkPolicies(ns).Create(context.TODO(), policy, metav1.CreateOptions{})
}

func makeEgressFirewall(ns string) error {
func makeEgressFirewall(ns, allowedDstIP, mask, denyCIDR string) error {
egressFirewallYaml := "egressfirewall.yaml"
var egressFirewallConfig = fmt.Sprintf(`apiVersion: k8s.ovn.org/v1
kind: EgressFirewall
Expand All @@ -632,11 +641,11 @@ spec:
egress:
- type: Allow
to:
cidrSelector: 172.18.0.1/32
cidrSelector: %s/%s
- type: Deny
to:
cidrSelector: 0.0.0.0/0
`)
cidrSelector: %s
`, allowedDstIP, mask, denyCIDR)

if err := os.WriteFile(egressFirewallYaml, []byte(egressFirewallConfig), 0644); err != nil {
framework.Failf("Unable to write CRD config to disk: %v", err)
Expand Down
81 changes: 4 additions & 77 deletions test/e2e/e2e.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,11 +333,11 @@ func isolateIPv6Networks(networkA, networkB string) error {
if len(bridgeInfNames) != 2 {
return fmt.Errorf("expected two bridge names but found %d", len(bridgeInfNames))
}
_, err := runCommand("ip6tables", "-t", "filter", "-A", "FORWARD", "-i", bridgeInfNames[0], "-o", bridgeInfNames[1], "-j", "DROP")
_, err := runCommand("sudo", "ip6tables", "-t", "filter", "-A", "FORWARD", "-i", bridgeInfNames[0], "-o", bridgeInfNames[1], "-j", "DROP")
if err != nil {
return err
}
_, err = runCommand("ip6tables", "-t", "filter", "-A", "FORWARD", "-i", bridgeInfNames[1], "-o", bridgeInfNames[0], "-j", "DROP")
_, err = runCommand("sudo", "ip6tables", "-t", "filter", "-A", "FORWARD", "-i", bridgeInfNames[1], "-o", bridgeInfNames[0], "-j", "DROP")
return err
}

Expand Down Expand Up @@ -753,7 +753,7 @@ var _ = ginkgo.Describe("e2e control plane", func() {
framework.ExpectNoError(err, "one or more nodes failed to go back ready, schedulable, and untainted")
})

ginkgo.It("should provide Internet connection continuously when all pods are killed on node running master instance of ovnkube-control-plane.", func() {
ginkgo.It("should provide Internet connection continuously when all pods are killed on node running master instance of ovnkube-control-plane", func() {
ginkgo.By(fmt.Sprintf("Running container which tries to connect to %s in a loop", extDNSIP))

ovnKubeControlPlaneNode, err := findOvnKubeControlPlaneNode(controlPlanePodName, controlPlaneLeaseName)
Expand Down Expand Up @@ -794,7 +794,7 @@ var _ = ginkgo.Describe("e2e control plane", func() {
framework.ExpectNoError(<-errChan)
})

ginkgo.It("should provide Internet connection continuously when all ovnkube-control-plane pods are killed.", func() {
ginkgo.It("should provide Internet connection continuously when all ovnkube-control-plane pods are killed", func() {
ginkgo.By(fmt.Sprintf("Running container which tries to connect to %s in a loop", extDNSIP))

podChan, errChan := make(chan *v1.Pod), make(chan error)
Expand Down Expand Up @@ -2277,76 +2277,3 @@ var _ = ginkgo.Describe("e2e delete databases", func() {
singlePodConnectivityTest(f, "after-delete-db-pods")
})
})

var _ = ginkgo.Describe("e2e IGMP validation", func() {
const (
svcname string = "igmp-test"
ovnNs string = "ovn-kubernetes"
port string = "8080"
ovnWorkerNode string = "ovn-worker"
ovnWorkerNode2 string = "ovn-worker2"
mcastGroup string = "224.1.1.1"
multicastListenerPod string = "multicast-listener-test-pod"
multicastSourcePod string = "multicast-source-test-pod"
tcpdumpFileName string = "tcpdump.txt"
retryTimeout = 5 * time.Minute // polling timeout
)
var (
tcpDumpCommand = []string{"bash", "-c",
fmt.Sprintf("apk update; apk add tcpdump ; tcpdump multicast > %s", tcpdumpFileName)}
// Multicast group (-c 224.1.1.1), UDP (-u), TTL (-T 2), during (-t 3000) seconds, report every (-i 5) seconds
multicastSourceCommand = []string{"bash", "-c",
fmt.Sprintf("iperf -c %s -u -T 2 -t 3000 -i 5", mcastGroup)}
)
f := wrappedTestFramework(svcname)
ginkgo.It("can retrieve multicast IGMP query", func() {
// Enable multicast of the test namespace annotation
ginkgo.By(fmt.Sprintf("annotating namespace: %s to enable multicast", f.Namespace.Name))
annotateArgs := []string{
"annotate",
"namespace",
f.Namespace.Name,
fmt.Sprintf("k8s.ovn.org/multicast-enabled=%s", "true"),
}
e2ekubectl.RunKubectlOrDie(f.Namespace.Name, annotateArgs...)

// Create a multicast source pod
ginkgo.By("creating a multicast source pod in node " + ovnWorkerNode)
createGenericPod(f, multicastSourcePod, ovnWorkerNode, f.Namespace.Name, multicastSourceCommand)

// Create a multicast listener pod
ginkgo.By("creating a multicast listener pod in node " + ovnWorkerNode2)
createGenericPod(f, multicastListenerPod, ovnWorkerNode2, f.Namespace.Name, tcpDumpCommand)

// Wait for tcpdump on listener pod to be ready
err := wait.PollImmediate(retryInterval, retryTimeout, func() (bool, error) {
kubectlOut, err := e2ekubectl.RunKubectl(f.Namespace.Name, "exec", multicastListenerPod, "--", "/bin/bash", "-c", "ls")
if err != nil {
framework.Failf("failed to retrieve multicast IGMP query: " + err.Error())
}
if !strings.Contains(kubectlOut, tcpdumpFileName) {
return false, nil
}
return true, nil
})
if err != nil {
framework.Failf("failed to retrieve multicast IGMP query: " + err.Error())
}

// The multicast listener pod join multicast group (-B 224.1.1.1), UDP (-u), during (-t 30) seconds, report every (-i 5) seconds
ginkgo.By("multicast listener pod join multicast group")
e2ekubectl.RunKubectl(f.Namespace.Name, "exec", multicastListenerPod, "--", "/bin/bash", "-c", fmt.Sprintf("iperf -s -B %s -u -t 30 -i 5", mcastGroup))

ginkgo.By(fmt.Sprintf("verifying that the IGMP query has been received"))
kubectlOut, err := e2ekubectl.RunKubectl(f.Namespace.Name, "exec", multicastListenerPod, "--", "/bin/bash", "-c", fmt.Sprintf("cat %s | grep igmp", tcpdumpFileName))
if err != nil {
framework.Failf("failed to retrieve multicast IGMP query: " + err.Error())
}
framework.Logf("output:")
framework.Logf(kubectlOut)
if kubectlOut == "" {
framework.Failf("failed to retrieve multicast IGMP query: igmp messages on the tcpdump logfile not found")
}
})

})
16 changes: 12 additions & 4 deletions test/e2e/egress_firewall.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ spec:
ginkgo.By(fmt.Sprintf("Verifying connectivity to an explicitly allowed host %s is permitted as defined by the external firewall policy", exFWPermitTcpDnsDest))
_, err = e2ekubectl.RunKubectl(f.Namespace.Name, "exec", srcPodName, testContainerFlag, "--", "nc", "-vz", "-w", testTimeout, exFWPermitTcpDnsDest, "53")
if err != nil {
framework.Failf("Failed to connect to the remote host %s from container %s on node %s: %v", exFWPermitTcpDnsDest, ovnContainer, serverNodeInfo.name, err)
framework.Failf("Failed to connect to the remote host %s from container %s on node %s: %v", exFWPermitTcpDnsDest, srcPodName, serverNodeInfo.name, err)
}
// Verify the remote host/port as implicitly denied by the firewall policy is not reachable
ginkgo.By(fmt.Sprintf("Verifying connectivity to an implicitly denied host %s is not permitted as defined by the external firewall policy", exFWDenyTcpDnsDest))
Expand Down Expand Up @@ -524,6 +524,10 @@ spec:
frameworkNsFlag := fmt.Sprintf("--namespace=%s", f.Namespace.Name)
testContainer := fmt.Sprintf("%s-container", efPodName)
testContainerFlag := fmt.Sprintf("--container=%s", testContainer)
denyCIDR := "0.0.0.0/0"
if IsIPv6Cluster(f.ClientSet) {
denyCIDR = "::/0"
}
// egress firewall crd yaml configuration
var egressFirewallConfig = fmt.Sprintf(`kind: EgressFirewall
apiVersion: k8s.ovn.org/v1
Expand All @@ -534,8 +538,8 @@ spec:
egress:
- type: Deny
to:
cidrSelector: 0.0.0.0/0
`, f.Namespace.Name)
cidrSelector: %s
`, f.Namespace.Name, denyCIDR)
// write the config to a file for application and defer the removal
if err := os.WriteFile(egressFirewallYamlFile, []byte(egressFirewallConfig), 0644); err != nil {
framework.Failf("Unable to write CRD config to disk: %v", err)
Expand Down Expand Up @@ -571,13 +575,17 @@ spec:
framework.ExpectNoError(err, "failed to validate endpoints for service %s in namespace: %s", serviceName, f.Namespace.Name)

nodeIP := serverNodeInfo.nodeIP
externalContainerIP, _ := createClusterExternalContainer(externalContainerName, agnhostImage,
externalContainerIPV4, externalContainerIPV6 := createClusterExternalContainer(externalContainerName, agnhostImage,
[]string{"--network", ciNetworkName, "-p", fmt.Sprintf("%d:%d", externalContainerPort, externalContainerPort)},
[]string{"netexec", fmt.Sprintf("--http-port=%d", externalContainerPort)})
defer deleteClusterExternalContainer(externalContainerName)

// 2. Check connectivity works both ways
// pod -> external container should work
externalContainerIP := externalContainerIPV4
if IsIPv6Cluster(f.ClientSet) {
externalContainerIP = externalContainerIPV6
}
ginkgo.By(fmt.Sprintf("Verifying connectivity from pod %s to external container [%s]:%d",
efPodName, externalContainerIP, externalContainerPort))
_, err = e2ekubectl.RunKubectl(f.Namespace.Name, "exec", efPodName, testContainerFlag,
Expand Down
Loading

0 comments on commit b4388c5

Please sign in to comment.