Skip to content

Commit 4608380

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 4608380

File tree

2 files changed

+291
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)