From 51c1f1585362f593b15d00ea49cc0f58d58a80fa Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 6 May 2014 16:58:22 -0600 Subject: [PATCH] New UDP and console port allocation system for IOU. Fixes duplicated port issues. --- gns3server/main.py | 6 +++ gns3server/modules/iou/__init__.py | 58 ++++++++++++---------------- gns3server/modules/iou/iou_device.py | 39 ++++++++++++++++++- 3 files changed, 67 insertions(+), 36 deletions(-) diff --git a/gns3server/main.py b/gns3server/main.py index a75c2556..71514fce 100644 --- a/gns3server/main.py +++ b/gns3server/main.py @@ -111,6 +111,12 @@ def main(): # (UNIX/Linux only) locale_check() + try: + os.getcwd() + except FileNotFoundError: + log.critical("the current working directory doesn't exist") + return + server = Server(options.host, options.port, ipc=options.ipc) diff --git a/gns3server/modules/iou/__init__.py b/gns3server/modules/iou/__init__.py index fb43a004..bc7678d2 100644 --- a/gns3server/modules/iou/__init__.py +++ b/gns3server/modules/iou/__init__.py @@ -91,11 +91,9 @@ class IOU(IModule): self._iou_instances = {} self._console_start_port_range = 4001 self._console_end_port_range = 4512 - self._allocated_console_ports = [] - self._current_console_port = self._console_start_port_range + self._allocated_udp_ports = [] self._udp_start_port_range = 30001 self._udp_end_port_range = 40001 - self._current_udp_port = self._udp_start_port_range self._host = kwargs["host"] self._projects_dir = kwargs["projects_dir"] self._tempdir = kwargs["temp_dir"] @@ -179,9 +177,7 @@ class IOU(IModule): IOUDevice.reset() self._iou_instances.clear() - self._remote_server = False - self._current_console_port = self._console_start_port_range - self._current_udp_port = self._udp_start_port_range + self._allocated_udp_ports.clear() if self._iourc and os.path.isfile(self._iourc): try: @@ -323,15 +319,13 @@ class IOU(IModule): except OSError as e: raise IOUError("Could not create working directory {}".format(e)) - iou_instance = IOUDevice(iou_path, self._working_dir, host=self._host, name=name) - # find a console port - if self._current_console_port > self._console_end_port_range: - self._current_console_port = self._console_start_port_range - try: - iou_instance.console = find_unused_port(self._current_console_port, self._console_end_port_range, self._host) - except Exception as e: - raise IOUError(e) - self._current_console_port += 1 + iou_instance = IOUDevice(iou_path, + self._working_dir, + self._host, + name, + self._console_start_port_range, + self._console_end_port_range) + except IOUError as e: self.send_custom_error(str(e)) return @@ -557,26 +551,20 @@ class IOU(IModule): return try: - - # find a UDP port - if self._current_udp_port >= self._udp_end_port_range: - self._current_udp_port = self._udp_start_port_range - try: - port = find_unused_port(self._current_udp_port, self._udp_end_port_range, host=self._host, socket_type="UDP") - except Exception as e: - raise IOUError(e) - self._current_udp_port += 1 - - log.info("{} [id={}] has allocated UDP port {} with host {}".format(iou_instance.name, - iou_instance.id, - port, - self._host)) - response = {"lport": port} - - except IOUError as e: + port = find_unused_port(self._udp_start_port_range, + self._udp_end_port_range, + host=self._host, + socket_type="UDP", + ignore_ports=self._allocated_udp_ports) + except Exception as e: self.send_custom_error(str(e)) - return + self._allocated_udp_ports.append(port) + log.info("{} [id={}] has allocated UDP port {} with host {}".format(iou_instance.name, + iou_instance.id, + port, + self._host)) + response = {"lport": port} response["port_id"] = request["port_id"] self.send_response(response) @@ -698,7 +686,9 @@ class IOU(IModule): slot = request["slot"] port = request["port"] try: - iou_instance.slot_remove_nio_binding(slot, port) + nio = iou_instance.slot_remove_nio_binding(slot, port) + if isinstance(nio, NIO_UDP) and nio.lport in self._allocated_udp_ports: + self._allocated_udp_ports.remove(nio.lport) except IOUError as e: self.send_custom_error(str(e)) return diff --git a/gns3server/modules/iou/iou_device.py b/gns3server/modules/iou/iou_device.py index 0090c36f..50878911 100644 --- a/gns3server/modules/iou/iou_device.py +++ b/gns3server/modules/iou/iou_device.py @@ -34,6 +34,7 @@ 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 ..attic import find_unused_port import logging log = logging.getLogger(__name__) @@ -47,11 +48,19 @@ class IOUDevice(object): :param working_dir: path to a working directory :param host: host/address to bind for console and UDP connections :param name: name of this IOU device + :param console_start_port_range: TCP console port range start + :param console_end_port_range: TCP console port range end """ _instances = [] + _allocated_console_ports = [] - def __init__(self, path, working_dir, host="127.0.0.1", name=None): + def __init__(self, path, + working_dir, + host="127.0.0.1", + name=None, + console_start_port_range=4001, + console_end_port_range=4512): # find an instance identifier (0 < id <= 512) self._id = 0 @@ -82,6 +91,8 @@ class IOUDevice(object): self._ioucon_thread_stop_event = None self._host = host self._started = False + self._console_start_port_range = console_start_port_range + self._console_end_port_range = console_end_port_range # IOU settings self._ethernet_adapters = [EthernetAdapter(), EthernetAdapter()] # one adapter = 4 interfaces @@ -94,6 +105,16 @@ class IOUDevice(object): # update the working directory self.working_dir = working_dir + # allocate a console port + try: + self._console = find_unused_port(self._console_start_port_range, + self._console_end_port_range, + self._host, + ignore_ports=self._allocated_console_ports) + except Exception as e: + raise IOUError(e) + + self._allocated_console_ports.append(self._console) log.info("IOU device {name} [id={id}] has been created".format(name=self._name, id=self._id)) @@ -132,6 +153,7 @@ class IOUDevice(object): """ cls._instances.clear() + cls._allocated_console_ports.clear() @property def name(self): @@ -275,7 +297,12 @@ class IOUDevice(object): :param console: console port (integer) """ + if console in self._allocated_console_ports: + raise IOUError("Console port {} is already in used by another IOU device".format(console)) + + self._allocated_console_ports.remove(self._console) self._console = console + self._allocated_console_ports.append(self._console) log.info("IOU {name} [id={id}]: console port set to {port}".format(name=self._name, id=self._id, port=console)) @@ -296,6 +323,10 @@ class IOUDevice(object): self.stop() self._instances.remove(self._id) + + if self.console: + self._allocated_console_ports.remove(self.console) + log.info("IOU device {name} [id={id}] has been deleted".format(name=self._name, id=self._id)) @@ -376,7 +407,7 @@ class IOUDevice(object): """ if not self._ioucon_thead: - telnet_server = "{}:{}".format(self._host, self._console) + telnet_server = "{}:{}".format(self._host, self.console) log.info("starting ioucon for IOU instance {} to accept Telnet connections on {}".format(self._name, telnet_server)) args = argparse.Namespace(appl_id=str(self._id), debug=False, escape='^^', telnet_limit=0, telnet_server=telnet_server) self._ioucon_thread_stop_event = threading.Event() @@ -611,6 +642,8 @@ class IOUDevice(object): :param slot_id: slot ID :param port_id: port ID + + :returns: NIO instance """ try: @@ -634,6 +667,8 @@ class IOUDevice(object): self._update_iouyap_config() os.kill(self._iouyap_process.pid, signal.SIGHUP) + return nio + def _build_command(self): """ Command to start the IOU process.