Skip to content

Commit 52747dc

Browse files
committed
add case for migrating guest with bridge interface
xxxx-299038: [bridge] migrate guest with bridge type interface Signed-off-by: nanli <[email protected]>
1 parent e002d4d commit 52747dc

File tree

2 files changed

+272
-0
lines changed

2 files changed

+272
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
- virtual_network.migrate.migrate_with_bridge_type_interface:
2+
type = migrate_with_bridge_type_interface
3+
start_vm = "no"
4+
take_regular_screendumps = no
5+
storage_type = 'nfs'
6+
setup_local_nfs = 'yes'
7+
disk_type = "file"
8+
disk_source_protocol = "netfs"
9+
nfs_mount_dir = "/var/lib/libvirt/migrate"
10+
nfs_mount_options = "soft,timeo=50,retrans=3"
11+
virsh_migrate_dest_state = running
12+
virsh_migrate_options = "--live --p2p --verbose"
13+
virsh_migrate_connect_uri = "qemu:///system"
14+
outside_ip = "www.google.com"
15+
migration_setup = "yes"
16+
iface_model = "virtio"
17+
iface_queues = "5"
18+
new_queues = "3"
19+
ssh_remote_auth = True
20+
unprivileged_user = ""
21+
#migrate_dest_host = "EXAMPLE.DEST.HOST"
22+
#migrate_source_host = "EXAMPLE.SOURCE.HOST"
23+
migrate_dest_host = "dell-per740-41.lab.eng.pek2.redhat.com"
24+
migrate_source_host = "dell-per740-43.lab.eng.pek2.redhat.com"
25+
nfs_server_ip = "${migrate_source_host}"
26+
migrate_desturi_port = "49152-49216"
27+
migrate_desturi_type = "ssh"
28+
virsh_migrate_desturi = "qemu+ssh://${migrate_dest_host}/system"
29+
vm_ping_outside = "pass"
30+
expected_xpath = [{'element_attrs': ["//interface/driver[@queues='${iface_queues}']"]}]
31+
check_network_accessibility_after_mig = "yes"
32+
variants:
33+
- linux_bridge:
34+
bridge_type = "linux"
35+
iface_type = "bridge"
36+
bridge_name = "br0"
37+
iface_dict = {'source': {'bridge': '${bridge_name}'},'type_name':'${iface_type}', 'model':'${iface_model}', 'driver': {'driver_attr': {'queues': '${iface_queues}'}}}
38+
- ovs_bridge:
39+
bridge_type = "ovs"
40+
ovs_bridge_name = "ovsbr0"
41+
network_dict = {'bridge': {'name': '${ovs_bridge_name}'}, 'forward': {'mode': 'bridge'}, 'name': 'ovs-net', 'virtualport_type': 'openvswitch'}
42+
iface_type = "network"
43+
iface_dict = {'network': 'ovs-net', 'type_name':'${iface_type}', 'model':'${iface_model}', 'driver': {'driver_attr': {'queues': '${iface_queues}'}}}
44+
variants:
45+
- precopy_migration:
46+
migration_type = "precopy"
47+
virsh_migrate_extra = ""
48+
migrate_vm_back = "yes"
49+
- postcopy_migration:
50+
migration_type = "postcopy"
51+
virsh_migrate_extra = "--postcopy"
52+
- cancel_migration:
53+
migration_type = "cancel"
54+
cancel_migration = "yes"
55+
status_error = "yes"
56+
err_msg = "operation aborted: migration out job: canceled by client|operation aborted: job 'migration out' canceled by client"
57+
virsh_migrate_extra = "--bandwidth 10"
58+
action_during_mig = '[{"func": "virsh.domjobabort", "after_event": "iteration: '1'", "func_param": "'%s' % params.get('migrate_main_vm')"}]'
59+
variants:
60+
- start_with_interface:
61+
interface_timing = "start"
62+
- hotplug_interface:
63+
interface_timing = "hotplug"
64+
hotplug = "yes"
65+
attach_interface = "yes"
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
import re
2+
3+
from virttest import utils_net
4+
from virttest import virsh
5+
from virttest.libvirt_xml import vm_xml
6+
from virttest.utils_libvirt import libvirt_network
7+
from virttest.utils_libvirt import libvirt_vmxml
8+
from virttest.libvirt_xml.vm_xml import VMXML
9+
10+
from provider.virtual_network import network_base
11+
from provider.migration import base_steps
12+
from provider.guest_os_booting import guest_os_booting_base as guest_os
13+
14+
15+
def run(test, params, env):
16+
"""
17+
Test migration with bridge type interface
18+
1. Setup bridge and virtual network according to bridge type
19+
2. Migrate to target host
20+
3. Check on target host for network functions:
21+
- Guest ping outside
22+
- Check for multiqueue
23+
- Check multiqueues in VM live XML (should have <driver ... queues='5'>)
24+
4. Migrate back from dst to src
25+
26+
:param test: test object
27+
:param params: Dictionary with the test parameters
28+
:param env: Dictionary with test environment.
29+
"""
30+
31+
def check_multiqueue_in_guest(vm_session):
32+
"""
33+
Check multiqueue configuration inside the guest.
34+
35+
:params, vm_session: vm session object.
36+
"""
37+
test.log.info("Checking multiqueue configuration in guest")
38+
guest_iface_info = vm_session.cmd_output("ip --color=never l").strip()
39+
iface_name = re.findall(
40+
r"^\d+: (\S+?)[@:].*state UP.*$", guest_iface_info, re.MULTILINE)[0]
41+
if not iface_name:
42+
test.fail("Failed to get network interface name in guest")
43+
44+
_, output = vm_session.cmd_status_output("ethtool -l %s" % iface_name)
45+
test.log.debug("ethtool cmd output:%s" % output)
46+
if not re.findall("Combined:.*?%s" % iface_queues, output):
47+
test.fail("Expected Current hardware settings Combined: %d" % iface_queues)
48+
49+
test.log.info("Setting combined queues to 3 for %s", iface_name)
50+
utils_net.set_channel(vm_session, iface_name, "combined", new_queues)
51+
_, output = vm_session.cmd_status_output("ethtool -l %s" % iface_name)
52+
if not re.findall("Combined:.*?%s" % new_queues, output):
53+
test.fail("Failed to set combined queues: %s" % new_queues)
54+
55+
def setup_vm_interface():
56+
"""
57+
Setup VM interface according to configuration
58+
"""
59+
vm_xml = VMXML.new_from_inactive_dumpxml(vm_name)
60+
vm_xml.remove_all_device_by_type('interface')
61+
vm_xml.sync()
62+
if interface_timing == "hotplug":
63+
if not vm.is_alive():
64+
vm.start()
65+
iface = libvirt_vmxml.create_vm_device_by_type('interface', iface_dict)
66+
virsh.attach_device(vm_name, iface.xml, flagstr="--config",
67+
debug=True, ignore_status=False)
68+
else:
69+
libvirt_vmxml.modify_vm_device(
70+
VMXML.new_from_inactive_dumpxml(vm_name), 'interface',
71+
iface_dict)
72+
vm.start()
73+
vm.wait_for_serial_login().close()
74+
test.log.debug("Guest xml:\n%s", VMXML.new_from_dumpxml(vm_name))
75+
76+
def cleanup_nvram():
77+
"""
78+
Clean up NVRAM file to avoid UEFI boot issues
79+
"""
80+
import os
81+
nvram_file = f"/var/lib/libvirt/qemu/nvram/{vm_name}_VARS.fd"
82+
if os.path.exists(nvram_file):
83+
test.log.info(f"Removing NVRAM file: {nvram_file}")
84+
os.remove(nvram_file)
85+
86+
def setup_test():
87+
"""
88+
Setup test environment for migration with bridge type interface
89+
"""
90+
test.log.info("Setting up test environment")
91+
# Clean up NVRAM to avoid UEFI boot issues
92+
cleanup_nvram()
93+
94+
if bridge_type == "linux":
95+
pass
96+
# utils_net.create_linux_bridge_tmux(bridge_name)
97+
# utils_net.create_linux_bridge_tmux(bridge_name, session=remote_session)
98+
elif bridge_type == "ovs":
99+
utils_net.create_ovs_bridge(ovs_bridge_name, ip_options='-color=never')
100+
101+
utils_net.create_ovs_bridge(ovs_bridge_name, session=virsh_session_remote,
102+
ip_options='-color=never')
103+
libvirt_network.create_or_del_network(network_dict, remote_args=remote_virsh_dargs)
104+
test.log.info("dest: network created")
105+
libvirt_network.create_or_del_network(network_dict)
106+
test.log.info("localhost: network created")
107+
108+
if vm.is_alive():
109+
vm.destroy()
110+
111+
setup_vm_interface()
112+
113+
def run_test():
114+
"""
115+
Run the main test: migration and verification
116+
"""
117+
test.log.info("TEST_STEP: Migrating VM to target host")
118+
migration_obj.setup_connection()
119+
if not vm.is_alive():
120+
vm.start()
121+
migration_obj.run_migration()
122+
123+
if not cancel_migration:
124+
test.log.info("TEST_STEP: Checking VM network connectivity on target host")
125+
backup_uri, vm.connect_uri = vm.connect_uri, dest_uri
126+
if vm.serial_console is not None:
127+
vm.cleanup_serial_console()
128+
vm.create_serial_console()
129+
vm_session_after_mig = vm.wait_for_serial_login(timeout=240)
130+
vm_session_after_mig.cmd("dhclient -r; dhclient")
131+
132+
test.log.info("TEST_STEP: Testing guest ping to outside")
133+
ips = {'outside_ip': outside_ip}
134+
network_base.ping_check(params, ips, vm_session_after_mig)
135+
136+
test.log.info("TEST_STEP: Checking multiqueue")
137+
check_multiqueue_in_guest(vm_session_after_mig)
138+
virsh_obj = virsh.VirshPersistent(uri=dest_uri)
139+
libvirt_vmxml.check_guest_xml_by_xpaths(
140+
VMXML.new_from_dumpxml(vm_name, virsh_instance=virsh_obj),
141+
expected_xpath)
142+
143+
if migrate_vm_back:
144+
test.log.info("TEST_STEP: Migrating VM back to source host")
145+
migration_obj.run_migration_back()
146+
147+
def teardown_test():
148+
"""
149+
Cleanup test environment
150+
"""
151+
test.log.info("Cleaning up test environment")
152+
backup_xml.sync()
153+
if bridge_type == "linux":
154+
pass
155+
# utils_net.delete_linux_bridge_tmux(bridge_name)
156+
# utils_net.delete_linux_bridge_tmux(bridge_name, session=remote_session)
157+
elif bridge_type == "ovs":
158+
utils_net.delete_ovs_bridge(ovs_bridge_name, ip_options='-color=never')
159+
utils_net.delete_ovs_bridge(ovs_bridge_name, session=virsh_session_remote, ip_options='-color=never')
160+
161+
libvirt_network.create_or_del_network(network_dict, is_del=True, remote_args=remote_virsh_dargs)
162+
libvirt_network.create_or_del_network(network_dict, is_del=True)
163+
migration_obj.cleanup_connection()
164+
165+
# Params to update disk using shared storage
166+
params["disk_type"] = params.get("disk_type", "file")
167+
params["disk_source_protocol"] = params.get("disk_source_protocol", "netfs")
168+
params["mnt_path_name"] = params.get("nfs_mount_dir")
169+
170+
server_ip = params["server_ip"] = params.get("migrate_dest_host")
171+
server_user = params.get("server_user")
172+
server_pwd = params.get("server_pwd") or params.get("migrate_dest_pwd")
173+
outside_ip = params.get("outside_ip")
174+
bridge_name = params.get("bridge_name")
175+
bridge_type = params.get("bridge_type")
176+
ovs_bridge_name = params.get("ovs_bridge_name")
177+
network_dict = eval(params.get("network_dict", "{}"))
178+
interface_timing = params.get("interface_timing")
179+
iface_queues = int(params.get("iface_queues", "5"))
180+
new_queues = int(params.get("new_queues", "3"))
181+
migrate_vm_back = params.get_boolean("migrate_vm_back")
182+
cancel_migration = params.get_boolean("cancel_migration")
183+
184+
remote_virsh_dargs = {'remote_ip': server_ip, 'remote_user': server_user,
185+
'remote_pwd': server_pwd, 'unprivileged_user': params.get("unprivileged_user"),
186+
'ssh_remote_auth': params.get("ssh_remote_auth")}
187+
188+
src_uri = params.get("virsh_migrate_connect_uri")
189+
dest_uri = params.get("virsh_migrate_desturi")
190+
expected_xpath = eval(params.get("expected_xpath"))
191+
iface_dict = eval(params.get("iface_dict", "{}"))
192+
193+
vm_name = guest_os.get_vm(params)
194+
vm = env.get_vm(vm_name)
195+
new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name)
196+
backup_xml = new_xml.copy()
197+
198+
virsh_session_remote = virsh.VirshPersistent(**remote_virsh_dargs)
199+
migration_obj = base_steps.MigrationBase(test, vm, params)
200+
201+
try:
202+
setup_test()
203+
run_test()
204+
finally:
205+
teardown_test()
206+
if virsh_session_remote:
207+
virsh_session_remote.close_session()

0 commit comments

Comments
 (0)