|
| 1 | +from pkgfixtures import host_with_saved_yum_state |
| 2 | +import ipaddress |
| 3 | +import logging |
| 4 | +import os |
| 5 | +import pytest |
| 6 | +import tempfile |
| 7 | + |
| 8 | +# Requirements: |
| 9 | +# - one XCP-ng host (--host) >= 8.2 |
| 10 | +# - a VM (--vm) |
| 11 | +# - the first network on the host can be used to reach the host |
| 12 | + |
| 13 | +vif_limit = 16 |
| 14 | +interface_name = "enX" |
| 15 | +vcpus = '8' |
| 16 | + |
| 17 | +# There is a ResourceWarning due to background=True on an ssh call |
| 18 | +# We do ensure the processes are killed |
| 19 | +@pytest.mark.filterwarnings("ignore::ResourceWarning") |
| 20 | +@pytest.mark.debian_uefi_vm |
| 21 | +class TestVIFLimit: |
| 22 | + def test_vif_limit(self, host_with_saved_yum_state, imported_vm): |
| 23 | + host = host_with_saved_yum_state |
| 24 | + vm = imported_vm |
| 25 | + if (vm.is_running()): |
| 26 | + logging.info("VM already running, shutting it down first") |
| 27 | + vm.shutdown(verify=True) |
| 28 | + |
| 29 | + network_uuid = vm.vifs()[0].param_get('network-uuid') |
| 30 | + existing_vifs = len(vm.vifs()) |
| 31 | + |
| 32 | + logging.info(f'Get {vcpus} vCPUs for the VM') |
| 33 | + vm.param_set('VCPUs-max', vcpus) |
| 34 | + vm.param_set('VCPUs-at-startup', vcpus) |
| 35 | + |
| 36 | + logging.info('Create VIFs before starting the VM') |
| 37 | + for i in range(existing_vifs, vif_limit): |
| 38 | + vm.create_vif(i, network_uuid=network_uuid) |
| 39 | + |
| 40 | + vm.start() |
| 41 | + vm.wait_for_os_booted() |
| 42 | + |
| 43 | + logging.info('Verify the interfaces exist in the guest') |
| 44 | + for i in range(0, vif_limit): |
| 45 | + if vm.ssh_with_result([f'test -d /sys/class/net/{interface_name}{i}']).returncode != 0: |
| 46 | + guest_error = vm.ssh_with_result(['dmesg | grep -B1 -A3 xen_netfront']).stdout |
| 47 | + logging.error("dmesg:\n%s", guest_error) |
| 48 | + assert False, "The interface does not exist in the guest, check dmesg output above for errors" |
| 49 | + |
| 50 | + logging.info('Configure interfaces') |
| 51 | + config = '\n'.join([f'iface {interface_name}{i} inet dhcp\n' |
| 52 | + f'auto {interface_name}{i}' |
| 53 | + for i in range(existing_vifs, vif_limit)]) |
| 54 | + vm.ssh([f'echo "{config}" >> /etc/network/interfaces']) |
| 55 | + |
| 56 | + logging.info('Install iperf3 on VM and host') |
| 57 | + if vm.ssh_with_result(['apt install iperf3 --assume-yes']).returncode != 0: |
| 58 | + assert False, "Failed to install iperf3 on the VM" |
| 59 | + host.yum_install(['iperf3']) |
| 60 | + |
| 61 | + logging.info('Reconfigure VM networking') |
| 62 | + if vm.ssh_with_result(['systemctl restart networking']).returncode != 0: |
| 63 | + assert False, "Failed to configure networking" |
| 64 | + |
| 65 | + # Test iperf on all interfaces in parallel |
| 66 | + # Clean up on exceptions |
| 67 | + try: |
| 68 | + logging.info('Create separate iperf servers on the host') |
| 69 | + with tempfile.NamedTemporaryFile('w') as host_script: |
| 70 | + iperf_configs = [f'iperf3 -s -p {5100+i} &' |
| 71 | + for i in range(0, vif_limit)] |
| 72 | + host_script.write('\n'.join(iperf_configs)) |
| 73 | + host_script.flush() |
| 74 | + host.scp(host_script.name, host_script.name) |
| 75 | + host.ssh([f'nohup bash -c "bash {host_script.name}" < /dev/null &>/dev/null &'], |
| 76 | + background=True) |
| 77 | + |
| 78 | + logging.info('Start multiple iperfs on separate interfaces on the VM') |
| 79 | + with tempfile.NamedTemporaryFile('w') as vm_script: |
| 80 | + iperf_configs = [f'iperf3 --no-delay -c {host.hostname_or_ip} ' |
| 81 | + f'-p {5100+i} --bind-dev {interface_name}{i} ' |
| 82 | + f'--interval 0 --parallel 1 --time 30 &' |
| 83 | + for i in range(0, vif_limit)] |
| 84 | + vm_script.write('\n'.join(iperf_configs)) |
| 85 | + vm_script.flush() |
| 86 | + vm.scp(vm_script.name, vm_script.name) |
| 87 | + stdout = vm.ssh([f'bash {vm_script.name}']) |
| 88 | + |
| 89 | + # TODO: log this into some performance time series DB |
| 90 | + logging.info(stdout) |
| 91 | + finally: |
| 92 | + vm.ssh(['pkill iperf3 || true']) |
| 93 | + host.ssh('killall iperf3') |
0 commit comments