From df718dad0712eb340685e11b6a03897cffbcc01c Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 12:07:46 +0200 Subject: [PATCH 01/17] Add MTU boundary testing infrastructure and 1500-MTU tests Add infrastructure for testing MTU boundaries using UDP datagrams with the DF (Don't Fragment) bit set via Python3 IP_PMTUDISC_DO sockets. This avoids NET_RAW capability so the test pod complies with the restricted PodSecurity standard. New test pod: - nettest-pod (UBI9 with Python3, no package installation needed) New shared keywords in ipsec.resource: - Ping With DF Bit And Verify / Should Fail (single-pair) - Ping DF Bit Between All Clusters / Should Fail (full 6-pair mesh) - Large Payload Between All Clusters (full 6-pair mesh) - Get Pod Interface MTU - Send Large Payload And Verify (moved from ipsec.robot) New tests in ipsec.robot (1500 MTU, no infrastructure changes): - DF Bit 64B, 1350B, 1450B pass through IPsec - DF Bit 1472B rejected at pod MTU boundary (1472+28=1500) - 64KB TCP transfer through IPsec Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- test/assets/c2cc/nettest-pod.yaml | 19 +++ test/resources/c2cc.resource | 5 +- test/resources/ipsec.resource | 81 +++++++++++++ test/suites/c2cc/extra/ipsec.robot | 184 +++++++++++++++++++++++++++++ 4 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 test/assets/c2cc/nettest-pod.yaml create mode 100644 test/suites/c2cc/extra/ipsec.robot diff --git a/test/assets/c2cc/nettest-pod.yaml b/test/assets/c2cc/nettest-pod.yaml new file mode 100644 index 0000000000..2dd1d0303c --- /dev/null +++ b/test/assets/c2cc/nettest-pod.yaml @@ -0,0 +1,19 @@ +kind: Pod +apiVersion: v1 +metadata: + name: nettest-pod +spec: + terminationGracePeriodSeconds: 0 + containers: + - name: nettest + image: registry.access.redhat.com/ubi9/ubi:9.6 + command: ["sleep", "infinity"] + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 10001 + seccompProfile: + type: RuntimeDefault diff --git a/test/resources/c2cc.resource b/test/resources/c2cc.resource index 827b4a9fbf..000510c719 100644 --- a/test/resources/c2cc.resource +++ b/test/resources/c2cc.resource @@ -299,13 +299,14 @@ Verify Corefile Does Not Contain C2CC Server Block Should Not Contain ${stdout} ${domain}:5353 Deploy Test Workloads - [Documentation] Create namespace and deploy hello-microshift + curl-pod on all clusters. + [Documentation] Create namespace and deploy hello-microshift, curl-pod, and nettest-pod on all clusters. VAR ${assets}= ${EXECDIR}/assets/c2cc FOR ${alias} IN cluster-a cluster-b cluster-c ${ns}= Create Unique Namespace On Cluster ${alias} Set To Dictionary ${NAMESPACES} ${alias} ${ns} Oc On Cluster ${alias} oc apply -n ${ns} -f ${assets}/hello-microshift.yaml Oc On Cluster ${alias} oc apply -n ${ns} -f ${assets}/curl-pod.yaml + Oc On Cluster ${alias} oc apply -n ${ns} -f ${assets}/nettest-pod.yaml END Wait For Test Pods Wait For Service Endpoints @@ -315,7 +316,7 @@ Wait For Test Pods FOR ${alias} IN cluster-a cluster-b cluster-c Oc On Cluster ... ${alias} - ... oc wait pod/hello-microshift pod/curl-pod -n ${NAMESPACES}[${alias}] --for=condition=Ready --timeout=120s + ... oc wait pod/hello-microshift pod/curl-pod pod/nettest-pod -n ${NAMESPACES}[${alias}] --for=condition=Ready --timeout=120s END Wait For Service Endpoints diff --git a/test/resources/ipsec.resource b/test/resources/ipsec.resource index 3ff6f66c22..bd9b22f3a4 100644 --- a/test/resources/ipsec.resource +++ b/test/resources/ipsec.resource @@ -126,3 +126,84 @@ Curl From Host Should Fail ${stdout}= Disruptive Command On Cluster ${alias} ... curl -sS --max-time 5 http://${pod_ip}:${port}/cgi-bin/hello 2>&1 || true Should Not Contain ${stdout} Hello from + +Ping With DF Bit And Verify + [Documentation] Send a UDP datagram with DF bit set (IP_PMTUDISC_DO) via Python3. + ... Asserts the kernel accepted the datagram (fits within ESP-adjusted PMTU). + ... Uses UDP instead of ICMP to avoid requiring NET_RAW capability. + ... UDP overhead (IP+UDP = 28B) matches ICMP overhead (IP+ICMP = 28B), + ... so payload sizes are equivalent to ping -s values. + [Arguments] ${alias} ${dest_ip} ${payload_size} + ${stdout}= Oc On Cluster ${alias} + ... oc exec nettest-pod -n ${NAMESPACES}[${alias}] -- python3 -c 'import socket,sys;s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM);s.setsockopt(socket.IPPROTO_IP,10,2);s.sendto(b"A"*${payload_size},(sys.argv[1],9999));print("OK")' ${dest_ip} 2>&1 + ... allow_fail=${TRUE} + Should Contain ${stdout} OK + ... DF-bit UDP send of ${payload_size}B to ${dest_ip} failed: ${stdout} + +Ping With DF Bit Should Fail + [Documentation] Send a UDP datagram with DF bit set. Asserts EMSGSIZE (Message too long). + ... Proves the datagram exceeds the ESP-adjusted PMTU. + [Arguments] ${alias} ${dest_ip} ${payload_size} + ${stdout}= Oc On Cluster ${alias} + ... oc exec nettest-pod -n ${NAMESPACES}[${alias}] -- python3 -c 'import socket,sys;s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM);s.setsockopt(socket.IPPROTO_IP,10,2);s.sendto(b"A"*${payload_size},(sys.argv[1],9999));print("OK")' ${dest_ip} 2>&1 || true + ... allow_fail=${TRUE} + Should Not Contain ${stdout} OK + ... DF-bit UDP send of ${payload_size}B should have been rejected but succeeded + +Get Pod Interface MTU + [Documentation] Return the MTU of the pod's eth0 interface. + [Arguments] ${alias} ${pod} ${ns} + ${stdout}= Oc On Cluster ${alias} + ... oc exec ${pod} -n ${ns} -- cat /sys/class/net/eth0/mtu + ${mtu}= Strip String ${stdout} + RETURN ${mtu} + +Send Large Payload And Verify + [Documentation] Send a large payload via curl POST and verify it succeeds. + [Arguments] ${alias} ${ip} ${size} + ${stdout}= Oc On Cluster + ... ${alias} + ... oc exec curl-pod -n ${NAMESPACES}[${alias}] -- sh -c 'dd if=/dev/zero bs=${size} count=1 2>/dev/null | curl -sS --max-time 15 --data-binary @- http://${ip}:8080/cgi-bin/hello' + Should Contain ${stdout} Hello from + +Ping DF Bit Between All Clusters + [Documentation] Send DF-bit UDP payload across all 6 cluster pairs. + [Arguments] ${size} + FOR ${src} ${dst} IN + ... cluster-a cluster-b + ... cluster-a cluster-c + ... cluster-b cluster-a + ... cluster-b cluster-c + ... cluster-c cluster-a + ... cluster-c cluster-b + ${ip}= Get Hello Pod IP ${dst} + Ping With DF Bit And Verify ${src} ${ip} ${size} + END + +Ping DF Bit Should Fail Between All Clusters + [Documentation] Send DF-bit UDP payload expecting rejection on all 6 pairs. + [Arguments] ${size} + FOR ${src} ${dst} IN + ... cluster-a cluster-b + ... cluster-a cluster-c + ... cluster-b cluster-a + ... cluster-b cluster-c + ... cluster-c cluster-a + ... cluster-c cluster-b + ${ip}= Get Hello Pod IP ${dst} + Ping With DF Bit Should Fail ${src} ${ip} ${size} + END + +Large Payload Between All Clusters + [Documentation] Send large TCP payload across all 6 cluster pairs. + [Arguments] ${size} + FOR ${src} ${dst} IN + ... cluster-a cluster-b + ... cluster-a cluster-c + ... cluster-b cluster-a + ... cluster-b cluster-c + ... cluster-c cluster-a + ... cluster-c cluster-b + ${ip}= Get Hello Pod IP ${dst} + Send Large Payload And Verify ${src} ${ip} ${size} + END diff --git a/test/suites/c2cc/extra/ipsec.robot b/test/suites/c2cc/extra/ipsec.robot new file mode 100644 index 0000000000..50d47361ce --- /dev/null +++ b/test/suites/c2cc/extra/ipsec.robot @@ -0,0 +1,184 @@ +*** Settings *** +Documentation IPsec E2E tests for C2CC. +... Validates that C2CC cross-cluster connectivity works through a +... Libreswan tunnel-mode IPsec mesh (subnet selectors, no Geneve). +... +... Tests cover ESP encapsulation, connectivity through the tunnel, +... source IP preservation, policy enforcement (SA flush/restore), +... plaintext rejection, host-to-pod rejection, MTU boundary (1500), +... and tunnel recovery. Jumbo MTU tests are in the c2cc-ipsec-mtu scenario. + +Resource ../../../resources/microshift-process.resource +Resource ../../../resources/kubeconfig.resource +Resource ../../../resources/oc.resource +Resource ../../../resources/c2cc.resource +Resource ../../../resources/ipsec.resource + +Suite Setup C2CC Suite Setup deploy_workloads=${TRUE} +Suite Teardown Teardown + +Test Tags c2cc ipsec + + +*** Test Cases *** +IPsec Tunnels Established On All Clusters + [Documentation] Verify all 3 hosts have 8 IPsec tunnel SAs each. + ... Each host has 2 remote hosts x 4 subnet pairs (2 local x 2 remote CIDRs). + Verify All IPsec Tunnels On Cluster cluster-a expected_count=8 + Verify All IPsec Tunnels On Cluster cluster-b expected_count=8 + Verify All IPsec Tunnels On Cluster cluster-c expected_count=8 + +ESP Encapsulation On Wire + [Documentation] Capture packets on the wire and verify ESP encapsulation. + ... Records XFRM byte counters before and after traffic, captures ESP packets + ... via tcpdump, and verifies counters incremented. + ${baseline_a}= Get XFRM Byte Counters cluster-a + ${baseline_b}= Get XFRM Byte Counters cluster-b + + ${pcap_file}= Start Tcpdump For ESP On Cluster cluster-b + ${ip_dest}= Get Hello Pod IP cluster-b + Curl From Cluster cluster-a ${ip_dest} 8080 + Wait For Tcpdump And Verify ESP cluster-b ${pcap_file} + + Verify XFRM Counters Incremented cluster-a ${baseline_a} + Verify XFRM Counters Incremented cluster-b ${baseline_b} + +Cross Cluster Connectivity Through IPsec + [Documentation] Verify pods on all clusters can reach pods/services on all + ... other clusters through the IPsec tunnel. + [Template] Verify Connectivity Between Clusters + cluster-a cluster-b pod + cluster-a cluster-b service + cluster-a cluster-c pod + cluster-a cluster-c service + cluster-b cluster-a pod + cluster-b cluster-a service + cluster-b cluster-c pod + cluster-b cluster-c service + cluster-c cluster-a pod + cluster-c cluster-a service + cluster-c cluster-b pod + cluster-c cluster-b service + +Source IP Preserved Through IPsec + [Documentation] Verify cross-cluster traffic through IPsec preserves the + ... source pod IP (no SNAT). + [Template] Verify Source IP Preserved Between Clusters + cluster-a cluster-b pod + cluster-a cluster-b service + cluster-a cluster-c pod + cluster-a cluster-c service + cluster-b cluster-a pod + cluster-b cluster-a service + cluster-b cluster-c pod + cluster-b cluster-c service + cluster-c cluster-a pod + cluster-c cluster-a service + cluster-c cluster-b pod + cluster-c cluster-b service + +Plaintext Rejection When IPsec Stopped + [Documentation] Stop IPsec on cluster-a. With nftables enforcement rules on + ... cluster-b, verify traffic is dropped rather than sent in plaintext. + [Setup] Add NFTables IPsec Enforcement Rules cluster-b ${CLUSTER_B_POD_CIDR} + + Stop IPsec Service On Cluster cluster-a + Sleep 3s reason=Wait for SAs to expire + ${ip_dest}= Get Hello Pod IP cluster-b + Curl Should Fail From Cluster cluster-a ${ip_dest} 8080 ${NAMESPACES}[cluster-a] + + [Teardown] Restore IPsec With Enforcement Cleanup cluster-a cluster-b + +Host To Remote Pod Rejected Without IPsec + [Documentation] Curl directly from cluster-a's host to a pod on cluster-b. + ... Host-originated traffic is not matched by tunnel-mode IPsec selectors + ... scoped to pod/service CIDRs, so it cannot reach the remote pod. + ${pod_ip}= Get Hello Pod IP cluster-b + Curl From Host Should Fail cluster-a ${pod_ip} 8080 + +Near MTU TCP Transfer Through IPsec + [Documentation] Send near-MTU-sized payloads via TCP (curl POST). + ... TCP handles PMTUD transparently through the IPsec tunnel. + ${ip_dest}= Get Hello Pod IP cluster-b + Send Large Payload And Verify cluster-a ${ip_dest} 1300 + Send Large Payload And Verify cluster-a ${ip_dest} 1400 + +DF Bit 64B Passes Through IPsec + [Documentation] Smoke test — small DF-bit payload through IPsec on all pairs. + Ping DF Bit Between All Clusters 64 + +DF Bit 1350B Passes Through IPsec + [Documentation] Mid-range DF-bit payload through IPsec on all pairs. + Ping DF Bit Between All Clusters 1350 + +DF Bit 1450B Passes Through IPsec + [Documentation] Near pod MTU — accepted by the kernel on all pairs. + Ping DF Bit Between All Clusters 1450 + +DF Bit 1472B Rejected At Pod MTU + [Documentation] 1472B + 28B = 1500B, hitting the pod interface MTU on all pairs. + Ping DF Bit Should Fail Between All Clusters 1472 + +Large TCP Transfer Through IPsec + [Documentation] 64KB curl POST through IPsec on all pairs. + Large Payload Between All Clusters 65536 + +Cross Cluster DNS Through IPsec + [Documentation] Verify pods can resolve and reach services on remote + ... clusters via DNS name through the IPsec tunnel. + [Template] Verify Remote Service Via DNS + cluster-a cluster-b + cluster-a cluster-c + cluster-b cluster-a + cluster-b cluster-c + cluster-c cluster-a + cluster-c cluster-b + +IPsec Tunnel Recovers After Local Restart + [Documentation] Restart IPsec on cluster-a and verify tunnels recover + ... and cross-cluster connectivity is restored. + Restart IPsec Service On Cluster cluster-a + Wait For IPsec Tunnel Reestablishment cluster-a expected_count=8 + Wait For IPsec Tunnel Reestablishment cluster-b expected_count=8 + Wait For IPsec Tunnel Reestablishment cluster-c expected_count=8 + ${ip_dest}= Get Hello Pod IP cluster-b + Curl From Cluster cluster-a ${ip_dest} 8080 + +IPsec Tunnel Recovers After Remote Stop Start + [Documentation] Stop IPsec on cluster-b, start it back, and verify + ... tunnels recover and cross-cluster connectivity is restored. + Stop IPsec Service On Cluster cluster-b + Sleep 5s reason=Wait for tunnel to go down + Start IPsec Service On Cluster cluster-b + Wait For IPsec Tunnel Reestablishment cluster-a expected_count=8 + Wait For IPsec Tunnel Reestablishment cluster-b expected_count=8 + Wait For IPsec Tunnel Reestablishment cluster-c expected_count=8 + ${ip_dest}= Get Hello Pod IP cluster-b + Curl From Cluster cluster-a ${ip_dest} 8080 + + +*** Keywords *** +Teardown + [Documentation] Ensure IPsec is running, then remove test workloads and close connections. + Ensure IPsec Running On All Clusters + C2CC Suite Teardown cleanup_workloads=${TRUE} + +Ensure IPsec Running On All Clusters + [Documentation] Make sure ipsec service is running on all clusters. + ... Tests may have stopped it. + FOR ${alias} IN cluster-a cluster-b cluster-c + Start IPsec Service On Cluster ${alias} + END + +Restore IPsec And Verify + [Documentation] Restart ipsec and wait for tunnels to come back up. + [Arguments] ${alias} + Restart IPsec Service On Cluster ${alias} + Wait For IPsec Tunnel Reestablishment ${alias} expected_count=8 + +Restore IPsec With Enforcement Cleanup + [Documentation] Remove enforcement rules and restore IPsec. + [Arguments] ${ipsec_alias} ${enforcement_alias} + Remove NFTables IPsec Enforcement Rules ${enforcement_alias} + Start IPsec Service On Cluster ${ipsec_alias} + Wait For IPsec Tunnel Reestablishment ${ipsec_alias} expected_count=8 From 0d1ca8cb5dbd6c8444c39c6caa425d9a6d6d9be3 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 12:07:58 +0200 Subject: [PATCH 02/17] Add c2cc-mtu scenario for plain C2CC at jumbo MTU (9000) Add a scenario that creates VMs on a jumbo-frame libvirt network (MTU 9000) and tests C2CC MTU boundaries without IPsec. The libvirt network XML includes which sets the hypervisor bridge and all tap devices to 9000, enabling end-to-end jumbo frame support between VMs. Tests (all 6 cluster pairs): - DF Bit 64B, 8400B, 8872B, 8950B pass - DF Bit 8972B rejected at pod MTU (8972+28=9000) - 64KB TCP transfer - Full C2CC connectivity with source IP preservation Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- test/assets/network/jumbo-network.xml | 10 ++++ test/bin/c2cc_common.sh | 12 +++++ .../c2cc/el102-src@c2cc-mtu.sh | 25 ++++++++++ .../scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh | 25 ++++++++++ test/suites/c2cc/extra/mtu.robot | 47 +++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 test/assets/network/jumbo-network.xml create mode 100644 test/scenarios-bootc/c2cc/el102-src@c2cc-mtu.sh create mode 100644 test/scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh create mode 100644 test/suites/c2cc/extra/mtu.robot diff --git a/test/assets/network/jumbo-network.xml b/test/assets/network/jumbo-network.xml new file mode 100644 index 0000000000..f4a038d340 --- /dev/null +++ b/test/assets/network/jumbo-network.xml @@ -0,0 +1,10 @@ + + jumbo + + + + + + + + diff --git a/test/bin/c2cc_common.sh b/test/bin/c2cc_common.sh index 9268aa2811..ad574f8374 100644 --- a/test/bin/c2cc_common.sh +++ b/test/bin/c2cc_common.sh @@ -228,6 +228,18 @@ c2cc_create_vms() { launch_vm "${boot_blueprint}" --vmname host3 --network "${network}" } +# c2cc_create_jumbo_network creates a libvirt network with MTU 9000 for +# jumbo frame testing. Idempotent — skips if the network already exists. +c2cc_create_jumbo_network() { + if sudo virsh net-info jumbo &>/dev/null; then + return 0 + fi + local -r netconfig="${ROOTDIR}/test/assets/network/jumbo-network.xml" + sudo virsh net-define "${netconfig}" + sudo virsh net-start jumbo + sudo virsh net-autostart jumbo +} + c2cc_remove_vms() { remove_vm host1 remove_vm host2 diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu.sh new file mode 100644 index 0000000000..071b747358 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. +# +# Sets up 3 MicroShift clusters with C2CC on a jumbo-frame network +# (MTU 9000). Tests validate MTU boundary behavior for plain C2CC +# traffic without IPsec. + +# shellcheck source=test/bin/c2cc_common.sh +source "${SCRIPTDIR}/c2cc_common.sh" + +scenario_create_vms() { + c2cc_create_jumbo_network + c2cc_create_vms "rhel102-bootc-source" "rhel102-bootc" "jumbo" +} + +scenario_remove_vms() { + c2cc_remove_vms +} + +scenario_run_tests() { + configure_c2cc_hosts "c2cc_mtu_pre_greenboot" "c2cc_mtu_greenboot" + + c2cc_run_tests "suites/c2cc/extra/mtu.robot" +} diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh new file mode 100644 index 0000000000..dfb8eb8adf --- /dev/null +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. +# +# Sets up 3 MicroShift clusters with C2CC on a jumbo-frame network +# (MTU 9000). Tests validate MTU boundary behavior for plain C2CC +# traffic without IPsec. + +# shellcheck source=test/bin/c2cc_common.sh +source "${SCRIPTDIR}/c2cc_common.sh" + +scenario_create_vms() { + c2cc_create_jumbo_network + c2cc_create_vms "rhel98-bootc-source" "rhel98-bootc" "jumbo" +} + +scenario_remove_vms() { + c2cc_remove_vms +} + +scenario_run_tests() { + configure_c2cc_hosts "c2cc_mtu_pre_greenboot" "c2cc_mtu_greenboot" + + c2cc_run_tests "suites/c2cc/extra/mtu.robot" +} diff --git a/test/suites/c2cc/extra/mtu.robot b/test/suites/c2cc/extra/mtu.robot new file mode 100644 index 0000000000..b2781cc0c5 --- /dev/null +++ b/test/suites/c2cc/extra/mtu.robot @@ -0,0 +1,47 @@ +*** Settings *** +Documentation MTU boundary tests for plain C2CC at jumbo frame size (9000 MTU). +... Sends UDP datagrams with the DF (Don't Fragment) bit set to +... verify packet acceptance and rejection at the pod MTU boundary. +... Tests all three cluster pairs. Requires the c2cc-mtu scenario. + +Resource ../../../resources/microshift-process.resource +Resource ../../../resources/kubeconfig.resource +Resource ../../../resources/oc.resource +Resource ../../../resources/c2cc.resource +Resource ../../../resources/ipsec.resource + +Suite Setup C2CC Suite Setup deploy_workloads=${TRUE} +Suite Teardown C2CC Suite Teardown cleanup_workloads=${TRUE} + +Test Tags c2cc mtu + + +*** Test Cases *** +DF Bit 64B Passes At Jumbo MTU + [Documentation] Smoke test — small DF-bit payload at jumbo MTU on all cluster pairs. + Ping DF Bit Between All Clusters 64 + +DF Bit 8400B Passes At Jumbo MTU + [Documentation] Mid-range jumbo payload on all cluster pairs. + Ping DF Bit Between All Clusters 8400 + +DF Bit 8872B Passes At Jumbo MTU + [Documentation] 8872B + 28B = 8900B — the max payload at recommended pod MTU 8900. + Ping DF Bit Between All Clusters 8872 + +DF Bit 8950B Passes At Jumbo MTU + [Documentation] Near pod MTU — accepted by the kernel on all cluster pairs. + Ping DF Bit Between All Clusters 8950 + +DF Bit 8972B Rejected At Pod MTU + [Documentation] 8972B + 28B = 9000B, hitting the pod interface MTU. + Ping DF Bit Should Fail Between All Clusters 8972 + +Large TCP Transfer At Jumbo MTU + [Documentation] 64KB curl POST across all cluster pairs. + Large Payload Between All Clusters 65536 + +Cross Cluster Connectivity At Jumbo MTU + [Documentation] Full connectivity check: all 6 cluster pairs, pod + service, + ... with source IP preservation. + Verify Full C2CC Connectivity From ea155fe675b1abb52f51c0947642f9d11706bc58 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 12:08:12 +0200 Subject: [PATCH 03/17] Add c2cc-ipsec-mtu scenario for IPsec at jumbo MTU with pod MTU 8900 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a scenario that creates VMs on a jumbo-frame network with IPsec and tests MTU boundaries through ESP tunnel-mode encapsulation. Two phases (ordered by TEST_RANDOMIZATION=none): Phase 1 — pod MTU 9000 (auto-detected from the jumbo network): - DF Bit boundary tests at 64B, 8400B, 8872B, 8950B (pass) and 8972B (rejected at pod MTU) - 64KB TCP transfer through IPsec - ESP encapsulation verified via XFRM byte counters Phase 2 — pod MTU 8900 (set via /etc/microshift/ovn.yaml): - Validates the doc recommendation to reduce pod MTU by ~100 for ESP headroom on jumbo networks - Verifies pod interface reports MTU 8900 after restart - Full pod MTU payload (8872B) passes through IPsec because 8900 + ESP overhead fits within the 9000 physical MTU - Full C2CC connectivity with source IP preservation Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- .../c2cc/el102-src@c2cc-ipsec-mtu.sh | 29 +++ .../c2cc/el102-src@c2cc-ipsec.sh | 2 +- .../c2cc/el98-src@c2cc-ipsec-mtu.sh | 29 +++ .../c2cc/el98-src@c2cc-ipsec.sh | 2 +- test/suites/c2cc/extra/ipsec-mtu.robot | 132 ++++++++++++++ test/suites/c2cc/ipsec/ipsec.robot | 172 ------------------ 6 files changed, 192 insertions(+), 174 deletions(-) create mode 100644 test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu.sh create mode 100644 test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu.sh create mode 100644 test/suites/c2cc/extra/ipsec-mtu.robot delete mode 100644 test/suites/c2cc/ipsec/ipsec.robot diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu.sh new file mode 100644 index 0000000000..39cbd3d334 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. +# +# Sets up 3 MicroShift clusters with C2CC and Libreswan IPsec on a +# jumbo-frame network (MTU 9000). Tests validate MTU boundary behavior +# through IPsec tunnel-mode ESP encapsulation and the recommended +# pod MTU reduction to 8900. + +# shellcheck source=test/bin/c2cc_common.sh +source "${SCRIPTDIR}/c2cc_common.sh" + +export TEST_RANDOMIZATION=none + +scenario_create_vms() { + c2cc_create_jumbo_network + c2cc_create_vms "rhel102-bootc-source-ipsec" "rhel102-bootc" "jumbo" +} + +scenario_remove_vms() { + c2cc_remove_vms +} + +scenario_run_tests() { + configure_c2cc_hosts "c2cc_ipsec_mtu_pre_greenboot" "c2cc_ipsec_mtu_greenboot" + configure_ipsec + + c2cc_run_tests "suites/c2cc/extra/ipsec-mtu.robot" +} diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec.sh index 2c6e13d50d..324d7c583c 100644 --- a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec.sh +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec.sh @@ -26,5 +26,5 @@ scenario_run_tests() { configure_c2cc_hosts "c2cc_ipsec_pre_greenboot" "c2cc_ipsec_greenboot" configure_ipsec - c2cc_run_tests "suites/c2cc/ipsec/" + c2cc_run_tests "suites/c2cc/extra/ipsec.robot" } diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu.sh new file mode 100644 index 0000000000..3ce5580d03 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. +# +# Sets up 3 MicroShift clusters with C2CC and Libreswan IPsec on a +# jumbo-frame network (MTU 9000). Tests validate MTU boundary behavior +# through IPsec tunnel-mode ESP encapsulation and the recommended +# pod MTU reduction to 8900. + +# shellcheck source=test/bin/c2cc_common.sh +source "${SCRIPTDIR}/c2cc_common.sh" + +export TEST_RANDOMIZATION=none + +scenario_create_vms() { + c2cc_create_jumbo_network + c2cc_create_vms "rhel98-bootc-source-ipsec" "rhel98-bootc" "jumbo" +} + +scenario_remove_vms() { + c2cc_remove_vms +} + +scenario_run_tests() { + configure_c2cc_hosts "c2cc_ipsec_mtu_pre_greenboot" "c2cc_ipsec_mtu_greenboot" + configure_ipsec + + c2cc_run_tests "suites/c2cc/extra/ipsec-mtu.robot" +} diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec.sh index e9900c4c7a..b08b4fa8b7 100644 --- a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec.sh +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec.sh @@ -26,5 +26,5 @@ scenario_run_tests() { configure_c2cc_hosts "c2cc_ipsec_pre_greenboot" "c2cc_ipsec_greenboot" configure_ipsec - c2cc_run_tests "suites/c2cc/ipsec/" + c2cc_run_tests "suites/c2cc/extra/ipsec.robot" } diff --git a/test/suites/c2cc/extra/ipsec-mtu.robot b/test/suites/c2cc/extra/ipsec-mtu.robot new file mode 100644 index 0000000000..6c6918bcb9 --- /dev/null +++ b/test/suites/c2cc/extra/ipsec-mtu.robot @@ -0,0 +1,132 @@ +*** Settings *** +Documentation MTU boundary tests for C2CC with IPsec at jumbo frame size (9000 MTU). +... Sends UDP datagrams with the DF bit set through IPsec tunnel-mode +... ESP encapsulation and validates the recommended pod MTU of 8900. +... Tests all three cluster pairs. +... +... Phase 1: pod MTU 9000 (default, auto-detected from network). +... Phase 2: pod MTU 8900 (set via ovn.yaml, validates ESP headroom). +... Requires the c2cc-ipsec-mtu scenario (jumbo network + IPsec). +... Test order is deterministic (TEST_RANDOMIZATION=none). + +Resource ../../../resources/microshift-process.resource +Resource ../../../resources/kubeconfig.resource +Resource ../../../resources/oc.resource +Resource ../../../resources/c2cc.resource +Resource ../../../resources/ipsec.resource + +Suite Setup C2CC Suite Setup deploy_workloads=${TRUE} +Suite Teardown Teardown + +Test Tags c2cc ipsec mtu + + +*** Test Cases *** +# ── Phase 1: pod MTU = 9000 (auto-detected from jumbo network) ──────────────── + +DF Bit 64B Passes Through IPsec At Jumbo MTU + [Documentation] Smoke test — small DF-bit payload through IPsec at jumbo MTU. + Ping DF Bit Between All Clusters 64 + +DF Bit 8400B Passes Through IPsec At Jumbo MTU + [Documentation] Mid-range jumbo payload through IPsec. + Ping DF Bit Between All Clusters 8400 + +DF Bit 8872B Passes Through IPsec At Jumbo MTU + [Documentation] 8872B + 28B = 8900B — the max payload at recommended pod MTU 8900. + Ping DF Bit Between All Clusters 8872 + +DF Bit 8950B Passes Through IPsec At Jumbo MTU + [Documentation] Near pod MTU — accepted by the kernel. + Ping DF Bit Between All Clusters 8950 + +DF Bit 8972B Rejected At Jumbo Pod MTU + [Documentation] 8972B + 28B = 9000B, hitting the pod interface MTU. + Ping DF Bit Should Fail Between All Clusters 8972 + +Large TCP Transfer Through IPsec At Jumbo MTU + [Documentation] 64KB curl POST through IPsec at jumbo MTU. + Large Payload Between All Clusters 65536 + +ESP Encapsulation At Jumbo MTU + [Documentation] Verify traffic is ESP-encapsulated at jumbo frame sizes. + ... Records XFRM byte counters before and after traffic on all clusters. + ${baseline_a}= Get XFRM Byte Counters cluster-a + ${baseline_b}= Get XFRM Byte Counters cluster-b + ${baseline_c}= Get XFRM Byte Counters cluster-c + Verify Full C2CC Connectivity + Verify XFRM Counters Incremented cluster-a ${baseline_a} + Verify XFRM Counters Incremented cluster-b ${baseline_b} + Verify XFRM Counters Incremented cluster-c ${baseline_c} + +# ── Phase 2 setup ───────────────────────────────────────────────────────────── + +Reconfigure Pod MTU To 8900 + [Documentation] Set pod MTU to 8900 via ovn.yaml, restart MicroShift, + ... and redeploy workloads. Validates the doc recommendation for + ... ESP headroom on jumbo networks. + Configure Pod MTU On All Clusters 8900 + Restart MicroShift On All Clusters + Redeploy Test Workloads + +# ── Phase 2: pod MTU = 8900 (recommended for ESP headroom) ──────────────────── + +Pod MTU Is 8900 After Reconfiguration + [Documentation] Verify the pod network interface reports MTU 8900 on all clusters. + FOR ${alias} IN @{ALL_CLUSTERS} + ${mtu}= Get Pod Interface MTU ${alias} nettest-pod ${NAMESPACES}[${alias}] + Should Be Equal As Strings ${mtu} 8900 + ... ${alias}: pod MTU is ${mtu}, expected 8900 + END + +DF Bit 8872B Passes At Reduced Pod MTU + [Documentation] Full pod MTU payload (8872B + 28B = 8900B) passes because + ... 8900 + ESP overhead fits within the 9000 physical MTU. + Ping DF Bit Between All Clusters 8872 + +Large TCP Transfer At Jumbo MTU + [Documentation] 64KB curl POST through IPsec at jumbo MTU. + Large Payload Between All Clusters 65536 + +Cross Cluster Connectivity At Jumbo MTU + [Documentation] Full connectivity check: all 6 cluster pairs, pod + service, + ... with source IP preservation. + Verify Full C2CC Connectivity + + +*** Keywords *** +Configure Pod MTU On All Clusters + [Documentation] Write /etc/microshift/ovn.yaml with the given MTU value. + [Arguments] ${mtu} + FOR ${alias} IN @{ALL_CLUSTERS} + Command On Cluster ${alias} + ... bash -c 'echo "mtu: ${mtu}" > /etc/microshift/ovn.yaml' + END + +Restart MicroShift On All Clusters + [Documentation] Restart MicroShift on all clusters and wait for health + IPsec. + FOR ${alias} IN @{ALL_CLUSTERS} + Command On Cluster ${alias} systemctl restart microshift + END + FOR ${alias} IN @{ALL_CLUSTERS} + Wait Until Keyword Succeeds 5m 15s + ... Command On Cluster ${alias} microshift healthcheck --timeout=30s + END + FOR ${alias} IN @{ALL_CLUSTERS} + Wait For IPsec Tunnel Reestablishment ${alias} expected_count=8 + END + +Redeploy Test Workloads + [Documentation] Delete and redeploy test workloads so pods pick up the new MTU. + Cleanup Test Workloads + Deploy Test Workloads + +Teardown + [Documentation] Clean up workloads, ensure IPsec running, close connections. + Ensure IPsec Running On All Clusters + C2CC Suite Teardown cleanup_workloads=${TRUE} + +Ensure IPsec Running On All Clusters + FOR ${alias} IN cluster-a cluster-b cluster-c + Start IPsec Service On Cluster ${alias} + END diff --git a/test/suites/c2cc/ipsec/ipsec.robot b/test/suites/c2cc/ipsec/ipsec.robot deleted file mode 100644 index 04717e4e76..0000000000 --- a/test/suites/c2cc/ipsec/ipsec.robot +++ /dev/null @@ -1,172 +0,0 @@ -*** Settings *** -Documentation IPsec E2E tests for C2CC. -... Validates that C2CC cross-cluster connectivity works through a -... Libreswan tunnel-mode IPsec mesh (subnet selectors, no Geneve). -... -... Tests cover ESP encapsulation, connectivity through the tunnel, -... source IP preservation, policy enforcement (SA flush/restore), -... plaintext rejection, host-to-pod rejection, and MTU validation. - -Resource ../../../resources/microshift-process.resource -Resource ../../../resources/kubeconfig.resource -Resource ../../../resources/oc.resource -Resource ../../../resources/c2cc.resource -Resource ../../../resources/ipsec.resource - -Suite Setup C2CC Suite Setup deploy_workloads=${TRUE} -Suite Teardown Teardown - -Test Tags c2cc ipsec - - -*** Test Cases *** -IPsec Tunnels Established On All Clusters - [Documentation] Verify all 3 hosts have 8 IPsec tunnel SAs each. - ... Each host has 2 remote hosts x 4 subnet pairs (2 local x 2 remote CIDRs). - Verify All IPsec Tunnels On Cluster cluster-a expected_count=8 - Verify All IPsec Tunnels On Cluster cluster-b expected_count=8 - Verify All IPsec Tunnels On Cluster cluster-c expected_count=8 - -ESP Encapsulation On Wire - [Documentation] Capture packets on the wire and verify ESP encapsulation. - ... Records XFRM byte counters before and after traffic, captures ESP packets - ... via tcpdump, and verifies counters incremented. - ${baseline_a}= Get XFRM Byte Counters cluster-a - ${baseline_b}= Get XFRM Byte Counters cluster-b - - ${pcap_file}= Start Tcpdump For ESP On Cluster cluster-b - ${ip_dest}= Get Hello Pod IP cluster-b - Curl From Cluster cluster-a ${ip_dest} 8080 - Wait For Tcpdump And Verify ESP cluster-b ${pcap_file} - - Verify XFRM Counters Incremented cluster-a ${baseline_a} - Verify XFRM Counters Incremented cluster-b ${baseline_b} - -Cross Cluster Connectivity Through IPsec - [Documentation] Verify pods on all clusters can reach pods/services on all - ... other clusters through the IPsec tunnel. - [Template] Verify Connectivity Between Clusters - cluster-a cluster-b pod - cluster-a cluster-b service - cluster-a cluster-c pod - cluster-a cluster-c service - cluster-b cluster-a pod - cluster-b cluster-a service - cluster-b cluster-c pod - cluster-b cluster-c service - cluster-c cluster-a pod - cluster-c cluster-a service - cluster-c cluster-b pod - cluster-c cluster-b service - -Source IP Preserved Through IPsec - [Documentation] Verify cross-cluster traffic through IPsec preserves the - ... source pod IP (no SNAT). - [Template] Verify Source IP Preserved Between Clusters - cluster-a cluster-b pod - cluster-a cluster-b service - cluster-a cluster-c pod - cluster-a cluster-c service - cluster-b cluster-a pod - cluster-b cluster-a service - cluster-b cluster-c pod - cluster-b cluster-c service - cluster-c cluster-a pod - cluster-c cluster-a service - cluster-c cluster-b pod - cluster-c cluster-b service - -Plaintext Rejection When IPsec Stopped - [Documentation] Stop IPsec on cluster-a. With nftables enforcement rules on - ... cluster-b, verify traffic is dropped rather than sent in plaintext. - [Setup] Add NFTables IPsec Enforcement Rules cluster-b ${CLUSTER_B_POD_CIDR} - - Stop IPsec Service On Cluster cluster-a - Sleep 3s reason=Wait for SAs to expire - ${ip_dest}= Get Hello Pod IP cluster-b - Curl Should Fail From Cluster cluster-a ${ip_dest} 8080 ${NAMESPACES}[cluster-a] - - [Teardown] Restore IPsec With Enforcement Cleanup cluster-a cluster-b - -Host To Remote Pod Rejected Without IPsec - [Documentation] Curl directly from cluster-a's host to a pod on cluster-b. - ... Host-originated traffic is not matched by tunnel-mode IPsec selectors - ... scoped to pod/service CIDRs, so it cannot reach the remote pod. - ${pod_ip}= Get Hello Pod IP cluster-b - Curl From Host Should Fail cluster-a ${pod_ip} 8080 - -Near MTU Packet Through IPsec Tunnel - [Documentation] Send near-MTU-sized payloads through IPsec tunnel-mode - ... encapsulation. Verifies no MTU blackhole from DF-bit issues. - ... ESP overhead ~36-52B total. - ${ip_dest}= Get Hello Pod IP cluster-b - Send Large Payload And Verify cluster-a ${ip_dest} 1300 - Send Large Payload And Verify cluster-a ${ip_dest} 1400 - -Cross Cluster DNS Through IPsec - [Documentation] Verify pods can resolve and reach services on remote - ... clusters via DNS name through the IPsec tunnel. - [Template] Verify Remote Service Via DNS - cluster-a cluster-b - cluster-a cluster-c - cluster-b cluster-a - cluster-b cluster-c - cluster-c cluster-a - cluster-c cluster-b - -IPsec Tunnel Recovers After Local Restart - [Documentation] Restart IPsec on cluster-a and verify tunnels recover - ... and cross-cluster connectivity is restored. - Restart IPsec Service On Cluster cluster-a - Wait For IPsec Tunnel Reestablishment cluster-a expected_count=8 - Wait For IPsec Tunnel Reestablishment cluster-b expected_count=8 - Wait For IPsec Tunnel Reestablishment cluster-c expected_count=8 - ${ip_dest}= Get Hello Pod IP cluster-b - Curl From Cluster cluster-a ${ip_dest} 8080 - -IPsec Tunnel Recovers After Remote Stop Start - [Documentation] Stop IPsec on cluster-b, start it back, and verify - ... tunnels recover and cross-cluster connectivity is restored. - Stop IPsec Service On Cluster cluster-b - Sleep 5s reason=Wait for tunnel to go down - Start IPsec Service On Cluster cluster-b - Wait For IPsec Tunnel Reestablishment cluster-a expected_count=8 - Wait For IPsec Tunnel Reestablishment cluster-b expected_count=8 - Wait For IPsec Tunnel Reestablishment cluster-c expected_count=8 - ${ip_dest}= Get Hello Pod IP cluster-b - Curl From Cluster cluster-a ${ip_dest} 8080 - - -*** Keywords *** -Teardown - [Documentation] Ensure IPsec is running, then remove test workloads and close connections. - Ensure IPsec Running On All Clusters - C2CC Suite Teardown cleanup_workloads=${TRUE} - -Ensure IPsec Running On All Clusters - [Documentation] Make sure ipsec service is running on all clusters. - ... Tests may have stopped it. - FOR ${alias} IN cluster-a cluster-b cluster-c - Start IPsec Service On Cluster ${alias} - END - -Restore IPsec And Verify - [Documentation] Restart ipsec and wait for tunnels to come back up. - [Arguments] ${alias} - Restart IPsec Service On Cluster ${alias} - Wait For IPsec Tunnel Reestablishment ${alias} expected_count=8 - -Restore IPsec With Enforcement Cleanup - [Documentation] Remove enforcement rules and restore IPsec. - [Arguments] ${ipsec_alias} ${enforcement_alias} - Remove NFTables IPsec Enforcement Rules ${enforcement_alias} - Start IPsec Service On Cluster ${ipsec_alias} - Wait For IPsec Tunnel Reestablishment ${ipsec_alias} expected_count=8 - -Send Large Payload And Verify - [Documentation] Send a large payload via curl POST and verify it succeeds. - [Arguments] ${alias} ${ip} ${size} - ${stdout}= Oc On Cluster - ... ${alias} - ... oc exec curl-pod -n ${NAMESPACES}[${alias}] -- sh -c 'dd if=/dev/zero bs=${size} count=1 2>/dev/null | curl -sS --max-time 15 --data-binary @- http://${ip}:8080/cgi-bin/hello' - Should Contain ${stdout} Hello from From bdfed31bf7840ce2017fd0052e6eaaefd34a93a1 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 14:29:59 +0200 Subject: [PATCH 04/17] Fix jumbo MTU scenarios: guest NICs never negotiated MTU 9000 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI showed pod interfaces stuck at MTU 1500 even on the jumbo libvirt network, causing every DF-bit payload over ~1450 bytes to fail with "Message too long" and the pod MTU 8900 override to silently no-op. Root cause: a libvirt network's own element only sets the MTU of the host-side bridge and tap devices. The guest's virtio-net driver only sees a larger interface MTU if QEMU also negotiates it via the domain's own XML — which requires an explicit mtu.size on the virt-install --network argument. Without it, guest NICs default to 1500 regardless of what the underlying tap/bridge supports. Add a --network_mtu option to launch_vm() in scenario.sh that appends mtu.size= to the virt-install network argument, thread it through c2cc_create_vms() as a new optional 5th parameter, and pass "9000" from the c2cc-mtu and c2cc-ipsec-mtu scenario scripts. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- test/bin/c2cc_common.sh | 12 ++++++++--- test/bin/scenario.sh | 21 ++++++++++++++++++- .../c2cc/el102-src@c2cc-ipsec-mtu.sh | 2 +- .../c2cc/el102-src@c2cc-mtu.sh | 2 +- .../c2cc/el98-src@c2cc-ipsec-mtu.sh | 2 +- .../scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh | 2 +- 6 files changed, 33 insertions(+), 8 deletions(-) diff --git a/test/bin/c2cc_common.sh b/test/bin/c2cc_common.sh index ad574f8374..9874cd180d 100644 --- a/test/bin/c2cc_common.sh +++ b/test/bin/c2cc_common.sh @@ -193,6 +193,7 @@ c2cc_create_vms() { local -r boot_blueprint="${2}" local -r network="${3:-default}" local -r ip_family="${4:-ipv4}" + local -r network_mtu="${5:-}" # Prepare kickstart for all hosts # prepare_kickstart args: vmname template commit_ref fips_enabled ipv6_only @@ -223,9 +224,14 @@ c2cc_create_vms() { "${CLUSTER_C_POD_CIDR}" "${CLUSTER_C_SVC_CIDR}" \ "${CLUSTER_C_POD_CIDR_DUAL}" "${CLUSTER_C_SVC_CIDR_DUAL}" - launch_vm "${boot_blueprint}" --vmname host1 --network "${network}" - launch_vm "${boot_blueprint}" --vmname host2 --network "${network}" - launch_vm "${boot_blueprint}" --vmname host3 --network "${network}" + local mtu_args=() + if [ -n "${network_mtu}" ]; then + mtu_args=(--network_mtu "${network_mtu}") + fi + + launch_vm "${boot_blueprint}" --vmname host1 --network "${network}" "${mtu_args[@]}" + launch_vm "${boot_blueprint}" --vmname host2 --network "${network}" "${mtu_args[@]}" + launch_vm "${boot_blueprint}" --vmname host3 --network "${network}" "${mtu_args[@]}" } # c2cc_create_jumbo_network creates a libvirt network with MTU 9000 for diff --git a/test/bin/scenario.sh b/test/bin/scenario.sh index cef81e6be3..2d2f0b3748 100755 --- a/test/bin/scenario.sh +++ b/test/bin/scenario.sh @@ -804,6 +804,7 @@ EOF # \ # [--vmname ] \ # [--network [,...]] \ +# [--network_mtu ] \ # [--vm_vcpus ] \ # [--vm_memory ] \ # [--vm_disksize ] \ @@ -820,6 +821,14 @@ EOF # [--network [,...]]: A comma-separated list for the networks used # when creating the VM. Each network entry will # create a NIC and they are repeatable. +# [--network_mtu ]: Sets the guest-visible MTU on every NIC via +# virt-install's mtu.size sub-option. Required +# in addition to a libvirt network's own +# element — QEMU only negotiates a larger MTU +# with the guest's virtio-net driver when the +# domain's own XML requests it; +# the network-level MTU alone only affects the +# host-side bridge and tap devices. # [--no_network]: Do not configure any network attachments (and # therefore no NICs) for the VM. # [--vm_vcpus ]: Number of vCPUs for the VM. @@ -830,6 +839,7 @@ launch_vm() { # Set default values for the optional arguments local vmname="host1" local network="default" + local network_mtu="" local vm_memory=4096 local vm_vcpus=2 local vm_disksize=20 @@ -848,7 +858,7 @@ launch_vm() { # Parse the optional arguments while [ $# -gt 0 ]; do case "$1" in - --vmname|--vm_vcpus|--vm_memory|--vm_disksize) + --vmname|--vm_vcpus|--vm_memory|--vm_disksize|--network_mtu) var="${1/--/}" if [ -n "$2" ] && [ "${2:0:1}" != "-" ]; then declare "${var}=$2" @@ -960,6 +970,15 @@ launch_vm() { if sudo virsh nwfilter-list | awk '{print $2}' | grep -qx "${n}"; then vm_network_args+=",filterref=${n}" fi + + # A libvirt network's own element only sets the host-side bridge + # and tap device MTU. The guest only sees a larger MTU if QEMU also + # negotiates it with the guest's virtio-net driver, which requires an + # explicit MTU on the domain's own interface. + if [ -n "${network_mtu}" ]; then + vm_network_args+=",mtu.size=${network_mtu}" + fi + vm_network_args+=" " done if [ -z "${vm_network_args}" ] ; then diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu.sh index 39cbd3d334..753394b173 100644 --- a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu.sh +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu.sh @@ -14,7 +14,7 @@ export TEST_RANDOMIZATION=none scenario_create_vms() { c2cc_create_jumbo_network - c2cc_create_vms "rhel102-bootc-source-ipsec" "rhel102-bootc" "jumbo" + c2cc_create_vms "rhel102-bootc-source-ipsec" "rhel102-bootc" "jumbo" "ipv4" "9000" } scenario_remove_vms() { diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu.sh index 071b747358..e3159a7189 100644 --- a/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu.sh +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu.sh @@ -11,7 +11,7 @@ source "${SCRIPTDIR}/c2cc_common.sh" scenario_create_vms() { c2cc_create_jumbo_network - c2cc_create_vms "rhel102-bootc-source" "rhel102-bootc" "jumbo" + c2cc_create_vms "rhel102-bootc-source" "rhel102-bootc" "jumbo" "ipv4" "9000" } scenario_remove_vms() { diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu.sh index 3ce5580d03..eac5896de0 100644 --- a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu.sh +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu.sh @@ -14,7 +14,7 @@ export TEST_RANDOMIZATION=none scenario_create_vms() { c2cc_create_jumbo_network - c2cc_create_vms "rhel98-bootc-source-ipsec" "rhel98-bootc" "jumbo" + c2cc_create_vms "rhel98-bootc-source-ipsec" "rhel98-bootc" "jumbo" "ipv4" "9000" } scenario_remove_vms() { diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh index dfb8eb8adf..00c9bfe2f2 100644 --- a/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh @@ -11,7 +11,7 @@ source "${SCRIPTDIR}/c2cc_common.sh" scenario_create_vms() { c2cc_create_jumbo_network - c2cc_create_vms "rhel98-bootc-source" "rhel98-bootc" "jumbo" + c2cc_create_vms "rhel98-bootc-source" "rhel98-bootc" "jumbo" "ipv4" "9000" } scenario_remove_vms() { From 6192e76278b349bc83eaa3e0378bf3d7b335707d Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 14:46:24 +0200 Subject: [PATCH 05/17] Add dual-stack support to IPsec/MTU test keywords MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add IPv4/IPv6 auto-detection (based on ':' in the address, matching the pattern already used by Curl From Cluster in c2cc.resource) to: - Ping With DF Bit And Verify / Should Fail: use AF_INET6 + IPPROTO_IPV6/IPV6_DONTFRAG when the destination is IPv6, instead of always hardcoding AF_INET + IP_MTU_DISCOVER/IP_PMTUDISC_DO. - Send Large Payload And Verify, Curl Should Fail From Cluster, Curl From Host Should Fail: wrap the URL host in brackets for IPv6. - Add NFTables IPsec Enforcement Rules: use "ip6 daddr" instead of "ip daddr" when the CIDR is IPv6. No caller changes needed — the family is inferred from the address values already passed in (Get Hello Pod IP returns whatever family the cluster is configured for). IPv4 behavior is unchanged. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- test/resources/ipsec.resource | 42 ++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/test/resources/ipsec.resource b/test/resources/ipsec.resource index bd9b22f3a4..d964704b33 100644 --- a/test/resources/ipsec.resource +++ b/test/resources/ipsec.resource @@ -97,11 +97,13 @@ Add NFTables IPsec Enforcement Rules ... In tunnel mode, decrypted packets have pod/service CIDRs as dst — plaintext ... packets arriving without ESP are caught by this rule. [Arguments] ${alias} ${local_pod_cidr} + ${is_ipv6}= Evaluate ':' in '''${local_pod_cidr}''' + ${daddr_family}= Set Variable If ${is_ipv6} ip6 ip Command On Cluster ${alias} nft add table inet c2cc_ipsec_test Command On Cluster ${alias} ... nft 'add chain inet c2cc_ipsec_test enforce { type filter hook input priority -150; policy accept; }' Command On Cluster ${alias} - ... nft add rule inet c2cc_ipsec_test enforce ip daddr ${local_pod_cidr} meta ipsec missing counter drop + ... nft add rule inet c2cc_ipsec_test enforce ${daddr_family} daddr ${local_pod_cidr} meta ipsec missing counter drop Remove NFTables IPsec Enforcement Rules [Documentation] Remove C2CC IPsec enforcement nftables table and all its rules. @@ -113,8 +115,13 @@ Remove NFTables IPsec Enforcement Rules Curl Should Fail From Cluster [Documentation] Verify curl from curl-pod times out or fails (no "Hello from" in response). [Arguments] ${alias} ${ip} ${port} ${ns} + ${is_ipv6}= Evaluate ':' in '''${ip}''' + ${url}= Set Variable If + ... ${is_ipv6} + ... http://[${ip}]:${port}/cgi-bin/hello + ... http://${ip}:${port}/cgi-bin/hello ${stdout}= Oc On Cluster ${alias} - ... oc exec curl-pod -n ${ns} -- curl -sS --max-time 5 http://${ip}:${port}/cgi-bin/hello 2>&1 || true + ... oc exec curl-pod -n ${ns} -- curl -sS --max-time 5 ${url} 2>&1 || true ... allow_fail=${TRUE} Should Not Contain ${stdout} Hello from @@ -123,29 +130,37 @@ Curl From Host Should Fail ... Expects failure — host-originated traffic is not matched by tunnel-mode ... IPsec selectors scoped to pod/service CIDRs. [Arguments] ${alias} ${pod_ip} ${port} + ${is_ipv6}= Evaluate ':' in '''${pod_ip}''' + ${url}= Set Variable If + ... ${is_ipv6} + ... http://[${pod_ip}]:${port}/cgi-bin/hello + ... http://${pod_ip}:${port}/cgi-bin/hello ${stdout}= Disruptive Command On Cluster ${alias} - ... curl -sS --max-time 5 http://${pod_ip}:${port}/cgi-bin/hello 2>&1 || true + ... curl -sS --max-time 5 ${url} 2>&1 || true Should Not Contain ${stdout} Hello from Ping With DF Bit And Verify - [Documentation] Send a UDP datagram with DF bit set (IP_PMTUDISC_DO) via Python3. - ... Asserts the kernel accepted the datagram (fits within ESP-adjusted PMTU). + [Documentation] Send a UDP datagram with DF bit set (IP_PMTUDISC_DO / IPV6_DONTFRAG) + ... via Python3. Asserts the kernel accepted the datagram (fits within the + ... ESP-adjusted PMTU). Auto-detects IPv4 vs IPv6 from the destination address. ... Uses UDP instead of ICMP to avoid requiring NET_RAW capability. - ... UDP overhead (IP+UDP = 28B) matches ICMP overhead (IP+ICMP = 28B), - ... so payload sizes are equivalent to ping -s values. + ... UDP overhead (IP+UDP) matches ICMP overhead (IP+ICMP): 28B for IPv4, + ... 48B for IPv6 (40B header instead of 20B), so payload sizes are + ... equivalent to ping -s values within each family. [Arguments] ${alias} ${dest_ip} ${payload_size} ${stdout}= Oc On Cluster ${alias} - ... oc exec nettest-pod -n ${NAMESPACES}[${alias}] -- python3 -c 'import socket,sys;s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM);s.setsockopt(socket.IPPROTO_IP,10,2);s.sendto(b"A"*${payload_size},(sys.argv[1],9999));print("OK")' ${dest_ip} 2>&1 + ... oc exec nettest-pod -n ${NAMESPACES}[${alias}] -- python3 -c 'import socket,sys;a=sys.argv[1];f=socket.AF_INET6 if ":" in a else socket.AF_INET;s=socket.socket(f,socket.SOCK_DGRAM);s.setsockopt(41,62,1) if f==socket.AF_INET6 else s.setsockopt(socket.IPPROTO_IP,10,2);s.sendto(b"A"*${payload_size},(a,9999));print("OK")' ${dest_ip} 2>&1 ... allow_fail=${TRUE} Should Contain ${stdout} OK ... DF-bit UDP send of ${payload_size}B to ${dest_ip} failed: ${stdout} Ping With DF Bit Should Fail [Documentation] Send a UDP datagram with DF bit set. Asserts EMSGSIZE (Message too long). - ... Proves the datagram exceeds the ESP-adjusted PMTU. + ... Proves the datagram exceeds the ESP-adjusted PMTU. Auto-detects IPv4 vs + ... IPv6 from the destination address. [Arguments] ${alias} ${dest_ip} ${payload_size} ${stdout}= Oc On Cluster ${alias} - ... oc exec nettest-pod -n ${NAMESPACES}[${alias}] -- python3 -c 'import socket,sys;s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM);s.setsockopt(socket.IPPROTO_IP,10,2);s.sendto(b"A"*${payload_size},(sys.argv[1],9999));print("OK")' ${dest_ip} 2>&1 || true + ... oc exec nettest-pod -n ${NAMESPACES}[${alias}] -- python3 -c 'import socket,sys;a=sys.argv[1];f=socket.AF_INET6 if ":" in a else socket.AF_INET;s=socket.socket(f,socket.SOCK_DGRAM);s.setsockopt(41,62,1) if f==socket.AF_INET6 else s.setsockopt(socket.IPPROTO_IP,10,2);s.sendto(b"A"*${payload_size},(a,9999));print("OK")' ${dest_ip} 2>&1 || true ... allow_fail=${TRUE} Should Not Contain ${stdout} OK ... DF-bit UDP send of ${payload_size}B should have been rejected but succeeded @@ -161,9 +176,14 @@ Get Pod Interface MTU Send Large Payload And Verify [Documentation] Send a large payload via curl POST and verify it succeeds. [Arguments] ${alias} ${ip} ${size} + ${is_ipv6}= Evaluate ':' in '''${ip}''' + ${url}= Set Variable If + ... ${is_ipv6} + ... http://[${ip}]:8080/cgi-bin/hello + ... http://${ip}:8080/cgi-bin/hello ${stdout}= Oc On Cluster ... ${alias} - ... oc exec curl-pod -n ${NAMESPACES}[${alias}] -- sh -c 'dd if=/dev/zero bs=${size} count=1 2>/dev/null | curl -sS --max-time 15 --data-binary @- http://${ip}:8080/cgi-bin/hello' + ... oc exec curl-pod -n ${NAMESPACES}[${alias}] -- sh -c 'dd if=/dev/zero bs=${size} count=1 2>/dev/null | curl -sS --max-time 15 --data-binary @- ${url}' Should Contain ${stdout} Hello from Ping DF Bit Between All Clusters From 00d78d1edade2bfa2a28ce3353e61fea052577d2 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 14:46:33 +0200 Subject: [PATCH 06/17] Add IPv6 jumbo-frame libvirt network New jumbo-ipv6 network (single-stack IPv6, NAT, MTU 9000) and its creation function, mirroring the existing IPv4 jumbo network. Kept separate from the shared VM_IPV6_NETWORK ("ipv6") so bumping MTU for jumbo-frame tests doesn't affect other IPv6 C2CC scenarios. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- test/assets/network/jumbo-ipv6-network.xml | 14 ++++++++++++++ test/bin/c2cc_common.sh | 14 ++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 test/assets/network/jumbo-ipv6-network.xml diff --git a/test/assets/network/jumbo-ipv6-network.xml b/test/assets/network/jumbo-ipv6-network.xml new file mode 100644 index 0000000000..1f2f855d12 --- /dev/null +++ b/test/assets/network/jumbo-ipv6-network.xml @@ -0,0 +1,14 @@ + + jumbo-ipv6 + + + + + + + + + + + + diff --git a/test/bin/c2cc_common.sh b/test/bin/c2cc_common.sh index 9874cd180d..0221c9f049 100644 --- a/test/bin/c2cc_common.sh +++ b/test/bin/c2cc_common.sh @@ -246,6 +246,20 @@ c2cc_create_jumbo_network() { sudo virsh net-autostart jumbo } +# c2cc_create_jumbo_ipv6_network creates a single-stack IPv6 libvirt network +# with MTU 9000 for jumbo frame testing. Idempotent — skips if the network +# already exists. Kept separate from the shared VM_IPV6_NETWORK ("ipv6") so +# jumbo MTU doesn't affect other IPv6 scenarios. +c2cc_create_jumbo_ipv6_network() { + if sudo virsh net-info jumbo-ipv6 &>/dev/null; then + return 0 + fi + local -r netconfig="${ROOTDIR}/test/assets/network/jumbo-ipv6-network.xml" + sudo virsh net-define "${netconfig}" + sudo virsh net-start jumbo-ipv6 + sudo virsh net-autostart jumbo-ipv6 +} + c2cc_remove_vms() { remove_vm host1 remove_vm host2 From a5a3e26793ae517a7784b0803a9efe9f206d1b9f Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 14:46:42 +0200 Subject: [PATCH 07/17] Add c2cc-ipsec-ipv6 scenario IPv6 variant of c2cc-ipsec: same suite (suites/c2cc/extra/ipsec.robot), same 1500 MTU, over a single-stack IPv6 network instead of IPv4. Follows the existing c2cc-ipv6 scenario's pattern for the IPv6 bridge IP, web server URL, and mirror registry overrides. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- .../c2cc/el102-src@c2cc-ipsec-ipv6.sh | 56 +++++++++++++++++++ .../c2cc/el98-src@c2cc-ipsec-ipv6.sh | 56 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-ipv6.sh create mode 100644 test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-ipv6.sh diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-ipv6.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-ipv6.sh new file mode 100644 index 0000000000..f68b5d1469 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-ipv6.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. +# +# Sets up 3 MicroShift clusters with C2CC and Libreswan IPsec (tunnel mode +# protecting pod/service CIDRs) on a single-stack IPv6 network. Same test +# suite as c2cc-ipsec, run over IPv6 instead of IPv4. + +# shellcheck source=test/bin/c2cc_common.sh +source "${SCRIPTDIR}/c2cc_common.sh" + +# IPsec tests have ordering dependencies (setup verification must pass before +# enforcement tests), so disable randomization. +export TEST_RANDOMIZATION=none + +# Redefine network-related settings to use the dedicated IPv6 network bridge +# shellcheck disable=SC2034 # used elsewhere +VM_BRIDGE_IP="$(get_vm_bridge_ip "${VM_IPV6_NETWORK}")" +# shellcheck disable=SC2034 # used elsewhere +WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" +# Using `hostname` here instead of a raw ip because skopeo only allows either +# ipv4 or fqdn's, but not ipv6. Since the registry is hosted on the ipv6 +# network gateway in the host, we need to use a combination of the hostname +# plus /etc/hosts resolution (which is taken care of by kickstart). +# shellcheck disable=SC2034 # used elsewhere +MIRROR_REGISTRY_URL="$(hostname):${MIRROR_REGISTRY_PORT}/microshift" + +# Cluster A (host1): non-overlapping CIDRs +CLUSTER_A_POD_CIDR="fd01::/48" +CLUSTER_A_SVC_CIDR="fd02::/112" +CLUSTER_A_DOMAIN="cluster-a.remote" + +# Cluster B (host2): non-overlapping CIDRs +CLUSTER_B_POD_CIDR="fd04::/48" +CLUSTER_B_SVC_CIDR="fd05::/112" +CLUSTER_B_DOMAIN="cluster-b.remote" + +# Cluster C (host3): non-overlapping CIDRs +CLUSTER_C_POD_CIDR="fd07::/48" +CLUSTER_C_SVC_CIDR="fd08::/112" +CLUSTER_C_DOMAIN="cluster-c.remote" + +scenario_create_vms() { + c2cc_create_vms "rhel102-bootc-source-ipsec" "rhel102-bootc" "${VM_IPV6_NETWORK}" ipv6 +} + +scenario_remove_vms() { + c2cc_remove_vms +} + +scenario_run_tests() { + configure_c2cc_hosts "c2cc_ipsec_pre_greenboot" "c2cc_ipsec_greenboot" + configure_ipsec + + c2cc_run_tests "suites/c2cc/extra/ipsec.robot" "" ipv6 +} diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-ipv6.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-ipv6.sh new file mode 100644 index 0000000000..e55075dfea --- /dev/null +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-ipv6.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. +# +# Sets up 3 MicroShift clusters with C2CC and Libreswan IPsec (tunnel mode +# protecting pod/service CIDRs) on a single-stack IPv6 network. Same test +# suite as c2cc-ipsec, run over IPv6 instead of IPv4. + +# shellcheck source=test/bin/c2cc_common.sh +source "${SCRIPTDIR}/c2cc_common.sh" + +# IPsec tests have ordering dependencies (setup verification must pass before +# enforcement tests), so disable randomization. +export TEST_RANDOMIZATION=none + +# Redefine network-related settings to use the dedicated IPv6 network bridge +# shellcheck disable=SC2034 # used elsewhere +VM_BRIDGE_IP="$(get_vm_bridge_ip "${VM_IPV6_NETWORK}")" +# shellcheck disable=SC2034 # used elsewhere +WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" +# Using `hostname` here instead of a raw ip because skopeo only allows either +# ipv4 or fqdn's, but not ipv6. Since the registry is hosted on the ipv6 +# network gateway in the host, we need to use a combination of the hostname +# plus /etc/hosts resolution (which is taken care of by kickstart). +# shellcheck disable=SC2034 # used elsewhere +MIRROR_REGISTRY_URL="$(hostname):${MIRROR_REGISTRY_PORT}/microshift" + +# Cluster A (host1): non-overlapping CIDRs +CLUSTER_A_POD_CIDR="fd01::/48" +CLUSTER_A_SVC_CIDR="fd02::/112" +CLUSTER_A_DOMAIN="cluster-a.remote" + +# Cluster B (host2): non-overlapping CIDRs +CLUSTER_B_POD_CIDR="fd04::/48" +CLUSTER_B_SVC_CIDR="fd05::/112" +CLUSTER_B_DOMAIN="cluster-b.remote" + +# Cluster C (host3): non-overlapping CIDRs +CLUSTER_C_POD_CIDR="fd07::/48" +CLUSTER_C_SVC_CIDR="fd08::/112" +CLUSTER_C_DOMAIN="cluster-c.remote" + +scenario_create_vms() { + c2cc_create_vms "rhel98-bootc-source-ipsec" "rhel98-bootc" "${VM_IPV6_NETWORK}" ipv6 +} + +scenario_remove_vms() { + c2cc_remove_vms +} + +scenario_run_tests() { + configure_c2cc_hosts "c2cc_ipsec_pre_greenboot" "c2cc_ipsec_greenboot" + configure_ipsec + + c2cc_run_tests "suites/c2cc/extra/ipsec.robot" "" ipv6 +} From 486558b5ca0e34c7f0a92585b1194e675a591c90 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 14:46:48 +0200 Subject: [PATCH 08/17] Add c2cc-mtu-ipv6 scenario IPv6 variant of c2cc-mtu: same suite (suites/c2cc/extra/mtu.robot), jumbo MTU (9000), plain C2CC without IPsec, over the new jumbo-ipv6 libvirt network. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- .../c2cc/el102-src@c2cc-mtu-ipv6.sh | 50 +++++++++++++++++++ .../c2cc/el98-src@c2cc-mtu-ipv6.sh | 50 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv6.sh create mode 100644 test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv6.sh diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv6.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv6.sh new file mode 100644 index 0000000000..b9e15683fb --- /dev/null +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv6.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. +# +# Sets up 3 MicroShift clusters with C2CC on a single-stack IPv6 jumbo-frame +# network (MTU 9000). Same test suite as c2cc-mtu, run over IPv6 instead of +# IPv4, without IPsec. + +# shellcheck source=test/bin/c2cc_common.sh +source "${SCRIPTDIR}/c2cc_common.sh" + +# Redefine network-related settings to use the IPv6 jumbo network bridge +# shellcheck disable=SC2034 # used elsewhere +VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" +# shellcheck disable=SC2034 # used elsewhere +WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" +# Using `hostname` here instead of a raw ip because skopeo only allows either +# ipv4 or fqdn's, but not ipv6. +# shellcheck disable=SC2034 # used elsewhere +MIRROR_REGISTRY_URL="$(hostname):${MIRROR_REGISTRY_PORT}/microshift" + +# Cluster A (host1): non-overlapping CIDRs +CLUSTER_A_POD_CIDR="fd01::/48" +CLUSTER_A_SVC_CIDR="fd02::/112" +CLUSTER_A_DOMAIN="cluster-a.remote" + +# Cluster B (host2): non-overlapping CIDRs +CLUSTER_B_POD_CIDR="fd04::/48" +CLUSTER_B_SVC_CIDR="fd05::/112" +CLUSTER_B_DOMAIN="cluster-b.remote" + +# Cluster C (host3): non-overlapping CIDRs +CLUSTER_C_POD_CIDR="fd07::/48" +CLUSTER_C_SVC_CIDR="fd08::/112" +CLUSTER_C_DOMAIN="cluster-c.remote" + +scenario_create_vms() { + c2cc_create_jumbo_ipv6_network + c2cc_create_vms "rhel102-bootc-source" "rhel102-bootc" "jumbo-ipv6" "ipv6" "9000" +} + +scenario_remove_vms() { + c2cc_remove_vms +} + +scenario_run_tests() { + configure_c2cc_hosts "c2cc_mtu_pre_greenboot" "c2cc_mtu_greenboot" + + c2cc_run_tests "suites/c2cc/extra/mtu.robot" "" ipv6 +} diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv6.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv6.sh new file mode 100644 index 0000000000..d0f627705c --- /dev/null +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv6.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. +# +# Sets up 3 MicroShift clusters with C2CC on a single-stack IPv6 jumbo-frame +# network (MTU 9000). Same test suite as c2cc-mtu, run over IPv6 instead of +# IPv4, without IPsec. + +# shellcheck source=test/bin/c2cc_common.sh +source "${SCRIPTDIR}/c2cc_common.sh" + +# Redefine network-related settings to use the IPv6 jumbo network bridge +# shellcheck disable=SC2034 # used elsewhere +VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" +# shellcheck disable=SC2034 # used elsewhere +WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" +# Using `hostname` here instead of a raw ip because skopeo only allows either +# ipv4 or fqdn's, but not ipv6. +# shellcheck disable=SC2034 # used elsewhere +MIRROR_REGISTRY_URL="$(hostname):${MIRROR_REGISTRY_PORT}/microshift" + +# Cluster A (host1): non-overlapping CIDRs +CLUSTER_A_POD_CIDR="fd01::/48" +CLUSTER_A_SVC_CIDR="fd02::/112" +CLUSTER_A_DOMAIN="cluster-a.remote" + +# Cluster B (host2): non-overlapping CIDRs +CLUSTER_B_POD_CIDR="fd04::/48" +CLUSTER_B_SVC_CIDR="fd05::/112" +CLUSTER_B_DOMAIN="cluster-b.remote" + +# Cluster C (host3): non-overlapping CIDRs +CLUSTER_C_POD_CIDR="fd07::/48" +CLUSTER_C_SVC_CIDR="fd08::/112" +CLUSTER_C_DOMAIN="cluster-c.remote" + +scenario_create_vms() { + c2cc_create_jumbo_ipv6_network + c2cc_create_vms "rhel98-bootc-source" "rhel98-bootc" "jumbo-ipv6" "ipv6" "9000" +} + +scenario_remove_vms() { + c2cc_remove_vms +} + +scenario_run_tests() { + configure_c2cc_hosts "c2cc_mtu_pre_greenboot" "c2cc_mtu_greenboot" + + c2cc_run_tests "suites/c2cc/extra/mtu.robot" "" ipv6 +} From ce662cc731a9c27c512525bfd421c8258997e8f2 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 14:46:56 +0200 Subject: [PATCH 09/17] Add c2cc-ipsec-mtu-ipv6 scenario IPv6 variant of c2cc-ipsec-mtu: same suite (suites/c2cc/extra/ipsec-mtu.robot), IPsec at jumbo MTU (9000) with the two-phase pod MTU 8900 validation, over the new jumbo-ipv6 libvirt network. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- .../c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh | 53 +++++++++++++++++++ .../c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh | 53 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh create mode 100644 test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh new file mode 100644 index 0000000000..d9250b2abf --- /dev/null +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. +# +# Sets up 3 MicroShift clusters with C2CC and Libreswan IPsec on a +# single-stack IPv6 jumbo-frame network (MTU 9000). Same test suite as +# c2cc-ipsec-mtu, run over IPv6 instead of IPv4. + +# shellcheck source=test/bin/c2cc_common.sh +source "${SCRIPTDIR}/c2cc_common.sh" + +export TEST_RANDOMIZATION=none + +# Redefine network-related settings to use the IPv6 jumbo network bridge +# shellcheck disable=SC2034 # used elsewhere +VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" +# shellcheck disable=SC2034 # used elsewhere +WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" +# Using `hostname` here instead of a raw ip because skopeo only allows either +# ipv4 or fqdn's, but not ipv6. +# shellcheck disable=SC2034 # used elsewhere +MIRROR_REGISTRY_URL="$(hostname):${MIRROR_REGISTRY_PORT}/microshift" + +# Cluster A (host1): non-overlapping CIDRs +CLUSTER_A_POD_CIDR="fd01::/48" +CLUSTER_A_SVC_CIDR="fd02::/112" +CLUSTER_A_DOMAIN="cluster-a.remote" + +# Cluster B (host2): non-overlapping CIDRs +CLUSTER_B_POD_CIDR="fd04::/48" +CLUSTER_B_SVC_CIDR="fd05::/112" +CLUSTER_B_DOMAIN="cluster-b.remote" + +# Cluster C (host3): non-overlapping CIDRs +CLUSTER_C_POD_CIDR="fd07::/48" +CLUSTER_C_SVC_CIDR="fd08::/112" +CLUSTER_C_DOMAIN="cluster-c.remote" + +scenario_create_vms() { + c2cc_create_jumbo_ipv6_network + c2cc_create_vms "rhel102-bootc-source-ipsec" "rhel102-bootc" "jumbo-ipv6" "ipv6" "9000" +} + +scenario_remove_vms() { + c2cc_remove_vms +} + +scenario_run_tests() { + configure_c2cc_hosts "c2cc_ipsec_mtu_pre_greenboot" "c2cc_ipsec_mtu_greenboot" + configure_ipsec + + c2cc_run_tests "suites/c2cc/extra/ipsec-mtu.robot" "" ipv6 +} diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh new file mode 100644 index 0000000000..5e5b6901d7 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. +# +# Sets up 3 MicroShift clusters with C2CC and Libreswan IPsec on a +# single-stack IPv6 jumbo-frame network (MTU 9000). Same test suite as +# c2cc-ipsec-mtu, run over IPv6 instead of IPv4. + +# shellcheck source=test/bin/c2cc_common.sh +source "${SCRIPTDIR}/c2cc_common.sh" + +export TEST_RANDOMIZATION=none + +# Redefine network-related settings to use the IPv6 jumbo network bridge +# shellcheck disable=SC2034 # used elsewhere +VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" +# shellcheck disable=SC2034 # used elsewhere +WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" +# Using `hostname` here instead of a raw ip because skopeo only allows either +# ipv4 or fqdn's, but not ipv6. +# shellcheck disable=SC2034 # used elsewhere +MIRROR_REGISTRY_URL="$(hostname):${MIRROR_REGISTRY_PORT}/microshift" + +# Cluster A (host1): non-overlapping CIDRs +CLUSTER_A_POD_CIDR="fd01::/48" +CLUSTER_A_SVC_CIDR="fd02::/112" +CLUSTER_A_DOMAIN="cluster-a.remote" + +# Cluster B (host2): non-overlapping CIDRs +CLUSTER_B_POD_CIDR="fd04::/48" +CLUSTER_B_SVC_CIDR="fd05::/112" +CLUSTER_B_DOMAIN="cluster-b.remote" + +# Cluster C (host3): non-overlapping CIDRs +CLUSTER_C_POD_CIDR="fd07::/48" +CLUSTER_C_SVC_CIDR="fd08::/112" +CLUSTER_C_DOMAIN="cluster-c.remote" + +scenario_create_vms() { + c2cc_create_jumbo_ipv6_network + c2cc_create_vms "rhel98-bootc-source-ipsec" "rhel98-bootc" "jumbo-ipv6" "ipv6" "9000" +} + +scenario_remove_vms() { + c2cc_remove_vms +} + +scenario_run_tests() { + configure_c2cc_hosts "c2cc_ipsec_mtu_pre_greenboot" "c2cc_ipsec_mtu_greenboot" + configure_ipsec + + c2cc_run_tests "suites/c2cc/extra/ipsec-mtu.robot" "" ipv6 +} From ccc6d516703b91b7338fe7a49bf346575af1c4d0 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 14:50:41 +0200 Subject: [PATCH 10/17] Rename IPv4 C2CC scenarios with -ipv4 suffix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename c2cc-ipsec, c2cc-mtu, and c2cc-ipsec-mtu (el98/el102) to c2cc-ipsec-ipv4, c2cc-mtu-ipv4, and c2cc-ipsec-mtu-ipv4 for symmetry with their c2cc-ipsec-ipv6, c2cc-mtu-ipv6, and c2cc-ipsec-mtu-ipv6 siblings added in this PR. Filenames only — no functional changes. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- .../{el102-src@c2cc-ipsec.sh => el102-src@c2cc-ipsec-ipv4.sh} | 0 ...102-src@c2cc-ipsec-mtu.sh => el102-src@c2cc-ipsec-mtu-ipv4.sh} | 0 .../c2cc/{el102-src@c2cc-mtu.sh => el102-src@c2cc-mtu-ipv4.sh} | 0 .../c2cc/{el98-src@c2cc-ipsec.sh => el98-src@c2cc-ipsec-ipv4.sh} | 0 ...el98-src@c2cc-ipsec-mtu.sh => el98-src@c2cc-ipsec-mtu-ipv4.sh} | 0 .../c2cc/{el98-src@c2cc-mtu.sh => el98-src@c2cc-mtu-ipv4.sh} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename test/scenarios-bootc/c2cc/{el102-src@c2cc-ipsec.sh => el102-src@c2cc-ipsec-ipv4.sh} (100%) rename test/scenarios-bootc/c2cc/{el102-src@c2cc-ipsec-mtu.sh => el102-src@c2cc-ipsec-mtu-ipv4.sh} (100%) rename test/scenarios-bootc/c2cc/{el102-src@c2cc-mtu.sh => el102-src@c2cc-mtu-ipv4.sh} (100%) rename test/scenarios-bootc/c2cc/{el98-src@c2cc-ipsec.sh => el98-src@c2cc-ipsec-ipv4.sh} (100%) rename test/scenarios-bootc/c2cc/{el98-src@c2cc-ipsec-mtu.sh => el98-src@c2cc-ipsec-mtu-ipv4.sh} (100%) rename test/scenarios-bootc/c2cc/{el98-src@c2cc-mtu.sh => el98-src@c2cc-mtu-ipv4.sh} (100%) diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-ipv4.sh similarity index 100% rename from test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec.sh rename to test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-ipv4.sh diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv4.sh similarity index 100% rename from test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu.sh rename to test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv4.sh diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv4.sh similarity index 100% rename from test/scenarios-bootc/c2cc/el102-src@c2cc-mtu.sh rename to test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv4.sh diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-ipv4.sh similarity index 100% rename from test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec.sh rename to test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-ipv4.sh diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv4.sh similarity index 100% rename from test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu.sh rename to test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv4.sh diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv4.sh similarity index 100% rename from test/scenarios-bootc/c2cc/el98-src@c2cc-mtu.sh rename to test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv4.sh From ddb6027b53ceb0e809a797c939a966c0059ac6c0 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 14:53:03 +0200 Subject: [PATCH 11/17] TEMPORARY: disable non-MTU c2cc scenarios for faster CI Append .disabled to all c2cc scenario files not touched by this PR so CI only runs the MTU/IPsec scenarios under test. Revert before merge. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- ...c@c2cc-disruptive.sh => el102-src@c2cc-disruptive.sh.disabled} | 0 ...-dual-stack-v4.sh => el102-src@c2cc-dual-stack-v4.sh.disabled} | 0 ...-dual-stack-v6.sh => el102-src@c2cc-dual-stack-v6.sh.disabled} | 0 .../{el102-src@c2cc-ipv6.sh => el102-src@c2cc-ipv6.sh.disabled} | 0 .../c2cc/{el102-src@c2cc.sh => el102-src@c2cc.sh.disabled} | 0 ...rc@c2cc-disruptive.sh => el98-src@c2cc-disruptive.sh.disabled} | 0 ...c-dual-stack-v4.sh => el98-src@c2cc-dual-stack-v4.sh.disabled} | 0 ...c-dual-stack-v6.sh => el98-src@c2cc-dual-stack-v6.sh.disabled} | 0 .../{el98-src@c2cc-ipv6.sh => el98-src@c2cc-ipv6.sh.disabled} | 0 .../c2cc/{el98-src@c2cc.sh => el98-src@c2cc.sh.disabled} | 0 ...grade-ok.sh => el98-src@el102-src@c2cc-upgrade-ok.sh.disabled} | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename test/scenarios-bootc/c2cc/{el102-src@c2cc-disruptive.sh => el102-src@c2cc-disruptive.sh.disabled} (100%) rename test/scenarios-bootc/c2cc/{el102-src@c2cc-dual-stack-v4.sh => el102-src@c2cc-dual-stack-v4.sh.disabled} (100%) rename test/scenarios-bootc/c2cc/{el102-src@c2cc-dual-stack-v6.sh => el102-src@c2cc-dual-stack-v6.sh.disabled} (100%) rename test/scenarios-bootc/c2cc/{el102-src@c2cc-ipv6.sh => el102-src@c2cc-ipv6.sh.disabled} (100%) rename test/scenarios-bootc/c2cc/{el102-src@c2cc.sh => el102-src@c2cc.sh.disabled} (100%) rename test/scenarios-bootc/c2cc/{el98-src@c2cc-disruptive.sh => el98-src@c2cc-disruptive.sh.disabled} (100%) rename test/scenarios-bootc/c2cc/{el98-src@c2cc-dual-stack-v4.sh => el98-src@c2cc-dual-stack-v4.sh.disabled} (100%) rename test/scenarios-bootc/c2cc/{el98-src@c2cc-dual-stack-v6.sh => el98-src@c2cc-dual-stack-v6.sh.disabled} (100%) rename test/scenarios-bootc/c2cc/{el98-src@c2cc-ipv6.sh => el98-src@c2cc-ipv6.sh.disabled} (100%) rename test/scenarios-bootc/c2cc/{el98-src@c2cc.sh => el98-src@c2cc.sh.disabled} (100%) rename test/scenarios-bootc/c2cc/{el98-src@el102-src@c2cc-upgrade-ok.sh => el98-src@el102-src@c2cc-upgrade-ok.sh.disabled} (100%) diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-disruptive.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-disruptive.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el102-src@c2cc-disruptive.sh rename to test/scenarios-bootc/c2cc/el102-src@c2cc-disruptive.sh.disabled diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-dual-stack-v4.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-dual-stack-v4.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el102-src@c2cc-dual-stack-v4.sh rename to test/scenarios-bootc/c2cc/el102-src@c2cc-dual-stack-v4.sh.disabled diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-dual-stack-v6.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-dual-stack-v6.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el102-src@c2cc-dual-stack-v6.sh rename to test/scenarios-bootc/c2cc/el102-src@c2cc-dual-stack-v6.sh.disabled diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipv6.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipv6.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el102-src@c2cc-ipv6.sh rename to test/scenarios-bootc/c2cc/el102-src@c2cc-ipv6.sh.disabled diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el102-src@c2cc.sh rename to test/scenarios-bootc/c2cc/el102-src@c2cc.sh.disabled diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-disruptive.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-disruptive.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el98-src@c2cc-disruptive.sh rename to test/scenarios-bootc/c2cc/el98-src@c2cc-disruptive.sh.disabled diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-dual-stack-v4.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-dual-stack-v4.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el98-src@c2cc-dual-stack-v4.sh rename to test/scenarios-bootc/c2cc/el98-src@c2cc-dual-stack-v4.sh.disabled diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-dual-stack-v6.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-dual-stack-v6.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el98-src@c2cc-dual-stack-v6.sh rename to test/scenarios-bootc/c2cc/el98-src@c2cc-dual-stack-v6.sh.disabled diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipv6.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipv6.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el98-src@c2cc-ipv6.sh rename to test/scenarios-bootc/c2cc/el98-src@c2cc-ipv6.sh.disabled diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el98-src@c2cc.sh rename to test/scenarios-bootc/c2cc/el98-src@c2cc.sh.disabled diff --git a/test/scenarios-bootc/c2cc/el98-src@el102-src@c2cc-upgrade-ok.sh b/test/scenarios-bootc/c2cc/el98-src@el102-src@c2cc-upgrade-ok.sh.disabled similarity index 100% rename from test/scenarios-bootc/c2cc/el98-src@el102-src@c2cc-upgrade-ok.sh rename to test/scenarios-bootc/c2cc/el98-src@el102-src@c2cc-upgrade-ok.sh.disabled From 16ce01a910b7a52f729c2ea5152ce4d2223889c4 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 17:10:34 +0200 Subject: [PATCH 12/17] Fix jumbo MTU: set guest NIC MTU via kickstart NetworkManager The virt-install mtu.size option is silently ignored by some QEMU/libvirt versions, leaving guest NICs at 1500 despite the jumbo libvirt network. Set the NIC MTU via NetworkManager in the kickstart post-install script instead, so the guest boots with the correct MTU before MicroShift first starts. When OVN-K creates br-ex on first boot, it inherits the NIC's 9000 MTU. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- test/bin/c2cc_common.sh | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/bin/c2cc_common.sh b/test/bin/c2cc_common.sh index 0221c9f049..8d2f8ca11b 100644 --- a/test/bin/c2cc_common.sh +++ b/test/bin/c2cc_common.sh @@ -188,6 +188,22 @@ ${network_yaml}IEOF EOF } +# inject_kickstart_mtu configures the physical NIC MTU via NetworkManager in +# the kickstart post-install script. This sets the MTU before MicroShift first +# starts, so OVN-K creates br-ex with the correct MTU from the beginning. +# The virt-install mtu.size option alone is not sufficient — some QEMU/libvirt +# versions silently ignore it, leaving the guest NIC at 1500. +# Args: host mtu +inject_kickstart_mtu() { + local -r host=$1 + local -r mtu=$2 + + local -r ks_dir="${SCENARIO_INFO_DIR}/${SCENARIO}/vms/${host}" + cat >> "${ks_dir}/post-microshift.cfg" < Date: Fri, 10 Jul 2026 17:15:10 +0200 Subject: [PATCH 13/17] Fix jumbo-ipv6 network: add bridge to firewall trusted zone The jumbo-ipv6 network is created on-the-fly by the scenario, but its bridge IPv6 subnet was not added to the firewall trusted zone. VMs on that network couldn't reach the hypervisor's kickstart web server or mirror registry, causing virt-install to time out. The standard IPv6 network gets firewall rules via manage_hypervisor_config.sh, but jumbo-ipv6 needs them explicitly since it's not in the managed network list. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- test/bin/c2cc_common.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/bin/c2cc_common.sh b/test/bin/c2cc_common.sh index 8d2f8ca11b..9dcbd4e2e2 100644 --- a/test/bin/c2cc_common.sh +++ b/test/bin/c2cc_common.sh @@ -279,6 +279,18 @@ c2cc_create_jumbo_ipv6_network() { sudo virsh net-define "${netconfig}" sudo virsh net-start jumbo-ipv6 sudo virsh net-autostart jumbo-ipv6 + + # Add the bridge's IPv6 subnet to the firewall trusted zone so VMs + # can reach the hypervisor's services (kickstart web server, registry). + # The standard IPv6 network ("ipv6") gets this via manage_hypervisor_config.sh, + # but jumbo-ipv6 is created on-the-fly and needs it explicitly. + local bridge + bridge=$(sudo virsh net-info jumbo-ipv6 | grep '^Bridge:' | awk '{print $2}') + local ip + for ip in $(ip addr show "${bridge}" | grep "scope global" | awk '{print $2}'); do + sudo firewall-cmd --permanent --zone=trusted --add-source="${ip}" + done + sudo firewall-cmd --reload } c2cc_remove_vms() { From 08cda5bb6c6b37e06569c83745a05ddf621e348a Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 19:41:31 +0200 Subject: [PATCH 14/17] Fix kickstart MTU: use systemd service instead of nmcli in chroot The previous inject_kickstart_mtu ran nmcli directly in the kickstart %post section, but NM isn't running inside the chroot so the command silently fails. Replace with a oneshot systemd service (set-jumbo-mtu.service) that: - Runs After=NetworkManager-wait-online.service (NM is up) - Runs Before=microshift.service (MTU set before OVN-K reads it) - Uses nmcli to set MTU on the active ethernet connection - Gets systemctl-enabled during kickstart (just creates symlinks) Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- test/bin/c2cc_common.sh | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/test/bin/c2cc_common.sh b/test/bin/c2cc_common.sh index 9dcbd4e2e2..2ef42fb0f3 100644 --- a/test/bin/c2cc_common.sh +++ b/test/bin/c2cc_common.sh @@ -188,19 +188,40 @@ ${network_yaml}IEOF EOF } -# inject_kickstart_mtu configures the physical NIC MTU via NetworkManager in -# the kickstart post-install script. This sets the MTU before MicroShift first -# starts, so OVN-K creates br-ex with the correct MTU from the beginning. -# The virt-install mtu.size option alone is not sufficient — some QEMU/libvirt -# versions silently ignore it, leaving the guest NIC at 1500. +# inject_kickstart_mtu installs a oneshot systemd service that sets the +# physical NIC MTU via NetworkManager on first boot, before MicroShift starts. +# The service runs after NM is online (connections active) and before +# microshift.service, so OVN-K creates br-ex with the correct MTU. +# +# We can't use nmcli directly in the kickstart %post because NM isn't +# running inside the chroot. The virt-install mtu.size option is also +# insufficient — some QEMU/libvirt versions silently ignore it. # Args: host mtu inject_kickstart_mtu() { local -r host=$1 local -r mtu=$2 local -r ks_dir="${SCENARIO_INFO_DIR}/${SCENARIO}/vms/${host}" + cat >> "${ks_dir}/post-microshift.cfg" <<'ESCEOF' +cat > /etc/systemd/system/set-jumbo-mtu.service <> "${ks_dir}/post-microshift.cfg" < Date: Fri, 10 Jul 2026 19:44:56 +0200 Subject: [PATCH 15/17] Fix jumbo-ipv6 scenarios: move bridge IP lookup after network creation The VM_BRIDGE_IP and WEB_SERVER_URL assignments ran at file-source time (top-level code), but the jumbo-ipv6 network doesn't exist until scenario_create_vms() calls c2cc_create_jumbo_ipv6_network(). This produced an empty bridge IP and a broken URL (http://[]:8080), causing VM installation to fail because it couldn't reach the kickstart server. Move the bridge IP lookup inside scenario_create_vms(), after the network is created. The existing c2cc-ipv6.sh doesn't have this problem because the shared "ipv6" network is pre-created by manage_hypervisor_config.sh before any scenarios run. Co-Authored-By: Claude Opus 4.6 (1M context) pre-commit.check-secrets: ENABLED --- .../c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh | 11 ++++++----- test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv6.sh | 11 ++++++----- .../c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh | 11 ++++++----- test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv6.sh | 11 ++++++----- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh index d9250b2abf..b778464aab 100644 --- a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh @@ -11,11 +11,6 @@ source "${SCRIPTDIR}/c2cc_common.sh" export TEST_RANDOMIZATION=none -# Redefine network-related settings to use the IPv6 jumbo network bridge -# shellcheck disable=SC2034 # used elsewhere -VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" -# shellcheck disable=SC2034 # used elsewhere -WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" # Using `hostname` here instead of a raw ip because skopeo only allows either # ipv4 or fqdn's, but not ipv6. # shellcheck disable=SC2034 # used elsewhere @@ -38,6 +33,12 @@ CLUSTER_C_DOMAIN="cluster-c.remote" scenario_create_vms() { c2cc_create_jumbo_ipv6_network + # Set bridge IP after network creation — can't do this at file level + # because the jumbo-ipv6 network doesn't exist until this point. + # shellcheck disable=SC2034 # used elsewhere + VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" + # shellcheck disable=SC2034 # used elsewhere + WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" c2cc_create_vms "rhel102-bootc-source-ipsec" "rhel102-bootc" "jumbo-ipv6" "ipv6" "9000" } diff --git a/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv6.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv6.sh index b9e15683fb..65afaa2e13 100644 --- a/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv6.sh +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv6.sh @@ -9,11 +9,6 @@ # shellcheck source=test/bin/c2cc_common.sh source "${SCRIPTDIR}/c2cc_common.sh" -# Redefine network-related settings to use the IPv6 jumbo network bridge -# shellcheck disable=SC2034 # used elsewhere -VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" -# shellcheck disable=SC2034 # used elsewhere -WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" # Using `hostname` here instead of a raw ip because skopeo only allows either # ipv4 or fqdn's, but not ipv6. # shellcheck disable=SC2034 # used elsewhere @@ -36,6 +31,12 @@ CLUSTER_C_DOMAIN="cluster-c.remote" scenario_create_vms() { c2cc_create_jumbo_ipv6_network + # Set bridge IP after network creation — can't do this at file level + # because the jumbo-ipv6 network doesn't exist until this point. + # shellcheck disable=SC2034 # used elsewhere + VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" + # shellcheck disable=SC2034 # used elsewhere + WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" c2cc_create_vms "rhel102-bootc-source" "rhel102-bootc" "jumbo-ipv6" "ipv6" "9000" } diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh index 5e5b6901d7..13f009aad1 100644 --- a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh @@ -11,11 +11,6 @@ source "${SCRIPTDIR}/c2cc_common.sh" export TEST_RANDOMIZATION=none -# Redefine network-related settings to use the IPv6 jumbo network bridge -# shellcheck disable=SC2034 # used elsewhere -VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" -# shellcheck disable=SC2034 # used elsewhere -WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" # Using `hostname` here instead of a raw ip because skopeo only allows either # ipv4 or fqdn's, but not ipv6. # shellcheck disable=SC2034 # used elsewhere @@ -38,6 +33,12 @@ CLUSTER_C_DOMAIN="cluster-c.remote" scenario_create_vms() { c2cc_create_jumbo_ipv6_network + # Set bridge IP after network creation — can't do this at file level + # because the jumbo-ipv6 network doesn't exist until this point. + # shellcheck disable=SC2034 # used elsewhere + VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" + # shellcheck disable=SC2034 # used elsewhere + WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" c2cc_create_vms "rhel98-bootc-source-ipsec" "rhel98-bootc" "jumbo-ipv6" "ipv6" "9000" } diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv6.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv6.sh index d0f627705c..736bfb7c1a 100644 --- a/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv6.sh +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv6.sh @@ -9,11 +9,6 @@ # shellcheck source=test/bin/c2cc_common.sh source "${SCRIPTDIR}/c2cc_common.sh" -# Redefine network-related settings to use the IPv6 jumbo network bridge -# shellcheck disable=SC2034 # used elsewhere -VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" -# shellcheck disable=SC2034 # used elsewhere -WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" # Using `hostname` here instead of a raw ip because skopeo only allows either # ipv4 or fqdn's, but not ipv6. # shellcheck disable=SC2034 # used elsewhere @@ -36,6 +31,12 @@ CLUSTER_C_DOMAIN="cluster-c.remote" scenario_create_vms() { c2cc_create_jumbo_ipv6_network + # Set bridge IP after network creation — can't do this at file level + # because the jumbo-ipv6 network doesn't exist until this point. + # shellcheck disable=SC2034 # used elsewhere + VM_BRIDGE_IP="$(get_vm_bridge_ip "jumbo-ipv6")" + # shellcheck disable=SC2034 # used elsewhere + WEB_SERVER_URL="http://[${VM_BRIDGE_IP}]:${WEB_SERVER_PORT}" c2cc_create_vms "rhel98-bootc-source" "rhel98-bootc" "jumbo-ipv6" "ipv6" "9000" } From 9f25047936247f5fba4fa11971a2ae4290fb8015 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Fri, 10 Jul 2026 21:39:27 +0200 Subject: [PATCH 16/17] fix: use NM connection profile for jumbo MTU + wait for IPv6 DAD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two fixes for jumbo frame CI failures: 1. Replace systemd oneshot service with a NetworkManager connection profile file (jumbo-mtu.nmconnection) written directly in kickstart %post. NM reads connection files from disk at startup — no running daemon needed during install. The previous systemd service approach was not setting the NIC MTU before MicroShift started, leaving pod MTU stuck at 1500. 2. After creating the jumbo-ipv6 libvirt network, wait for IPv6 DAD (Duplicate Address Detection) to complete on the bridge interface. Until DAD finishes, the address is in "tentative" state and nginx cannot bind to it, causing kickstart fetch failures and VM boot timeouts. Co-Authored-By: Claude Sonnet 5 pre-commit.check-secrets: ENABLED --- test/bin/c2cc_common.sh | 63 +++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/test/bin/c2cc_common.sh b/test/bin/c2cc_common.sh index 2ef42fb0f3..9444de29c3 100644 --- a/test/bin/c2cc_common.sh +++ b/test/bin/c2cc_common.sh @@ -188,40 +188,35 @@ ${network_yaml}IEOF EOF } -# inject_kickstart_mtu installs a oneshot systemd service that sets the -# physical NIC MTU via NetworkManager on first boot, before MicroShift starts. -# The service runs after NM is online (connections active) and before -# microshift.service, so OVN-K creates br-ex with the correct MTU. -# -# We can't use nmcli directly in the kickstart %post because NM isn't -# running inside the chroot. The virt-install mtu.size option is also -# insufficient — some QEMU/libvirt versions silently ignore it. +# inject_kickstart_mtu writes a NetworkManager connection profile that sets +# jumbo MTU on the first ethernet interface. NM reads connection files from +# /etc/NetworkManager/system-connections/ at startup — no running daemon +# needed during kickstart %post. The high autoconnect-priority ensures NM +# picks this profile over the auto-created default. # Args: host mtu inject_kickstart_mtu() { local -r host=$1 local -r mtu=$2 local -r ks_dir="${SCENARIO_INFO_DIR}/${SCENARIO}/vms/${host}" - cat >> "${ks_dir}/post-microshift.cfg" <<'ESCEOF' -cat > /etc/systemd/system/set-jumbo-mtu.service <> "${ks_dir}/post-microshift.cfg" < /etc/NetworkManager/system-connections/jumbo-mtu.nmconnection <<'NMEOF' +[connection] +id=jumbo-mtu +type=ethernet +autoconnect=true +autoconnect-priority=999 + +[ethernet] +mtu=${mtu} + +[ipv4] +method=auto + +[ipv6] +method=auto +NMEOF +chmod 600 /etc/NetworkManager/system-connections/jumbo-mtu.nmconnection EOF } @@ -312,6 +307,20 @@ c2cc_create_jumbo_ipv6_network() { sudo firewall-cmd --permanent --zone=trusted --add-source="${ip}" done sudo firewall-cmd --reload + + # Wait for IPv6 DAD (Duplicate Address Detection) to complete on the + # bridge. Until DAD finishes, the address is in "tentative" state and + # services (nginx kickstart server) cannot bind to it. + local -r max_wait=30 + local waited=0 + while ip -6 addr show dev "${bridge}" | grep -q "tentative"; do + if (( waited >= max_wait )); then + echo "WARNING: IPv6 DAD still not complete on ${bridge} after ${max_wait}s" + break + fi + sleep 1 + (( waited++ )) + done } c2cc_remove_vms() { From 8025f5b2942ee5474b65f715dd7c276a2b3aeee4 Mon Sep 17 00:00:00 2001 From: Alejandro Gullon Date: Sat, 11 Jul 2026 00:02:01 +0200 Subject: [PATCH 17/17] fix: triple-layer NIC MTU + IPv6 readiness + test boundaries Three changes to fix jumbo MTU CI failures: 1. Replace NM connection profile with three-layer MTU approach: - udev rule (earliest, sets MTU at device detection) - NM conf.d (default MTU for auto-created connections) - systemd service with manual enable (ip link set fallback) The NM connection profile alone failed because NM auto-creates a device-specific connection that overrides generic profiles. 2. Replace DAD tentative-flag check with a curl readiness poll: wait until the web server is actually reachable on the new IPv6 bridge address, which subsumes both DAD completion and any other transient connectivity issues. 3. Fix jumbo MTU test boundaries: OVN-K subtracts 78B Geneve overhead in multinode mode, so auto-detected pod MTU from a 9000 NIC is 8922, not 9000. Changed the near-boundary test from 8950B (which exceeds 8922) to 8850B (safely below). Co-Authored-By: Claude Sonnet 5 pre-commit.check-secrets: ENABLED --- test/bin/c2cc_common.sh | 69 ++++++++++++++++---------- test/suites/c2cc/extra/ipsec-mtu.robot | 11 ++-- test/suites/c2cc/extra/mtu.robot | 11 ++-- 3 files changed, 54 insertions(+), 37 deletions(-) diff --git a/test/bin/c2cc_common.sh b/test/bin/c2cc_common.sh index 9444de29c3..97d224f642 100644 --- a/test/bin/c2cc_common.sh +++ b/test/bin/c2cc_common.sh @@ -188,11 +188,11 @@ ${network_yaml}IEOF EOF } -# inject_kickstart_mtu writes a NetworkManager connection profile that sets -# jumbo MTU on the first ethernet interface. NM reads connection files from -# /etc/NetworkManager/system-connections/ at startup — no running daemon -# needed during kickstart %post. The high autoconnect-priority ensures NM -# picks this profile over the auto-created default. +# inject_kickstart_mtu sets the NIC MTU via three layered mechanisms to +# guarantee the interface has jumbo MTU before MicroShift starts: +# 1. udev rule — sets MTU at device detection time (before NM) +# 2. NM conf.d — sets default MTU for all ethernet connections +# 3. systemd service — final safety net, uses ip link set directly # Args: host mtu inject_kickstart_mtu() { local -r host=$1 @@ -200,23 +200,35 @@ inject_kickstart_mtu() { local -r ks_dir="${SCENARIO_INFO_DIR}/${SCENARIO}/vms/${host}" cat >> "${ks_dir}/post-microshift.cfg" < /etc/NetworkManager/system-connections/jumbo-mtu.nmconnection <<'NMEOF' -[connection] -id=jumbo-mtu -type=ethernet -autoconnect=true -autoconnect-priority=999 - -[ethernet] -mtu=${mtu} - -[ipv4] -method=auto - -[ipv6] -method=auto -NMEOF -chmod 600 /etc/NetworkManager/system-connections/jumbo-mtu.nmconnection +# Layer 1: udev rule — earliest point to set MTU, runs before NM +cat > /etc/udev/rules.d/99-jumbo-mtu.rules <<'UDEVEOF' +ACTION=="add", SUBSYSTEM=="net", ATTR{type}=="1", ATTR{mtu}="${mtu}" +UDEVEOF + +# Layer 2: NM conf.d — default ethernet MTU for auto-created connections +cat > /etc/NetworkManager/conf.d/99-jumbo-mtu.conf <<'NMCONF' +[connection-ethernet-jumbo] +match-device=type:ethernet +ethernet.mtu=${mtu} +NMCONF + +# Layer 3: systemd service — runs ip link set before MicroShift +cat > /etc/systemd/system/set-jumbo-mtu.service <<'SVCEOF' +[Unit] +Description=Set jumbo frame MTU on ethernet interfaces +Before=microshift.service +After=NetworkManager-wait-online.service + +[Service] +Type=oneshot +ExecStart=/bin/bash -c 'for dev in \$(ip -o link show type ether | awk -F: "{print \\\$2}" | tr -d " "); do ip link set dev "\$dev" mtu ${mtu}; done' +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target +SVCEOF +mkdir -p /etc/systemd/system/multi-user.target.wants +ln -sf /etc/systemd/system/set-jumbo-mtu.service /etc/systemd/system/multi-user.target.wants/set-jumbo-mtu.service EOF } @@ -308,14 +320,17 @@ c2cc_create_jumbo_ipv6_network() { done sudo firewall-cmd --reload - # Wait for IPv6 DAD (Duplicate Address Detection) to complete on the - # bridge. Until DAD finishes, the address is in "tentative" state and - # services (nginx kickstart server) cannot bind to it. + # Wait for IPv6 DAD (Duplicate Address Detection) to complete and the + # web server to become reachable on the new bridge address. Until DAD + # finishes, the address is in "tentative" state and the kernel rejects + # incoming connections, causing kickstart file fetch to fail. + local bridge_ip + bridge_ip=$(ip -6 addr show dev "${bridge}" scope global | awk '/inet6/{print $2}' | cut -d/ -f1 | head -1) local -r max_wait=30 local waited=0 - while ip -6 addr show dev "${bridge}" | grep -q "tentative"; do + while ! curl -s -o /dev/null --connect-timeout 2 "http://[${bridge_ip}]:${WEB_SERVER_PORT}/"; do if (( waited >= max_wait )); then - echo "WARNING: IPv6 DAD still not complete on ${bridge} after ${max_wait}s" + echo "WARNING: web server not reachable on [${bridge_ip}]:${WEB_SERVER_PORT} after ${max_wait}s" break fi sleep 1 diff --git a/test/suites/c2cc/extra/ipsec-mtu.robot b/test/suites/c2cc/extra/ipsec-mtu.robot index 6c6918bcb9..e5c5486f1e 100644 --- a/test/suites/c2cc/extra/ipsec-mtu.robot +++ b/test/suites/c2cc/extra/ipsec-mtu.robot @@ -36,12 +36,13 @@ DF Bit 8872B Passes Through IPsec At Jumbo MTU [Documentation] 8872B + 28B = 8900B — the max payload at recommended pod MTU 8900. Ping DF Bit Between All Clusters 8872 -DF Bit 8950B Passes Through IPsec At Jumbo MTU - [Documentation] Near pod MTU — accepted by the kernel. - Ping DF Bit Between All Clusters 8950 +DF Bit 8850B Passes Through IPsec At Jumbo MTU + [Documentation] Near pod MTU — accepted by the kernel. OVN-K subtracts + ... 78B Geneve overhead in multinode mode, so auto-detected pod MTU is 8922. + Ping DF Bit Between All Clusters 8850 -DF Bit 8972B Rejected At Jumbo Pod MTU - [Documentation] 8972B + 28B = 9000B, hitting the pod interface MTU. +DF Bit 8972B Rejected Above Jumbo Pod MTU + [Documentation] 8972B + 28B = 9000B, well above the auto-detected pod MTU (8922B). Ping DF Bit Should Fail Between All Clusters 8972 Large TCP Transfer Through IPsec At Jumbo MTU diff --git a/test/suites/c2cc/extra/mtu.robot b/test/suites/c2cc/extra/mtu.robot index b2781cc0c5..ef159b3816 100644 --- a/test/suites/c2cc/extra/mtu.robot +++ b/test/suites/c2cc/extra/mtu.robot @@ -29,12 +29,13 @@ DF Bit 8872B Passes At Jumbo MTU [Documentation] 8872B + 28B = 8900B — the max payload at recommended pod MTU 8900. Ping DF Bit Between All Clusters 8872 -DF Bit 8950B Passes At Jumbo MTU - [Documentation] Near pod MTU — accepted by the kernel on all cluster pairs. - Ping DF Bit Between All Clusters 8950 +DF Bit 8850B Passes At Jumbo MTU + [Documentation] Near pod MTU — accepted on all cluster pairs. OVN-K subtracts + ... 78B Geneve overhead in multinode mode, so auto-detected pod MTU is 8922. + Ping DF Bit Between All Clusters 8850 -DF Bit 8972B Rejected At Pod MTU - [Documentation] 8972B + 28B = 9000B, hitting the pod interface MTU. +DF Bit 8972B Rejected Above Pod MTU + [Documentation] 8972B + 28B = 9000B, well above the auto-detected pod MTU (8922B). Ping DF Bit Should Fail Between All Clusters 8972 Large TCP Transfer At Jumbo MTU