diff --git a/gns3server/modules/qemu/__init__.py b/gns3server/modules/qemu/__init__.py index 960a0beb..0e9fe9b7 100644 --- a/gns3server/modules/qemu/__init__.py +++ b/gns3server/modules/qemu/__init__.py @@ -86,7 +86,7 @@ class Qemu(BaseManager): os.access(os.path.join(path, f), os.X_OK) and \ os.path.isfile(os.path.join(path, f)): qemu_path = os.path.join(path, f) - version = yield from Qemu._get_qemu_version(qemu_path) + version = yield from Qemu.get_qemu_version(qemu_path) qemus.append({"path": qemu_path, "version": version}) except OSError: continue @@ -95,7 +95,7 @@ class Qemu(BaseManager): @staticmethod @asyncio.coroutine - def _get_qemu_version(qemu_path): + def get_qemu_version(qemu_path): """ Gets the Qemu version. @@ -103,17 +103,30 @@ class Qemu(BaseManager): """ if sys.platform.startswith("win"): + # Qemu on Windows doesn't return anything with parameter -version + # look for a version number in version.txt file in the same directory instead + version_file = os.path.join(os.path.dirname(qemu_path), "version.txt") + if os.path.isfile(version_file): + try: + with open(version_file, "rb") as file: + version = file.read().decode("utf-8").strip() + match = re.search("[0-9\.]+", version) + if match: + return version + except (UnicodeDecodeError, OSError) as e: + log.warn("could not read {}: {}".format(version_file, e)) return "" - try: - output = yield from subprocess_check_output(qemu_path, "-version") - match = re.search("version\s+([0-9a-z\-\.]+)", output) - if match: - version = match.group(1) - return version - else: - raise QemuError("Could not determine the Qemu version for {}".format(qemu_path)) - except subprocess.SubprocessError as e: - raise QemuError("Error while looking for the Qemu version: {}".format(e)) + else: + try: + output = yield from subprocess_check_output(qemu_path, "-version") + match = re.search("version\s+([0-9a-z\-\.]+)", output) + if match: + version = match.group(1) + return version + else: + raise QemuError("Could not determine the Qemu version for {}".format(qemu_path)) + except subprocess.SubprocessError as e: + raise QemuError("Error while looking for the Qemu version: {}".format(e)) @staticmethod def get_legacy_vm_workdir(legacy_vm_id, name): diff --git a/gns3server/modules/qemu/qemu_vm.py b/gns3server/modules/qemu/qemu_vm.py index 94d0d334..afe7bebc 100644 --- a/gns3server/modules/qemu/qemu_vm.py +++ b/gns3server/modules/qemu/qemu_vm.py @@ -28,6 +28,7 @@ import shlex import asyncio import socket +from pkg_resources import parse_version from .qemu_error import QemuError from ..adapters.ethernet_adapter import EthernetAdapter from ..nios.nio_udp import NIOUDP @@ -990,6 +991,14 @@ class QemuVM(BaseVM): network_options = [] network_options.extend(["-net", "none"]) # we do not want any user networking back-end if no adapter is connected. + + patched_qemu = False + if self._legacy_networking: + version = yield from self.manager.get_qemu_version(self.qemu_path) + if version and parse_version(version) < parse_version("1.1.0"): + # this is a patched Qemu if version is below 1.1.0 + patched_qemu = True + for adapter_number, adapter in enumerate(self._ethernet_adapters): # TODO: let users specify a base mac address mac = "00:00:ab:%s:%s:%02x" % (self.id[-4:-2], self.id[-2:], adapter_number) @@ -999,11 +1008,21 @@ class QemuVM(BaseVM): if nio: network_options.extend(["-net", "nic,vlan={},macaddr={},model={}".format(adapter_number, mac, self._adapter_type)]) if isinstance(nio, NIOUDP): - network_options.extend(["-net", "udp,vlan={},name=gns3-{},sport={},dport={},daddr={}".format(adapter_number, - adapter_number, - nio.lport, - nio.rport, - nio.rhost)]) + if patched_qemu: + # use patched Qemu syntax + network_options.extend(["-net", "udp,vlan={},name=gns3-{},sport={},dport={},daddr={}".format(adapter_number, + adapter_number, + nio.lport, + nio.rport, + nio.rhost)]) + else: + # use UDP tunnel support added in Qemu 1.1.0 + network_options.extend(["-net", "socket,vlan={},name=gns3-{},udp={}:{},localaddr={}:{}".format(adapter_number, + adapter_number, + nio.rhost, + nio.rport, + self._host, + nio.lport)]) elif isinstance(nio, NIOTAP): network_options.extend(["-net", "tap,name=gns3-{},ifname={}".format(adapter_number, nio.tap_device)]) elif isinstance(nio, NIONAT):