From 08956e438cb9308029f8cf76e6efdfef69c5ebe4 Mon Sep 17 00:00:00 2001 From: grossmj Date: Wed, 6 Jul 2016 22:00:39 -0600 Subject: [PATCH 1/4] Add NIO TAP support for Docker and VMware. Fixes #603. --- gns3server/handlers/api/docker_handler.py | 14 ++----- gns3server/handlers/api/vmware_handler.py | 2 +- gns3server/modules/docker/docker_vm.py | 47 +++++++++++------------ gns3server/modules/vmware/vmware_vm.py | 3 ++ 4 files changed, 30 insertions(+), 36 deletions(-) diff --git a/gns3server/handlers/api/docker_handler.py b/gns3server/handlers/api/docker_handler.py index 4888763f..64ea94ee 100644 --- a/gns3server/handlers/api/docker_handler.py +++ b/gns3server/handlers/api/docker_handler.py @@ -221,16 +221,10 @@ class DockerHandler: request.match_info["vm_id"], project_id=request.match_info["project_id"]) nio_type = request.json["type"] - if nio_type not in ("nio_udp"): - raise HTTPConflict( - text="NIO of type {} is not supported".format(nio_type)) - nio = docker_manager.create_nio( - int(request.match_info["adapter_number"]), request.json) - adapter = container._ethernet_adapters[ - int(request.match_info["adapter_number"]) - ] - yield from container.adapter_add_nio_binding( - int(request.match_info["adapter_number"]), nio) + if nio_type not in ("nio_udp", "nio_tap"): + raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type)) + nio = docker_manager.create_nio(int(request.match_info["adapter_number"]), request.json) + yield from container.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio) response.set_status(201) response.json(nio) diff --git a/gns3server/handlers/api/vmware_handler.py b/gns3server/handlers/api/vmware_handler.py index d2b3d1ce..515a234e 100644 --- a/gns3server/handlers/api/vmware_handler.py +++ b/gns3server/handlers/api/vmware_handler.py @@ -271,7 +271,7 @@ class VMwareHandler: vmware_manager = VMware.instance() vm = vmware_manager.get_vm(request.match_info["vm_id"], project_id=request.match_info["project_id"]) nio_type = request.json["type"] - if nio_type not in ("nio_udp", "nio_vmnet", "nio_nat"): + if nio_type not in ("nio_udp", "nio_vmnet", "nio_nat", "nio_tap"): raise HTTPConflict(text="NIO of type {} is not supported".format(nio_type)) nio = vmware_manager.create_nio(None, request.json) yield from vm.adapter_add_nio_binding(int(request.match_info["adapter_number"]), nio) diff --git a/gns3server/modules/docker/docker_vm.py b/gns3server/modules/docker/docker_vm.py index 2c602e04..386d73e9 100644 --- a/gns3server/modules/docker/docker_vm.py +++ b/gns3server/modules/docker/docker_vm.py @@ -31,6 +31,7 @@ from .docker_error import * from ..base_vm import BaseVM from ..adapters.ethernet_adapter import EthernetAdapter from ..nios.nio_udp import NIOUDP +from ..nios.nio_tap import NIOTAP from ...utils.asyncio.telnet_server import AsyncioTelnetServer from ...utils.asyncio.raw_command_server import AsyncioRawCommandServer from ...utils.asyncio import wait_for_file_creation @@ -616,6 +617,7 @@ class DockerVM(BaseVM): :param adapter_number: adapter number :param namespace: Container namespace (pid) """ + try: adapter = self._ethernet_adapters[adapter_number] except IndexError: @@ -629,41 +631,36 @@ class DockerVM(BaseVM): adapter.guest_ifc = "veth-gns3-i{}".format(str(index)) break if not hasattr(adapter, "ifc"): - raise DockerError( - "Adapter {adapter_number} couldn't allocate interface on Docker container '{name}'. Too many Docker interfaces already exists".format( - name=self.name, adapter_number=adapter_number)) + raise DockerError("Adapter {adapter_number} couldn't allocate interface on Docker container '{name}'. Too many Docker interfaces already exists".format(name=self.name, + adapter_number=adapter_number)) - yield from self._ubridge_hypervisor.send( - 'docker create_veth {hostif} {guestif}'.format( - guestif=adapter.guest_ifc, hostif=adapter.host_ifc)) + yield from self._ubridge_hypervisor.send('docker create_veth {hostif} {guestif}'.format(guestif=adapter.guest_ifc, + hostif=adapter.host_ifc)) log.debug("Move container %s adapter %s to namespace %s", self.name, adapter.guest_ifc, namespace) try: - yield from self._ubridge_hypervisor.send( - 'docker move_to_ns {ifc} {ns} eth{adapter}'.format( - ifc=adapter.guest_ifc, ns=namespace, adapter=adapter_number)) + yield from self._ubridge_hypervisor.send('docker move_to_ns {ifc} {ns} eth{adapter}'.format(ifc=adapter.guest_ifc, + ns=namespace, + adapter=adapter_number)) except UbridgeError as e: raise UbridgeNamespaceError(e) - if isinstance(nio, NIOUDP): - yield from self._ubridge_hypervisor.send( - 'bridge create bridge{}'.format(adapter_number)) - yield from self._ubridge_hypervisor.send( - 'bridge add_nio_linux_raw bridge{adapter} {ifc}'.format( - ifc=adapter.host_ifc, adapter=adapter_number)) - - yield from self._ubridge_hypervisor.send( - 'bridge add_nio_udp bridge{adapter} {lport} {rhost} {rport}'.format( - adapter=adapter_number, lport=nio.lport, rhost=nio.rhost, - rport=nio.rport)) + if nio: + yield from self._ubridge_hypervisor.send('bridge create bridge{}'.format(adapter_number)) + yield from self._ubridge_hypervisor.send('bridge add_nio_linux_raw bridge{adapter} {ifc}'.format(ifc=adapter.host_ifc, adapter=adapter_number)) + if isinstance(nio, NIOUDP): + yield from self._ubridge_hypervisor.send('bridge add_nio_udp bridge{adapter} {lport} {rhost} {rport}'.format(adapter=adapter_number, + lport=nio.lport, + rhost=nio.rhost, + rport=nio.rport)) + elif isinstance(nio, NIOTAP): + yield from self._ubridge_hypervisor.send('bridge add_nio_tap bridge{adapter} {tap}'.format(adapter=adapter_number, tap=nio.tap_device)) if nio.capturing: - yield from self._ubridge_hypervisor.send( - 'bridge start_capture bridge{adapter} "{pcap_file}"'.format( - adapter=adapter_number, pcap_file=nio.pcap_output_file)) + yield from self._ubridge_hypervisor.send('bridge start_capture bridge{adapter} "{pcap_file}"'.format(adapter=adapter_number, + pcap_file=nio.pcap_output_file)) - yield from self._ubridge_hypervisor.send( - 'bridge start bridge{adapter}'.format(adapter=adapter_number)) + yield from self._ubridge_hypervisor.send('bridge start bridge{adapter}'.format(adapter=adapter_number)) def _delete_ubridge_connection(self, adapter_number): """Deletes a connection in uBridge. diff --git a/gns3server/modules/vmware/vmware_vm.py b/gns3server/modules/vmware/vmware_vm.py index fe75b5fa..503c59f5 100644 --- a/gns3server/modules/vmware/vmware_vm.py +++ b/gns3server/modules/vmware/vmware_vm.py @@ -32,6 +32,7 @@ from collections import OrderedDict from .vmware_error import VMwareError from ..nios.nio_udp import NIOUDP from ..nios.nio_nat import NIONAT +from ..nios.nio_tap import NIOTAP from .nio_vmnet import NIOVMNET from ..adapters.ethernet_adapter import EthernetAdapter from ..base_vm import BaseVM @@ -345,6 +346,8 @@ class VMwareVM(BaseVM): lport=nio.lport, rhost=nio.rhost, rport=nio.rport)) + elif isinstance(nio, NIOTAP): + yield from self._ubridge_hypervisor.send('bridge add_nio_tap {name} {tap}'.format(name=vnet, tap=nio.tap_device)) if nio.capturing: yield from self._ubridge_hypervisor.send('bridge start_capture {name} "{pcap_file}"'.format(name=vnet, From e1a7efad603292d6af55b57ef09d8068d751d43c Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Thu, 7 Jul 2016 18:57:18 +0200 Subject: [PATCH 2/4] 1.5.1 --- CHANGELOG | 9 +++++++++ gns3server/version.py | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e7e59199..c8ccf5ea 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,14 @@ # Change Log +## 1.5.1 07/07/2016 + +* Increase the number of interface for docker +* Add the method in the bad request answer +* Fix a rare crash in IOU +* Fix a crash when docker is used but not installed +* Backport Docker node hot linking +* Allows hot-linking for Docker containers. Ref #267. + ## 1.5.0 27/06/2016 * Fix import of project with no disk diff --git a/gns3server/version.py b/gns3server/version.py index 3a76b51c..6f26e27d 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,5 +23,5 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "1.5.1dev1" -__version_info__ = (1, 5, 1, -99) +__version__ = "1.5.1" +__version_info__ = (1, 5, 1, 0) From 26d49f19c17c11af05e589c05b954f744e92e475 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Thu, 7 Jul 2016 18:57:48 +0200 Subject: [PATCH 3/4] 1.5.2dev1 --- gns3server/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gns3server/version.py b/gns3server/version.py index 6f26e27d..3b1585c1 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -23,5 +23,5 @@ # or negative for a release candidate or beta (after the base version # number has been incremented) -__version__ = "1.5.1" -__version_info__ = (1, 5, 1, 0) +__version__ = "1.5.2dev1" +__version_info__ = (1, 5, 2, -99) From febf0f783965a07fac698fc048fc9afad6cec3cb Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Tue, 12 Jul 2016 13:09:08 +0200 Subject: [PATCH 4/4] Fix crash when winpcap is not installed Ref https://github.com/GNS3/gns3-gui/issues/1380 --- gns3server/utils/interfaces.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gns3server/utils/interfaces.py b/gns3server/utils/interfaces.py index bb12151d..e58030b7 100644 --- a/gns3server/utils/interfaces.py +++ b/gns3server/utils/interfaces.py @@ -138,6 +138,7 @@ def is_interface_up(interface): # TODO: Windows & OSX support return True + def _check_windows_service(service_name): import pywintypes @@ -154,6 +155,7 @@ def _check_windows_service(service_name): raise aiohttp.web.HTTPInternalServerError(text="Could not check if the {} service is running: {}".format(service_name, e.strerror)) return True + def interfaces(): """ Gets the network interfaces on this server. @@ -178,13 +180,19 @@ def interfaces(): "mac_address": mac_address}) else: try: + service_installed = True if not _check_windows_service("npf") and not _check_windows_service("npcap"): - raise aiohttp.web.HTTPInternalServerError("The NPF or Npcap is not installed or running") - results = get_windows_interfaces() + service_installed = False + else: + results = get_windows_interfaces() except ImportError: message = "pywin32 module is not installed, please install it on the server to get the available interface names" raise aiohttp.web.HTTPInternalServerError(text=message) except Exception as e: log.error("uncaught exception {type}".format(type=type(e)), exc_info=1) raise aiohttp.web.HTTPInternalServerError(text="uncaught exception: {}".format(e)) + + if service_installed is False: + raise aiohttp.web.HTTPInternalServerError(text="The Winpcap or Npcap is not installed or running") + return results