-
Notifications
You must be signed in to change notification settings - Fork 231
USHIFT-7382: Add MTU boundary tests for C2CC and C2CC+IPsec #7024
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
dd5b5be
0050ad0
0103c22
85de2cf
8fc8fe9
2969e02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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") | ||
| 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 |
| 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> |
| 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> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
|
@@ -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() { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I must say, this is pretty neat idea |
||
| fi | ||
|
|
||
| TEST_OK=true | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -804,6 +804,7 @@ EOF | |
| # <boot_blueprint> \ | ||
| # [--vmname <name>] \ | ||
| # [--network <name>[,<name>...]] \ | ||
| # [--network_mtu <size>] \ | ||
| # [--vm_vcpus <vcpus>] \ | ||
| # [--vm_memory <memory>] \ | ||
| # [--vm_disksize <disksize>] \ | ||
|
|
@@ -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. | ||
|
|
@@ -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,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 | ||
|
|
@@ -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 \ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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}" \ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the
sendtofails, it won't reach OK and we'll get an exception?Should we also close the socket? Just for correctness :)