From 42c07cee1ab9617553ada73832990cad46b1a436 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Mon, 23 Feb 2015 19:00:34 -0700 Subject: [PATCH] Properly release UDP ports when closing a project or deleting a link. --- gns3server/modules/base_manager.py | 12 +- gns3server/modules/dynamips/__init__.py | 7 - .../modules/dynamips/dynamips_hypervisor.py | 29 ---- .../modules/dynamips/nios/nio_udp_auto.py | 140 ------------------ .../modules/dynamips/nodes/atm_switch.py | 7 + .../modules/dynamips/nodes/ethernet_hub.py | 7 + .../modules/dynamips/nodes/ethernet_switch.py | 7 + .../dynamips/nodes/frame_relay_switch.py | 8 + gns3server/modules/dynamips/nodes/router.py | 25 +++- gns3server/modules/iou/iou_vm.py | 24 ++- .../modules/nios/nio_generic_ethernet.py | 2 +- gns3server/modules/nios/nio_tap.py | 2 +- gns3server/modules/nios/nio_udp.py | 2 +- gns3server/modules/qemu/qemu_vm.py | 6 +- .../modules/virtualbox/virtualbox_vm.py | 13 +- gns3server/modules/vpcs/vpcs_vm.py | 15 +- 16 files changed, 96 insertions(+), 210 deletions(-) delete mode 100644 gns3server/modules/dynamips/nios/nio_udp_auto.py diff --git a/gns3server/modules/base_manager.py b/gns3server/modules/base_manager.py index d379a59b..acf9c1ab 100644 --- a/gns3server/modules/base_manager.py +++ b/gns3server/modules/base_manager.py @@ -32,9 +32,9 @@ from ..config import Config from ..utils.asyncio import wait_run_in_executor from .project_manager import ProjectManager -from .nios.nio_udp import NIO_UDP -from .nios.nio_tap import NIO_TAP -from .nios.nio_generic_ethernet import NIO_GenericEthernet +from .nios.nio_udp import NIOUDP +from .nios.nio_tap import NIOTAP +from .nios.nio_generic_ethernet import NIOGenericEthernet class BaseManager: @@ -283,13 +283,13 @@ class BaseManager: sock.connect((rhost, rport)) except OSError as e: raise aiohttp.web.HTTPInternalServerError(text="Could not create an UDP connection to {}:{}: {}".format(rhost, rport, e)) - nio = NIO_UDP(lport, rhost, rport) + nio = NIOUDP(lport, rhost, rport) elif nio_settings["type"] == "nio_tap": tap_device = nio_settings["tap_device"] if not self._has_privileged_access(executable): raise aiohttp.web.HTTPForbidden(text="{} has no privileged access to {}.".format(executable, tap_device)) - nio = NIO_TAP(tap_device) + nio = NIOTAP(tap_device) elif nio_settings["type"] == "nio_generic_ethernet": - nio = NIO_GenericEthernet(nio_settings["ethernet_device"]) + nio = NIOGenericEthernet(nio_settings["ethernet_device"]) assert nio is not None return nio diff --git a/gns3server/modules/dynamips/__init__.py b/gns3server/modules/dynamips/__init__.py index d8f70ab6..e01fc388 100644 --- a/gns3server/modules/dynamips/__init__.py +++ b/gns3server/modules/dynamips/__init__.py @@ -46,7 +46,6 @@ from .dynamips_device import DynamipsDevice # NIOs from .nios.nio_udp import NIOUDP -from .nios.nio_udp_auto import NIOUDPAuto from .nios.nio_unix import NIOUNIX from .nios.nio_vde import NIOVDE from .nios.nio_tap import NIOTAP @@ -355,13 +354,7 @@ class Dynamips(BaseManager): sock.connect((rhost, rport)) except OSError as e: raise DynamipsError("Could not create an UDP connection to {}:{}: {}".format(rhost, rport, e)) - # check if we have an allocated NIO UDP auto - #nio = node.hypervisor.get_nio_udp_auto(lport) - # if not nio: - # otherwise create an NIO UDP nio = NIOUDP(node.hypervisor, lport, rhost, rport) - # else: - # nio.connect(rhost, rport) elif nio_settings["type"] == "nio_generic_ethernet": ethernet_device = nio_settings["ethernet_device"] if sys.platform.startswith("win"): diff --git a/gns3server/modules/dynamips/dynamips_hypervisor.py b/gns3server/modules/dynamips/dynamips_hypervisor.py index b6c9304f..4895b9fe 100644 --- a/gns3server/modules/dynamips/dynamips_hypervisor.py +++ b/gns3server/modules/dynamips/dynamips_hypervisor.py @@ -25,7 +25,6 @@ import logging import asyncio from .dynamips_error import DynamipsError -from .nios.nio_udp_auto import NIOUDPAuto log = logging.getLogger(__name__) @@ -53,7 +52,6 @@ class DynamipsHypervisor: self._devices = [] self._working_dir = working_dir - self._nio_udp_auto_instances = {} self._version = "N/A" self._timeout = timeout self._uuid = None @@ -130,7 +128,6 @@ class DynamipsHypervisor: except OSError as e: log.debug("Stopping hypervisor {}:{} {}".format(self._host, self._port, e)) self._reader = self._writer = None - self._nio_udp_auto_instances.clear() @asyncio.coroutine def reset(self): @@ -139,7 +136,6 @@ class DynamipsHypervisor: """ yield from self.send("hypervisor reset") - self._nio_udp_auto_instances.clear() @asyncio.coroutine def set_working_dir(self, working_dir): @@ -224,31 +220,6 @@ class DynamipsHypervisor: self._host = host - def get_nio_udp_auto(self, port): - """ - Returns an allocated NIO UDP auto instance. - - :returns: NIO UDP auto instance - """ - - if port in self._nio_udp_auto_instances: - return self._nio_udp_auto_instances.pop(port) - else: - return None - - def allocate_udp_port(self): - """ - Allocates a new UDP port for creating an UDP NIO Auto. - - :returns: port number (integer) - """ - - # use Dynamips's NIO UDP auto back-end. - nio = NIOUDPAuto(self, self._host, self._udp_start_port_range, self._udp_end_port_range) - self._nio_udp_auto_instances[nio.lport] = nio - allocated_port = nio.lport - return allocated_port - @asyncio.coroutine def send(self, command): """ diff --git a/gns3server/modules/dynamips/nios/nio_udp_auto.py b/gns3server/modules/dynamips/nios/nio_udp_auto.py deleted file mode 100644 index a7757199..00000000 --- a/gns3server/modules/dynamips/nios/nio_udp_auto.py +++ /dev/null @@ -1,140 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013 GNS3 Technologies Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -Interface for automatic UDP NIOs. -""" - -import asyncio -from .nio import NIO - -import logging -log = logging.getLogger(__name__) - - -class NIOUDPAuto(NIO): - - """ - Dynamips auto UDP NIO. - - :param hypervisor: Dynamips hypervisor instance - :param laddr: local address - :param lport_start: start local port range - :param lport_end: end local port range - """ - - _instance_count = 0 - - def __init__(self, hypervisor, laddr, lport_start, lport_end): - - # create an unique ID and name - nio_id = NIOUDPAuto._instance_count - NIOUDPAuto._instance_count += 1 - name = 'nio_udp_auto' + str(nio_id) - self._laddr = laddr - self._lport = None - self._raddr = None - self._rport = None - NIO.__init__(self, name, hypervisor) - - @classmethod - def reset(cls): - """ - Reset the instance count. - """ - - cls._instance_count = 0 - - @asyncio.coroutine - def create(self): - - port = yield from self._hypervisor.send("nio create_udp_auto {name} {laddr} {lport_start} {lport_end}".format(name=self._name, - laddr=self._laddr, - lport_start=self._lport_start, - lport_end=self._lport_end)) - self._lport = int(port[0]) - - log.info("NIO UDP AUTO {name} created with laddr={laddr}, lport_start={start}, lport_end={end}".format(name=self._name, - laddr=self._laddr, - start=self._lport_start, - end=self._lport_end)) - - @property - def laddr(self): - """ - Returns the local address - - :returns: local address - """ - - return self._laddr - - @property - def lport(self): - """ - Returns the local port - - :returns: local port number - """ - - return self._lport - - @property - def raddr(self): - """ - Returns the remote address - - :returns: remote address - """ - - return self._raddr - - @property - def rport(self): - """ - Returns the remote port - - :returns: remote port number - """ - - return self._rport - - @asyncio.coroutine - def connect(self, raddr, rport): - """ - Connects this NIO to a remote socket - - :param raddr: remote address - :param rport: remote port number - """ - - yield from self._hypervisor.send("nio connect_udp_auto {name} {raddr} {rport}".format(name=self._name, - raddr=raddr, - rport=rport)) - self._raddr = raddr - self._rport = rport - - log.info("NIO UDP AUTO {name} connected to {raddr}:{rport}".format(name=self._name, - raddr=raddr, - rport=rport)) - - def __json__(self): - - return {"type": "nio_udp_auto", - "lport": self._lport, - "rport": self._rport, - "raddr": self._raddr} diff --git a/gns3server/modules/dynamips/nodes/atm_switch.py b/gns3server/modules/dynamips/nodes/atm_switch.py index 5c620221..36b8f343 100644 --- a/gns3server/modules/dynamips/nodes/atm_switch.py +++ b/gns3server/modules/dynamips/nodes/atm_switch.py @@ -24,6 +24,7 @@ import asyncio import re from .device import Device +from ..nios.nio_udp import NIOUDP from ..dynamips_error import DynamipsError import logging @@ -106,6 +107,10 @@ class ATMSwitch(Device): Deletes this ATM switch. """ + for nio in self._nios.values(): + if nio and isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) + try: yield from self._hypervisor.send('atmsw delete "{}"'.format(self._name)) log.info('ATM switch "{name}" [{id}] has been deleted'.format(name=self._name, id=self._id)) @@ -155,6 +160,8 @@ class ATMSwitch(Device): raise DynamipsError("Port {} is not allocated".format(port_number)) nio = self._nios[port_number] + if isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) log.info('ATM switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name, id=self._id, nio=nio, diff --git a/gns3server/modules/dynamips/nodes/ethernet_hub.py b/gns3server/modules/dynamips/nodes/ethernet_hub.py index 39a891ab..33807c97 100644 --- a/gns3server/modules/dynamips/nodes/ethernet_hub.py +++ b/gns3server/modules/dynamips/nodes/ethernet_hub.py @@ -22,6 +22,7 @@ Hub object that uses the Bridge interface to create a hub with ports. import asyncio from .bridge import Bridge +from ..nios.nio_udp import NIOUDP from ..dynamips_error import DynamipsError import logging @@ -73,6 +74,10 @@ class EthernetHub(Bridge): Deletes this hub. """ + for nio in self._nios.values(): + if nio and isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) + try: yield from Bridge.delete(self) log.info('Ethernet hub "{name}" [{id}] has been deleted'.format(name=self._name, id=self._id)) @@ -115,6 +120,8 @@ class EthernetHub(Bridge): raise DynamipsError("Port {} is not allocated".format(port_number)) nio = self._mappings[port_number] + if isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) yield from Bridge.remove_nio(self, nio) log.info('Ethernet switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name, diff --git a/gns3server/modules/dynamips/nodes/ethernet_switch.py b/gns3server/modules/dynamips/nodes/ethernet_switch.py index 7a8d8abe..1f3abdbe 100644 --- a/gns3server/modules/dynamips/nodes/ethernet_switch.py +++ b/gns3server/modules/dynamips/nodes/ethernet_switch.py @@ -23,6 +23,7 @@ http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L558 import asyncio from .device import Device +from ..nios.nio_udp import NIOUDP from ..dynamips_error import DynamipsError @@ -114,6 +115,10 @@ class EthernetSwitch(Device): Deletes this Ethernet switch. """ + for nio in self._nios.values(): + if nio and isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) + try: yield from self._hypervisor.send('ethsw delete "{}"'.format(self._name)) log.info('Ethernet switch "{name}" [{id}] has been deleted'.format(name=self._name, id=self._id)) @@ -157,6 +162,8 @@ class EthernetSwitch(Device): raise DynamipsError("Port {} is not allocated".format(port_number)) nio = self._nios[port_number] + if isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) yield from self._hypervisor.send('ethsw remove_nio "{name}" {nio}'.format(name=self._name, nio=nio)) log.info('Ethernet switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name, diff --git a/gns3server/modules/dynamips/nodes/frame_relay_switch.py b/gns3server/modules/dynamips/nodes/frame_relay_switch.py index 74fdda1c..d30578be 100644 --- a/gns3server/modules/dynamips/nodes/frame_relay_switch.py +++ b/gns3server/modules/dynamips/nodes/frame_relay_switch.py @@ -23,6 +23,7 @@ http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L642 import asyncio from .device import Device +from ..nios.nio_udp import NIOUDP from ..dynamips_error import DynamipsError import logging @@ -105,6 +106,10 @@ class FrameRelaySwitch(Device): Deletes this Frame Relay switch. """ + for nio in self._nios.values(): + if nio and isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) + try: yield from self._hypervisor.send('frsw delete "{}"'.format(self._name)) log.info('Frame Relay switch "{name}" [{id}] has been deleted'.format(name=self._name, id=self._id)) @@ -156,6 +161,9 @@ class FrameRelaySwitch(Device): raise DynamipsError("Port {} is not allocated".format(port_number)) nio = self._nios[port_number] + if isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) + log.info('Frame Relay switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name, id=self._id, nio=nio, diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py index eb16c275..7b456fed 100644 --- a/gns3server/modules/dynamips/nodes/router.py +++ b/gns3server/modules/dynamips/nodes/router.py @@ -32,6 +32,7 @@ log = logging.getLogger(__name__) from ...base_vm import BaseVM from ..dynamips_error import DynamipsError +from ..nios.nio_udp import NIOUDP from gns3server.utils.asyncio import wait_run_in_executor @@ -312,6 +313,20 @@ class Router(BaseVM): if self._dynamips_id in self._dynamips_ids[self._project.id]: self._dynamips_ids[self._project.id].remove(self._dynamips_id) + if self._console: + self._manager.port_manager.release_tcp_port(self._console) + self._console = None + + if self._aux: + self._manager.port_manager.release_tcp_port(self._aux) + self._aux = None + + for adapter in self._slots: + if adapter is not None: + for nio in adapter.ports.values(): + if nio and isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) + if self in self._hypervisor.devices: self._hypervisor.devices.remove(self) if self._hypervisor and not self._hypervisor.devices: @@ -323,14 +338,6 @@ class Router(BaseVM): pass yield from self.hypervisor.stop() - if self._console: - self._manager.port_manager.release_tcp_port(self._console) - self._console = None - - if self._aux: - self._manager.port_manager.release_tcp_port(self._aux) - self._aux = None - self._closed = True @property @@ -1226,6 +1233,8 @@ class Router(BaseVM): port_number=port_number)) nio = adapter.get_nio(port_number) + if isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) adapter.remove_nio(port_number) log.info('Router "{name}" [{id}]: NIO {nio_name} removed from port {slot_number}/{port_number}'.format(name=self._name, diff --git a/gns3server/modules/iou/iou_vm.py b/gns3server/modules/iou/iou_vm.py index 1ab6302d..79682479 100644 --- a/gns3server/modules/iou/iou_vm.py +++ b/gns3server/modules/iou/iou_vm.py @@ -34,9 +34,9 @@ import glob from .iou_error import IOUError from ..adapters.ethernet_adapter import EthernetAdapter from ..adapters.serial_adapter import SerialAdapter -from ..nios.nio_udp import NIO_UDP -from ..nios.nio_tap import NIO_TAP -from ..nios.nio_generic_ethernet import NIO_GenericEthernet +from ..nios.nio_udp import NIOUDP +from ..nios.nio_tap import NIOTAP +from ..nios.nio_generic_ethernet import NIOGenericEthernet from ..base_vm import BaseVM from .ioucon import start_ioucon import gns3server.utils.asyncio @@ -104,11 +104,19 @@ class IOUVM(BaseVM): @asyncio.coroutine def close(self): - yield from self.stop() if self._console: self._manager.port_manager.release_tcp_port(self._console) self._console = None + adapters = self._ethernet_adapters + self._serial_adapters + for adapter in adapters: + if adapter is not None: + for nio in adapter.ports.values(): + if nio and isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) + + yield from self.stop() + @property def path(self): """Path of the iou binary""" @@ -410,16 +418,16 @@ class IOUVM(BaseVM): nio = adapter.get_nio(unit) if nio: connection = None - if isinstance(nio, NIO_UDP): + if isinstance(nio, NIOUDP): # UDP tunnel connection = {"tunnel_udp": "{lport}:{rhost}:{rport}".format(lport=nio.lport, rhost=nio.rhost, rport=nio.rport)} - elif isinstance(nio, NIO_TAP): + elif isinstance(nio, NIOTAP): # TAP interface connection = {"tap_dev": "{tap_device}".format(tap_device=nio.tap_device)} - elif isinstance(nio, NIO_GenericEthernet): + elif isinstance(nio, NIOGenericEthernet): # Ethernet interface connection = {"eth_dev": "{ethernet_device}".format(ethernet_device=nio.ethernet_device)} @@ -750,6 +758,8 @@ class IOUVM(BaseVM): port_number=port_number)) nio = adapter.get_nio(port_number) + if isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) adapter.remove_nio(port_number) log.info("IOU {name} [id={id}]: {nio} removed from {adapter_number}/{port_number}".format(name=self._name, id=self._id, diff --git a/gns3server/modules/nios/nio_generic_ethernet.py b/gns3server/modules/nios/nio_generic_ethernet.py index 98dc91ca..da729565 100644 --- a/gns3server/modules/nios/nio_generic_ethernet.py +++ b/gns3server/modules/nios/nio_generic_ethernet.py @@ -22,7 +22,7 @@ Interface for generic Ethernet NIOs (PCAP library). from .nio import NIO -class NIO_GenericEthernet(NIO): +class NIOGenericEthernet(NIO): """ Generic Ethernet NIO. diff --git a/gns3server/modules/nios/nio_tap.py b/gns3server/modules/nios/nio_tap.py index a63a72c3..9f51ce13 100644 --- a/gns3server/modules/nios/nio_tap.py +++ b/gns3server/modules/nios/nio_tap.py @@ -22,7 +22,7 @@ Interface for TAP NIOs (UNIX based OSes only). from .nio import NIO -class NIO_TAP(NIO): +class NIOTAP(NIO): """ TAP NIO. diff --git a/gns3server/modules/nios/nio_udp.py b/gns3server/modules/nios/nio_udp.py index 4af43cd6..a87875fe 100644 --- a/gns3server/modules/nios/nio_udp.py +++ b/gns3server/modules/nios/nio_udp.py @@ -22,7 +22,7 @@ Interface for UDP NIOs. from .nio import NIO -class NIO_UDP(NIO): +class NIOUDP(NIO): """ UDP NIO. diff --git a/gns3server/modules/qemu/qemu_vm.py b/gns3server/modules/qemu/qemu_vm.py index 0e89a4ef..54ae3e4c 100644 --- a/gns3server/modules/qemu/qemu_vm.py +++ b/gns3server/modules/qemu/qemu_vm.py @@ -29,7 +29,7 @@ import asyncio from .qemu_error import QemuError from ..adapters.ethernet_adapter import EthernetAdapter -from ..nios.nio_udp import NIO_UDP +from ..nios.nio_udp import NIOUDP from ..base_vm import BaseVM from ...schemas.qemu import QEMU_OBJECT_SCHEMA @@ -719,7 +719,7 @@ class QemuVM(BaseVM): if self.is_running(): # dynamically configure an UDP tunnel on the QEMU VM adapter - if nio and isinstance(nio, NIO_UDP): + if nio and isinstance(nio, NIOUDP): if self._legacy_networking: yield from self._control_vm("host_net_remove {} gns3-{}".format(adapter_id, adapter_id)) yield from self._control_vm("host_net_add udp vlan={},name=gns3-{},sport={},dport={},daddr={}".format(adapter_id, @@ -928,7 +928,7 @@ class QemuVM(BaseVM): mac = self._get_random_mac(adapter_id) network_options.extend(["-net", "nic,vlan={},macaddr={},model={}".format(adapter_id, mac, self._adapter_type)]) nio = adapter.get_nio(0) - if nio and isinstance(nio, NIO_UDP): + if nio and isinstance(nio, NIOUDP): if self._legacy_networking: network_options.extend(["-net", "udp,vlan={},name=gns3-{},sport={},dport={},daddr={}".format(adapter_id, adapter_id, diff --git a/gns3server/modules/virtualbox/virtualbox_vm.py b/gns3server/modules/virtualbox/virtualbox_vm.py index 4b77b090..a7728f94 100644 --- a/gns3server/modules/virtualbox/virtualbox_vm.py +++ b/gns3server/modules/virtualbox/virtualbox_vm.py @@ -30,6 +30,7 @@ import asyncio from pkg_resources import parse_version from .virtualbox_error import VirtualBoxError +from ..nios.nio_udp import NIOUDP from ..adapters.ethernet_adapter import EthernetAdapter from .telnet_server import TelnetServer # TODO: port TelnetServer to asyncio from ..base_vm import BaseVM @@ -296,12 +297,18 @@ class VirtualBoxVM(BaseVM): # VM is already closed return - yield from self.stop() - if self._console: self._manager.port_manager.release_tcp_port(self._console) self._console = None + for adapter in self._ethernet_adapters: + if adapter is not None: + for nio in adapter.ports.values(): + if nio and isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) + + yield from self.stop() + if self._linked_clone: hdd_table = [] if os.path.exists(self.working_dir): @@ -781,7 +788,7 @@ class VirtualBoxVM(BaseVM): yield from self._control_vm("nic{} null".format(adapter_number + 1)) nio = adapter.get_nio(0) - if str(nio) == "NIO UDP": + if isinstance(nio, NIOUDP): self.manager.port_manager.release_udp_port(nio.lport) adapter.remove_nio(0) diff --git a/gns3server/modules/vpcs/vpcs_vm.py b/gns3server/modules/vpcs/vpcs_vm.py index 52c1736e..6549ebbc 100644 --- a/gns3server/modules/vpcs/vpcs_vm.py +++ b/gns3server/modules/vpcs/vpcs_vm.py @@ -31,6 +31,8 @@ import shutil from pkg_resources import parse_version from .vpcs_error import VPCSError from ..adapters.ethernet_adapter import EthernetAdapter +from ..nios.nio_udp import NIOUDP +from ..nios.nio_tap import NIOTAP from ..base_vm import BaseVM from ...utils.asyncio import subprocess_check_output @@ -70,11 +72,16 @@ class VPCSVM(BaseVM): @asyncio.coroutine def close(self): - self._terminate_process() if self._console: self._manager.port_manager.release_tcp_port(self._console) self._console = None + nio = self._ethernet_adapter.get_nio(0) + if isinstance(nio, NIOUDP): + self.manager.port_manager.release_udp_port(nio.lport) + + self._terminate_process() + @asyncio.coroutine def _check_requirements(self): """ @@ -310,7 +317,7 @@ class VPCSVM(BaseVM): port_number=port_number)) nio = self._ethernet_adapter.get_nio(port_number) - if str(nio) == "NIO UDP": + if isinstance(nio, NIOUDP): self.manager.port_manager.release_udp_port(nio.lport) self._ethernet_adapter.remove_nio(port_number) @@ -361,13 +368,13 @@ class VPCSVM(BaseVM): nio = self._ethernet_adapter.get_nio(0) if nio: - if str(nio) == "NIO UDP": + if isinstance(nio, NIOUDP): # UDP tunnel command.extend(["-s", str(nio.lport)]) # source UDP port command.extend(["-c", str(nio.rport)]) # destination UDP port command.extend(["-t", nio.rhost]) # destination host - elif str(nio) == "NIO TAP": + elif isinstance(nio, NIOTAP): # TAP interface command.extend(["-e"]) command.extend(["-d", nio.tap_vm])