From d5aefca40e1e013f741d565c9f6286fe293de298 Mon Sep 17 00:00:00 2001 From: Sebastian Mitterle Date: Mon, 16 Oct 2023 19:06:41 +0800 Subject: [PATCH] passt: fix tests on s390x 1. s390x doesn't have ACPI 2. s390x virtual interface name inside VM is encX 3. Remove unsupported DAC security driver for unprivileged user if present 4. Pass 'vm_iface' to 'passt.check_vm_ip' to avoid default value with wrong interface naming scheme 5. passt/check_nameserver: remove interface name from ipv6 entry as it might be different between host and guest 6. passt/check_default_gw: let us select which entry to choose because utils_net.get_default_gateway might return more than one, e.g. with multipath routes or when there's more than one interface on the host; same for passt/check_connection 7. passt/check_port_listen: only check for partial process user "'passt" because on x86_64 there's specializatoin 'passt.avx2' but on s390x it's just 'passt' 8. Don't use utils_net.get_host_ip_address because it doesn't let us choose which interface to get the ip address from; use utils_net.get_ip_address_by_interface instead Signed-off-by: Sebastian Mitterle --- .../passt/passt_attach_detach.cfg | 4 ++ .../passt/passt_connectivity_between_2vms.cfg | 4 ++ .../virtual_network/passt/passt_function.cfg | 6 +++ .../virtual_network/passt/passt_reconnect.cfg | 3 ++ .../passt/passt_transfer_file.cfg | 3 ++ .../passt/passt_attach_detach.py | 18 +++++---- .../passt/passt_connectivity_between_2vms.py | 38 +++++++++++-------- .../virtual_network/passt/passt_function.py | 12 +++--- .../virtual_network/passt/passt_reconnect.py | 2 +- provider/virtual_network/passt.py | 28 ++++++++++---- 10 files changed, 82 insertions(+), 36 deletions(-) diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_attach_detach.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_attach_detach.cfg index 4b0062b4d5..e2d58309f5 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_attach_detach.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_attach_detach.cfg @@ -2,6 +2,7 @@ type = passt_attach_detach func_supported_since_libvirt_ver = (9, 0, 0) host_iface = + host_iface_index = outside_ip = 'www.redhat.com' start_vm = no mtu = 65520 @@ -45,3 +46,6 @@ conn_check_args_1 = ('TCP6', 'localhost', 31339, 41339, True, None) conn_check_args_2 = ('UDP4', 'localhost', 2025, 2025, True, None) conn_check_args_3 = ('UDP6', 'localhost', 2025, 2025, True, None) + s390-virtio: + vm_iface = enc1 + iface_attrs = {'model': 'virtio', 'ips': ${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, 'alias': ${alias}, 'type_name': 'user', 'portForwards': ${portForwards}} diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_connectivity_between_2vms.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_connectivity_between_2vms.cfg index 09cf6bd6d0..9c8097882f 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_connectivity_between_2vms.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_connectivity_between_2vms.cfg @@ -41,3 +41,7 @@ conn_check_args_1 = ('TCP6', server_default_gw_v6, vm_c_iface, 41335, 41335) conn_check_args_2 = ('UDP4', server_default_gw, None, 21335, 21335) conn_check_args_3 = ('UDP6', server_default_gw_v6, vm_c_iface, 21335, 21335) + s390-virtio: + vm_c_iface = enc1 + iface_attrs = {'model': 'virtio', **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, 'type_name': 'user', **${portForwards}} + iface_c_attrs = {'model': 'virtio', **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, 'type_name': 'user'} diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_function.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_function.cfg index f8951abd3f..946ec72132 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_function.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_function.cfg @@ -22,6 +22,9 @@ iface_attrs = {'model': 'virtio', 'acpi': {'index': '1'}, 'type_name': 'user', 'backend': {'type': 'passt'}, 'source': {'dev': '${host_iface}'}} vm_iface = eno1 vm_ping_outside = pass + s390-virtio: + iface_attrs = {'model': 'virtio', 'type_name': 'user', 'backend': {'type': 'passt'}, 'source': {'dev': '${host_iface}'}} + vm_iface = enc1 - ip_portfw: alias = {'name': 'ua-c87b89ff-b769-4abc-921f-30d42d7aec5b'} backend = {'type': 'passt'} @@ -49,3 +52,6 @@ conn_check_args_7 = ('UDP4', 'localhost', 2025, 2025, True, None) conn_check_args_8 = ('UDP6', host_ip_v6, 4431, 4432, True, None) conn_check_args_9 = ('UDP6', '::1', 4431, 4432, False, None) + s390-virtio: + iface_attrs = {'model': 'virtio', 'ips': ${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, 'alias': ${alias}, 'type_name': 'user', 'portForwards': ${portForwards}} + vm_iface = enc1 diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_reconnect.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_reconnect.cfg index 023d3911a4..b6043ec9b9 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_reconnect.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_reconnect.cfg @@ -40,3 +40,6 @@ conn_check_args_1 = ('TCP6', 'localhost', 31339, 41339, True, None) conn_check_args_2 = ('UDP4', 'localhost', 2025, 2025, True, None) conn_check_args_3 = ('UDP6', 'localhost', 2025, 2025, True, None) + s390-virtio: + vm_iface = enc1 + iface_attrs = {'model': 'virtio', **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, **${alias}, 'type_name': 'user', **${portForwards}} diff --git a/libvirt/tests/cfg/virtual_network/passt/passt_transfer_file.cfg b/libvirt/tests/cfg/virtual_network/passt/passt_transfer_file.cfg index f5182c2746..ecdd45f75a 100644 --- a/libvirt/tests/cfg/virtual_network/passt/passt_transfer_file.cfg +++ b/libvirt/tests/cfg/virtual_network/passt/passt_transfer_file.cfg @@ -29,6 +29,9 @@ iface_attrs = {'model': 'virtio', 'acpi': {'index': '1'}, **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, **${alias}, 'type_name': 'user', **${portForwards}} ipv6_prefix = 128 vm_iface = eno1 + s390-virtio: + vm_iface = enc1 + iface_attrs = {'model': 'virtio', **${ips}, 'backend': ${backend}, 'source': {'dev': '${host_iface}'}, **${alias}, 'type_name': 'user', **${portForwards}} variants file_size: - 10M: bs = 1M diff --git a/libvirt/tests/src/virtual_network/passt/passt_attach_detach.py b/libvirt/tests/src/virtual_network/passt/passt_attach_detach.py index 153e644084..0033d935e3 100644 --- a/libvirt/tests/src/virtual_network/passt/passt_attach_detach.py +++ b/libvirt/tests/src/virtual_network/passt/passt_attach_detach.py @@ -65,17 +65,18 @@ def run(test, params, env): scenario = params.get('scenario') virsh_uri = params.get('virsh_uri') add_iface = 'yes' == params.get('add_iface', 'no') - host_ip = utils_net.get_host_ip_address(ip_ver='ipv4') - host_ip_v6 = utils_net.get_host_ip_address(ip_ver='ipv6') + host_iface = params.get('host_iface') + host_iface = host_iface if host_iface else utils_net.get_net_if( + state="UP")[0] + host_iface_index = int(params.get('host_iface_index', 0)) + host_ip = utils_net.get_ip_address_by_interface(host_iface, ip_ver='ipv4') + host_ip_v6 = utils_net.get_ip_address_by_interface(host_iface, ip_ver='ipv6') iface_attrs = eval(params.get('iface_attrs')) params['socket_dir'] = socket_dir = eval(params.get('socket_dir')) params['proc_checks'] = proc_checks = eval(params.get('proc_checks', '{}')) vm_iface = params.get('vm_iface', 'eno1') mtu = params.get('mtu') outside_ip = params.get('outside_ip') - host_iface = params.get('host_iface') - host_iface = host_iface if host_iface else utils_net.get_net_if( - state="UP")[0] log_file = f'/run/user/{user_id}/passt.log' iface_attrs['backend']['logFile'] = log_file iface_attrs['source']['dev'] = host_iface @@ -124,9 +125,9 @@ def run(test, params, env): test.fail(f'Logfile of passt "{log_file}" not created') session = vm.wait_for_serial_login(timeout=60) - passt.check_vm_ip(iface_attrs, session, host_iface) + passt.check_vm_ip(iface_attrs, session, host_iface, vm_iface) passt.check_vm_mtu(session, vm_iface, mtu) - passt.check_default_gw(session) + passt.check_default_gw(session, host_iface_index) passt.check_nameserver(session) ips = { @@ -138,7 +139,8 @@ def run(test, params, env): firewalld.stop() LOG.debug(f'Service status of firewalld: {firewalld.status()}') passt.check_connection(vm, vm_iface, - ['TCP4', 'TCP6', 'UDP4', 'UDP6']) + ['TCP4', 'TCP6', 'UDP4', 'UDP6'], + host_iface_index) if 'portForwards' in iface_attrs: passt.check_portforward(vm, host_ip, params) diff --git a/libvirt/tests/src/virtual_network/passt/passt_connectivity_between_2vms.py b/libvirt/tests/src/virtual_network/passt/passt_connectivity_between_2vms.py index d4ea9a86d3..555e3de9f4 100644 --- a/libvirt/tests/src/virtual_network/passt/passt_connectivity_between_2vms.py +++ b/libvirt/tests/src/virtual_network/passt/passt_connectivity_between_2vms.py @@ -27,31 +27,46 @@ def run(test, params, env): root = 'root_user' == params.get('user_type', '') if root: vm_name = params.get('main_vm') - vm = env.get_vm(vm_name) - vm_c = env.get_vm(params.get('vm_c_name')) + vm_c_name = params.get('vm_c_name') virsh_ins = virsh + else: + test_user = params.get('test_user', '') + test_passwd = params.get('test_passwd', '') + vm_name = params.get('unpr_vm_name') + uri = f'qemu+ssh://{test_user}@localhost/session' + virsh_ins = virsh.VirshPersistent(uri=uri) + vm_c_name = params.get('unpr_vm_c_name') + + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, + virsh_instance=virsh_ins) + vmxml_c = vm_xml.VMXML.new_from_inactive_dumpxml(vm_c_name, + virsh_instance=virsh_ins) + bkxml = vmxml.copy() + bkxml_c = vmxml_c.copy() + + if root: + vm = env.get_vm(vm_name) + vm_c = env.get_vm(vm_c_name) log_dir = params.get('log_dir') user_id = params.get('user_id') log_file = f'/run/user/{user_id}/passt.log' log_file_c = f'/run/user/{user_id}/passt_c.log' else: - vm_name = params.get('unpr_vm_name') - test_user = params.get('test_user', '') - test_passwd = params.get('test_passwd', '') user_id = passt.get_user_id(test_user) unpr_vm_args = { 'username': params.get('username'), 'password': params.get('password'), } + LOG.debug("Remove 'dac' security driver for unprivileged users") + vmxml.del_seclabel(by_attr=[('model', 'dac')]) + vmxml_c.del_seclabel(by_attr=[('model', 'dac')]) vm = libvirt_unprivileged.get_unprivileged_vm(vm_name, test_user, test_passwd, **unpr_vm_args) - vm_c = libvirt_unprivileged.get_unprivileged_vm(params.get('unpr_vm_c_name'), + vm_c = libvirt_unprivileged.get_unprivileged_vm(vm_c_name, test_user, test_passwd, **unpr_vm_args) - uri = f'qemu+ssh://{test_user}@localhost/session' - virsh_ins = virsh.VirshPersistent(uri=uri) host_session = aexpect.ShellSession('su') remote.VMManager.set_ssh_auth(host_session, 'localhost', test_user, test_passwd) @@ -73,13 +88,6 @@ def run(test, params, env): iface_attrs['source']['dev'] = host_iface iface_c_attrs['source']['dev'] = host_iface - vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, - virsh_instance=virsh_ins) - vmxml_c = vm_xml.VMXML.new_from_inactive_dumpxml(vm_c.name, - virsh_instance=virsh_ins) - bkxml = vmxml.copy() - bkxml_c = vmxml_c.copy() - selinux_status = passt.ensure_selinux_enforcing() passt.check_socat_installed() diff --git a/libvirt/tests/src/virtual_network/passt/passt_function.py b/libvirt/tests/src/virtual_network/passt/passt_function.py index 97c1425f41..361aa768a8 100644 --- a/libvirt/tests/src/virtual_network/passt/passt_function.py +++ b/libvirt/tests/src/virtual_network/passt/passt_function.py @@ -27,6 +27,10 @@ def run(test, params, env): """ libvirt_version.is_libvirt_feature_supported(params) root = 'root_user' == params.get('user_type', '') + vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, + virsh_instance=virsh_ins) + bkxml = vmxml.copy() + if root: vm_name = params.get('main_vm') vm = env.get_vm(vm_name) @@ -42,6 +46,8 @@ def run(test, params, env): 'username': params.get('username'), 'password': params.get('password'), } + LOG.debug("Remove 'dac' security driver for unprivileged user") + vmxml.del_seclabel(by_attr=[('model', 'dac')]) vm = libvirt_unprivileged.get_unprivileged_vm(vm_name, test_user, test_passwd, **unpr_vm_args) @@ -68,10 +74,6 @@ def run(test, params, env): iface_attrs['backend']['logFile'] = log_file iface_attrs['source']['dev'] = host_iface - vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name, - virsh_instance=virsh_ins) - bkxml = vmxml.copy() - selinux_status = passt.ensure_selinux_enforcing() passt.check_socat_installed() @@ -98,7 +100,7 @@ def run(test, params, env): test.fail(f'Logfile of passt "{log_file}" not created') session = vm.wait_for_serial_login(timeout=60) - passt.check_vm_ip(iface_attrs, session, host_iface) + passt.check_vm_ip(iface_attrs, session, host_iface, vm_iface) passt.check_vm_mtu(session, vm_iface, mtu) passt.check_default_gw(session) passt.check_nameserver(session) diff --git a/libvirt/tests/src/virtual_network/passt/passt_reconnect.py b/libvirt/tests/src/virtual_network/passt/passt_reconnect.py index 0531d8806b..16ed2121d6 100644 --- a/libvirt/tests/src/virtual_network/passt/passt_reconnect.py +++ b/libvirt/tests/src/virtual_network/passt/passt_reconnect.py @@ -109,7 +109,7 @@ def run(test, params, env): test.fail(f'Logfile of passt "{log_file}" not created') session = vm.wait_for_serial_login(timeout=60) - passt.check_vm_ip(iface_attrs, session, host_iface) + passt.check_vm_ip(iface_attrs, session, host_iface, vm_iface) passt.check_vm_mtu(session, vm_iface, mtu) passt.check_default_gw(session) passt.check_nameserver(session) diff --git a/provider/virtual_network/passt.py b/provider/virtual_network/passt.py index ae14893eb2..db95c98b81 100644 --- a/provider/virtual_network/passt.py +++ b/provider/virtual_network/passt.py @@ -1,5 +1,6 @@ import logging import os +import re from socket import socket import aexpect @@ -169,15 +170,17 @@ def check_proc(target): raise exceptions.TestFail(';'.join(failed_check)) -def check_vm_ip(iface_attrs, session, host_iface): +def check_vm_ip(iface_attrs, session, host_iface, vm_iface=None): """ Check if vm ip and prefix meet expectation :param iface_attrs: attributes of interface :param session: shell session instance of vm :param host_iface: host interface + :param vm_iface: vm interface, will be constructed for x86_64 if None """ - vm_iface = 'eno' + iface_attrs.get('acpi', {'index': '1'})['index'] + if not vm_iface: + vm_iface = 'eno' + iface_attrs.get('acpi', {'index': '1'})['index'] vm_ip, prefix = get_iface_ip_and_prefix(vm_iface, session=session) LOG.debug(f'VM ip and prefix: {vm_ip}, {prefix}') if 'ips' in iface_attrs: @@ -230,16 +233,20 @@ def check_vm_mtu(session, iface, mtu): raise exceptions.TestFail(f'Wrong vm mtu: {vm_mtu}, should be {mtu}') -def check_default_gw(session): +def check_default_gw(session, host_iface_index=0): """ Check whether default host gateways of host and guest are consistent :param session: vm shell session instance + :param host_iface_index: in case, there's more than one default gateway on + the host, which one to select """ host_gw = utils_net.get_default_gateway(force_dhcp=True) + host_gw = host_gw.split('\n')[host_iface_index] vm_gw = utils_net.get_default_gateway(session=session, force_dhcp=True) LOG.debug(f'Host and vm default ipv4 gateway: {host_gw}, {vm_gw}') host_gw_v6 = utils_net.get_default_gateway(ip_ver='ipv6') + host_gw_v6 = host_gw_v6.split('\n')[host_iface_index] vm_gw_v6 = utils_net.get_default_gateway(session=session, ip_ver='ipv6') LOG.debug(f'Host and vm default ipv6 gateway: {host_gw_v6}, {vm_gw_v6}') @@ -258,8 +265,11 @@ def check_nameserver(session): :param session: vm shell session instance """ get_cmd = 'cat /etc/resolv.conf|grep -vE "#|;"' - on_host = process.run(get_cmd, shell=True).stdout_text.strip() - on_vm = session.cmd_output(get_cmd).strip() + on_host = process.run(get_cmd, shell=True).stdout_text.strip().split('\n') + on_vm = session.cmd_output(get_cmd).strip().split('\n') + if cleanup: + on_host = [re.sub(r'%.*', '', x) for x in on_host] + on_vm = [re.sub(r'%.*', '', x) for x in on_vm] if on_host == on_vm: LOG.debug(f'Nameserver on vm is consistent with host:\n{on_host}') else: @@ -320,16 +330,20 @@ def check_protocol_connection(src_sess, tar_sess, protocol, addr, f'actually is {conneted}') -def check_connection(vm, vm_iface, protocols): +def check_connection(vm, vm_iface, protocols, host_iface_index=0): """ Check connection of vm and host :param vm: vm instance :param vm_iface: interface of vm :param protocols: protocols to check + :param host_iface_index: in case, there's more than one default gateway on + the host, which one to select """ default_gw = utils_net.get_default_gateway(force_dhcp=True) + default_gw = default_gw.split('\n')[host_iface_index] default_gw_v6 = utils_net.get_default_gateway(ip_ver='ipv6') + default_gw_v6 = default_gw_v6.split('\n')[host_iface_index] for protocol in protocols: host_sess = aexpect.ShellSession('su') vm_sess = vm.wait_for_serial_login(timeout=60) @@ -379,7 +393,7 @@ def check_port_listen(ports, protocol, host_ip=None): """ if protocol.lower() not in ('tcp', 'udp'): raise exceptions.TestError(f'Unsupported protocol: {protocol}') - cmd_listen = process.run(f"ss -{protocol[0].lower()}lpn|egrep 'passt.avx2'", + cmd_listen = process.run(f"ss -{protocol[0].lower()}lpn|egrep 'passt'", shell=True).stdout_text for item in ports: if item in cmd_listen: