Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions test/assets/c2cc/df-bit-send.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""Send a UDP datagram with the DF (Don't Fragment) bit set.

Uses IP_PMTUDISC_DO (IPv4) or IPV6_DONTFRAG (IPv6) so the kernel
rejects datagrams that exceed the path MTU with EMSGSIZE instead of
fragmenting them. Auto-detects the address family 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, so payload sizes are equivalent to ping -s values
within each address family.

Usage: python3 df-bit-send.py <dest_ip> <payload_size>
Exit: prints "OK" on success, raises OSError on rejection.
"""

import socket
import sys

IPPROTO_IPV6 = 41
IPV6_DONTFRAG = 62
IP_MTU_DISCOVER = 10
IP_PMTUDISC_DO = 2

dest = sys.argv[1]
size = int(sys.argv[2])

family = socket.AF_INET6 if ":" in dest else socket.AF_INET
sock = socket.socket(family, socket.SOCK_DGRAM)

if family == socket.AF_INET6:
sock.setsockopt(IPPROTO_IPV6, IPV6_DONTFRAG, 1)
else:
sock.setsockopt(socket.IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DO)

sock.sendto(b"A" * size, (dest, 9999))
print("OK")
Comment on lines +37 to +38

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the sendto fails, it won't reach OK and we'll get an exception?
Should we also close the socket? Just for correctness :)

19 changes: 19 additions & 0 deletions test/assets/c2cc/nettest-pod.yaml
Original file line number Diff line number Diff line change
@@ -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
14 changes: 14 additions & 0 deletions test/assets/network/jumbo-ipv6-network.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<network>
<name>jumbo-ipv6</name>
<forward mode="nat">
<nat ipv6='yes'>
<port start='1024' end='65535'/>
</nat>
</forward>
<mtu size='9000'/>
<ip family="ipv6" address="2001:db8:ca7:fe::1" prefix="96">
<dhcp>
<range start="2001:db8:ca7:fe::1000" end="2001:db8:ca7:fe::2000" />
</dhcp>
</ip>
</network>
10 changes: 10 additions & 0 deletions test/assets/network/jumbo-network.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<network>
<name>jumbo</name>
<forward mode='nat'/>
<mtu size='9000'/>
<ip address='192.168.150.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.150.100' end='192.168.150.254'/>
</dhcp>
</ip>
</network>
132 changes: 129 additions & 3 deletions test/bin/c2cc_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,84 @@ ${network_yaml}IEOF
EOF
}

# inject_kickstart_mtu configures jumbo MTU on the guest VM via kickstart.
# Two things must happen before MicroShift first starts:
# A) NIC MTU must be set so OVN-K creates br-ex at jumbo size.
# B) OVN config must specify pod MTU explicitly -- C2CC VMs have no default
# route, so MicroShift auto-detection falls back to 1500.
# For (A): NM conf.d, NM dispatcher, and systemd service set the NIC MTU.
# For (B): writes mtu to /etc/microshift/ovn.yaml.
# Args: host nic_mtu [pod_mtu]
# pod_mtu defaults to nic_mtu - 78 (conservative headroom matching
# OVN-K's IPv6 Geneve constant). Pass explicitly for ipsec-mtu
# scenarios that need the recommended 8900.
inject_kickstart_mtu() {
local -r host="${1}"
local -r mtu="${2}"
local -r pod_mtu="${3:-$(( mtu - 78 ))}"

local -r ks_dir="${SCENARIO_INFO_DIR}/${SCENARIO}/vms/${host}"
cat >> "${ks_dir}/post-microshift.cfg" <<EOF
# NM conf.d -- default ethernet MTU for auto-created connections
mkdir -p /etc/NetworkManager/conf.d
cat > /etc/NetworkManager/conf.d/99-jumbo-mtu.conf <<'NMCONF'
[connection-ethernet-jumbo]
match-device=type:ethernet
ethernet.mtu=${mtu}
NMCONF

# NM dispatcher -- runs ip link set during connection activation
mkdir -p /etc/NetworkManager/dispatcher.d
cat > /etc/NetworkManager/dispatcher.d/99-jumbo-mtu <<'DISPEOF'
#!/bin/bash
[ "\$2" != "up" ] && exit 0
ip link set dev "\$1" mtu ${mtu} 2>&1 || logger -t jumbo-mtu "Failed to set MTU ${mtu} on \$1"
DISPEOF
chmod 755 /etc/NetworkManager/dispatcher.d/99-jumbo-mtu
restorecon -R /etc/NetworkManager/dispatcher.d/ 2>&1 || logger -t jumbo-mtu "restorecon failed for dispatcher.d"

# Systemd service -- runs before microshift.service.
# Script in /etc/ because /usr/ is read-only on bootc images.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But is the system readonly during installation? I think it might not be yet, only after rebooting

cat > /etc/set-jumbo-mtu.sh <<'SCRIPTEOF'
#!/bin/bash
for dev in \$(ip -o link show type ether | awk -F: '{print \$2}' | tr -d ' '); do
ip link set dev "\$dev" mtu ${mtu}
done
SCRIPTEOF
chmod 755 /etc/set-jumbo-mtu.sh
restorecon /etc/set-jumbo-mtu.sh 2>&1 || logger -t jumbo-mtu "restorecon failed for set-jumbo-mtu.sh"

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=/etc/set-jumbo-mtu.sh
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

# Set explicit pod MTU -- MicroShift auto-detection fails in C2CC VMs
# (no default route), falling back to 1500 regardless of NIC MTU.
mkdir -p /etc/microshift
echo "mtu: ${pod_mtu}" > /etc/microshift/ovn.yaml
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:-}"
local -r pod_mtu="${6:-}"

# Prepare kickstart for all hosts
# prepare_kickstart args: vmname template commit_ref fips_enabled ipv6_only
Expand Down Expand Up @@ -223,9 +296,62 @@ 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
if [ -n "${pod_mtu}" ]; then
inject_kickstart_mtu "${host}" "${network_mtu}" "${pod_mtu}"
else
inject_kickstart_mtu "${host}" "${network_mtu}"
fi
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. Race-safe — multiple parallel scenarios may call
# this simultaneously, so each step tolerates "already done" errors and
# a final check verifies the network is active.
c2cc_create_jumbo_network() {
local -r netconfig="${ROOTDIR}/test/assets/network/jumbo-network.xml"
sudo virsh net-define "${netconfig}" 2>/dev/null || true
sudo virsh net-start jumbo 2>/dev/null || true
sudo virsh net-autostart jumbo 2>/dev/null || true
sudo virsh net-info jumbo | grep "Active:.*yes" >/dev/null
}

# 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() {
local -r netconfig="${ROOTDIR}/test/assets/network/jumbo-ipv6-network.xml"
sudo virsh net-define "${netconfig}" 2>/dev/null || true
sudo virsh net-start jumbo-ipv6 2>/dev/null || true
sudo virsh net-autostart jumbo-ipv6 2>/dev/null || true
sudo virsh net-info jumbo-ipv6 | grep "Active:.*yes" >/dev/null

# Add the bridge's IPv6 subnet to the firewall trusted zone so VMs
# can reach the hypervisor's services (registry mirror via hostname).
# Re-applied on every run in case the firewall was reset since creation.
local bridge
bridge=$(sudo virsh net-info jumbo-ipv6 | grep '^Bridge:' | awk '{print $2}')
if [[ -z "${bridge}" ]]; then
echo "ERROR: Could not determine bridge name for jumbo-ipv6 network" >&2
return 1
fi
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() {
Expand Down
35 changes: 30 additions & 5 deletions test/bin/ci_phase_boot_and_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,41 @@ else
progress=""
fi

# Limit amount of parallel scenarios for the C2CC jobs to avoid
# over-provisioning the resources: each C2CC scenario runs 3 VMs
# (2 vCPUs / 4GiB each) and the c7g.metal instance has 64 cores / 128GiB.
# Powering off the VMs of passed scenarios makes the job limit an
# actual cap on the number of running VMs.
# Each C2CC scenario runs 3 VMs (2 vCPUs / 4GiB each)
# and the c7g.metal instance has 64 cores / 128GiB.
jobs_arg=""
scenario_action="create-and-run"
if [[ "${SCENARIO_SOURCES}" =~ c2cc ]]; then
# Limit amount of parallel scenarios for the C2CC jobs
# to avoid over-provisioning the resources.
jobs_arg="-j 8"

# Power off passed VMs so the job limit is an actual cap on running VMs.
scenario_action="create-run-shutdown"

# Each arch runs one RHEL version to halve the scenario count.
# The assignment rotates per commit so both combos get coverage:
# flip=0: x86 → el98, ARM → el102
# flip=1: x86 → el102, ARM → el98
commit_digit=$(git rev-parse HEAD | cut -c1)
flip=$(( 16#${commit_digit} % 2 ))

if [[ "$(uname -m)" == "x86_64" ]]; then
if [[ "${flip}" -eq 0 ]]; then
delete_ver=el102
else
delete_ver=el98
fi
else
if [[ "${flip}" -eq 0 ]]; then
delete_ver=el98
else
delete_ver=el102
fi
fi

echo "C2CC arch split: deleting ${delete_ver}-* (flip=${flip})"
find "${SCENARIOS_TO_RUN}" -name "${delete_ver}-*.sh" -delete
Comment on lines +100 to +122

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must say, this is pretty neat idea

fi

TEST_OK=true
Expand Down
19 changes: 18 additions & 1 deletion test/bin/scenario.sh
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,7 @@ EOF
# <boot_blueprint> \
# [--vmname <name>] \
# [--network <name>[,<name>...]] \
# [--network_mtu <size>] \
# [--vm_vcpus <vcpus>] \
# [--vm_memory <memory>] \
# [--vm_disksize <disksize>] \
Expand All @@ -820,6 +821,14 @@ EOF
# [--network <name>[,<name>...]]: 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 <size>]: 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 <mtu>
# element — QEMU only negotiates a larger MTU
# with the guest's virtio-net driver when the
# domain's own <interface> 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 <vcpus>]: Number of vCPUs for the VM.
Expand All @@ -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
Expand All @@ -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"
Expand Down Expand Up @@ -960,6 +970,12 @@ launch_vm() {
if sudo virsh nwfilter-list | awk '{print $2}' | grep -qx "${n}"; then
vm_network_args+=",filterref=${n}"
fi

# Propagate MTU to the domain interface (see --network_mtu doc above).
if [ -n "${network_mtu}" ]; then
vm_network_args+=",mtu.size=${network_mtu}"
fi

vm_network_args+=" "
done
if [ -z "${vm_network_args}" ] ; then
Expand Down Expand Up @@ -1001,6 +1017,7 @@ launch_vm() {
# to attach to the console. `unbuffer` provides the TTY.
# shellcheck disable=SC2086
if ${timeout_install} unbuffer sudo virt-install \
--check disk_size=off \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need that already?

--autoconsole text \
--graphics "${graphics_args}" \
--name "${full_vmname}" \
Expand Down
5 changes: 3 additions & 2 deletions test/resources/c2cc.resource
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Loading