Skip to content

Commit

Permalink
Merge pull request #2255 from GNS3/fix/2243
Browse files Browse the repository at this point in the history
Only add speed/duplex params when using Qemu >= v2.12
  • Loading branch information
grossmj authored Jul 6, 2023
2 parents 24c0340 + 8e2989d commit c5c4e1a
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 32 deletions.
30 changes: 14 additions & 16 deletions gns3server/compute/qemu/qemu_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def __init__(self, name, node_id, project, manager, linked_clone=True, qemu_path
self._local_udp_tunnels = {}
self._guest_cid = None
self._command_line_changed = False
self._qemu_version = None

# QEMU VM settings
if qemu_path:
Expand Down Expand Up @@ -1871,8 +1872,7 @@ async def _disk_interface_options(self, disk, disk_index, interface, format=None
# special case, sata controller doesn't exist in Qemu
options.extend(["-device", 'ahci,id=ahci{}'.format(disk_index)])
options.extend(["-drive", 'file={},if=none,id=drive{},index={},media=disk{}'.format(disk, disk_index, disk_index, extra_drive_options)])
qemu_version = await self.manager.get_qemu_version(self.qemu_path)
if qemu_version and parse_version(qemu_version) >= parse_version("4.2.0"):
if self._qemu_version and parse_version(self._qemu_version) >= parse_version("4.2.0"):
# The ‘ide-drive’ device is deprecated since version 4.2.0
# https://qemu.readthedocs.io/en/latest/system/deprecated.html#ide-drive-since-4-2
options.extend(["-device", 'ide-hd,drive=drive{},bus=ahci{}.0,id=drive{}'.format(disk_index, disk_index, disk_index)])
Expand Down Expand Up @@ -2131,11 +2131,10 @@ async def _network_options(self):

patched_qemu = False
if self._legacy_networking:
qemu_version = await self.manager.get_qemu_version(self.qemu_path)
if qemu_version:
if parse_version(qemu_version) >= parse_version("2.9.0"):
if self._qemu_version:
if parse_version(self._qemu_version) >= parse_version("2.9.0"):
raise QemuError("Qemu version 2.9.0 and later doesn't support legacy networking mode")
if parse_version(qemu_version) < parse_version("1.1.0"):
if parse_version(self._qemu_version) < parse_version("1.1.0"):
# this is a patched Qemu if version is below 1.1.0
patched_qemu = True

Expand All @@ -2144,8 +2143,7 @@ async def _network_options(self):
pci_bridges = math.floor(pci_devices / 32)
pci_bridges_created = 0
if pci_bridges >= 1:
qemu_version = await self.manager.get_qemu_version(self.qemu_path)
if qemu_version and parse_version(qemu_version) < parse_version("2.4.0"):
if self._qemu_version and parse_version(self._qemu_version) < parse_version("2.4.0"):
raise QemuError("Qemu version 2.4 or later is required to run this VM with a large number of network adapters")

pci_device_id = 4 + pci_bridges # Bridge consume PCI ports
Expand Down Expand Up @@ -2191,7 +2189,9 @@ async def _network_options(self):
else:
# newer QEMU networking syntax
device_string = "{},mac={}".format(adapter_type, mac)
if adapter_type == "virtio-net-pci":
if adapter_type == "virtio-net-pci" and \
self._qemu_version and parse_version(self._qemu_version) >= parse_version("2.12"):
# speed and duplex support was added in Qemu 2.12
device_string = "{},speed=10000,duplex=full".format(device_string)
bridge_id = math.floor(pci_device_id / 32)
if bridge_id > 0:
Expand Down Expand Up @@ -2224,8 +2224,7 @@ async def _disable_graphics(self):

if any(opt in self._options for opt in ["-display", "-nographic", "-curses", "-sdl" "-spice", "-vnc"]):
return []
version = await self.manager.get_qemu_version(self.qemu_path)
if version and parse_version(version) >= parse_version("3.0"):
if self._qemu_version and parse_version(self._qemu_version) >= parse_version("3.0"):
return ["-display", "none"]
else:
return ["-nographic"]
Expand Down Expand Up @@ -2270,9 +2269,8 @@ async def _run_with_hardware_acceleration(self, qemu_path, options):
elif sys.platform.startswith("win"):
if require_hardware_accel:
# HAXM is only available starting with Qemu version 2.9.0
version = await self.manager.get_qemu_version(self.qemu_path)
if version and parse_version(version) < parse_version("2.9.0"):
raise QemuError("HAXM acceleration can only be enable for Qemu version 2.9.0 and above (current version: {})".format(version))
if self._qemu_version and parse_version(self._qemu_version) < parse_version("2.9.0"):
raise QemuError("HAXM acceleration can only be enable for Qemu version 2.9.0 and above (current version: {})".format(self._qemu_version))

# check if HAXM is installed
version = self.manager.get_haxm_windows_version()
Expand Down Expand Up @@ -2372,6 +2370,7 @@ async def _build_command(self):
(to be passed to subprocess.Popen())
"""

self._qemu_version = await self.manager.get_qemu_version(self.qemu_path)
vm_name = self._name.replace(",", ",,")
project_path = self.project.path.replace(",", ",,")
additional_options = self._options.strip()
Expand All @@ -2389,10 +2388,9 @@ async def _build_command(self):
if await self._run_with_hardware_acceleration(self.qemu_path, self._options):
if sys.platform.startswith("linux"):
command.extend(["-enable-kvm"])
version = await self.manager.get_qemu_version(self.qemu_path)
# Issue on some combo Intel CPU + KVM + Qemu 2.4.0
# https://github.com/GNS3/gns3-server/issues/685
if version and parse_version(version) >= parse_version("2.4.0") and self.platform == "x86_64":
if self._qemu_version and parse_version(self._qemu_version) >= parse_version("2.4.0") and self.platform == "x86_64":
command.extend(["-machine", "smm=off"])
elif sys.platform.startswith("win") or sys.platform.startswith("darwin"):
command.extend(["-enable-hax"])
Expand Down
18 changes: 2 additions & 16 deletions tests/compute/qemu/test_qemu_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ async def vm(compute_project, manager, fake_qemu_binary, fake_qemu_img_binary):
vm._start_ubridge = AsyncioMagicMock()
vm._ubridge_hypervisor = MagicMock()
vm._ubridge_hypervisor.is_running.return_value = True
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="6.2.0")
vm.manager.config.set("Qemu", "enable_hardware_acceleration", False)
return vm

Expand Down Expand Up @@ -141,7 +142,6 @@ async def test_is_running(vm, running_subprocess_mock):

async def test_start(vm, running_subprocess_mock):

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
with asyncio_patch("gns3server.compute.qemu.QemuVM.start_wrap_console"):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=running_subprocess_mock) as mock:
await vm.start()
Expand All @@ -156,7 +156,6 @@ async def test_stop(vm, running_subprocess_mock):
future = asyncio.Future()
future.set_result(True)
process.wait.return_value = future
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")

with asyncio_patch("gns3server.compute.qemu.QemuVM.start_wrap_console"):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
Expand Down Expand Up @@ -241,7 +240,6 @@ async def test_port_remove_nio_binding(vm):

async def test_close(vm, port_manager):

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
with asyncio_patch("gns3server.compute.qemu.QemuVM.start_wrap_console"):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
await vm.start()
Expand Down Expand Up @@ -369,7 +367,6 @@ async def test_disk_options(vm, tmpdir, fake_qemu_img_binary):

async def test_cdrom_option(vm, tmpdir, fake_qemu_img_binary):

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm._cdrom_image = str(tmpdir / "test.iso")
open(vm._cdrom_image, "w+").close()

Expand All @@ -380,7 +377,6 @@ async def test_cdrom_option(vm, tmpdir, fake_qemu_img_binary):

async def test_bios_option(vm, tmpdir, fake_qemu_img_binary):

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm._bios_image = str(tmpdir / "test.img")
open(vm._bios_image, "w+").close()
options = await vm._build_command()
Expand All @@ -390,7 +386,6 @@ async def test_bios_option(vm, tmpdir, fake_qemu_img_binary):
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Test not working on Windows")
async def test_uefi_boot_mode_option(vm, tmpdir, images_dir, fake_qemu_img_binary):

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm._uefi = True

# create fake OVMF files
Expand All @@ -408,7 +403,6 @@ async def test_uefi_boot_mode_option(vm, tmpdir, images_dir, fake_qemu_img_binar

async def test_uefi_with_bios_image_already_configured(vm, tmpdir, fake_qemu_img_binary):

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm._bios_image = str(tmpdir / "test.img")
vm._uefi = True
with pytest.raises(QemuError):
Expand All @@ -434,7 +428,6 @@ async def test_spice_option(vm, fake_qemu_img_binary):

async def test_tpm_option(vm, tmpdir, fake_qemu_img_binary):

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm._tpm = True
tpm_sock = os.path.join(vm.temporary_directory, "swtpm.sock")
with patch("os.path.exists", return_value=True) as os_path:
Expand Down Expand Up @@ -528,7 +521,6 @@ async def test_control_vm_expect_text(vm, running_subprocess_mock):

async def test_build_command(vm, fake_qemu_binary):

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
os.environ["DISPLAY"] = "0:0"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
cmd = await vm._build_command()
Expand Down Expand Up @@ -563,7 +555,6 @@ async def test_build_command_manual_uuid(vm):
If user has set a uuid we keep it
"""

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm.options = "-uuid e1c307a4-896f-11e6-81a5-3c07547807cc"
os.environ["DISPLAY"] = "0:0"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
Expand Down Expand Up @@ -698,7 +689,6 @@ async def test_build_command_two_adapters_mac_address(vm):
Should support multiple base vmac address
"""

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.5.0")
vm.adapters = 2
vm.mac_address = "00:00:ab:0e:0f:09"
mac_0 = vm._mac_address
Expand All @@ -723,12 +713,9 @@ async def test_build_command_two_adapters_mac_address(vm):
async def test_build_command_large_number_of_adapters(vm):
"""
When we have more than 28 interface we need to add a pci bridge for
additional interfaces
additional interfaces (supported only with Qemu 2.4 and later)
"""

# It's supported only with Qemu 2.4 and later
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.4.0")

vm.adapters = 100
vm.mac_address = "00:00:ab:0e:0f:09"
mac_0 = vm._mac_address
Expand Down Expand Up @@ -770,7 +757,6 @@ async def test_build_command_with_virtio_net_pci_adapter(vm):
Test virtio-net-pci adapter which has parameters speed=1000 & duplex=full hard-coded
"""

vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.4.0")
vm.adapters = 1
vm.mac_address = "00:00:ab:0e:0f:09"
vm._adapter_type = "virtio-net-pci"
Expand Down

0 comments on commit c5c4e1a

Please sign in to comment.