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/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/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..97d224f642 100644 --- a/test/bin/c2cc_common.sh +++ b/test/bin/c2cc_common.sh @@ -188,11 +188,56 @@ ${network_yaml}IEOF EOF } +# 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 + local -r mtu=$2 + + local -r ks_dir="${SCENARIO_INFO_DIR}/${SCENARIO}/vms/${host}" + cat >> "${ks_dir}/post-microshift.cfg" < /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 +} + c2cc_create_vms() { local -r boot_commit_ref="${1}" 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 +268,74 @@ 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}" + # Set the NIC MTU via NetworkManager in the kickstart so the guest boots + # with the correct MTU before MicroShift starts. + local mtu_args=() + if [ -n "${network_mtu}" ]; then + mtu_args=(--network_mtu "${network_mtu}") + for host in host1 host2 host3; do + inject_kickstart_mtu "${host}" "${network_mtu}" + done + 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 +# 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_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 + + # 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 + + # 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 ! curl -s -o /dev/null --connect-timeout 2 "http://[${bridge_ip}]:${WEB_SERVER_PORT}/"; do + if (( waited >= max_wait )); then + echo "WARNING: web server not reachable on [${bridge_ip}]:${WEB_SERVER_PORT} after ${max_wait}s" + break + fi + sleep 1 + (( waited++ )) + done } c2cc_remove_vms() { 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/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..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,6 +130,100 @@ 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 / 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) 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;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. 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;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 + +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} + ${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 @- ${url}' + 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/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-ipsec.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-ipv4.sh similarity index 94% rename from test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec.sh rename to test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-ipv4.sh index 2c6e13d50d..324d7c583c 100644 --- a/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec.sh +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-ipv4.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/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/el102-src@c2cc-ipsec-mtu-ipv4.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv4.sh new file mode 100644 index 0000000000..753394b173 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv4.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" "ipv4" "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" +} 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..b778464aab --- /dev/null +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-ipsec-mtu-ipv6.sh @@ -0,0 +1,54 @@ +#!/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 + +# 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 + # 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" +} + +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/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-mtu-ipv4.sh b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv4.sh new file mode 100644 index 0000000000..e3159a7189 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv4.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" "ipv4" "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" +} 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..65afaa2e13 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el102-src@c2cc-mtu-ipv6.sh @@ -0,0 +1,51 @@ +#!/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" + +# 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 + # 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" +} + +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/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-ipsec.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-ipv4.sh similarity index 94% rename from test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec.sh rename to test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-ipv4.sh index e9900c4c7a..b08b4fa8b7 100644 --- a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec.sh +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-ipv4.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-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 +} diff --git a/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv4.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv4.sh new file mode 100644 index 0000000000..eac5896de0 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv4.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" "ipv4" "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" +} 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..13f009aad1 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-ipsec-mtu-ipv6.sh @@ -0,0 +1,54 @@ +#!/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 + +# 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 + # 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" +} + +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-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-mtu-ipv4.sh b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv4.sh new file mode 100644 index 0000000000..00c9bfe2f2 --- /dev/null +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv4.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" "ipv4" "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" +} 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..736bfb7c1a --- /dev/null +++ b/test/scenarios-bootc/c2cc/el98-src@c2cc-mtu-ipv6.sh @@ -0,0 +1,51 @@ +#!/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" + +# 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 + # 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" +} + +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.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 diff --git a/test/suites/c2cc/extra/ipsec-mtu.robot b/test/suites/c2cc/extra/ipsec-mtu.robot new file mode 100644 index 0000000000..e5c5486f1e --- /dev/null +++ b/test/suites/c2cc/extra/ipsec-mtu.robot @@ -0,0 +1,133 @@ +*** 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 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 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 + [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/extra/ipsec.robot similarity index 86% rename from test/suites/c2cc/ipsec/ipsec.robot rename to test/suites/c2cc/extra/ipsec.robot index 04717e4e76..50d47361ce 100644 --- a/test/suites/c2cc/ipsec/ipsec.robot +++ b/test/suites/c2cc/extra/ipsec.robot @@ -5,7 +5,8 @@ Documentation IPsec E2E tests for C2CC. ... ... 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. +... 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 @@ -95,14 +96,33 @@ Host To Remote Pod Rejected Without IPsec ${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. +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. @@ -162,11 +182,3 @@ Restore IPsec With Enforcement Cleanup 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 diff --git a/test/suites/c2cc/extra/mtu.robot b/test/suites/c2cc/extra/mtu.robot new file mode 100644 index 0000000000..ef159b3816 --- /dev/null +++ b/test/suites/c2cc/extra/mtu.robot @@ -0,0 +1,48 @@ +*** 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 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 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 + [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