diff --git a/gns3server/handlers/api/qemu_handler.py b/gns3server/handlers/api/qemu_handler.py
index 3be59314..9a8cff10 100644
--- a/gns3server/handlers/api/qemu_handler.py
+++ b/gns3server/handlers/api/qemu_handler.py
@@ -15,8 +15,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+import sys
from aiohttp.web import HTTPConflict
from ...web.route import Route
+from ...modules.project_manager import ProjectManager
from ...schemas.nio import NIO_SCHEMA
from ...schemas.qemu import QEMU_CREATE_SCHEMA
from ...schemas.qemu import QEMU_UPDATE_SCHEMA
@@ -146,6 +148,11 @@ class QEMUHandler:
qemu_manager = Qemu.instance()
vm = qemu_manager.get_vm(request.match_info["vm_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:
+ pm = ProjectManager.instance()
+ if pm.check_hardware_virtualization(vm) is False:
+ raise HTTPConflict(text="Cannot start VM with KVM enabled because hardware virtualization is already used by another software like VMware or VirtualBox")
yield from vm.start()
response.set_status(204)
diff --git a/gns3server/handlers/api/virtualbox_handler.py b/gns3server/handlers/api/virtualbox_handler.py
index 5036bef7..a66e472d 100644
--- a/gns3server/handlers/api/virtualbox_handler.py
+++ b/gns3server/handlers/api/virtualbox_handler.py
@@ -16,6 +16,8 @@
# along with this program. If not, see .
import os
+import sys
+
from aiohttp.web import HTTPConflict
from ...web.route import Route
from ...schemas.nio import NIO_SCHEMA
@@ -190,6 +192,10 @@ class VirtualBoxHandler:
vbox_manager = VirtualBox.instance()
vm = vbox_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"])
+ if sys.platform.startswith("linux") and (yield from vm.check_hw_virtualization()):
+ pm = ProjectManager.instance()
+ if pm.check_hardware_virtualization(vm) is False:
+ raise HTTPConflict(text="Cannot start VM because KVM is being used by a Qemu VM")
yield from vm.start()
response.set_status(204)
diff --git a/gns3server/modules/base_manager.py b/gns3server/modules/base_manager.py
index ebf6d0d3..37478b43 100644
--- a/gns3server/modules/base_manager.py
+++ b/gns3server/modules/base_manager.py
@@ -372,7 +372,7 @@ class BaseManager:
elif nio_settings["type"] == "nio_tap":
tap_device = nio_settings["tap_device"]
if not is_interface_up(tap_device):
- raise aiohttp.web.HTTPConflict(text="TAP interface {} is down".format(tap_device))
+ raise aiohttp.web.HTTPConflict(text="TAP interface {} does not exist or is down".format(tap_device))
# FIXME: check for permissions on tap device
# if not self._has_privileged_access(executable):
# raise aiohttp.web.HTTPForbidden(text="{} has no privileged access to {}.".format(executable, tap_device))
@@ -380,7 +380,7 @@ class BaseManager:
elif nio_settings["type"] == "nio_generic_ethernet":
ethernet_device = nio_settings["ethernet_device"]
if not is_interface_up(ethernet_device):
- raise aiohttp.web.HTTPConflict(text="Ethernet interface {} is down".format(ethernet_device))
+ raise aiohttp.web.HTTPConflict(text="Ethernet interface {} does not exist or is down".format(ethernet_device))
nio = NIOGenericEthernet(ethernet_device)
elif nio_settings["type"] == "nio_nat":
nio = NIONAT()
diff --git a/gns3server/modules/base_vm.py b/gns3server/modules/base_vm.py
index 19c78d5e..197bb84b 100644
--- a/gns3server/modules/base_vm.py
+++ b/gns3server/modules/base_vm.py
@@ -49,6 +49,7 @@ class BaseVM:
self._console = console
self._console_type = console_type
self._temporary_directory = None
+ self._hw_virtualization = False
self._vm_status = "stopped"
if self._console is not None:
@@ -262,3 +263,13 @@ class BaseVM:
name=self.name,
id=self.id,
console_type=console_type))
+
+ @property
+ def hw_virtualization(self):
+ """
+ Returns either the VM is using hardware virtualization or not.
+
+ :return: boolean
+ """
+
+ return self._hw_virtualization
diff --git a/gns3server/modules/project_manager.py b/gns3server/modules/project_manager.py
index 4ea21612..6d30bc99 100644
--- a/gns3server/modules/project_manager.py
+++ b/gns3server/modules/project_manager.py
@@ -95,3 +95,27 @@ class ProjectManager:
if project_id not in self._projects:
raise aiohttp.web.HTTPNotFound(text="Project ID {} doesn't exist".format(project_id))
del self._projects[project_id]
+
+ def check_hardware_virtualization(self, source_vm):
+ """
+ Checks if hardware virtualization can be used.
+
+ :returns: boolean
+ """
+
+ from .qemu import QemuVM
+ from .virtualbox import VirtualBoxVM
+ from .vmware import VMwareVM
+ for project in self._projects.values():
+ for vm in project.vms:
+ if vm == source_vm:
+ continue
+ if vm.hw_virtualization:
+ if isinstance(source_vm, QemuVM) and not isinstance(vm, QemuVM):
+ # A Qemu VM won't start if any other virtualization software uses hardware virtualization
+ return False
+ elif isinstance(source_vm, VirtualBoxVM) and not isinstance(vm, VirtualBoxVM) and not isinstance(vm, VMwareVM):
+ # A VirtualBox VM won't start if KVM is being used
+ return False
+ # VMware doesn't seem to be bothered by any other virtualization software.
+ return True
diff --git a/gns3server/modules/qemu/qemu_vm.py b/gns3server/modules/qemu/qemu_vm.py
index 979a28ce..54e54297 100644
--- a/gns3server/modules/qemu/qemu_vm.py
+++ b/gns3server/modules/qemu/qemu_vm.py
@@ -73,7 +73,6 @@ class QemuVM(BaseVM):
self._stdout_file = ""
# QEMU VM settings
-
if qemu_path:
try:
self.qemu_path = qemu_path
@@ -483,8 +482,11 @@ class QemuVM(BaseVM):
id=self._id,
options=options))
- if not sys.platform.startswith("linux") and "-no-kvm" in options:
- options = options.replace("-no-kvm")
+ if not sys.platform.startswith("linux"):
+ if "-no-kvm" in options:
+ options = options.replace("-no-kvm")
+ if "-enable-kvm" in options:
+ options = options.replace("-enable-kvm")
self._options = options.strip()
@property
@@ -696,6 +698,9 @@ class QemuVM(BaseVM):
if self._cpu_throttling:
self._set_cpu_throttling()
+ if "-enable-kvm" in command_string:
+ self._hw_virtualization = True
+
def _termination_callback(self, returncode):
"""
Called when the process has stopped.
@@ -706,6 +711,7 @@ class QemuVM(BaseVM):
if self.started:
log.info("QEMU process has stopped, return code: %d", returncode)
self.status = "stopped"
+ self._hw_virtualization = False
self._process = None
if returncode != 0:
self.project.emit("log.error", {"message": "QEMU process has stopped, return code: {}\n{}".format(returncode, self.read_stdout())})
@@ -717,6 +723,7 @@ class QemuVM(BaseVM):
"""
# stop the QEMU process
+ self._hw_virtualization = False
if self.is_running():
log.info('Stopping QEMU VM "{}" PID={}'.format(self._name, self._process.pid))
try:
diff --git a/gns3server/modules/virtualbox/virtualbox_vm.py b/gns3server/modules/virtualbox/virtualbox_vm.py
index 7c48ccdf..8fd750d7 100644
--- a/gns3server/modules/virtualbox/virtualbox_vm.py
+++ b/gns3server/modules/virtualbox/virtualbox_vm.py
@@ -169,6 +169,19 @@ class VirtualBoxVM(BaseVM):
if "memory" in vm_info:
self._ram = int(vm_info["memory"])
+ @asyncio.coroutine
+ def check_hw_virtualization(self):
+ """
+ Returns either hardware virtualization is activated or not.
+
+ :returns: boolean
+ """
+
+ vm_info = yield from self._get_vm_info()
+ if "hwvirtex" in vm_info and vm_info["hwvirtex"] == "on":
+ return True
+ return False
+
@asyncio.coroutine
def start(self):
"""
@@ -203,12 +216,16 @@ class VirtualBoxVM(BaseVM):
if self._enable_remote_console and self._console is not None:
self._start_remote_console()
+ if (yield from self.check_hw_virtualization()):
+ self._hw_virtualization = True
+
@asyncio.coroutine
def stop(self):
"""
Stops this VirtualBox VM.
"""
+ self._hw_virtualization = False
self._stop_remote_console()
vm_state = yield from self._get_vm_state()
if vm_state == "running" or vm_state == "paused" or vm_state == "stuck":
diff --git a/gns3server/modules/vmware/vmware_vm.py b/gns3server/modules/vmware/vmware_vm.py
index be1f352f..99705ac1 100644
--- a/gns3server/modules/vmware/vmware_vm.py
+++ b/gns3server/modules/vmware/vmware_vm.py
@@ -28,7 +28,6 @@ import tempfile
from pkg_resources import parse_version
from gns3server.ubridge.hypervisor import Hypervisor
-from gns3server.ubridge.ubridge_error import UbridgeError
from gns3server.utils.telnet_server import TelnetServer
from gns3server.utils.interfaces import get_windows_interfaces
from collections import OrderedDict
@@ -387,6 +386,9 @@ class VMwareVM(BaseVM):
yield from asyncio.sleep(1) # give some time to VMware to create the pipe file.
self._start_remote_console()
+ if self._get_vmx_setting("vhv.enable", "TRUE"):
+ self._hw_virtualization = True
+
self._started = True
log.info("VMware VM '{name}' [{id}] started".format(name=self.name, id=self.id))
@@ -396,6 +398,7 @@ class VMwareVM(BaseVM):
Stops this VMware VM.
"""
+ self._hw_virtualization = False
self._stop_remote_console()
if self._ubridge_hypervisor and self._ubridge_hypervisor.is_running():
yield from self._ubridge_hypervisor.stop()