mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-30 20:28:08 +00:00
Support Qemu with HAXM acceleration. Ref #1242.
This commit is contained in:
parent
85dcb985eb
commit
44f2acffa5
@ -69,7 +69,11 @@ iourc_path = /home/gns3/.iourc
|
|||||||
license_check = True
|
license_check = True
|
||||||
|
|
||||||
[Qemu]
|
[Qemu]
|
||||||
; !! Remember to add the gns3 user to the KVM group, otherwise you will not have read / write permssions to /dev/kvm !!
|
; !! Remember to add the gns3 user to the KVM group, otherwise you will not have read / write permissions to /dev/kvm !! (Linux only, has priority over enable_hardware_acceleration)
|
||||||
enable_kvm = True
|
enable_kvm = True
|
||||||
; Require KVM to be installed in order to start VMs
|
; Require KVM to be installed in order to start VMs (Linux only, has priority over require_hardware_acceleration)
|
||||||
require_kvm = True
|
require_kvm = True
|
||||||
|
; Enable hardware acceleration (all platforms)
|
||||||
|
enable_hardware_acceleration = True
|
||||||
|
; Require hardware acceleration in order to start VMs (all platforms)
|
||||||
|
require_hardware_acceleration = True
|
||||||
|
@ -217,6 +217,34 @@ class Qemu(BaseManager):
|
|||||||
except subprocess.SubprocessError as e:
|
except subprocess.SubprocessError as e:
|
||||||
raise QemuError("Error while looking for the Qemu-img version: {}".format(e))
|
raise QemuError("Error while looking for the Qemu-img version: {}".format(e))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_haxm_windows_version():
|
||||||
|
"""
|
||||||
|
Gets the HAXM version number (Windows).
|
||||||
|
|
||||||
|
:returns: HAXM version number. Returns None if HAXM is not installed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert(sys.platform.startswith("win"))
|
||||||
|
import winreg
|
||||||
|
|
||||||
|
hkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products")
|
||||||
|
version = None
|
||||||
|
for index in range(winreg.QueryInfoKey(hkey)[0]):
|
||||||
|
product_id = winreg.EnumKey(hkey, index)
|
||||||
|
try:
|
||||||
|
product_key = winreg.OpenKey(hkey, r"{}\InstallProperties".format(product_id))
|
||||||
|
try:
|
||||||
|
if winreg.QueryValueEx(product_key, "DisplayName")[0].endswith("Hardware Accelerated Execution Manager"):
|
||||||
|
version = winreg.QueryValueEx(product_key, "DisplayVersion")[0]
|
||||||
|
break
|
||||||
|
finally:
|
||||||
|
winreg.CloseKey(product_key)
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
winreg.CloseKey(hkey)
|
||||||
|
return version
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_legacy_vm_workdir(legacy_vm_id, name):
|
def get_legacy_vm_workdir(legacy_vm_id, name):
|
||||||
"""
|
"""
|
||||||
|
@ -711,7 +711,12 @@ class QemuVM(BaseNode):
|
|||||||
options = options.replace("-no-kvm", "")
|
options = options.replace("-no-kvm", "")
|
||||||
if "-enable-kvm" in options:
|
if "-enable-kvm" in options:
|
||||||
options = options.replace("-enable-kvm", "")
|
options = options.replace("-enable-kvm", "")
|
||||||
elif "-icount" in options and ("-no-kvm" not in options):
|
else:
|
||||||
|
if "-no-hax" in options:
|
||||||
|
options = options.replace("-no-hax", "")
|
||||||
|
if "-enable-hax" in options:
|
||||||
|
options = options.replace("-enable-hax", "")
|
||||||
|
if "-icount" in options and ("-no-kvm" not in options):
|
||||||
# automatically add the -no-kvm option if -icount is detected
|
# automatically add the -no-kvm option if -icount is detected
|
||||||
# to help with the migration of ASA VMs created before version 1.4
|
# to help with the migration of ASA VMs created before version 1.4
|
||||||
options = "-no-kvm " + options
|
options = "-no-kvm " + options
|
||||||
@ -947,7 +952,7 @@ class QemuVM(BaseNode):
|
|||||||
if self._cpu_throttling:
|
if self._cpu_throttling:
|
||||||
self._set_cpu_throttling()
|
self._set_cpu_throttling()
|
||||||
|
|
||||||
if "-enable-kvm" in command_string:
|
if "-enable-kvm" in command_string or "-enable-hax" in command_string:
|
||||||
self._hw_virtualization = True
|
self._hw_virtualization = True
|
||||||
|
|
||||||
yield from self._start_ubridge()
|
yield from self._start_ubridge()
|
||||||
@ -1642,27 +1647,57 @@ class QemuVM(BaseNode):
|
|||||||
return ["-nographic"]
|
return ["-nographic"]
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def _run_with_kvm(self, qemu_path, options):
|
def _run_with_hardware_acceleration(self, qemu_path, options):
|
||||||
"""
|
"""
|
||||||
Check if we could run qemu with KVM
|
Check if we can run Qemu with hardware acceleration
|
||||||
|
|
||||||
:param qemu_path: Path to qemu
|
:param qemu_path: Path to qemu
|
||||||
:param options: String of qemu user options
|
:param options: String of qemu user options
|
||||||
:returns: Boolean True if we need to enable KVM
|
:returns: Boolean True if we need to enable hardware acceleration
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if sys.platform.startswith("linux") and self.manager.config.get_section_config("Qemu").getboolean("enable_kvm", True) \
|
enable_hardware_accel = self.manager.config.get_section_config("Qemu").getboolean("enable_hardware_acceleration", True)
|
||||||
and "-no-kvm" not in options:
|
require_hardware_accel = self.manager.config.get_section_config("Qemu").getboolean("require_hardware_acceleration", True)
|
||||||
|
if sys.platform.startswith("linux"):
|
||||||
|
# compatibility: these options were used before version 2.0 and have priority
|
||||||
|
enable_kvm = self.manager.config.get_section_config("Qemu").getboolean("enable_kvm")
|
||||||
|
if enable_kvm is not None:
|
||||||
|
enable_hardware_accel = enable_kvm
|
||||||
|
require_kvm = self.manager.config.get_section_config("Qemu").getboolean("require_kvm")
|
||||||
|
if require_kvm is not None:
|
||||||
|
require_hardware_accel = require_kvm
|
||||||
|
|
||||||
# Turn OFF kvm for non x86 architectures
|
if enable_hardware_accel and "-no-kvm" not in options and "-no-hax" not in options:
|
||||||
if os.path.basename(qemu_path) not in ["qemu-system-x86_64", "qemu-system-i386", "qemu-kvm"]:
|
# Turn OFF hardware acceleration for non x86 architectures
|
||||||
return False
|
supported_archs = ["qemu-system-x86_64", "qemu-system-i386", "qemu-kvm"]
|
||||||
|
if os.path.basename(qemu_path) not in supported_archs:
|
||||||
if not os.path.exists("/dev/kvm"):
|
if require_hardware_accel:
|
||||||
if self.manager.config.get_section_config("Qemu").getboolean("require_kvm", True):
|
raise QemuError("Hardware acceleration can only be used with the following Qemu executables: {}".format(", ".join(supported_archs)))
|
||||||
raise QemuError("KVM acceleration cannot be used (/dev/kvm doesn't exist). You can turn off KVM support in the gns3_server.conf by adding enable_kvm = false to the [Qemu] section.")
|
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if sys.platform.startswith("linux") and not os.path.exists("/dev/kvm"):
|
||||||
|
if require_hardware_accel:
|
||||||
|
raise QemuError("KVM acceleration cannot be used (/dev/kvm doesn't exist). It is possible to turn off KVM support in the gns3_server.conf by adding enable_kvm = false to the [Qemu] section.")
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
elif sys.platform.startswith("win"):
|
||||||
|
if require_hardware_accel:
|
||||||
|
# HAXM is only available starting with Qemu version 2.9.0
|
||||||
|
version = yield from 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))
|
||||||
|
|
||||||
|
# check if HAXM is installed
|
||||||
|
version = self.manager.get_haxm_windows_version()
|
||||||
|
if not version:
|
||||||
|
raise QemuError("HAXM acceleration support is not installed on this host")
|
||||||
|
log.info("HAXM support version {} detected".format(version))
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
elif sys.platform.startswith("darwin"):
|
||||||
|
# TODO: support for macOS
|
||||||
|
raise QemuError("HAXM acceleration is not yet supported on macOS")
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -1682,13 +1717,16 @@ class QemuVM(BaseNode):
|
|||||||
command.extend(["-name", self._name])
|
command.extend(["-name", self._name])
|
||||||
command.extend(["-m", "{}M".format(self._ram)])
|
command.extend(["-m", "{}M".format(self._ram)])
|
||||||
command.extend(["-smp", "cpus={}".format(self._cpus)])
|
command.extend(["-smp", "cpus={}".format(self._cpus)])
|
||||||
if self._run_with_kvm(self.qemu_path, self._options):
|
if self._run_with_hardware_acceleration(self.qemu_path, self._options):
|
||||||
|
if sys.platform.startswith("linux"):
|
||||||
command.extend(["-enable-kvm"])
|
command.extend(["-enable-kvm"])
|
||||||
version = yield from self.manager.get_qemu_version(self.qemu_path)
|
version = yield from self.manager.get_qemu_version(self.qemu_path)
|
||||||
# Issue on some combo Intel CPU + KVM + Qemu 2.4.0
|
# Issue on some combo Intel CPU + KVM + Qemu 2.4.0
|
||||||
# https://github.com/GNS3/gns3-server/issues/685
|
# 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 version and parse_version(version) >= parse_version("2.4.0") and self.platform == "x86_64":
|
||||||
command.extend(["-machine", "smm=off"])
|
command.extend(["-machine", "smm=off"])
|
||||||
|
elif sys.platform.startswith("win") or sys.platform.startswith("darwin"):
|
||||||
|
command.extend(["-enable-hax"])
|
||||||
command.extend(["-boot", "order={}".format(self._boot_priority)])
|
command.extend(["-boot", "order={}".format(self._boot_priority)])
|
||||||
command.extend(self._bios_option())
|
command.extend(self._bios_option())
|
||||||
command.extend(self._cdrom_option())
|
command.extend(self._cdrom_option())
|
||||||
|
@ -180,10 +180,16 @@ class QEMUHandler:
|
|||||||
|
|
||||||
qemu_manager = Qemu.instance()
|
qemu_manager = Qemu.instance()
|
||||||
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
vm = qemu_manager.get_node(request.match_info["node_id"], project_id=request.match_info["project_id"])
|
||||||
if sys.platform.startswith("linux") and qemu_manager.config.get_section_config("Qemu").getboolean("enable_kvm", True) and "-no-kvm" not in vm.options:
|
hardware_accel = qemu_manager.config.get_section_config("Qemu").getboolean("enable_hardware_acceleration", True)
|
||||||
|
if sys.platform.startswith("linux"):
|
||||||
|
# the enable_kvm option was used before version 2.0 and has priority
|
||||||
|
enable_kvm = qemu_manager.config.get_section_config("Qemu").getboolean("enable_kvm")
|
||||||
|
if enable_kvm is not None:
|
||||||
|
hardware_accel = enable_kvm
|
||||||
|
if hardware_accel and "-no-kvm" not in vm.options and "-no-hax" not in vm.options:
|
||||||
pm = ProjectManager.instance()
|
pm = ProjectManager.instance()
|
||||||
if pm.check_hardware_virtualization(vm) is False:
|
if pm.check_hardware_virtualization(vm) is False:
|
||||||
raise aiohttp.web.HTTPConflict(text="Cannot start VM with KVM enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
|
raise aiohttp.web.HTTPConflict(text="Cannot start VM with hardware acceleration (KVM/HAX) enabled because hardware virtualization (VT-x/AMD-V) is already used by another software like VMware or VirtualBox")
|
||||||
yield from vm.start()
|
yield from vm.start()
|
||||||
response.json(vm)
|
response.json(vm)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user