diff --git a/gns3server/modules/dynamips/__init__.py b/gns3server/modules/dynamips/__init__.py
index 83261edc..5ae34ad3 100644
--- a/gns3server/modules/dynamips/__init__.py
+++ b/gns3server/modules/dynamips/__init__.py
@@ -16,10 +16,61 @@
# along with this program. If not, see .
from gns3server.modules import IModule
+import gns3server.jsonrpc as jsonrpc
from .hypervisor import Hypervisor
from .hypervisor_manager import HypervisorManager
from .dynamips_error import DynamipsError
+
+# nodes
from .nodes.router import Router
+from .nodes.c1700 import C1700
+from .nodes.c2600 import C2600
+from .nodes.c2691 import C2691
+from .nodes.c3600 import C3600
+from .nodes.c3725 import C3725
+from .nodes.c3745 import C3745
+from .nodes.c7200 import C7200
+from .nodes.bridge import Bridge
+from .nodes.ethernet_switch import EthernetSwitch
+from .nodes.atm_switch import ATMSwitch
+from .nodes.atm_bridge import ATMBridge
+from .nodes.frame_relay_switch import FrameRelaySwitch
+from .nodes.hub import Hub
+
+# adapters
+from .adapters.c7200_io_2fe import C7200_IO_2FE
+from .adapters.c7200_io_fe import C7200_IO_FE
+from .adapters.c7200_io_ge_e import C7200_IO_GE_E
+from .adapters.nm_16esw import NM_16ESW
+from .adapters.nm_1e import NM_1E
+from .adapters.nm_1fe_tx import NM_1FE_TX
+from .adapters.nm_4e import NM_4E
+from .adapters.nm_4t import NM_4T
+from .adapters.pa_2fe_tx import PA_2FE_TX
+from .adapters.pa_4e import PA_4E
+from .adapters.pa_4t import PA_4T
+from .adapters.pa_8e import PA_8E
+from .adapters.pa_8t import PA_8T
+from .adapters.pa_a1 import PA_A1
+from .adapters.pa_fe_tx import PA_FE_TX
+from .adapters.pa_ge import PA_GE
+from .adapters.pa_pos_oc3 import PA_POS_OC3
+from .adapters.wic_1t import WIC_1T
+from .adapters.wic_2t import WIC_2T
+from .adapters.wic_1enet import WIC_1ENET
+
+# NIOs
+from .nios.nio_udp import NIO_UDP
+from .nios.nio_udp_auto import NIO_UDP_auto
+from .nios.nio_unix import NIO_UNIX
+from .nios.nio_vde import NIO_VDE
+from .nios.nio_tap import NIO_TAP
+from .nios.nio_generic_ethernet import NIO_GenericEthernet
+from .nios.nio_linux_ethernet import NIO_LinuxEthernet
+from .nios.nio_fifo import NIO_FIFO
+from .nios.nio_mcast import NIO_Mcast
+from .nios.nio_null import NIO_Null
+
import logging
log = logging.getLogger(__name__)
@@ -29,21 +80,25 @@ class Dynamips(IModule):
def __init__(self, name=None, args=(), kwargs={}):
IModule.__init__(self, name=name, args=args, kwargs=kwargs)
+
+ # start the hypervisor manager
#self._hypervisor_manager = HypervisorManager("/usr/bin/dynamips", "/tmp")
- @IModule.route("dynamips/echo")
+ @IModule.route("dynamips.echo")
def echo(self, request):
- print("Echo!")
+ if request == None:
+ self.send_param_error()
+ return
log.debug("received request {}".format(request))
self.send_response(request)
- @IModule.route("dynamips/create_vm")
+ @IModule.route("dynamips.create_vm")
def create_vm(self, request):
print("Create VM!")
log.debug("received request {}".format(request))
self.send_response(request)
- @IModule.route("dynamips/start_vm")
+ @IModule.route("dynamips.start_vm")
def start_vm(self, request):
print("Start VM!")
log.debug("received request {}".format(request))
diff --git a/gns3server/stomp/__init__.py b/gns3server/modules/dynamips/adapters/__init__.py
similarity index 100%
rename from gns3server/stomp/__init__.py
rename to gns3server/modules/dynamips/adapters/__init__.py
diff --git a/gns3server/modules/dynamips/adapters/adapter.py b/gns3server/modules/dynamips/adapters/adapter.py
new file mode 100644
index 00000000..4e10bf99
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/adapter.py
@@ -0,0 +1,155 @@
+# -*- 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 .
+
+
+class Adapter(object):
+ """
+ Base class for adapters.
+
+ :param interfaces: number of interfaces supported by this adapter.
+ :param wics: number of wics supported by this adapter.
+ """
+
+ def __init__(self, interfaces=0, wics=0):
+
+ self._interfaces = interfaces
+
+ self._ports = {}
+ for port_id in range(0, interfaces):
+ self._ports[port_id] = None
+ self._wics = wics * [None]
+
+ def removable(self):
+ """
+ Returns True if the adapter can be removed from a slot
+ and False if not.
+
+ :returns: boolean
+ """
+
+ return True
+
+ def port_exists(self, port_id):
+ """
+ Checks if a port exists on this adapter.
+
+ :returns: True is the port exists,
+ False otherwise.
+ """
+
+ if port_id in self._ports:
+ return True
+ return False
+
+ def wic_slot_available(self, wic_slot_id):
+ """
+ Checks if a WIC slot is available
+
+ :returns: True is the WIC slot is available,
+ False otherwise.
+ """
+
+ if self._wics[wic_slot_id] == None:
+ return True
+ return False
+
+ def install_wic(self, wic_slot_id, wic):
+ """
+ Installs a WIC on this adapter.
+
+ :param wic_slot_id: WIC slot ID (integer)
+ :param wic: WIC object
+ """
+
+ self._wics[wic_slot_id] = wic
+
+ # Dynamips WICs ports start on a multiple of 16 + port number
+ # WIC1 port 1 = 16, WIC1 port 2 = 17
+ # WIC2 port 1 = 32, WIC2 port 2 = 33
+ # WIC3 port 1 = 48, WIC3 port 2 = 49
+ base = 16 * (wic_slot_id + 1)
+ for wic_port in range(0, wic.interfaces):
+ port_id = base + wic_port
+ self._ports[port_id] = None
+
+ def uninstall_wic(self, wic_slot_id):
+ """
+ Removes a WIC from this adapter.
+
+ :param wic_slot_id: WIC slot ID (integer)
+ """
+
+ wic = self._wics[wic_slot_id]
+
+ # Dynamips WICs ports start on a multiple of 16 + port number
+ # WIC1 port 1 = 16, WIC1 port 2 = 17
+ # WIC2 port 1 = 32, WIC2 port 2 = 33
+ # WIC3 port 1 = 48, WIC3 port 2 = 49
+ base = 16 * (wic_slot_id + 1)
+ for wic_port in range(0, wic.interfaces):
+ port_id = base + wic_port
+ del self._ports[port_id]
+ self._wics[wic_slot_id] = None
+
+ def add_nio(self, port_id, nio):
+ """
+ Adds a NIO to a port on this adapter.
+
+ :param port_id: port ID (integer)
+ :param nio: NIO object
+ """
+
+ self._ports[port_id] = nio
+
+ def remove_nio(self, port_id):
+ """
+ Removes a NIO from a port on this adapter.
+
+ :param port_id: port ID (integer)
+ """
+
+ self._ports[port_id] = None
+
+ @property
+ def ports(self):
+ """
+ Returns port to NIO mapping
+
+ :returns: dictionary port -> NIO
+ """
+
+ return self._ports
+
+ @property
+ def interfaces(self):
+ """
+ Returns the number of interfaces supported by this adapter.
+
+ :returns: number of interfaces
+ """
+
+ return self._interfaces
+
+ @property
+ def wics(self):
+ """
+ Returns the wics adapters inserted in this adapter.
+
+ :returns: list WIC objects
+ """
+
+ return self._wics
diff --git a/gns3server/modules/dynamips/adapters/c1700_mb_1fe.py b/gns3server/modules/dynamips/adapters/c1700_mb_1fe.py
new file mode 100644
index 00000000..71f992e7
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/c1700_mb_1fe.py
@@ -0,0 +1,43 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class C1700_MB_1FE(Adapter):
+ """
+ Integrated 1 port FastEthernet adapter for c1700 platform.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1, wics=2)
+
+ def __str__(self):
+
+ return "C1700-MB-1FE"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/c1700_mb_wic1.py b/gns3server/modules/dynamips/adapters/c1700_mb_wic1.py
new file mode 100644
index 00000000..7705984c
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/c1700_mb_wic1.py
@@ -0,0 +1,44 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class C1700_MB_WIC1(Adapter):
+ """
+ Fake module to provide a placeholder for slot 1 interfaces when WICs
+ are inserted into WIC slot 1.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=0, wics=2)
+
+ def __str__(self):
+
+ return "C1700_MB_WIC1"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "N/A"
+
+ def medium(self):
+
+ return "N/A"
diff --git a/gns3server/modules/dynamips/adapters/c2600_mb_1e.py b/gns3server/modules/dynamips/adapters/c2600_mb_1e.py
new file mode 100644
index 00000000..2ccb1661
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/c2600_mb_1e.py
@@ -0,0 +1,43 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class C2600_MB_1E(Adapter):
+ """
+ Integrated 1 port Ethernet adapter for the c2600 platform.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1, wics=3)
+
+ def __str__(self):
+
+ return "C2600-MB-1E"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "Ethernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/c2600_mb_1fe.py b/gns3server/modules/dynamips/adapters/c2600_mb_1fe.py
new file mode 100644
index 00000000..a630c194
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/c2600_mb_1fe.py
@@ -0,0 +1,44 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class C2600_MB_1FE(Adapter):
+ """
+ Integrated 1 port FastEthernet adapter for the c2600 platform.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1, wics=3)
+ self._interfaces = 1
+
+ def __str__(self):
+
+ return "C2600-MB-1FE"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/c2600_mb_2e.py b/gns3server/modules/dynamips/adapters/c2600_mb_2e.py
new file mode 100644
index 00000000..68ea2db8
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/c2600_mb_2e.py
@@ -0,0 +1,43 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class C2600_MB_2E(Adapter):
+ """
+ Integrated 2 port Ethernet adapter for the c2600 platform.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=2, wics=3)
+
+ def __str__(self):
+
+ return "C2600-MB-2E"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "Ethernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/c2600_mb_2fe.py b/gns3server/modules/dynamips/adapters/c2600_mb_2fe.py
new file mode 100644
index 00000000..3a2d59be
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/c2600_mb_2fe.py
@@ -0,0 +1,43 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class C2600_MB_2FE(Adapter):
+ """
+ Integrated 2 port FastEthernet adapter for the c2600 platform.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=2, wics=3)
+
+ def __str__(self):
+
+ return "C2600-MB-2FE"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/c7200_io_2fe.py b/gns3server/modules/dynamips/adapters/c7200_io_2fe.py
new file mode 100644
index 00000000..0ee8674f
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/c7200_io_2fe.py
@@ -0,0 +1,43 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class C7200_IO_2FE(Adapter):
+ """
+ C7200-IO-2FE FastEthernet Input/Ouput controller.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=2)
+
+ def __str__(self):
+
+ return "C7200_IO_2FE"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/c7200_io_fe.py b/gns3server/modules/dynamips/adapters/c7200_io_fe.py
new file mode 100644
index 00000000..22200ded
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/c7200_io_fe.py
@@ -0,0 +1,43 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class C7200_IO_FE(Adapter):
+ """
+ C7200-IO-FE FastEthernet Input/Ouput controller.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1)
+
+ def __str__(self):
+
+ return "C7200_IO_FE"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/c7200_io_ge_e.py b/gns3server/modules/dynamips/adapters/c7200_io_ge_e.py
new file mode 100644
index 00000000..dd732dfa
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/c7200_io_ge_e.py
@@ -0,0 +1,43 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class C7200_IO_GE_E(Adapter):
+ """
+ C7200-IO-GE-E GigabitEthernet Input/Ouput controller.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1)
+
+ def __str__(self):
+
+ return "C7200-IO-GE-E"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "GigabitEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/gt96100_fe.py b/gns3server/modules/dynamips/adapters/gt96100_fe.py
new file mode 100644
index 00000000..27217e31
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/gt96100_fe.py
@@ -0,0 +1,40 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class GT96100_FE(Adapter):
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=2, wics=3)
+
+ def __str__(self):
+
+ return "GT96100-FE"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/leopard_2fe.py b/gns3server/modules/dynamips/adapters/leopard_2fe.py
new file mode 100644
index 00000000..c25744eb
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/leopard_2fe.py
@@ -0,0 +1,44 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class Leopard_2FE(Adapter):
+ """
+ Integrated 2 port FastEthernet adapter for c3660 router.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=2)
+ self._interfaces = 2
+
+ def __str__(self):
+
+ return "Leopard-2FE"
+
+ def removable(self):
+
+ return False
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/nm_16esw.py b/gns3server/modules/dynamips/adapters/nm_16esw.py
new file mode 100644
index 00000000..ea7bccce
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/nm_16esw.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class NM_16ESW(Adapter):
+ """
+ NM-16ESW FastEthernet network module.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=16)
+
+ def __str__(self):
+
+ return "NM-16ESW"
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/nm_1e.py b/gns3server/modules/dynamips/adapters/nm_1e.py
new file mode 100644
index 00000000..7663f934
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/nm_1e.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class NM_1E(Adapter):
+ """
+ NM-1E Ethernet network module.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1)
+
+ def __str__(self):
+
+ return "NM-1E"
+
+ def interface_type(self):
+
+ return "Ethernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/nm_1fe_tx.py b/gns3server/modules/dynamips/adapters/nm_1fe_tx.py
new file mode 100644
index 00000000..02f19248
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/nm_1fe_tx.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class NM_1FE_TX(Adapter):
+ """
+ NM-1FE-TX FastEthernet network module.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1)
+
+ def __str__(self):
+
+ return "NM-1FE-TX"
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/nm_4e.py b/gns3server/modules/dynamips/adapters/nm_4e.py
new file mode 100644
index 00000000..32219522
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/nm_4e.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class NM_4E(Adapter):
+ """
+ NM-4E Ethernet network module.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=4)
+
+ def __str__(self):
+
+ return "NM-4E"
+
+ def interface_type(self):
+
+ return "Ethernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/nm_4t.py b/gns3server/modules/dynamips/adapters/nm_4t.py
new file mode 100644
index 00000000..1021dc51
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/nm_4t.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class NM_4T(Adapter):
+ """
+ NM-4T Serial network module.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=4)
+
+ def __str__(self):
+
+ return "NM-4T"
+
+ def interface_type(self):
+
+ return "Serial"
+
+ def medium(self):
+
+ return "Serial"
diff --git a/gns3server/modules/dynamips/adapters/pa_2fe_tx.py b/gns3server/modules/dynamips/adapters/pa_2fe_tx.py
new file mode 100644
index 00000000..2706f51d
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/pa_2fe_tx.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class PA_2FE_TX(Adapter):
+ """
+ PA-2FE-TX FastEthernet port adapter.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=2)
+
+ def __str__(self):
+
+ return "PA-2FE-TX"
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/pa_4e.py b/gns3server/modules/dynamips/adapters/pa_4e.py
new file mode 100644
index 00000000..44f5437d
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/pa_4e.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class PA_4E(Adapter):
+ """
+ PA-4E Ethernet port adapter.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=4)
+
+ def __str__(self):
+
+ return "PA-4E"
+
+ def interface_type(self):
+
+ return "Ethernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/pa_4t.py b/gns3server/modules/dynamips/adapters/pa_4t.py
new file mode 100644
index 00000000..592eb688
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/pa_4t.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class PA_4T(Adapter):
+ """
+ PA-4T+ Serial port adapter.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=4)
+
+ def __str__(self):
+
+ return "PA-4T+"
+
+ def interface_type(self):
+
+ return "Serial"
+
+ def medium(self):
+
+ return "Serial"
diff --git a/gns3server/modules/dynamips/adapters/pa_8e.py b/gns3server/modules/dynamips/adapters/pa_8e.py
new file mode 100644
index 00000000..4e5b5a7f
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/pa_8e.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class PA_8E(Adapter):
+ """
+ PA-8E Ethernet port adapter.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=8)
+
+ def __str__(self):
+
+ return "PA-8E"
+
+ def interface_type(self):
+
+ return "Ethernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/pa_8t.py b/gns3server/modules/dynamips/adapters/pa_8t.py
new file mode 100644
index 00000000..c4851154
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/pa_8t.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class PA_8T(Adapter):
+ """
+ PA-8T Serial port adapter.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=8)
+
+ def __str__(self):
+
+ return "PA-8T"
+
+ def interface_type(self):
+
+ return "Serial"
+
+ def medium(self):
+
+ return "Serial"
diff --git a/gns3server/modules/dynamips/adapters/pa_a1.py b/gns3server/modules/dynamips/adapters/pa_a1.py
new file mode 100644
index 00000000..72cb455e
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/pa_a1.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class PA_A1(Adapter):
+ """
+ PA-A1 ATM port adapter.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1)
+
+ def __str__(self):
+
+ return "PA-A1"
+
+ def interface_type(self):
+
+ return "ATM"
+
+ def medium(self):
+
+ return "Serial"
diff --git a/gns3server/modules/dynamips/adapters/pa_fe_tx.py b/gns3server/modules/dynamips/adapters/pa_fe_tx.py
new file mode 100644
index 00000000..7a22e2af
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/pa_fe_tx.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class PA_FE_TX(Adapter):
+ """
+ PA-FE-TX FastEthernet port adapter.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1)
+
+ def __str__(self):
+
+ return "PA-FE-TX"
+
+ def interface_type(self):
+
+ return "FastEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/pa_ge.py b/gns3server/modules/dynamips/adapters/pa_ge.py
new file mode 100644
index 00000000..20d5994b
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/pa_ge.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class PA_GE(Adapter):
+ """
+ PA-GE GigabitEthernet port adapter.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1)
+
+ def __str__(self):
+
+ return "PA-GE"
+
+ def interface_type(self):
+
+ return "GigabitEthernet"
+
+ def medium(self):
+
+ return "Ethernet"
diff --git a/gns3server/modules/dynamips/adapters/pa_pos_oc3.py b/gns3server/modules/dynamips/adapters/pa_pos_oc3.py
new file mode 100644
index 00000000..064f63cf
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/pa_pos_oc3.py
@@ -0,0 +1,39 @@
+# -*- 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 .
+
+from .adapter import Adapter
+
+
+class PA_POS_OC3(Adapter):
+ """
+ PA-POS-OC3 port adapter.
+ """
+
+ def __init__(self):
+ Adapter.__init__(self, interfaces=1)
+
+ def __str__(self):
+
+ return "PA-POS-OC3"
+
+ def interface_type(self):
+
+ return "POS"
+
+ def medium(self):
+
+ return "SONET"
diff --git a/gns3server/modules/dynamips/adapters/wic_1enet.py b/gns3server/modules/dynamips/adapters/wic_1enet.py
new file mode 100644
index 00000000..790cf618
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/wic_1enet.py
@@ -0,0 +1,48 @@
+# -*- 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 .
+
+
+class WIC_1ENET(object):
+ """
+ WIC-1ENET Ethernet
+ """
+
+ def __init__(self):
+
+ self._interfaces = 2
+
+ def __str__(self):
+
+ return "WIC-1ENET"
+
+ def interface_type(self):
+
+ return "Ethernet"
+
+ def medium(self):
+
+ return "Ethernet"
+
+ @property
+ def interfaces(self):
+ """
+ Returns the number of interfaces supported by this WIC.
+
+ :returns: number of interfaces
+ """
+
+ return self._interfaces
diff --git a/gns3server/modules/dynamips/adapters/wic_1t.py b/gns3server/modules/dynamips/adapters/wic_1t.py
new file mode 100644
index 00000000..c6f30c26
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/wic_1t.py
@@ -0,0 +1,48 @@
+# -*- 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 .
+
+
+class WIC_1T(object):
+ """
+ WIC-1T Serial
+ """
+
+ def __init__(self):
+
+ self._interfaces = 1
+
+ def __str__(self):
+
+ return "WIC-1T"
+
+ def interface_type(self):
+
+ return "Serial"
+
+ def medium(self):
+
+ return "Serial"
+
+ @property
+ def interfaces(self):
+ """
+ Returns the number of interfaces supported by this WIC.
+
+ :returns: number of interfaces
+ """
+
+ return self._interfaces
diff --git a/gns3server/modules/dynamips/adapters/wic_2t.py b/gns3server/modules/dynamips/adapters/wic_2t.py
new file mode 100644
index 00000000..8e73cb35
--- /dev/null
+++ b/gns3server/modules/dynamips/adapters/wic_2t.py
@@ -0,0 +1,48 @@
+# -*- 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 .
+
+
+class WIC_2T(object):
+ """
+ WIC-2T Serial
+ """
+
+ def __init__(self):
+
+ self._interfaces = 2
+
+ def __str__(self):
+
+ return "WIC-2T"
+
+ def interface_type(self):
+
+ return "Serial"
+
+ def medium(self):
+
+ return "Serial"
+
+ @property
+ def interfaces(self):
+ """
+ Returns the number of interfaces supported by this WIC.
+
+ :returns: number of interfaces
+ """
+
+ return self._interfaces
diff --git a/gns3server/stomp/utils.py b/gns3server/modules/dynamips/dynamips_error.py
similarity index 55%
rename from gns3server/stomp/utils.py
rename to gns3server/modules/dynamips/dynamips_error.py
index 8dd1b7e4..285e4a7b 100644
--- a/gns3server/stomp/utils.py
+++ b/gns3server/modules/dynamips/dynamips_error.py
@@ -16,28 +16,18 @@
# along with this program. If not, see .
"""
-Utilitary functions for STOMP implementation
+Custom exceptions for Dynamips module.
"""
-import sys
-PY2 = sys.version_info[0] == 2
+class DynamipsError(Exception):
-if not PY2:
- def encode(char_data):
- if type(char_data) is str:
- return char_data.encode()
- elif type(char_data) is bytes:
- return char_data
- else:
- raise TypeError('message should be a string or bytes')
-else:
- def encode(char_data):
- if type(char_data) is unicode:
- return char_data.encode('utf-8')
- else:
- return char_data
+ def __init__(self, message, original_exception=None):
+ Exception.__init__(self, message)
+ self._message = message
+ self._original_exception = original_exception
-def hasbyte(byte, byte_data):
- return bytes([byte]) in byte_data
+ def __repr__(self):
+
+ return self._message
diff --git a/gns3server/modules/dynamips/dynamips_hypervisor.py b/gns3server/modules/dynamips/dynamips_hypervisor.py
new file mode 100644
index 00000000..0bedc7b7
--- /dev/null
+++ b/gns3server/modules/dynamips/dynamips_hypervisor.py
@@ -0,0 +1,419 @@
+# -*- 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 Dynamips hypervisor management module ("hypervisor")
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L46
+"""
+
+import socket
+import re
+import logging
+from .dynamips_error import DynamipsError
+
+log = logging.getLogger(__name__)
+
+
+class DynamipsHypervisor(object):
+ """
+ Creates a new connection to a Dynamips server (also called hypervisor)
+
+ :param host: the hostname or ip address string of the Dynamips server
+ :param port: the tcp port integer (defaults to 7200)
+ :param timeout: timeout integer for how long to wait for a response to commands sent to the
+ hypervisor (defaults to 30 seconds)
+ """
+
+ # Used to parse Dynamips response codes
+ error_re = re.compile(r"""^2[0-9]{2}-""")
+ success_re = re.compile(r"""^1[0-9]{2}\s{1}""")
+
+ def __init__(self, host, port=7200, timeout=30.0):
+
+ self._host = host
+ self._port = port
+
+ self._devices = []
+ self._ghosts = {}
+ self._jitsharing_groups = {}
+ self._working_dir = ""
+ self._baseconsole = 2000
+ self._baseaux = 2100
+ self._baseudp = 10000
+ self._version = "N/A"
+ self._timeout = 30
+ self._socket = None
+ self._uuid = None
+
+ def connect(self):
+ """
+ Connects to the hypervisor.
+ """
+
+ try:
+ self._socket = socket.create_connection((self._host,
+ self._port),
+ self._timeout)
+ except socket.error as e:
+ raise DynamipsError("Could not connect to server: {}".format(e))
+
+ try:
+ self._version = self.send("hypervisor version")[0][4:]
+ except IndexError:
+ self._version = "Unknown"
+
+ self._uuid = self.send("hypervisor uuid")
+
+ @property
+ def version(self):
+ """
+ Returns Dynamips version.
+
+ :returns: version string
+ """
+
+ return self._version
+
+ def module_list(self):
+ """
+ Returns the modules supported by this hypervisor.
+
+ :returns: module list
+ """
+
+ return self.send("hypervisor module_list")
+
+ def cmd_list(self, module):
+ """
+ Returns commands recognized by the specified module.
+
+ :param module: the module name
+ :returns: command list
+ """
+
+ return self.send("hypervisor cmd_list {}".format(module))
+
+ def close(self):
+ """
+ Closes the connection to this hypervisor (but leave it running).
+ """
+
+ self.send("hypervisor close")
+ self._socket.close()
+ self._socket = None
+
+ def stop(self):
+ """
+ Stops this hypervisor (will no longer run).
+ """
+
+ self.send("hypervisor stop")
+ self._socket.close()
+ self._socket = None
+
+ def reset(self):
+ """
+ Resets this hypervisor (used to get an empty configuration).
+ """
+
+ self.send('hypervisor reset')
+
+ @property
+ def working_dir(self):
+ """
+ Returns current working directory
+
+ :returns: path to the working directory
+ """
+
+ return self._working_dir
+
+ @working_dir.setter
+ def working_dir(self, working_dir):
+ """
+ Set the working directory for this hypervisor.
+
+ :param working_dir: path to the working directory
+ """
+
+ # encase working_dir in quotes to protect spaces in the path
+ self.send("hypervisor working_dir {}".format('"' + working_dir + '"'))
+ self._working_dir = working_dir
+
+ def save_config(self, filename):
+ """
+ Saves the configuration of all Dynamips objects into the specified file.
+
+ :param filename: path string
+ """
+
+ # encase working_dir in quotes to protect spaces in the path
+ self.send("hypervisor save_config {}".format('"' + filename + '"'))
+
+ @property
+ def uuid(self):
+ """
+ Returns this hypervisor UUID.
+
+ :Returns: uuid string
+ """
+
+ return self._uuid
+
+ @property
+ def socket(self):
+ """
+ Returns the current socket used to communicate with this hypervisor.
+
+ :returns: socket object
+ """
+
+ assert self._socket
+ return self._socket
+
+ @property
+ def devices(self):
+ """
+ Returns the list of devices managed by this hypervisor instance.
+
+ :returns: a list of device objects
+ """
+
+ return self._devices
+
+ @devices.setter
+ def devices(self, devices):
+ """
+ Set the list of devices managed by this hypervisor instance.
+ This method is for internal use.
+
+ :param devices: a list of device objects
+ """
+
+ self._devices = devices
+
+ @property
+ def baseconsole(self):
+ """
+ Returns base console TCP port for this hypervisor.
+
+ :returns: base console value (integer)
+ """
+
+ return self._baseconsole
+
+ @baseconsole.setter
+ def baseconsole(self, baseconsole):
+ """
+ Set the base console TCP port for this hypervisor.
+
+ :param baseconsole: base console value (integer)
+ """
+
+ self._baseconsole = baseconsole
+
+ @property
+ def baseaux(self):
+ """
+ Returns base auxiliary port for this hypervisor.
+
+ :returns: base auxiliary port value (integer)
+ """
+
+ return self._baseaux
+
+ @baseaux.setter
+ def baseaux(self, baseaux):
+ """
+ Set the base auxiliary TCP port for this hypervisor.
+
+ :param baseaux: base auxiliary port value (integer)
+ """
+
+ self._baseaux = baseaux
+
+ @property
+ def baseudp(self):
+ """
+ Returns the next available UDP port for UDP NIOs.
+
+ :returns: base UDP port value (integer)
+ """
+
+ return self._baseudp
+
+ @baseudp.setter
+ def baseudp(self, baseudp):
+ """
+ Set the next open UDP port for NIOs for this hypervisor.
+
+ :param baseudp: base UDP port value (integer)
+ """
+
+ self._baseudp = baseudp
+
+ @property
+ def ghosts(self):
+ """
+ Returns a list of the ghosts hosted by this hypervisor.
+
+ :returns: Ghosts dict (image_name -> device)
+ """
+
+ return self._ghosts
+
+ def add_ghost(self, image_name, router):
+ """
+ Adds a ghost name to the list of ghosts created on this hypervisor.
+
+ :param image_name: name of the ghost image
+ :param router: router object
+ """
+
+ self._ghosts[image_name] = router
+
+ @property
+ def jitsharing_groups(self):
+ """
+ Returns a list of the JIT sharing groups hosted by this hypervisor.
+
+ :returns: JIT sharing groups dict (image_name -> group number)
+ """
+
+ return self._ghosts
+
+ def add_jitsharing_group(self, image_name, group_number):
+ """
+ Adds a JIT blocks sharing group name to the list of groups created on this hypervisor.
+
+ :param image_name: name of the ghost image
+ :param group_number: group (integer)
+ """
+
+ self._jitsharing_groups[image_name] = group_number
+
+ @property
+ def host(self):
+ """
+ Returns this hypervisor host.
+
+ :returns: host (string)
+ """
+
+ return self._host
+
+ @property
+ def port(self):
+ """
+ Returns this hypervisor port.
+
+ :returns: port (integer)
+ """
+
+ return self._port
+
+ def send_raw(self, string):
+ """
+ Sends a raw command to this hypervisor. Use sparingly.
+
+ :param string: command string.
+
+ :returns: command result (string)
+ """
+
+ result = self.send(string)
+ return result
+
+ def send(self, command):
+ """
+ Sends commands to this hypervisor.
+
+ :param command: a Dynamips hypervisor command
+
+ :returns: results as a list
+ """
+
+ # Dynamips responses are of the form:
+ # 1xx yyyyyy\r\n
+ # 1xx yyyyyy\r\n
+ # ...
+ # 100-yyyy\r\n
+ # or
+ # 2xx-yyyy\r\n
+ #
+ # Where 1xx is a code from 100-199 for a success or 200-299 for an error
+ # The result might be multiple lines and might be less than the buffer size
+ # but still have more data. The only thing we know for sure is the last line
+ # will begin with '100-' or a '2xx-' and end with '\r\n'
+
+ if not self._socket:
+ raise DynamipsError("Not connected")
+
+ try:
+ command = command.strip() + '\n'
+ log.debug("sending {}".format(command))
+ self.socket.sendall(command.encode('utf-8'))
+ except socket.error as e:
+ raise DynamipsError("Lost communication with {host}:{port} :{error}"
+ .format(host=self._host, port=self._port, error=e))
+
+ # Now retrieve the result
+ data = []
+ buf = ''
+ while True:
+ try:
+ chunk = self.socket.recv(1024) # match to Dynamips' buffer size
+ buf += chunk.decode("utf-8")
+ except socket.error as e:
+ raise DynamipsError("Communication timed out with {host}:{port} :{error}"
+ .format(host=self._host, port=self._port, error=e))
+
+ # If the buffer doesn't end in '\n' then we can't be done
+ try:
+ if buf[-1] != '\n':
+ continue
+ except IndexError:
+ raise DynamipsError("Could not communicate with {host}:{port}"
+ .format(host=self._host, port=self._port))
+
+ data += buf.split('\r\n')
+ if data[-1] == '':
+ data.pop()
+ buf = ''
+
+ if len(data) == 0:
+ raise DynamipsError("no data returned from {host}:{port}"
+ .format(host=self._host, port=self._port))
+
+ # Does it contain an error code?
+ if self.error_re.search(data[-1]):
+ raise DynamipsError(data[-1][4:])
+
+ # Or does the last line begin with '100-'? Then we are done!
+ if data[-1][:4] == '100-':
+ data[-1] = data[-1][4:]
+ if data[-1] == 'OK':
+ data.pop()
+ break
+
+ # Remove success responses codes
+ for index in range(len(data)):
+ if self.success_re.search(data[index]):
+ data[index] = data[index][4:]
+
+ log.debug("returned result {}".format(data))
+ return data
diff --git a/gns3server/modules/dynamips/hypervisor.py b/gns3server/modules/dynamips/hypervisor.py
new file mode 100644
index 00000000..3a8933f3
--- /dev/null
+++ b/gns3server/modules/dynamips/hypervisor.py
@@ -0,0 +1,270 @@
+# -*- 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 .
+
+"""
+Represents a Dynamips hypervisor and starts/stops the associated Dynamips process.
+"""
+
+import os
+import subprocess
+import logging
+
+from .dynamips_hypervisor import DynamipsHypervisor
+
+logger = logging.getLogger(__name__)
+
+
+class Hypervisor(DynamipsHypervisor):
+ """
+ Hypervisor.
+
+ :param path: path to Dynamips executable
+ :param workingdir: working directory
+ :param port: port for this hypervisor
+ :param host: host/address for this hypervisor
+ """
+
+ _instance_count = 0
+
+ def __init__(self, path, workingdir, host, port):
+
+ DynamipsHypervisor.__init__(self, host, port)
+
+ # create an unique ID
+ self._id = Hypervisor._instance_count
+ Hypervisor._instance_count += 1
+
+ self._path = path
+ self._workingdir = workingdir
+ self._command = []
+ self._process = None
+ self._stdout = None
+
+ # settings used the load-balance hypervisors
+ # (for the hypervisor manager)
+ self._memory_load = 0
+ self._ios_image_ref = ""
+
+ @property
+ def id(self):
+ """
+ Returns the unique ID for this hypervisor.
+
+ :returns: id (integer)
+ """
+
+ return(self._id)
+
+ @property
+ def path(self):
+ """
+ Returns the path to the Dynamips executable.
+
+ :returns: path to Dynamips
+ """
+
+ return(self._path)
+
+ @path.setter
+ def path(self, path):
+ """
+ Set the path to the Dynamips executable.
+
+ :param path: path to Dynamips
+ """
+
+ self._path = path
+
+ @property
+ def port(self):
+ """
+ Returns the port used to start the Dynamips hypervisor.
+
+ :returns: port number (integer)
+ """
+
+ return(self._port)
+
+ @port.setter
+ def port(self, port):
+ """
+ Set the port used to start the Dynamips hypervisor.
+
+ :param port: port number (integer)
+ """
+
+ self._port = port
+
+ @property
+ def host(self):
+ """
+ Returns the host (binding) used to start the Dynamips hypervisor.
+
+ :returns: host/address (string)
+ """
+
+ return(self._host)
+
+ @host.setter
+ def host(self, host):
+ """
+ Set the host (binding) used to start the Dynamips hypervisor.
+
+ :param host: host/address (string)
+ """
+
+ self._host = host
+
+ @property
+ def workingdir(self):
+ """
+ Returns the working directory used to start the Dynamips hypervisor.
+
+ :returns: path to a working directory
+ """
+
+ return(self._workingdir)
+
+ @workingdir.setter
+ def workingdir(self, workingdir):
+ """
+ Set the working directory used to start the Dynamips hypervisor.
+
+ :param workingdir: path to a working directory
+ """
+
+ self._workingdir = workingdir
+
+ @property
+ def image_ref(self):
+ """
+ Returns the reference IOS image name
+ (used by the hypervisor manager for load-balancing purposes).
+
+ :returns: image reference name
+ """
+
+ return self._ios_image_ref
+
+ @image_ref.setter
+ def image_ref(self, ios_image_name):
+ """
+ Set the reference IOS image name
+ (used by the hypervisor manager for load-balancing purposes).
+
+ :param ios_image_name: image reference name
+ """
+
+ self._ios_image_ref = ios_image_name
+
+ def increase_memory_load(self, memory):
+ """
+ Increases the memory load of this hypervisor.
+ (used by the hypervisor manager for load-balancing purposes).
+
+ :param memory: amount of RAM (integer)
+ """
+
+ self._memory_load += memory
+
+ def decrease_memory_load(self, memory):
+ """
+ Decreases the memory load of this hypervisor.
+ (used by the hypervisor manager for load-balancing purposes).
+
+ :param memory: amount of RAM (integer)
+ """
+
+ self._memory_load -= memory
+
+ @property
+ def memory_load(self):
+ """
+ Returns the memory load of this hypervisor.
+ (used by the hypervisor manager for load-balancing purposes).
+
+ :returns: amount of RAM (integer)
+ """
+
+ return self._memory_load
+
+ def start(self):
+ """
+ Starts the Dynamips hypervisor process.
+ """
+
+ self._command = self._build_command()
+ try:
+ logger.info("Starting Dynamips: {}".format(self._command))
+ # TODO: create unique filename for stdout
+ self.stdout_file = os.path.join(self._workingdir, "dynamips.log")
+ fd = open(self.stdout_file, "w")
+ # TODO: check for exceptions and if process has already been started
+ self._process = subprocess.Popen(self._command,
+ stdout=fd,
+ stderr=subprocess.STDOUT,
+ cwd=self._workingdir)
+ logger.info("Dynamips started PID={}".format(self._process.pid))
+ except OSError as e:
+ logger.error("Could not start Dynamips: {}".format(e))
+ finally:
+ fd.close()
+
+ def stop(self):
+ """
+ Stops the Dynamips hypervisor process.
+ """
+
+ if self.is_running():
+ logger.info("Stopping Dynamips PID={}".format(self._process.pid))
+ self._process.kill()
+
+ def read_stdout(self):
+ """
+ Reads the standard output of the Dynamips process.
+ Only use when the process has been stopped or has crashed.
+ """
+
+ # TODO: check for exceptions
+ with open(self.stdout_file) as file:
+ output = file.read()
+ return output
+
+ def is_running(self):
+ """
+ Checks if the process is running
+
+ :returns: True or False
+ """
+
+ if self._process and self._process.poll() == None:
+ return True
+ return False
+
+ def _build_command(self):
+ """
+ Command to start the Dynamips hypervisor process.
+ (to be passed to subprocess.Popen())
+ """
+
+ command = [self._path]
+ command.extend(["-N1"]) # use instance IDs for filenames
+ if self._host != '0.0.0.0':
+ command.extend(['-H', self._host + ':' + str(self._port)])
+ else:
+ command.extend(['-H', self._port])
+ return command
diff --git a/gns3server/modules/dynamips/hypervisor_manager.py b/gns3server/modules/dynamips/hypervisor_manager.py
new file mode 100644
index 00000000..d759cd1b
--- /dev/null
+++ b/gns3server/modules/dynamips/hypervisor_manager.py
@@ -0,0 +1,235 @@
+# -*- 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 .
+
+"""
+Manages Dynamips hypervisors (load-balancing etc.)
+"""
+
+from __future__ import unicode_literals
+from .hypervisor import Hypervisor
+import socket
+import time
+import logging
+
+log = logging.getLogger(__name__)
+
+
+class HypervisorManager(object):
+ """
+ Manages Dynamips hypervisors.
+
+ :param path: path to the Dynamips executable
+ :param workingdir: path to a working directory
+ :param host: host/address for hypervisors to listen to
+ :param base_port: base TCP port for hypervisors
+ :param base_console: base TCP port for consoles
+ :param base_aux: base TCP port for auxiliary consoles
+ :param base_udp: base UDP port for UDP tunnels
+ """
+
+ def __init__(self,
+ path,
+ workingdir,
+ host='127.0.0.1',
+ base_port=7200,
+ base_console=2000,
+ base_aux=3000,
+ base_udp=10000):
+
+ self._hypervisors = []
+ self._path = path
+ self._workingdir = workingdir
+ self._base_port = base_port
+ self._current_port = self._base_port
+ self._base_console = base_console
+ self._base_aux = base_aux
+ self._base_udp = base_udp
+ self._host = host
+ self._clean_workingdir = False
+ self._ghost_ios = True
+ self._mmap = True
+ self._jit_sharing = False
+ self._sparsemem = True
+ self._memory_usage_limit_per_hypervisor = 1024
+ self._group_ios_per_hypervisor = True
+
+ def __del__(self):
+ """
+ Shutdowns all started hypervisors
+ """
+
+ self.stop_all_hypervisors()
+
+ @property
+ def hypervisors(self):
+ """
+ Returns all hypervisor instances.
+
+ :returns: list of hypervisor objects
+ """
+
+ return self._hypervisors
+
+ @property
+ def memory_usage_limit_per_hypervisor(self):
+ """
+ Returns the memory usage limit per hypervisor
+
+ :returns: limit value (integer)
+ """
+
+ return self._memory_usage_limit_per_hypervisor
+
+ @memory_usage_limit_per_hypervisor.setter
+ def memory_usage_limit_per_hypervisor(self, memory_limit):
+ """
+ Set the memory usage limit per hypervisor
+
+ :param memory_limit: memory limit value (integer)
+ """
+
+ self._memory_usage_limit_per_hypervisor = memory_limit
+
+ @property
+ def group_ios_per_hypervisor(self):
+ """
+ Returns if router are grouped per hypervisor
+ based on their IOS image.
+
+ :returns: True or False
+ """
+
+ return self._group_ios_per_hypervisor
+
+ @group_ios_per_hypervisor.setter
+ def group_ios_per_hypervisor(self, value):
+ """
+ Set if router are grouped per hypervisor
+ based on their IOS image.
+
+ :param value: True or False
+ """
+
+ self._group_ios_per_hypervisor = value
+
+ def wait_for_hypervisor(self, host, port, timeout=10):
+ """
+ Waits for an hypervisor to be started (accepting a socket connection)
+
+ :param host: host/address to connect to the hypervisor
+ :param port: port to connect to the hypervisor
+ :param timeout: timeout value (default is 10 seconds)
+ """
+
+ # try to connect 5 times
+ for _ in range(0, 5):
+ try:
+ s = socket.create_connection((host, port), timeout)
+ except socket.error as e:
+ time.sleep(0.5)
+ last_exception = e
+ continue
+ connection_success = True
+ break
+
+ if connection_success:
+ s.close()
+ #time.sleep(0.1)
+ else:
+ log.critical("Couldn't connect to hypervisor on {}:{} :{}".format(host, port,
+ last_exception))
+
+ def start_new_hypervisor(self):
+ """
+ Creates a new Dynamips process and start it.
+
+ :returns: the new hypervisor object
+ """
+
+ hypervisor = Hypervisor(self._path,
+ self._workingdir,
+ self._host,
+ self._current_port)
+
+ log.info("creating new hypervisor {}:{}".format(hypervisor.host, hypervisor.port))
+ hypervisor.start()
+
+ self.wait_for_hypervisor(self._host, self._current_port)
+ log.info("hypervisor {}:{} has successfully started".format(hypervisor.host, hypervisor.port))
+
+ hypervisor.connect()
+ self._hypervisors.append(hypervisor)
+ self._current_port += 1
+ return hypervisor
+
+ def allocate_hypervisor_for_router(self, router_ios_image, router_ram):
+ """
+ Allocates a Dynamips hypervisor for a specific router
+ (new or existing depending on the RAM amount and IOS image)
+
+ :param router_ios_image: IOS image name
+ :param router_ram: amount of RAM (integer)
+
+ :returns: the allocated hypervisor object
+ """
+
+ for hypervisor in self._hypervisors:
+ if self._group_ios_per_hypervisor and hypervisor.image_ref != router_ios_image:
+ continue
+ if (hypervisor.memory_load + router_ram) <= self._memory_usage_limit_per_hypervisor:
+ current_memory_load = hypervisor.memory_load
+ hypervisor.increase_memory_load(router_ram)
+ log.info("allocating existing hypervisor {}:{}, RAM={}+{}".format(hypervisor.host,
+ hypervisor.port,
+ current_memory_load,
+ router_ram))
+ return hypervisor
+
+ hypervisor = self.start_new_hypervisor()
+ hypervisor.image_ref = router_ios_image
+ hypervisor.increase_memory_load(router_ram)
+ return hypervisor
+
+ def unallocate_hypervisor_for_router(self, router):
+ """
+ Unallocates a Dynamips hypervisor for a specific router.
+
+ :param router: router object
+ """
+
+ hypervisor = router.hypervisor
+ hypervisor.decrease_memory_load(router.ram)
+
+ if hypervisor.memory_load < 0:
+ log.warn("hypervisor {}:{} has a memory load below 0 ({})".format(hypervisor.host,
+ hypervisor.port,
+ hypervisor.memory_load))
+ hypervisor.memory_load = 0
+
+ # memory load at 0MB and no devices managed anymore...
+ # let's stop this hypervisor
+ if hypervisor.memory_load == 0 and not hypervisor.devices:
+ hypervisor.stop()
+ self._hypervisors.remove(hypervisor)
+
+ def stop_all_hypervisors(self):
+ """
+ Stops all hypervisors.
+ """
+
+ for hypervisor in self._hypervisors:
+ hypervisor.stop()
diff --git a/gns3server/modules/dynamips/nios/__init__.py b/gns3server/modules/dynamips/nios/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/gns3server/modules/dynamips/nios/nio.py b/gns3server/modules/dynamips/nios/nio.py
new file mode 100644
index 00000000..41346ce5
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio.py
@@ -0,0 +1,236 @@
+# -*- 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 .
+
+"""
+Base interface for Dynamips Network Input/Output (NIO) module ("nio").
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L451
+"""
+
+from ..dynamips_error import DynamipsError
+
+
+class NIO(object):
+ """
+ Base NIO class
+
+ :param hypervisor: Dynamips hypervisor object
+ """
+
+ def __init__(self, hypervisor):
+
+ self._hypervisor = hypervisor
+ self._bandwidth = None # no bandwidth constraint by default
+ self._input_filter = None # no input filter applied by default
+ self._output_filter = None # no output filter applied by default
+ self._input_filter_options = None # no input filter options by default
+ self._output_filter_options = None # no output filter options by default
+ self._dynamips_direction = {"in": 0, "out": 1, "both": 2}
+
+ def list(self):
+ """
+ Returns all NIOs.
+
+ :returns: NIO list
+ """
+
+ return self._hypervisor.send("nio list")
+
+ def delete(self):
+ """
+ Deletes this NIO.
+ """
+
+ self._hypervisor.send("nio delete {}".format(self._name))
+
+ def rename(self, new_name):
+ """
+ Renames this NIO
+
+ :param new_name: new NIO name
+ """
+
+ self._hypervisor.send("nio rename {name} {new_name}".format(name=self._name,
+ new_name=new_name))
+ self._name = new_name
+
+ def debug(self, debug):
+ """
+ Enables/Disables debugging for this NIO.
+
+ :param debug: debug value (0 = disable, enable = 1)
+ """
+
+ self._hypervisor.send("nio set_debug {name} {debug}".format(name=self._name,
+ debug=debug))
+
+ def bind_filter(self, direction, filter_name):
+ """
+ Adds a packet filter to this NIO.
+ Filter "freq_drop" drops packets.
+ Filter "capture" captures packets.
+
+ :param direction: "in", "out" or "both"
+ :param filter_name: name of the filter to apply
+ """
+
+ if direction not in self._dynamips_direction:
+ raise DynamipsError("Unknown direction {} to bind filter {}:".format(direction, filter_name))
+ dynamips_direction = self._dynamips_direction[direction]
+
+ self._hypervisor.send("nio bind_filter {name} {direction} {filter}".format(name=self._name,
+ direction=dynamips_direction,
+ filter=filter_name))
+
+ if direction == "in":
+ self._input_filter = filter_name
+ elif direction == "out":
+ self._output_filter = filter_name
+ elif direction == "both":
+ self._input_filter = filter_name
+ self._output_filter = filter_name
+
+ def unbind_filter(self, direction):
+ """
+ Removes packet filter for this NIO.
+
+ :param direction: "in", "out" or "both"
+ """
+
+ if direction not in self._dynamips_direction:
+ raise DynamipsError("Unknown direction {} to unbind filter:".format(direction))
+ dynamips_direction = self._dynamips_direction[direction]
+
+ self._hypervisor.send("nio unbind_filter {name} {direction}".format(name=self._name,
+ direction=dynamips_direction))
+
+ if direction == "in":
+ self._input_filter = None
+ elif direction == "out":
+ self._output_filter = None
+ elif direction == "both":
+ self._input_filter = None
+ self._output_filter = None
+
+ def setup_filter(self, direction, options):
+ """
+ Setups a packet filter binded with this NIO.
+
+ Filter "freq_drop" has 1 argument "". It will drop
+ everything with a -1 frequency, drop every Nth packet with a
+ positive frequency, or drop nothing.
+
+ Filter "capture" has 2 arguments " ".
+ It will capture packets to the target output file. The link type
+ name is a case-insensitive DLT_ name from the PCAP library
+ constants with the DLT_ part removed.See http://www.tcpdump.org/linktypes.html
+ for a list of all available DLT values.
+
+ :param direction: "in", "out" or "both"
+ :param options: options for the packet filter (string)
+ """
+
+ if direction not in self._dynamips_direction:
+ raise DynamipsError("Unknown direction {} to setup filter:".format(direction))
+ dynamips_direction = self._dynamips_direction[direction]
+
+ self._hypervisor.send("nio setup_filter {name} {direction} {options}".format(name=self._name,
+ direction=dynamips_direction,
+ options=options))
+
+ if direction == "in":
+ self._input_filter_options = options
+ elif direction == "out":
+ self._output_filter_options = options
+ elif direction == "both":
+ self._input_filter_options = options
+ self._output_filter_options = options
+
+ @property
+ def input_filter(self):
+ """
+ Returns the input packet filter for this NIO.
+
+ :returns: tuple (filter name, filter options)
+ """
+
+ return (self._input_filter, self._input_filter_options)
+
+ @property
+ def output_filter(self):
+ """
+ Returns the output packet filter for this NIO.
+
+ :returns: tuple (filter name, filter options)
+ """
+
+ return (self._output_filter, self._output_filter_options)
+
+ def get_stats(self):
+ """
+ Gets statistics for this NIO.
+
+ :returns: NIO statistics (string with packets in, packets out, bytes in, bytes out)
+ """
+
+ return self._hypervisor.send("nio get_stats {}".format(self._name))[0]
+
+ def reset_stats(self):
+ """
+ Resets statistics for this NIO.
+ """
+
+ self._hypervisor.send("nio reset_stats {}".format(self._name))
+
+ def set_bandwidth(self, bandwidth):
+ """
+ Set bandwidth constraint.
+
+ :param bandwidth: bandwidth integer value (in Kb/s)
+ """
+
+ self._hypervisor.send("nio set_bandwidth {name} {bandwidth}".format(name=self._name,
+ bandwidth=bandwidth))
+ self._bandwidth = bandwidth
+
+ @property
+ def bandwidth(self):
+ """
+ Returns the bandwidth constraint for this NIO.
+
+ :returns: bandwidth integer value (in Kb/s)
+ """
+
+ return self._bandwidth
+
+ def __str__(self):
+ """
+ NIO string representation.
+
+ :returns: NIO name
+ """
+
+ return self._name
+
+ @property
+ def name(self):
+ """
+ Returns the NIO name.
+
+ :returns: NIO name
+ """
+
+ return self._name
diff --git a/gns3server/modules/dynamips/nios/nio_fifo.py b/gns3server/modules/dynamips/nios/nio_fifo.py
new file mode 100644
index 00000000..e4153f53
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio_fifo.py
@@ -0,0 +1,53 @@
+# -*- 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 FIFO NIOs.
+"""
+
+from .nio import NIO
+
+
+class NIO_FIFO(NIO):
+ """
+ Dynamips FIFO NIO.
+
+ :param hypervisor: Dynamips hypervisor object
+ """
+
+ _instance_count = 0
+
+ def __init__(self, hypervisor):
+
+ NIO.__init__(self, hypervisor)
+
+ # create an unique ID
+ self._id = NIO_FIFO._instance_count
+ NIO_FIFO._instance_count += 1
+ self._name = 'nio_fifo' + str(self._id)
+
+ self._hypervisor.send("nio create_fifo {}".format(self._name))
+
+ def crossconnect(self, nio):
+ """
+ Establishes a cross-connect between this FIFO NIO and another one.
+
+ :param nio: FIFO NIO object.
+ """
+
+ self._hypervisor.send("nio crossconnect_fifo {name} {nio}".format(name=self._name,
+ nio=nio))
diff --git a/gns3server/modules/dynamips/nios/nio_generic_ethernet.py b/gns3server/modules/dynamips/nios/nio_generic_ethernet.py
new file mode 100644
index 00000000..48a2c9c5
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio_generic_ethernet.py
@@ -0,0 +1,56 @@
+# -*- 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 generic Ethernet NIOs (PCAP library).
+"""
+
+from .nio import NIO
+
+
+class NIO_GenericEthernet(NIO):
+ """
+ Dynamips generic Ethernet NIO.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param ethernet_device: Ethernet device name (e.g. eth0)
+ """
+
+ _instance_count = 0
+
+ def __init__(self, hypervisor, ethernet_device):
+
+ NIO.__init__(self, hypervisor)
+
+ # create an unique ID
+ self._id = NIO_GenericEthernet._instance_count
+ NIO_GenericEthernet._instance_count += 1
+ self._name = 'nio_gen_eth' + str(self._id)
+ self._ethernet_device = ethernet_device
+
+ self._hypervisor.send("nio create_gen_eth {name} {eth_device}".format(name=self._name,
+ eth_device=ethernet_device))
+
+ @property
+ def ethernet_device(self):
+ """
+ Returns the Ethernet device used by this NIO.
+
+ :returns: the Ethernet device name
+ """
+
+ return self._ethernet_device
diff --git a/gns3server/modules/dynamips/nios/nio_linux_ethernet.py b/gns3server/modules/dynamips/nios/nio_linux_ethernet.py
new file mode 100644
index 00000000..afee21b9
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio_linux_ethernet.py
@@ -0,0 +1,56 @@
+# -*- 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 Linux Ethernet NIOs (Linux only).
+"""
+
+from .nio import NIO
+
+
+class NIO_LinuxEthernet(NIO):
+ """
+ Dynamips Linux Ethernet NIO.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param ethernet_device: Ethernet device name (e.g. eth0)
+ """
+
+ _instance_count = 0
+
+ def __init__(self, hypervisor, ethernet_device):
+
+ NIO.__init__(self, hypervisor)
+
+ # create an unique ID
+ self._id = NIO_LinuxEthernet._instance_count
+ NIO_LinuxEthernet._instance_count += 1
+ self._name = 'nio_linux_eth' + str(self._id)
+ self._ethernet_device = ethernet_device
+
+ self._hypervisor.send("nio create_linux_eth {name} {eth_device}".format(name=self._name,
+ eth_device=ethernet_device))
+
+ @property
+ def ethernet_device(self):
+ """
+ Returns the Ethernet device used by this NIO.
+
+ :returns: the Ethernet device name
+ """
+
+ return self._ethernet_device
diff --git a/gns3server/modules/dynamips/nios/nio_mcast.py b/gns3server/modules/dynamips/nios/nio_mcast.py
new file mode 100644
index 00000000..6b80fd65
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio_mcast.py
@@ -0,0 +1,92 @@
+# -*- 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 multicast NIOs.
+"""
+
+from .nio import NIO
+
+
+class NIO_Mcast(NIO):
+ """
+ Dynamips Linux Ethernet NIO.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param group: multicast group to bind
+ :param port: port for binding
+ """
+
+ _instance_count = 0
+
+ def __init__(self, hypervisor, group, port):
+
+ NIO.__init__(self, hypervisor)
+
+ # create an unique ID
+ self._id = NIO_Mcast._instance_count
+ NIO_Mcast._instance_count += 1
+ self._name = 'nio_mcast' + str(self._id)
+ self._group = group
+ self._port = port
+ self._ttl = 1 # default TTL
+
+ self._hypervisor.send("nio create_mcast {name} {mgroup} {mport}".format(name=self._name,
+ mgroup=group,
+ mport=port))
+
+ @property
+ def group(self):
+ """
+ Returns the multicast group
+
+ :returns: multicast group address
+ """
+
+ return self._group
+
+ @property
+ def port(self):
+ """
+ Returns the port
+
+ :returns: port number
+ """
+
+ return self._port
+
+ @property
+ def ttl(self):
+ """
+ Returns the TTL associated with the multicast address.
+
+ :returns: TTL value
+ """
+
+ return self._ttl
+
+ @ttl.setter
+ def ttl(self, ttl):
+ """
+ Set the TTL for the multicast address
+
+ :param ttl: TTL value
+ """
+
+ self._hypervisor.send("nio set_mcast_ttl {name} {ttl}".format(name=self._name,
+ ttl=ttl))
+ self._ttl = ttl
diff --git a/gns3server/modules/dynamips/nios/nio_null.py b/gns3server/modules/dynamips/nios/nio_null.py
new file mode 100644
index 00000000..7795e2c4
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio_null.py
@@ -0,0 +1,43 @@
+# -*- 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 dummy NIOs (mostly for tests).
+"""
+
+from .nio import NIO
+
+
+class NIO_Null(NIO):
+ """
+ Dynamips NULL NIO.
+
+ :param hypervisor: Dynamips hypervisor object
+ """
+
+ _instance_count = 0
+
+ def __init__(self, hypervisor):
+
+ NIO.__init__(self, hypervisor)
+
+ # create an unique ID
+ self._id = NIO_Null._instance_count
+ NIO_Null._instance_count += 1
+ self._name = 'nio_null' + str(self._id)
+
+ self._hypervisor.send("nio create_null {}".format(self._name))
diff --git a/gns3server/modules/dynamips/nios/nio_tap.py b/gns3server/modules/dynamips/nios/nio_tap.py
new file mode 100644
index 00000000..28ce710d
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio_tap.py
@@ -0,0 +1,56 @@
+# -*- 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 TAP NIOs (UNIX based OSes only).
+"""
+
+from .nio import NIO
+
+
+class NIO_TAP(NIO):
+ """
+ Dynamips TAP NIO.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param tap_device: TAP device name (e.g. tap0)
+ """
+
+ _instance_count = 0
+
+ def __init__(self, hypervisor, tap_device):
+
+ NIO.__init__(self, hypervisor)
+
+ # create an unique ID
+ self._id = NIO_TAP._instance_count
+ NIO_TAP._instance_count += 1
+ self._name = 'nio_tap' + str(self._id)
+ self._tap_device = tap_device
+
+ self._hypervisor.send("nio create_tap {name} {tap}".format(name=self._name,
+ tap=tap_device))
+
+ @property
+ def tap_device(self):
+ """
+ Returns the TAP device used by this NIO.
+
+ :returns: the TAP device name
+ """
+
+ return self._tap_device
diff --git a/gns3server/modules/dynamips/nios/nio_udp.py b/gns3server/modules/dynamips/nios/nio_udp.py
new file mode 100644
index 00000000..6021cfe9
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio_udp.py
@@ -0,0 +1,82 @@
+# -*- 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 UDP NIOs.
+"""
+
+from .nio import NIO
+
+
+class NIO_UDP(NIO):
+ """
+ Dynamips UDP NIO.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param lport: local port number
+ :param rhost: remote address/host
+ :param rport: remote port number
+ """
+
+ _instance_count = 0
+
+ def __init__(self, hypervisor, lport, rhost, rport):
+
+ NIO.__init__(self, hypervisor)
+
+ # create an unique ID
+ self._id = NIO_UDP._instance_count
+ NIO_UDP._instance_count += 1
+ self._name = 'nio_udp' + str(self._id)
+ self._lport = lport
+ self._rhost = rhost
+ self._rport = rport
+
+ self._hypervisor.send("nio create_udp {name} {lport} {rhost} {rport}".format(name=self._name,
+ lport=lport,
+ rhost=rhost,
+ rport=rport))
+
+ @property
+ def lport(self):
+ """
+ Returns the local port
+
+ :returns: local port number
+ """
+
+ return self._lport
+
+ @property
+ def rhost(self):
+ """
+ Returns the remote host
+
+ :returns: remote address/host
+ """
+
+ return self._rhost
+
+ @property
+ def rport(self):
+ """
+ Returns the remote port
+
+ :returns: remote port number
+ """
+
+ return self._rport
diff --git a/gns3server/modules/dynamips/nios/nio_udp_auto.py b/gns3server/modules/dynamips/nios/nio_udp_auto.py
new file mode 100644
index 00000000..eedbbcd5
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio_udp_auto.py
@@ -0,0 +1,106 @@
+# -*- 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.
+"""
+
+from .nio import NIO
+
+
+class NIO_UDP_auto(NIO):
+ """
+ Dynamips auto UDP NIO.
+
+ :param hypervisor: Dynamips hypervisor object
+ :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):
+
+ NIO.__init__(self, hypervisor)
+
+ # create an unique ID
+ self._id = NIO_UDP_auto._instance_count
+ NIO_UDP_auto._instance_count += 1
+ self._name = 'nio_udp_auto' + str(self._id)
+
+ self._laddr = laddr
+ self._lport = int(self._hypervisor.send("nio create_udp_auto {name} {laddr} {lport_start} {lport_end}".format(name=self._name,
+ laddr=laddr,
+ lport_start=lport_start,
+ lport_end=lport_end))[0])
+ self._raddr = None
+ self._rport = None
+
+ @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
+
+ def connect(self, raddr, rport):
+ """
+ Connects this NIO to a remote socket
+
+ :param raddr: remote address
+ :param rport: remote port number
+ """
+
+ self._hypervisor.send("nio connect_udp_auto {name} {raddr} {rport}".format(name=self._name,
+ raddr=raddr,
+ rport=rport))
+ self._raddr = raddr
+ self._rport = rport
diff --git a/gns3server/modules/dynamips/nios/nio_unix.py b/gns3server/modules/dynamips/nios/nio_unix.py
new file mode 100644
index 00000000..304c7f72
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio_unix.py
@@ -0,0 +1,69 @@
+# -*- 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 UNIX NIOs (Unix based OSes only).
+"""
+
+from .nio import NIO
+
+
+class NIO_UNIX(NIO):
+ """
+ Dynamips UNIX NIO.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param local_file: local UNIX socket filename
+ :param remote_file: remote UNIX socket filename
+ """
+
+ _instance_count = 0
+
+ def __init__(self, hypervisor, local_file, remote_file):
+
+ NIO.__init__(self, hypervisor)
+
+ # create an unique ID
+ self._id = NIO_UNIX._instance_count
+ NIO_UNIX._instance_count += 1
+ self._name = 'nio_unix' + str(self._id)
+ self._local_file = local_file
+ self._remote_file = remote_file
+
+ self._hypervisor.send("nio create_unix {name} {local} {remote}".format(name=self._name,
+ local=local_file,
+ remote=remote_file))
+
+ @property
+ def local_file(self):
+ """
+ Returns the local UNIX socket.
+
+ :returns: local UNIX socket filename
+ """
+
+ return self._local_file
+
+ @property
+ def remote_file(self):
+ """
+ Returns the remote UNIX socket.
+
+ :returns: remote UNIX socket filename
+ """
+
+ return self._remote_file
diff --git a/gns3server/modules/dynamips/nios/nio_vde.py b/gns3server/modules/dynamips/nios/nio_vde.py
new file mode 100644
index 00000000..9f4df297
--- /dev/null
+++ b/gns3server/modules/dynamips/nios/nio_vde.py
@@ -0,0 +1,69 @@
+# -*- 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 VDE (Virtual Distributed Ethernet) NIOs (Unix based OSes only).
+"""
+
+from .nio import NIO
+
+
+class NIO_VDE(NIO):
+ """
+ Dynamips VDE NIO.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param control_file: VDE control filename
+ :param local_file: VDE local filename
+ """
+
+ _instance_count = 0
+
+ def __init__(self, hypervisor, control_file, local_file):
+
+ NIO.__init__(self, hypervisor)
+
+ # create an unique ID
+ self._id = NIO_VDE._instance_count
+ NIO_VDE._instance_count += 1
+ self._name = 'nio_vde' + str(self._id)
+ self._control_file = control_file
+ self._local_file = local_file
+
+ self._hypervisor.send("nio create_vde {name} {control} {local}".format(name=self._name,
+ control=control_file,
+ local=local_file))
+
+ @property
+ def control_file(self):
+ """
+ Returns the VDE control file.
+
+ :returns: VDE control filename
+ """
+
+ return self._control_file
+
+ @property
+ def local_file(self):
+ """
+ Returns the VDE local file.
+
+ :returns: VDE local filename
+ """
+
+ return self._local_file
diff --git a/gns3server/modules/dynamips/nodes/__init__.py b/gns3server/modules/dynamips/nodes/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/gns3server/modules/dynamips/nodes/atm_bridge.py b/gns3server/modules/dynamips/nodes/atm_bridge.py
new file mode 100644
index 00000000..1028249f
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/atm_bridge.py
@@ -0,0 +1,170 @@
+# -*- 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 Dynamips virtual ATM bridge module ("atm_bridge").
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L622
+"""
+
+from __future__ import unicode_literals
+from ..dynamips_error import DynamipsError
+
+
+class ATMBridge(object):
+ """
+ Dynamips bridge switch.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this switch
+ """
+
+ def __init__(self, hypervisor, name):
+
+ self._hypervisor = hypervisor
+ self._name = '"' + name + '"' # put name into quotes to protect spaces
+ self._hypervisor.send("atm_bridge create {}".format(self._name))
+ self._hypervisor.devices.append(self)
+ self._nios = {}
+ self._mapping = {}
+
+ @property
+ def name(self):
+ """
+ Returns the current name of this ATM bridge.
+
+ :returns: ATM bridge name
+ """
+
+ return self._name[1:-1] # remove quotes
+
+ @property
+ def hypervisor(self):
+ """
+ Returns the current hypervisor.
+
+ :returns: hypervisor object
+ """
+
+ return self._hypervisor
+
+ def list(self):
+ """
+ Returns all ATM bridge instances.
+
+ :returns: list of all ATM bridges
+ """
+
+ return self._hypervisor.send("atm_bridge list")
+
+ @property
+ def nios(self):
+ """
+ Returns all the NIOs member of this ATM bridge.
+
+ :returns: nio list
+ """
+
+ return self._nios
+
+ @property
+ def mapping(self):
+ """
+ Returns port mapping
+
+ :returns: mapping list
+ """
+
+ return self._mapping
+
+ def rename(self, new_name):
+ """
+ Renames this ATM bridge.
+
+ :param new_name: New name for this bridge
+ """
+
+ new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
+ self._hypervisor.send("atm_bridge rename {name} {new_name}".format(name=self._name,
+ new_name=new_name))
+ self._name = new_name
+
+ def delete(self):
+ """
+ Deletes this ATM bridge.
+ """
+
+ self._hypervisor.send("atm_bridge delete {}".format(self._name))
+ self._hypervisor.devices.remove(self)
+
+ def add_nio(self, nio, port):
+ """
+ Adds a NIO as new port on ATM bridge.
+
+ :param nio: NIO object to add
+ :param port: port to allocate for the NIO
+ """
+
+ if port in self._nios:
+ raise DynamipsError("Port {} isn't free".format(port))
+
+ self._nios[port] = nio
+
+ def remove_nio(self, port):
+ """
+ Removes the specified NIO as member of this ATM switch.
+
+ :param port: allocated port
+ """
+
+ if port not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port))
+
+ del self._nios[port]
+
+ def configure(self, eth_port, atm_port, atm_vpi, atm_vci):
+ """
+ Configures this ATM bridge.
+
+ :param eth_port: Ethernet port
+ :param atm_port: ATM port
+ :param atm_vpi: ATM VPI
+ :param atm_vci: ATM VCI
+ """
+
+ if eth_port not in self._nios:
+ raise DynamipsError("Ethernet port {} is not allocated".format(eth_port))
+
+ if atm_port not in self._nios:
+ raise DynamipsError("ATM port {} is not allocated".format(atm_port))
+
+ eth_nio = self._nios[eth_port]
+ atm_nio = self._nios[atm_port]
+
+ self._hypervisor.send("atm_bridge configure {name} {eth_nio} {atm_nio} {vpi} {vci}".format(name=self._name,
+ eth_nio=eth_nio,
+ atm_nio=atm_nio,
+ vpi=atm_vpi,
+ vci=atm_vci))
+ self._mapping[eth_port] = (atm_port, atm_vpi, atm_vci)
+
+ def unconfigure(self):
+ """
+ Unconfigures this ATM bridge.
+ """
+
+ self._hypervisor.send("atm_bridge unconfigure {}".format(self._name))
+ del self._mapping
diff --git a/gns3server/modules/dynamips/nodes/atm_switch.py b/gns3server/modules/dynamips/nodes/atm_switch.py
new file mode 100644
index 00000000..99474912
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/atm_switch.py
@@ -0,0 +1,248 @@
+# -*- 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 Dynamips virtual ATM switch module ("atmsw").
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L593
+"""
+
+from __future__ import unicode_literals
+from ..dynamips_error import DynamipsError
+
+
+class ATMSwitch(object):
+ """
+ Dynamips ATM switch.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this switch
+ """
+
+ def __init__(self, hypervisor, name):
+
+ self._hypervisor = hypervisor
+ self._name = '"' + name + '"' # put name into quotes to protect spaces
+ self._hypervisor.send("atmsw create {}".format(self._name))
+ self._hypervisor.devices.append(self)
+ self._nios = {}
+ self._mapping = {}
+
+ @property
+ def name(self):
+ """
+ Returns the current name of this ATM switch.
+
+ :returns: ATM switch name
+ """
+
+ return self._name[1:-1] # remove quotes
+
+ @property
+ def hypervisor(self):
+ """
+ Returns the current hypervisor.
+
+ :returns: hypervisor object
+ """
+
+ return self._hypervisor
+
+ def list(self):
+ """
+ Returns all ATM switches instances.
+
+ :returns: list of all ATM switches
+ """
+
+ return self._hypervisor.send("atmsw list")
+
+ @property
+ def nios(self):
+ """
+ Returns all the NIOs member of this ATM switch.
+
+ :returns: nio list
+ """
+
+ return self._nios
+
+ @property
+ def mapping(self):
+ """
+ Returns port mapping
+
+ :returns: mapping list
+ """
+
+ return self._mapping
+
+ def rename(self, new_name):
+ """
+ Renames this ATM switch.
+
+ :param new_name: New name for this switch
+ """
+
+ new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
+ self._hypervisor.send("atmsw rename {name} {new_name}".format(name=self._name,
+ new_name=new_name))
+ self._name = new_name
+
+ def delete(self):
+ """
+ Deletes this ATM switch.
+ """
+
+ self._hypervisor.send("atmsw delete {}".format(self._name))
+ self._hypervisor.devices.remove(self)
+
+ def add_nio(self, nio, port):
+ """
+ Adds a NIO as new port on ATM switch.
+
+ :param nio: NIO object to add
+ :param port: port to allocate for the NIO
+ """
+
+ if port in self._nios:
+ raise DynamipsError("Port {} isn't free".format(port))
+
+ self._nios[port] = nio
+
+ def remove_nio(self, port):
+ """
+ Removes the specified NIO as member of this ATM switch.
+
+ :param port: allocated port
+ """
+
+ if port not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port))
+
+ del self._nios[port]
+
+ def map_vp(self, port1, vpi1, port2, vpi2):
+ """
+ Creates a new Virtual Path connection.
+
+ :param port1: input port
+ :param vpi1: input vpi
+ :param port2: output port
+ :param vpi2: output vpi
+ """
+
+ if port1 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port1))
+
+ if port2 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port2))
+
+ nio1 = self._nios[port1]
+ nio2 = self._nios[port2]
+
+ self._hypervisor.send("atmsw create_vpc {name} {input_nio} {input_vpi} {output_nio} {output_vpi}".format(name=self._name,
+ input_nio=nio1,
+ input_vpi=vpi1,
+ output_nio=nio2,
+ output_vpi=vpi2))
+ self._mapping[(port1, vpi1)] = (port2, vpi2)
+
+ def unmap_vp(self, port1, vpi1, port2, vpi2):
+ """
+ Deletes a new Virtual Path connection.
+
+ :param port1: input port
+ :param vpi1: input vpi
+ :param port2: output port
+ :param vpi2: output vpi
+ """
+
+ if port1 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port1))
+
+ if port2 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port2))
+
+ nio1 = self._nios[port1]
+ nio2 = self._nios[port2]
+
+ self._hypervisor.send("atmsw delete_vpc {name} {input_nio} {input_vpi} {output_nio} {output_vpi}".format(name=self._name,
+ input_nio=nio1,
+ input_vpi=vpi1,
+ output_nio=nio2,
+ output_vpi=vpi2))
+ del self._mapping[(port1, vpi1)]
+
+ def map_pvc(self, port1, vpi1, vci1, port2, vpi2, vci2):
+ """
+ Creates a new Virtual Channel connection (unidirectional).
+
+ :param port1: input port
+ :param vpi1: input vpi
+ :param vci1: input vci
+ :param port2: output port
+ :param vpi2: output vpi
+ :param vci2: output vci
+ """
+
+ if port1 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port1))
+
+ if port2 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port2))
+
+ nio1 = self._nios[port1]
+ nio2 = self._nios[port2]
+
+ self._hypervisor.send("atmsw create_vcc {name} {input_nio} {input_vpi} {input_vci} {output_nio} {output_vpi} {output_vci}".format(name=self._name,
+ input_nio=nio1,
+ input_vpi=vpi1,
+ input_vci=vci1,
+ output_nio=nio2,
+ output_vpi=vpi2,
+ output_vci=vci2))
+ self._mapping[(port1, vpi1, vci1)] = (port2, vpi2, vci2)
+
+ def unmap_pvc(self, port1, vpi1, vci1, port2, vpi2, vci2):
+ """
+ Deletes a new Virtual Channel connection (unidirectional).
+
+ :param port1: input port
+ :param vpi1: input vpi
+ :param vci1: input vci
+ :param port2: output port
+ :param vpi2: output vpi
+ :param vci2: output vci
+ """
+
+ if port1 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port1))
+
+ if port2 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port2))
+
+ nio1 = self._nios[port1]
+ nio2 = self._nios[port2]
+
+ self._hypervisor.send("atmsw delete_vcc {name} {input_nio} {input_vpi} {input_vci} {output_nio} {output_vpi} {output_vci}".format(name=self._name,
+ input_nio=nio1,
+ input_vpi=vpi1,
+ input_vci=vci1,
+ output_nio=nio2,
+ output_vpi=vpi2,
+ output_vci=vci2))
+ del self._mapping[(port1, vpi1, vci1)]
diff --git a/gns3server/modules/dynamips/nodes/bridge.py b/gns3server/modules/dynamips/nodes/bridge.py
new file mode 100644
index 00000000..9e5a8af1
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/bridge.py
@@ -0,0 +1,121 @@
+# -*- 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 Dynamips NIO bridge module ("nio_bridge").
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L538
+"""
+
+from __future__ import unicode_literals
+
+
+class Bridge(object):
+ """
+ Dynamips bridge.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this bridge
+ """
+
+ def __init__(self, hypervisor, name):
+
+ self._hypervisor = hypervisor
+ self._name = '"' + name + '"' # put name into quotes to protect spaces
+ self._hypervisor.send("nio_bridge create {}".format(self._name))
+ self._hypervisor.devices.append(self)
+ self._nios = []
+
+ @property
+ def name(self):
+ """
+ Returns the current name of this bridge.
+
+ :returns: bridge name
+ """
+
+ return self._name[1:-1] # remove quotes
+
+ @property
+ def hypervisor(self):
+ """
+ Returns the current hypervisor.
+
+ :returns: hypervisor object
+ """
+
+ return self._hypervisor
+
+ def list(self):
+ """
+ Returns all bridge instances.
+
+ :returns: list of all bridges
+ """
+
+ return self._hypervisor.send("nio_bridge list")
+
+ @property
+ def nios(self):
+ """
+ Returns all the NIOs member of this bridge.
+
+ :returns: nio list
+ """
+
+ return self._nios
+
+ def rename(self, new_name):
+ """
+ Renames this bridge.
+
+ :param new_name: New name for this bridge
+ """
+
+ new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
+ self._hypervisor.send("nio_bridge rename {name} {new_name}".format(name=self._name,
+ new_name=new_name))
+ self._name = new_name
+
+ def delete(self):
+ """
+ Deletes this bridge.
+ """
+
+ self._hypervisor.send("nio_bridge delete {}".format(self._name))
+ self._hypervisor.devices.remove(self)
+
+ def add_nio(self, nio):
+ """
+ Adds a NIO as new port on this bridge.
+
+ :param nio: NIO object to add
+ """
+
+ self._hypervisor.send("nio_bridge add_nio {name} {nio}".format(name=self._name,
+ nio=nio))
+ self._nios.append(nio)
+
+ def remove_nio(self, nio):
+ """
+ Removes the specified NIO as member of this bridge.
+
+ :param nio: NIO object to remove
+ """
+
+ self._hypervisor.send("nio_bridge remove_nio {name} {nio}".format(name=self._name,
+ nio=nio))
+ self._nios.remove(nio)
diff --git a/gns3server/modules/dynamips/nodes/c1700.py b/gns3server/modules/dynamips/nodes/c1700.py
new file mode 100644
index 00000000..96b4ec72
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/c1700.py
@@ -0,0 +1,125 @@
+# -*- 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 Dynamips virtual Cisco 1700 instances module ("c1700")
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L428
+"""
+
+from __future__ import unicode_literals
+from .router import Router
+from ..adapters.c1700_mb_1fe import C1700_MB_1FE
+from ..adapters.c1700_mb_wic1 import C1700_MB_WIC1
+
+
+class C1700(Router):
+ """
+ Dynamips c1700 router.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this router
+ :param chassis: chassis for this router:
+ 1720, 1721, 1750, 1751 or 1760 (default = 1720).
+ 1710 is not supported.
+ """
+
+ def __init__(self, hypervisor, name, chassis="1720"):
+ Router.__init__(self, hypervisor, name, platform="c1700")
+
+ # Set default values for this platform
+ self._ram = 64
+ self._nvram = 32
+ self._disk0 = 0
+ self._disk1 = 0
+ self._chassis = chassis
+ self._iomem = 15 # percentage
+ self._clock_divisor = 8
+
+ if chassis != "1720":
+ self.chassis = chassis
+
+ self._setup_chassis()
+
+ def list(self):
+ """
+ Returns all c1700 instances
+
+ :returns: c1700 instance list
+ """
+
+ return self._hypervisor.send("c1700 list")
+
+ def _setup_chassis(self):
+ """
+ Set up the router with the corresponding chassis
+ (create slots and insert default adapters).
+ """
+
+ # With 1751 and 1760, WICs in WIC slot 1 show up as in slot 1, not 0
+ # e.g. s1/0 not s0/2
+ if self._chassis in ['1751', '1760']:
+ self._create_slots(2)
+ self._slots[1] = C1700_MB_WIC1()
+ else:
+ self._create_slots(1)
+ self._slots[0] = C1700_MB_1FE()
+
+ @property
+ def chassis(self):
+ """
+ Returns the chassis.
+
+ :returns: chassis string
+ """
+
+ return self._chassis
+
+ @chassis.setter
+ def chassis(self, chassis):
+ """
+ Set the chassis.
+
+ :param: chassis string:
+ 1720, 1721, 1750, 1751 or 1760
+ """
+
+ self._hypervisor.send("c1700 set_chassis {name} {chassis}".format(name=self._name,
+ chassis=chassis))
+ self._chassis = chassis
+ self._setup_chassis()
+
+ @property
+ def iomem(self):
+ """
+ Returns I/O memory size for this router.
+
+ :returns: I/O memory size (integer)
+ """
+
+ return self._iomem
+
+ @iomem.setter
+ def iomem(self, iomem):
+ """
+ Set I/O memory size for this router.
+
+ :param iomem: I/O memory size
+ """
+
+ self._hypervisor.send("c1700 set_iomem {name} {size}".format(name=self._name,
+ size=iomem))
+ self._iomem = iomem
diff --git a/gns3server/modules/dynamips/nodes/c2600.py b/gns3server/modules/dynamips/nodes/c2600.py
new file mode 100644
index 00000000..eaf75cde
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/c2600.py
@@ -0,0 +1,135 @@
+# -*- 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 Dynamips virtual Cisco 2600 instances module ("c2600")
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L404
+"""
+
+from __future__ import unicode_literals
+from .router import Router
+from ..adapters.c2600_mb_1e import C2600_MB_1E
+from ..adapters.c2600_mb_2e import C2600_MB_2E
+from ..adapters.c2600_mb_1fe import C2600_MB_1FE
+from ..adapters.c2600_mb_2fe import C2600_MB_2FE
+
+
+class C2600(Router):
+ """
+ Dynamips c2600 router.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this router
+ :param chassis: chassis for this router:
+ 2610, 2611, 2620, 2621, 2610XM, 2611XM
+ 2620XM, 2621XM, 2650XM or 2651XM (default = 2610).
+ """
+
+ # adapters to insert by default corresponding the
+ # chosen chassis.
+ integrated_adapters = {'2610': C2600_MB_1E,
+ '2611': C2600_MB_2E,
+ '2620': C2600_MB_1FE,
+ '2621': C2600_MB_2FE,
+ '2610XM': C2600_MB_1FE,
+ '2611XM': C2600_MB_2FE,
+ '2620XM': C2600_MB_1FE,
+ '2621XM': C2600_MB_2FE,
+ '2650XM': C2600_MB_1FE,
+ '2651XM': C2600_MB_2FE}
+
+ def __init__(self, hypervisor, name, chassis="2610"):
+ Router.__init__(self, hypervisor, name, platform="c2600")
+
+ # Set default values for this platform
+ self._ram = 64
+ self._nvram = 128
+ self._disk0 = 0
+ self._disk1 = 0
+ self._chassis = chassis
+ self._iomem = 15 # percentage
+ self._clock_divisor = 8
+
+ if chassis != "2610":
+ self.chassis = chassis
+
+ self._setup_chassis()
+
+ def list(self):
+ """
+ Returns all c2600 instances
+
+ :returns: c2600 instance list
+ """
+
+ return self._hypervisor.send("c2600 list")
+
+ def _setup_chassis(self):
+ """
+ Set up the router with the corresponding chassis
+ (create slots and insert default adapters).
+ """
+
+ self._create_slots(2)
+ self._slots[0] = self.integrated_adapters[self._chassis]()
+
+ @property
+ def chassis(self):
+ """
+ Returns the chassis.
+
+ :returns: chassis string
+ """
+
+ return self._chassis
+
+ @chassis.setter
+ def chassis(self, chassis):
+ """
+ Set the chassis.
+
+ :param: chassis string:
+ 2610, 2611, 2620, 2621, 2610XM, 2611XM
+ 2620XM, 2621XM, 2650XM or 2651XM
+ """
+
+ self._hypervisor.send("c2600 set_chassis {name} {chassis}".format(name=self._name,
+ chassis=chassis))
+ self._chassis = chassis
+ self._setup_chassis()
+
+ @property
+ def iomem(self):
+ """
+ Returns I/O memory size for this router.
+
+ :returns: I/O memory size (integer)
+ """
+
+ return self._iomem
+
+ @iomem.setter
+ def iomem(self, iomem):
+ """
+ Set I/O memory size for this router.
+
+ :param iomem: I/O memory size
+ """
+
+ self._hypervisor.send("c2600 set_iomem {name} {size}".format(name=self._name,
+ size=iomem))
+ self._iomem = iomem
diff --git a/gns3server/modules/dynamips/nodes/c2691.py b/gns3server/modules/dynamips/nodes/c2691.py
new file mode 100644
index 00000000..d075bbd5
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/c2691.py
@@ -0,0 +1,79 @@
+# -*- 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 Dynamips virtual Cisco 2691 instances module ("c2691")
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L387
+"""
+
+from __future__ import unicode_literals
+from .router import Router
+from ..adapters.gt96100_fe import GT96100_FE
+
+
+class C2691(Router):
+ """
+ Dynamips c2691 router.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this router
+ """
+
+ def __init__(self, hypervisor, name):
+ Router.__init__(self, hypervisor, name, platform="c2691")
+
+ # Set default values for this platform
+ self._ram = 128
+ self._nvram = 112
+ self._disk0 = 16
+ self._disk1 = 0
+ self._iomem = 5 # percentage
+ self._clock_divisor = 8
+
+ self._create_slots(2)
+ self._slots[0] = GT96100_FE()
+
+ def list(self):
+ """
+ Returns all c2691 instances
+
+ :returns: c2691 instance list
+ """
+
+ return self._hypervisor.send("c2691 list")
+
+ @property
+ def iomem(self):
+ """
+ Returns I/O memory size for this router.
+
+ :returns: I/O memory size (integer)
+ """
+
+ return self._iomem
+
+ @iomem.setter
+ def iomem(self, iomem):
+ """
+ Set I/O memory size for this router.
+
+ :param iomem: I/O memory size
+ """
+
+ self._hypervisor.send("c2691 set_iomem {name} {size}".format(name=self._name,
+ size=iomem))
+ self._iomem = iomem
diff --git a/gns3server/modules/dynamips/nodes/c3600.py b/gns3server/modules/dynamips/nodes/c3600.py
new file mode 100644
index 00000000..7806da54
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/c3600.py
@@ -0,0 +1,121 @@
+# -*- 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 Dynamips virtual Cisco 3600 instances module ("c3600")
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L366
+"""
+
+from __future__ import unicode_literals
+from .router import Router
+from ..adapters.leopard_2fe import Leopard_2FE
+
+
+class C3600(Router):
+ """
+ Dynamips c3600 router.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this router
+ :param chassis: chassis for this router:
+ 3620, 3640 or 3660 (default = 3640).
+ """
+
+ def __init__(self, hypervisor, name, chassis="3640"):
+ Router.__init__(self, hypervisor, name, platform="c3600")
+
+ # Set default values for this platform
+ self._ram = 128
+ self._nvram = 128
+ self._disk0 = 0
+ self._disk1 = 0
+ self._iomem = 5 # percentage
+ self._chassis = chassis
+ self._clock_divisor = 4
+
+ if chassis != "3640":
+ self.chassis = chassis
+
+ self._setup_chassis()
+
+ def list(self):
+ """
+ Returns all c3600 instances
+
+ :returns: c3600 instance list
+ """
+
+ return self._hypervisor.send("c3600 list")
+
+ def _setup_chassis(self):
+ """
+ Set up the router with the corresponding chassis
+ (create slots and insert default adapters).
+ """
+
+ if self._chassis == "3620":
+ self._create_slots(2)
+ elif self._chassis == "3640":
+ self._create_slots(4)
+ elif self._chassis == "3660":
+ self._create_slots(7)
+ self._slots[0] = Leopard_2FE()
+
+ @property
+ def chassis(self):
+ """
+ Returns the chassis.
+
+ :returns: chassis string
+ """
+
+ return self._chassis
+
+ @chassis.setter
+ def chassis(self, chassis):
+ """
+ Set the chassis.
+
+ :param: chassis string: 3620, 3640 or 3660
+ """
+
+ self._hypervisor.send("c3600 set_chassis {name} {chassis}".format(name=self._name,
+ chassis=chassis))
+ self._chassis = chassis
+ self._setup_chassis()
+
+ @property
+ def iomem(self):
+ """
+ Returns I/O memory size for this router.
+
+ :returns: I/O memory size (integer)
+ """
+
+ return self._iomem
+
+ @iomem.setter
+ def iomem(self, iomem):
+ """
+ Set I/O memory size for this router.
+
+ :param iomem: I/O memory size
+ """
+
+ self._hypervisor.send("c3600 set_iomem {name} {size}".format(name=self._name,
+ size=iomem))
+ self._iomem = iomem
diff --git a/gns3server/modules/dynamips/nodes/c3725.py b/gns3server/modules/dynamips/nodes/c3725.py
new file mode 100644
index 00000000..1730b48d
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/c3725.py
@@ -0,0 +1,79 @@
+# -*- 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 Dynamips virtual Cisco 3725 instances module ("c3725")
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L346
+"""
+
+from __future__ import unicode_literals
+from .router import Router
+from ..adapters.gt96100_fe import GT96100_FE
+
+
+class C3725(Router):
+ """
+ Dynamips c3725 router.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this router
+ """
+
+ def __init__(self, hypervisor, name):
+ Router.__init__(self, hypervisor, name, platform="c3725")
+
+ # Set default values for this platform
+ self._ram = 128
+ self._nvram = 112
+ self._disk0 = 16
+ self._disk1 = 0
+ self._iomem = 5 # percentage
+ self._clock_divisor = 8
+
+ self._create_slots(3)
+ self._slots[0] = GT96100_FE()
+
+ def list(self):
+ """
+ Returns all c3725 instances.
+
+ :returns: c3725 instance list
+ """
+
+ return self._hypervisor.send("c3725 list")
+
+ @property
+ def iomem(self):
+ """
+ Returns I/O memory size for this router.
+
+ :returns: I/O memory size (integer)
+ """
+
+ return self._iomem
+
+ @iomem.setter
+ def iomem(self, iomem):
+ """
+ Set I/O memory size for this router.
+
+ :param iomem: I/O memory size
+ """
+
+ self._hypervisor.send("c3725 set_iomem {name} {size}".format(name=self._name,
+ size=iomem))
+ self._iomem = iomem
diff --git a/gns3server/modules/dynamips/nodes/c3745.py b/gns3server/modules/dynamips/nodes/c3745.py
new file mode 100644
index 00000000..1ed94a40
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/c3745.py
@@ -0,0 +1,79 @@
+# -*- 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 Dynamips virtual Cisco 3745 instances module ("c3745")
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L326
+"""
+
+from __future__ import unicode_literals
+from .router import Router
+from ..adapters.gt96100_fe import GT96100_FE
+
+
+class C3745(Router):
+ """
+ Dynamips c3745 router.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this router
+ """
+
+ def __init__(self, hypervisor, name):
+ Router.__init__(self, hypervisor, name, platform="c3745")
+
+ # Set default values for this platform
+ self._ram = 128
+ self._nvram = 304
+ self._disk0 = 16
+ self._disk1 = 0
+ self._iomem = 5 # percentage
+ self._clock_divisor = 8
+
+ self._create_slots(5)
+ self._slots[0] = GT96100_FE()
+
+ def list(self):
+ """
+ Returns all c3745 instances.
+
+ :returns: c3745 instance list
+ """
+
+ return self._hypervisor.send("c3745 list")
+
+ @property
+ def iomem(self):
+ """
+ Returns I/O memory size for this router.
+
+ :returns: I/O memory size (integer)
+ """
+
+ return self._iomem
+
+ @iomem.setter
+ def iomem(self, iomem):
+ """
+ Set I/O memory size for this router.
+
+ :param iomem: I/O memory size
+ """
+
+ self._hypervisor.send("c3745 set_iomem {name} {size}".format(name=self._name,
+ size=iomem))
+ self._iomem = iomem
diff --git a/gns3server/modules/dynamips/nodes/c7200.py b/gns3server/modules/dynamips/nodes/c7200.py
new file mode 100644
index 00000000..baa981c6
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/c7200.py
@@ -0,0 +1,187 @@
+# -*- 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 Dynamips virtual Cisco 7200 instances module ("c7200")
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L294
+"""
+
+
+from __future__ import unicode_literals
+from ..dynamips_error import DynamipsError
+from .router import Router
+from ..adapters.c7200_io_2fe import C7200_IO_2FE
+from ..adapters.c7200_io_ge_e import C7200_IO_GE_E
+
+
+class C7200(Router):
+ """
+ Dynamips c7200 router (model is 7206).
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this router
+ :param npe: default NPE
+ """
+
+ def __init__(self, hypervisor, name, npe="npe-400"):
+ Router.__init__(self, hypervisor, name, platform="c7200")
+
+ # Set default values for this platform
+ self._ram = 256
+ self._nvram = 128
+ self._disk0 = 64
+ self._disk1 = 0
+ self._npe = npe
+ self._midplane = "vxr"
+ self._clock_divisor = 4
+
+ if npe != "npe-400":
+ self.npe = npe
+
+ # 4 sensors with a default temperature of 22C:
+ # sensor 1 = I/0 controller inlet
+ # sensor 2 = I/0 controller outlet
+ # sensor 3 = NPE inlet
+ # sensor 4 = NPE outlet
+ self._sensors = [22, 22, 22, 22]
+
+ # 2 power supplies powered on
+ self._power_supplies = [1, 1]
+
+ self._create_slots(7)
+
+ # first slot is a mandatory Input/Output controller (based on NPE type)
+ if npe == "npe-g2":
+ self._slots[0] = C7200_IO_GE_E()
+ else:
+ self._slots[0] = C7200_IO_2FE()
+
+ def list(self):
+ """
+ Returns all c7200 instances.
+
+ :returns: c7200 instance list
+ """
+
+ return self._hypervisor.send("c7200 list")
+
+ @property
+ def npe(self):
+ """
+ Returns the NPE model.
+
+ :returns: NPE model string (e.g. "npe-200")
+ """
+
+ return self._npe
+
+ @npe.setter
+ def npe(self, npe):
+ """
+ Set the NPE model.
+
+ :params npe: NPE model string (e.g. "npe-200")
+ NPE models are npe-100, npe-150, npe-175, npe-200,
+ npe-225, npe-300, npe-400 and npe-g2 (PowerPC c7200 only)
+ """
+
+ if self.is_running():
+ raise DynamipsError("Cannot change NPE on running router")
+
+ self._hypervisor.send("c7200 set_npe {name} {npe}".format(name=self._name,
+ npe=npe))
+ self._npe = npe
+
+ @property
+ def midplane(self):
+ """
+ Returns the midplane model.
+
+ :returns: midplane model string (e.g. "vxr" or "std")
+ """
+
+ return self._midplane
+
+ @midplane.setter
+ def midplane(self, midplane):
+ """
+ Set the midplane model.
+
+ :returns: midplane model string (e.g. "vxr" or "std")
+ """
+
+ self._hypervisor.send("c7200 set_midplane {name} {midplane}".format(name=self._name,
+ midplane=midplane))
+ self._midplane = midplane
+
+ @property
+ def sensors(self):
+ """
+ Returns the 4 sensors with temperature in degree Celcius.
+
+ :returns: list of 4 sensor temperatures
+ """
+
+ return self._sensors
+
+ @sensors.setter
+ def sensors(self, sensors):
+ """
+ Set the 4 sensors with temperature in degree Celcius.
+
+ :param sensors: list of 4 sensor temperatures corresponding to
+ sensor 1 = I/0 controller inlet
+ sensor 2 = I/0 controller outlet
+ sensor 3 = NPE inlet
+ sensor 4 = NPE outlet
+ Example: [22, 22, 22, 22]
+ """
+
+ sensor_id = 0
+ for sensor in sensors:
+ self._hypervisor.send("c7200 set_temp_sensor {name} {sensor_id} {temp}".format(name=self._name,
+ sensor_id=sensor_id,
+ temp=sensor))
+ sensor_id += 1
+ self._sensors = sensors
+
+ @property
+ def power_supplies(self):
+ """
+ Returns the 2 power supplies with 0 = off, 1 = on.
+
+ :returns: list of 2 power supplies.
+ """
+
+ return self._power_supplies
+
+ @power_supplies.setter
+ def power_supplies(self, power_supplies):
+ """
+ Set the 2 power supplies with 0 = off, 1 = on.
+
+ :param power_supplies: list of 2 power supplies.
+ Example: [1, 0] = first power supply is on, second is off.
+ """
+
+ power_supply_id = 0
+ for power_supply in power_supplies:
+ self._hypervisor.send("c7200 set_power_supply {name} {power_supply_id} {powered_on}".format(name=self._name,
+ power_supply_id=power_supply_id,
+ powered_on=power_supply))
+ power_supply_id += 1
+ self._power_supplies = power_supplies
diff --git a/gns3server/modules/dynamips/nodes/ethernet_switch.py b/gns3server/modules/dynamips/nodes/ethernet_switch.py
new file mode 100644
index 00000000..b0bde746
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/ethernet_switch.py
@@ -0,0 +1,212 @@
+# -*- 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 Dynamips virtual Ethernet switch module ("ethsw").
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L558
+"""
+
+
+from __future__ import unicode_literals
+from ..dynamips_error import DynamipsError
+
+
+class EthernetSwitch(object):
+ """
+ Dynamips Ethernet switch.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this switch
+ """
+
+ def __init__(self, hypervisor, name):
+
+ self._hypervisor = hypervisor
+ self._name = '"' + name + '"' # put name into quotes to protect spaces
+ self._hypervisor.send("ethsw create {}".format(self._name))
+ self._hypervisor.devices.append(self)
+ self._nios = {}
+ self._mapping = {}
+
+ @property
+ def name(self):
+ """
+ Returns the current name of this Ethernet switch.
+
+ :returns: Ethernet switch name
+ """
+
+ return self._name[1:-1] # remove quotes
+
+ @property
+ def hypervisor(self):
+ """
+ Returns the current hypervisor.
+
+ :returns: hypervisor object
+ """
+
+ return self._hypervisor
+
+ def list(self):
+ """
+ Returns all Ethernet switches instances.
+
+ :returns: list of all Ethernet switches
+ """
+
+ return self._hypervisor.send("ethsw list")
+
+ @property
+ def nios(self):
+ """
+ Returns all the NIOs member of this Ethernet switch.
+
+ :returns: nio list
+ """
+
+ return self._nios
+
+ @property
+ def mapping(self):
+ """
+ Returns port mapping
+
+ :returns: mapping list
+ """
+
+ return self._mapping
+
+ def rename(self, new_name):
+ """
+ Renames this Ethernet switch.
+
+ :param new_name: New name for this switch
+ """
+
+ new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
+ self._hypervisor.send("ethsw rename {name} {new_name}".format(name=self._name,
+ new_name=new_name))
+ self._name = new_name
+
+ def delete(self):
+ """
+ Deletes this Ethernet switch.
+ """
+
+ self._hypervisor.send("ethsw delete {}".format(self._name))
+ self._hypervisor.devices.remove(self)
+
+ def add_nio(self, nio, port):
+ """
+ Adds a NIO as new port on Ethernet switch.
+
+ :param nio: NIO object to add
+ :param port: port to allocate for the NIO
+ """
+
+ if port in self._nios:
+ raise DynamipsError("Port {} isn't free".format(port))
+
+ self._hypervisor.send("ethsw add_nio {name} {nio}".format(name=self._name,
+ nio=nio))
+ self._nios[port] = nio
+
+ def remove_nio(self, port):
+ """
+ Removes the specified NIO as member of this Ethernet switch.
+
+ :param port: allocated port
+ """
+
+ if port not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port))
+
+ nio = self._nios[port]
+ self._hypervisor.send("ethsw remove_nio {name} {nio}".format(name=self._name,
+ nio=nio))
+ del self._nios[port]
+
+ if port in self._mapping:
+ del self._mapping[port]
+
+ def set_access_port(self, port, vlan_id):
+ """
+ Set the specified port as an ACCESS port.
+
+ :param port: allocated port
+ :param vlan_id: VLAN number membership
+ """
+
+ if port not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port))
+
+ nio = self._nios[port]
+ self._hypervisor.send("ethsw set_access_port {name} {nio} {vlan_id}".format(name=self._name,
+ nio=nio,
+ vlan_id=vlan_id))
+ self._mapping[port] = ("access", vlan_id)
+
+ def set_dot1q_port(self, port, native_vlan):
+ """
+ Set the specified port as a 802.1Q trunk port.
+
+ :param port: allocated port
+ :param native_vlan: native VLAN for this trunk port
+ """
+
+ if port not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port))
+
+ nio = self._nios[port]
+ self._hypervisor.send("ethsw set_dot1q_port {name} {nio} {native_vlan}".format(name=self._name,
+ nio=nio,
+ native_vlan=native_vlan))
+ self._mapping[port] = ("dot1q", native_vlan)
+
+ def set_qinq_port(self, port, outer_vlan):
+ """
+ Set the specified port as a trunk (QinQ) port.
+
+ :param port: allocated port
+ :param outer_vlan: outer VLAN (transport VLAN) for this QinQ port
+ """
+
+ if port not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port))
+
+ nio = self._nios[port]
+ self._hypervisor.send("ethsw set_qinq_port {name} {nio} {outer_vlan}".format(name=self._name,
+ nio=nio,
+ outer_vlan=outer_vlan))
+ self._mapping[port] = ("qinq", outer_vlan)
+
+ def get_mac_addr_table(self):
+ """
+ Returns the MAC address table for this Ethernet switch.
+
+ :returns: list of entries (Ethernet address, VLAN, NIO)
+ """
+
+ return self._hypervisor.send("ethsw show_mac_addr_table {}".format(self._name))
+
+ def clear_mac_addr_table(self):
+ """
+ Clears the MAC address table for this Ethernet switch.
+ """
+
+ self._hypervisor.send("ethsw clear_mac_addr_table {}".format(self._name))
diff --git a/gns3server/modules/dynamips/nodes/frame_relay_switch.py b/gns3server/modules/dynamips/nodes/frame_relay_switch.py
new file mode 100644
index 00000000..d27f282a
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/frame_relay_switch.py
@@ -0,0 +1,188 @@
+# -*- 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 Dynamips virtual Frame-Relay switch module.
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L642
+"""
+
+from __future__ import unicode_literals
+from ..dynamips_error import DynamipsError
+
+
+class FrameRelaySwitch(object):
+ """
+ Dynamips Frame Relay switch.
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this switch
+ """
+
+ def __init__(self, hypervisor, name):
+
+ self._hypervisor = hypervisor
+ self._name = '"' + name + '"' # put name into quotes to protect spaces
+ self._hypervisor.send("frsw create {}".format(self._name))
+ self._hypervisor.devices.append(self)
+ self._nios = {}
+ self._mapping = {}
+
+ @property
+ def name(self):
+ """
+ Returns the current name of this Frame Relay switch.
+
+ :returns: Frame Relay switch name
+ """
+
+ return self._name[1:-1] # remove quotes
+
+ @property
+ def hypervisor(self):
+ """
+ Returns the current hypervisor.
+
+ :returns: hypervisor object
+ """
+
+ return self._hypervisor
+
+ def list(self):
+ """
+ Returns all Frame Relay switches instances.
+
+ :returns: list of all Frame Relay switches
+ """
+
+ return self._hypervisor.send("frsw list")
+
+ @property
+ def nios(self):
+ """
+ Returns all the NIOs member of this Frame Relay switch.
+
+ :returns: nio list
+ """
+
+ return self._nios
+
+ @property
+ def mapping(self):
+ """
+ Returns port mapping
+
+ :returns: mapping list
+ """
+
+ return self._mapping
+
+ def rename(self, new_name):
+ """
+ Renames this Frame Relay switch.
+
+ :param new_name: New name for this switch
+ """
+
+ new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
+ self._hypervisor.send("frsw rename {name} {new_name}".format(name=self._name,
+ new_name=new_name))
+ self._name = new_name
+
+ def delete(self):
+ """
+ Deletes this Frame Relay switch.
+ """
+
+ self._hypervisor.send("frsw delete {}".format(self._name))
+ self._hypervisor.devices.remove(self)
+
+ def add_nio(self, nio, port):
+ """
+ Adds a NIO as new port on Frame Relay switch.
+
+ :param nio: NIO object to add
+ :param port: port to allocate for the NIO
+ """
+
+ if port in self._nios:
+ raise DynamipsError("Port {} isn't free".format(port))
+
+ self._nios[port] = nio
+
+ def remove_nio(self, port):
+ """
+ Removes the specified NIO as member of this Frame Relay switch.
+
+ :param port: allocated port
+ """
+
+ if port not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port))
+
+ del self._nios[port]
+
+ def map_vc(self, port1, dlci1, port2, dlci2):
+ """
+ Creates a new Virtual Circuit connection (unidirectional).
+
+ :param port1: input port
+ :param dlci1: input DLCI
+ :param port2: output port
+ :param dlci2: output DLCI
+ """
+
+ if port1 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port1))
+
+ if port2 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port2))
+
+ nio1 = self._nios[port1]
+ nio2 = self._nios[port2]
+
+ self._hypervisor.send("frsw create_vc {name} {input_nio} {input_dlci} {output_nio} {output_dlci}".format(name=self._name,
+ input_nio=nio1,
+ input_dlci=dlci1,
+ output_nio=nio2,
+ output_dlci=dlci2))
+ self._mapping[(port1, dlci1)] = (port2, dlci2)
+
+ def unmap_vc(self, port1, dlci1, port2, dlci2):
+ """
+ Deletes a Virtual Circuit connection (unidirectional).
+
+ :param port1: input port
+ :param dlci1: input DLCI
+ :param port2: output port
+ :param dlci2: output DLCI
+ """
+
+ if port1 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port1))
+
+ if port2 not in self._nios:
+ raise DynamipsError("Port {} is not allocated".format(port2))
+
+ nio1 = self._nios[port1]
+ nio2 = self._nios[port2]
+
+ self._hypervisor.send("frsw delete_vc {name} {input_nio} {input_dlci} {output_nio} {output_dlci}".format(name=self._name,
+ input_nio=nio1,
+ input_dlci=dlci1,
+ output_nio=nio2,
+ output_dlci=dlci2))
+ del self._mapping[(port1, dlci1)]
diff --git a/gns3server/modules/dynamips/nodes/hub.py b/gns3server/modules/dynamips/nodes/hub.py
new file mode 100644
index 00000000..ff3f8c41
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/hub.py
@@ -0,0 +1,76 @@
+# -*- 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 .
+
+"""
+Hub object that uses the Bridge interface to create a hub with ports.
+"""
+
+from __future__ import unicode_literals
+from .bridge import Bridge
+from ..dynamips_error import DynamipsError
+
+
+class Hub(Bridge):
+ """
+ Dynamips hub (based on Bridge)
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this hub
+ """
+
+ def __init__(self, hypervisor, name):
+
+ Bridge.__init__(self, hypervisor, name)
+ self._mapping = {}
+
+ @property
+ def mapping(self):
+ """
+ Returns port mapping
+
+ :returns: mapping list
+ """
+
+ return self._mapping
+
+ def add_nio(self, nio, port):
+ """
+ Adds a NIO as new port on this hub.
+
+ :param nio: NIO object to add
+ :param port: port to allocate for the NIO
+ """
+
+ if port in self._mapping:
+ raise DynamipsError("Port {} isn't free".format(port))
+
+ Bridge.add_nio(self, nio)
+ self._mapping[port] = nio
+
+ def remove_nio(self, port):
+ """
+ Removes the specified NIO as member of this hub.
+
+ :param port: allocated port
+ """
+
+ if port not in self._mapping:
+ raise DynamipsError("Port {} is not allocated".format(port))
+
+ nio = self._mapping[port]
+ Bridge.remove_nio(self, nio)
+ del self._mapping[port]
diff --git a/gns3server/modules/dynamips/nodes/router.py b/gns3server/modules/dynamips/nodes/router.py
new file mode 100644
index 00000000..16259299
--- /dev/null
+++ b/gns3server/modules/dynamips/nodes/router.py
@@ -0,0 +1,1085 @@
+# -*- 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 Dynamips virtual Machine module ("vm")
+http://github.com/GNS3/dynamips/blob/master/README.hypervisor#L77
+"""
+
+from __future__ import unicode_literals
+from ..dynamips_error import DynamipsError
+import os
+
+
+class Router(object):
+ """
+ Dynamips router
+
+ :param hypervisor: Dynamips hypervisor object
+ :param name: name for this router
+ :param platform: c7200, c3745, c3725, c3600, c2691, c2600 or c1700
+ :param console_flag: create console ports if True.
+ """
+
+ _instance_count = 0
+ _status = {0: "inactive",
+ 1: "shutting down",
+ 2: "running",
+ 3: "suspended"}
+
+ def __init__(self, hypervisor, name, platform="c7200", console_flag=True):
+
+ # create an unique ID
+ self._id = Router._instance_count
+ Router._instance_count += 1
+
+ self._hypervisor = hypervisor
+ self._name = '"' + name + '"' # put name into quotes to protect spaces
+ self._platform = platform
+ self._image = ""
+ self._ram = 128 # Megabytes
+ self._nvram = 128 # Kilobytes
+ self._mmap = True
+ self._sparsemem = True
+ self._clock_divisor = 8
+ self._idlepc = ""
+ self._idlemax = 1500
+ self._idlesleep = 30
+ self._ghost_file = ""
+ self._ghost_status = 0
+ self._exec_area = None # Megabytes (None = default for the router platform)
+ self._jit_sharing_group = None
+ self._disk0 = 0 # Megabytes
+ self._disk1 = 0 # Megabytes
+ self._confreg = '0x2102'
+ self._console = None
+ self._aux = None
+ self._mac_addr = None
+ self._system_id = None # processor board ID in IOS
+ self._slots = []
+
+ self._hypervisor.send("vm create {name} {id} {platform}".format(name=self._name,
+ id=self._id,
+ platform=self._platform))
+
+ if console_flag:
+ self.console = self._hypervisor.baseconsole + self._id
+ self.aux = self._hypervisor.baseaux + self._id
+
+ self._hypervisor.devices.append(self)
+
+ @property
+ def id(self):
+ """
+ Returns the unique ID for this router.
+
+ :returns: id (integer)
+ """
+
+ return self._id
+
+ @property
+ def name(self):
+ """
+ Returns the name of this router.
+
+ :returns: name (string)
+ """
+
+ return self._name[1:-1] # remove quotes
+
+ @property
+ def platform(self):
+ """
+ Returns the platform of this router.
+
+ :returns: platform name (string):
+ c7200, c3745, c3725, c3600, c2691, c2600 or c1700
+ """
+
+ return self._platform
+
+ @property
+ def hypervisor(self):
+ """
+ Returns the current hypervisor.
+
+ :returns: hypervisor object
+ """
+
+ return self._hypervisor
+
+ def list(self):
+ """
+ Returns all VM instances
+
+ :returns: list of all VM instances
+ """
+
+ return self._hypervisor.send("vm list")
+
+ def list_con_ports(self):
+ """
+ Returns all VM console TCP ports
+
+ :returns: list of port numbers
+ """
+
+ return self._hypervisor.send("vm list_con_ports")
+
+ def rename(self, new_name):
+ """
+ Renames this router.
+
+ :param new_name: new name string
+ """
+
+ new_name = '"' + new_name + '"' # put the new name into quotes to protect spaces
+ self._hypervisor.send("vm rename {name} {new_name}".format(name=self._name,
+ new_name=new_name))
+ self._name = new_name
+
+ def delete(self):
+ """
+ Deletes this router.
+ """
+
+ self._hypervisor.send("vm delete {}".format(self._name))
+ self._hypervisor.devices.remove(self)
+
+ def start(self):
+ """
+ Starts this router.
+ At least the IOS image must be set.
+ """
+
+ self._hypervisor.send("vm start {}".format(self._name))
+
+ def stop(self):
+ """
+ Stops this router.
+ The settings are kept.
+ """
+
+ self._hypervisor.send("vm stop {}".format(self._name))
+
+ def suspend(self):
+ """
+ Suspends this router
+ """
+
+ self._hypervisor.send("vm suspend {}".format(self._name))
+
+ def resume(self):
+ """
+ Resumes this suspended router
+ """
+
+ self._hypervisor.send("vm resume {}".format(self._name))
+
+ def get_status(self):
+ """
+ Returns the status of this router
+
+ :returns: 0=inactive, 1=shutting down, 2=running, 3=suspended
+ """
+
+ status_id = int(self._hypervisor.send("vm get_status {}".format(self._name))[0])
+ return self._status[status_id]
+
+ def is_running(self):
+ """
+ Checks if this router is running.
+
+ :returns: True if running, False otherwise
+ """
+
+ if self.get_status() == "running":
+ return True
+ return False
+
+ @property
+ def jit_sharing_group(self):
+ """
+ Returns the JIT sharing group for this router.
+
+ :returns: translation sharing group ID
+ """
+
+ return self._jit_sharing_group
+
+ @jit_sharing_group.setter
+ def jit_sharing_group(self, group_id):
+ """
+ Set the translation sharing group (unstable).
+
+ :param group_id: translation sharing group ID
+ """
+
+ if not self._image:
+ raise DynamipsError("Register an IOS image fist")
+
+ self._hypervisor.send("vm set_tsg {name} {group_id}".format(name=self._name,
+ group_id=group_id))
+
+ self._jit_sharing_group = group_id
+ self._hypervisor.add_jitsharing_group(os.path.basename(self._image), group_id)
+
+ def set_debug_level(self, level):
+ """
+ Set the debug level for this router (default is 0).
+
+ :param level: level number
+ """
+
+ self._hypervisor.send("vm set_debug_level {name} {level}".format(name=self._name,
+ level=level))
+
+ @property
+ def image(self):
+ """
+ Returns this IOS image for this router.
+
+ :returns: path to IOS image file
+ """
+
+ return self._image
+
+ @image.setter
+ def image(self, image):
+ """
+ Set the IOS image for this router.
+ There is no default.
+
+ :param image: path to IOS image file
+ """
+
+ # encase image in quotes to protect spaces in the path
+ self._hypervisor.send("vm set_ios {name} {image}".format(name=self._name,
+ image='"' + image + '"'))
+ self._image = image
+
+ def set_config(self, startup_config, private_config=''):
+ """
+ Set the config files that are pushed to startup-config and
+ private-config in NVRAM when the instance is started.
+
+ :param startup_config: path to statup-config file
+ :param private_config: path to private-config file
+ (keep existing data when if an empty string)
+ """
+
+ self._hypervisor.send("vm set_config {name} {startup} {private}".format(name=self._name,
+ startup='"' + startup_config + '"',
+ private='"' + private_config + '"'))
+
+ def extract_config(self):
+ """
+ Gets the contents of the config files
+ startup-config and private-config from NVRAM.
+
+ :returns: tuple (startup-config, private-config) base64 encoded
+ """
+
+ try:
+ reply = self._hypervisor.send("vm extract_config {}".format(self._name))[0].rsplit(' ', 2)[-2:]
+ except IOError:
+ #for some reason Dynamips gets frozen when it does not find the magic number in the NVRAM file.
+ return (None, None)
+ startup_config = reply[0][1:-1] # get statup-config and remove single quotes
+ private_config = reply[1][1:-1] # get private-config and remove single quotes
+ return (startup_config, private_config)
+
+ def push_config(self, startup_config, private_config='(keep)'):
+ """
+ Pushes configuration to the config files startup-config and private-config in NVRAM.
+ The data is a Base64 encoded string, or '(keep)' to keep existing data.
+
+ :param startup_config: statup-config string base64 encoded
+ :param private_config: private-config string base64 encoded
+ (keep existing data when if the value is ('keep'))
+ """
+
+ self._hypervisor.send("vm push_config {name} {startup} {private}".format(name=self._name,
+ startup=startup_config,
+ private=private_config))
+
+ @property
+ def ram(self):
+ """
+ Returns the amount of RAM allocated to this router.
+
+ :returns: amount of RAM in Mbytes (integer)
+ """
+
+ return self._ram
+
+ @ram.setter
+ def ram(self, ram):
+ """
+ Set amount of RAM allocated to this router
+
+ :param ram: amount of RAM in Mbytes (integer)
+ """
+
+ self._hypervisor.send("vm set_ram {name} {ram}".format(name=self._name,
+ ram=self._ram))
+ self._hypervisor.decrease_memory_load(self._ram)
+ self._ram = ram
+ self._hypervisor.increase_memory_load(self._ram)
+
+ @property
+ def nvram(self):
+ """
+ Returns the mount of NVRAM allocated to this router.
+
+ :returns: amount of NVRAM in Kbytes (integer)
+ """
+
+ return self._nvram
+
+ @nvram.setter
+ def nvram(self, nvram):
+ """
+ Set amount of NVRAM allocated to this router
+
+ :param nvram: amount of NVRAM in Kbytes (integer)
+ """
+
+ self._hypervisor.send("vm set_nvram {name} {nvram}".format(name=self._name,
+ nvram=self._nvram))
+ self._nvram = nvram
+
+ @property
+ def mmap(self):
+ """
+ Returns True if a mapped file is used to simulate this router memory.
+
+ :returns: boolean either mmap is activated or not
+ """
+
+ return self._mmap
+
+ @mmap.setter
+ def mmap(self, mmap):
+ """
+ Enable/Disable use of a mapped file to simulate router memory.
+ By default, a mapped file is used. This is a bit slower, but requires less memory.
+
+ :param mmap: activate/deactivate mmap (boolean)
+ """
+
+ if mmap:
+ flag = 1
+ else:
+ flag = 0
+ self._hypervisor.send("vm set_ram_mmap {name} {mmap}".format(name=self._name,
+ mmap=flag))
+ self._mmap = mmap
+
+ @property
+ def sparsemem(self):
+ """
+ Returns True if sparse memory is used on this router.
+
+ :returns: boolean either mmap is activated or not
+ """
+
+ return self._sparsemem
+
+ @sparsemem.setter
+ def sparsemem(self, sparsemem):
+ """
+ Enable/disable use of sparse memory
+
+ :param sparsemem: activate/deactivate sparsemem (boolean)
+ """
+
+ if sparsemem:
+ flag = 1
+ else:
+ flag = 0
+ self._hypervisor.send("vm set_sparse_mem {name} {sparsemem}".format(name=self._name,
+ sparsemem=flag))
+ self._sparsemem = sparsemem
+
+ @property
+ def clock_divisor(self):
+ """
+ Returns the clock divisor value for this router.
+
+ :returns: clock divisor value (integer)
+ """
+
+ return self._clock_divisor
+
+ @clock_divisor.setter
+ def clock_divisor(self, clock_divisor):
+ """
+ Set the clock divisor value. The higher is the value, the faster is the clock in the
+ virtual machine. The default is 4, but it is often required to adjust it.
+
+ :param clock_divisor: clock divisor value (integer)
+ """
+
+ self._hypervisor.send("vm set_clock_divisor {name} {clock}".format(name=self._name,
+ clock=clock_divisor))
+ self._clock_divisor = clock_divisor
+
+ @property
+ def idlepc(self):
+ """
+ Returns the idle Pointer Counter (PC).
+
+ :returns: idlepc value (string)
+ """
+
+ return self._idlepc
+
+ @idlepc.setter
+ def idlepc(self, idlepc):
+ """
+ Set the idle Pointer Counter (PC)
+
+ :param idlepc: idlepc value (string)
+ """
+
+ if not self.is_running():
+ # router is not running
+ self._hypervisor.send("vm set_idle_pc {name} {idlepc}".format(name=self._name,
+ idlepc=idlepc))
+ else:
+ self._hypervisor.send("vm set_idle_pc_online {name} 0 {idlepc}".format(name=self._name,
+ idlepc=idlepc))
+ self._idlepc = idlepc
+
+ def get_idle_pc_prop(self):
+ """
+ Gets the idle PC proposals.
+ Takes 1000 measurements and records up to 10 idle PC proposals.
+ There is a 10ms wait between each measurement.
+
+ :returns: list of idle PC proposal
+ """
+
+ return self._hypervisor.send("vm get_idle_pc_prop {} 0".format(self._name))
+
+ def show_idle_pc_prop(self):
+ """
+ Dumps the idle PC proposals (previously generated).
+
+ :returns: list of idle PC proposal
+ """
+
+ return self._hypervisor.send("vm show_idle_pc_prop {} 0".format(self._name))
+
+ @property
+ def idlemax(self):
+ """
+ Returns CPU idle max value.
+
+ :returns: idle max (integer)
+ """
+
+ return self._idlemax
+
+ @idlemax.setter
+ def idlemax(self, idlemax):
+ """
+ Set CPU idle max value
+
+ :param idlemax: idle max value (integer)
+ """
+
+ if self.is_running(): # router is running
+ self._hypervisor.send("vm set_idle_max {name} 0 {idlemax}".format(name=self._name,
+ idlemax=idlemax))
+ self._idlemax = idlemax
+
+ @property
+ def idlesleep(self):
+ """
+ Returns CPU idle sleep time value.
+
+ :returns: idle sleep (integer)
+ """
+
+ return self._idlesleep
+
+ @idlesleep.setter
+ def idlesleep(self, idlesleep):
+ """
+ Set CPU idle sleep time value.
+
+ :param idlesleep: idle sleep value (integer)
+ """
+
+ if self.is_running(): # router is running
+ self._hypervisor.send("vm set_idle_sleep_time {name} 0 {idlesleep}".format(name=self._name,
+ idlesleep=idlesleep))
+ self._idlesleep = idlesleep
+
+ def show_timer_drift(self):
+ """
+ Shows info about potential timer drift.
+
+ :returns: timer drift info.
+ """
+
+ return self._hypervisor.send("vm show_timer_drift {} 0".format(self._name))
+
+ @property
+ def ghost_file(self):
+ """
+ Returns ghost RAM file.
+
+ :returns: path to ghost file
+ """
+
+ return self._ghost_file
+
+ @ghost_file.setter
+ def ghost_file(self, ghost_file):
+ """
+ Set ghost RAM file
+
+ :ghost_file: path to ghost file
+ """
+
+ self._hypervisor.send("vm set_ghost_file {name} {ghost_file}".format(name=self._name,
+ ghost_file=ghost_file))
+ self._ghost_file = ghost_file
+
+ # If this is a ghost instance, track this as a hosted ghost instance by this hypervisor
+ if self.ghost_status == 1:
+ self._hypervisor.add_ghost(ghost_file, self)
+
+ def formatted_ghost_file(self):
+ """
+ Returns a properly formatted ghost file name.
+
+ :returns: formatted ghost_file name (string)
+ """
+
+ # Replace specials characters in 'drive:\filename' in Linux and Dynamips in MS Windows or viceversa.
+ ghost_file = os.path.basename(self._image) + '-' + self._hypervisor.host + '.ghost'
+ ghost_file = ghost_file.replace('\\', '-').replace('/', '-').replace(':', '-')
+ return ghost_file
+
+ @property
+ def ghost_status(self):
+ """Returns ghost RAM status
+
+ :returns: ghost status (integer)
+ """
+
+ return self._ghost_status
+
+ @ghost_status.setter
+ def ghost_status(self, ghost_status):
+ """
+ Set ghost RAM status
+
+ :param ghost_status: state flag indicating status
+ 0 => Do not use IOS ghosting
+ 1 => This is a ghost instance
+ 2 => Use an existing ghost instance
+ """
+
+ self._hypervisor.send("vm set_ghost_status {name} {ghost_status}".format(name=self._name,
+ ghost_status=ghost_status))
+ self._ghost_status = ghost_status
+
+ @property
+ def exec_area(self):
+ """
+ Returns the exec area value.
+
+ :returns: exec area value (integer)
+ """
+
+ return self._exec_area
+
+ @exec_area.setter
+ def exec_area(self, exec_area):
+ """
+ Set the exec area value.
+ The exec area is a pool of host memory used to store pages
+ translated by the JIT (they contain the native code
+ corresponding to MIPS code pages).
+
+ :param excec_area: exec area value (integer)
+ """
+
+ self._hypervisor.send("vm set_exec_area {name} {exec_area}".format(name=self._name,
+ exec_area=exec_area))
+ self._exec_area = exec_area
+
+ @property
+ def disk0(self):
+ """
+ Returns the size (MB) for PCMCIA disk0.
+
+ :returns: disk0 size (integer)
+ """
+
+ return self._disk0
+
+ @disk0.setter
+ def disk0(self, disk0):
+ """
+ Set the size (MB) for PCMCIA disk0.
+
+ :param disk0: disk0 size (integer)
+ """
+
+ self._hypervisor.send("vm set_disk0 {name} {disk0}".format(name=self._name,
+ disk0=disk0))
+ self._disk0 = disk0
+
+ @property
+ def disk1(self):
+ """
+ Returns the size (MB) for PCMCIA disk1.
+
+ :returns: disk1 size (integer)
+ """
+
+ return self._disk1
+
+ @disk1.setter
+ def disk1(self, disk1):
+ """
+ Set the size (MB) for PCMCIA disk1.
+
+ :param disk1: disk1 size (integer)
+ """
+
+ self._hypervisor.send("vm set_disk1 {name} {disk1}".format(name=self._name,
+ disk1=disk1))
+ self._disk1 = disk1
+
+ @property
+ def confreg(self):
+ """
+ Returns the configuration register.
+ The default is 0x2102.
+
+ :returns: configuration register value (string)
+ """
+
+ return self._confreg
+
+ @confreg.setter
+ def confreg(self, confreg):
+ """
+ Set the configuration register.
+
+ :param confreg: configuration register value (string)
+ """
+
+ self._hypervisor.send("vm set_conf_reg {name} {confreg}".format(name=self._name,
+ confreg=confreg))
+ self._confreg = confreg
+
+ @property
+ def console(self):
+ """
+ Returns the TCP console port.
+
+ :returns: console port (integer)
+ """
+
+ return self._console
+
+ @console.setter
+ def console(self, console):
+ """
+ Set the TCP console port.
+
+ :param console: console port (integer)
+ """
+
+ if console == self._console:
+ return
+
+ self._hypervisor.send("vm set_con_tcp_port {name} {console}".format(name=self._name,
+ console=console))
+ self._console = console
+
+ @property
+ def aux(self):
+ """
+ Returns the TCP auxiliary port.
+
+ :returns: console auxiliary port (integer)
+ """
+
+ return self._aux
+
+ @aux.setter
+ def aux(self, aux):
+ """
+ Set the TCP auxiliary port.
+
+ :param aux: console auxiliary port (integer)
+ """
+
+ if aux == self._aux:
+ return
+
+ self._hypervisor.send("vm set_aux_tcp_port {name} {aux}".format(name=self._name,
+ aux=aux))
+ self._aux = aux
+
+ def get_cpu_info(self, cpu_id=0):
+ """
+ Shows info about the CPU identified by cpu_id.
+ The boot CPU (which is typically the only CPU) has ID 0.
+
+ :returns: ? (could not test)
+ """
+
+ # FIXME: nothing returned by Dynamips.
+ return self._hypervisor.send("vm cpu_info {name} {cpu_id}".format(name=self._name,
+ cpu_id=cpu_id))
+
+ def get_cpu_usage(self, cpu_id=0):
+ """
+ Shows cpu usage in seconds, "cpu_id" is ignored.
+
+ :returns: cpu usage in seconds
+ """
+
+ return int(self._hypervisor.send("vm cpu_usage {name} {cpu_id}".format(name=self._name,
+ cpu_id=cpu_id))[0])
+
+ def send_console_msg(self, message):
+ """
+ Sends a message to the console.
+
+ :param message: message to send to the console
+ """
+
+ self._hypervisor.send("vm send_con_msg {name} {message}".format(name=self._name,
+ message=message))
+
+ def send_aux_msg(self, message):
+ """
+ Sends a message to the auxiliary console.
+
+ :param message: message to send to the auxiliary console
+ """
+
+ self._hypervisor.send("vm send_aux_msg {name} {message}".format(name=self._name,
+ message=message))
+
+ @property
+ def mac_addr(self):
+ """
+ Returns the MAC address.
+
+ :returns: the MAC address (hexadecimal format: hh:hh:hh:hh:hh:hh)
+ """
+
+ return self._mac_addr
+
+ @mac_addr.setter
+ def mac_addr(self, mac_addr):
+ """
+ Set the MAC address.
+
+ :param mac_addr: a MAC address (hexadecimal format: hh:hh:hh:hh:hh:hh)
+ """
+
+ self._hypervisor.send("{platform} set_mac_addr {name} {mac_addr}".format(platform=self._platform,
+ name=self._name,
+ mac_addr=mac_addr))
+ self._mac_addr = mac_addr
+
+ @property
+ def system_id(self):
+ """
+ Returns the system ID.
+
+ :returns: the system ID (also called board processor ID)
+ """
+
+ return self._system_id
+
+ @system_id.setter
+ def system_id(self, system_id):
+ """
+ Set the system ID.
+
+ :param system_id: a system ID (also called board processor ID)
+ """
+
+ self._hypervisor.send("{platform} set_system_id {name} {system_id}".format(platform=self._platform,
+ name=self._name,
+ system_id=system_id))
+ self._system_id = system_id
+
+ def get_hardware_info(self):
+ """
+ Get some hardware info about this router.
+
+ :returns: ? (could not test)
+ """
+
+ # FIXME: nothing returned by Dynamips.
+ return (self._hypervisor.send("{platform} show_hardware {name}".format(platform=self._platform,
+ name=self._name)))
+
+ def get_slot_bindings(self):
+ """
+ Returns slot bindings.
+
+ :returns: slot bindings (adapter names) list
+ """
+
+ return (self._hypervisor.send("vm slot_bindings {}".format(self._name)))
+
+ def slot_add_binding(self, slot_id, adapter):
+ """
+ Adds a slot binding.
+
+ :param slot_id: slot ID
+ :param adapter: device to add in the corresponding slot (object)
+ """
+
+ try:
+ slot = self._slots[slot_id]
+ except IndexError:
+ raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name,
+ slot_id=slot_id))
+
+ if slot != None:
+ current_adapter = slot
+ raise DynamipsError("Slot {slot_id} is already occupied by adapter {adapter} on router {name}".format(name=self._name,
+ slot_id=slot_id,
+ adapter=current_adapter))
+
+ self._hypervisor.send("vm slot_add_binding {name} {slot_id} 0 {adapter}".format(name=self._name,
+ slot_id=slot_id,
+ adapter=adapter))
+ self._slots[slot_id] = adapter
+
+ # Generate an OIR event if the router is running and
+ # only for c7200, c3600 and c3745 (NM-4T only)
+ if self.is_running() and self._platform == 'c7200' \
+ or (self._platform == 'c3600' and self.chassis == '3660') \
+ or (self._platform == 'c3745' and adapter == 'NM-4T'):
+
+ self._hypervisor.send("vm slot_oir_start {name} {slot_id} 0".format(name=self._name,
+ slot_id=slot_id))
+
+ def slot_remove_binding(self, slot_id):
+ """
+ Removes a slot binding.
+
+ :param slot_id: slot ID
+ """
+
+ try:
+ slot = self._slots[slot_id]
+ except IndexError:
+ raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name,
+ slot_id=slot_id))
+
+ if slot == None:
+ return
+
+ # Generate an OIR event if the router is running and
+ # only for c7200, c3600 and c3745 (NM-4T only)
+ if self.is_running() and self._platform == 'c7200' \
+ or (self._platform == 'c3600' and self.chassis == '3660') \
+ or (self._platform == 'c3745' and slot == 'NM-4T'):
+
+ self._hypervisor.send("vm slot_oir_stop {name} {slot_id} 0".format(name=self._name,
+ slot_id=slot_id))
+
+ self._hypervisor.send("vm slot_remove_binding {name} {slot_id} 0".format(name=self._name,
+ slot_id=slot_id))
+ self._slots[slot_id] = None
+
+ def install_wic(self, wic_slot_id, wic):
+ """
+ Installs a WIC adapter into this router.
+
+ :param wic_slot_id: WIC slot ID
+ :param wic: WIC to be install (object)
+ """
+
+ # WICs are always installed on adapters in slot 0
+ slot_id = 0
+
+ # Do not check if slot has an adapter because adapters with WICs interfaces
+ # must be inserted by default in the router and cannot be removed.
+ adapter = self._slots[slot_id]
+
+ if wic_slot_id > len(adapter.wics) - 1:
+ raise DynamipsError("WIC slot {wic_slot_id} doesn't exist".format(name=self._name,
+ wic_slot_id=wic_slot_id))
+
+ if not adapter.wic_slot_available(wic_slot_id):
+ raise DynamipsError("WIC slot {wic_slot_id} is already occupied by another WIC".format(name=self._name,
+ wic_slot_id=wic_slot_id))
+
+ # Dynamips WICs slot IDs start on a multiple of 16
+ # WIC1 = 16, WIC2 = 32 and WIC3 = 48
+ internal_wic_slot_id = 16 * (wic_slot_id + 1)
+ self._hypervisor.send("vm slot_add_binding {name} {slot_id} {wic_slot_id} {wic}".format(name=self._name,
+ slot_id=slot_id,
+ wic_slot_id=internal_wic_slot_id,
+ wic=wic))
+ adapter.install_wic(wic_slot_id, wic)
+
+ def uninstall_wic(self, wic_slot_id):
+ """
+ Uninstalls a WIC adapter from this router.
+
+ :param wic_slot_id: WIC slot ID
+ """
+
+ # WICs are always installed on adapters in slot 0
+ slot_id = 0
+
+ # Do not check if slot has an adapter because adapters with WICs interfaces
+ # must be inserted by default in the router and cannot be removed.
+ adapter = self._slots[slot_id]
+
+ if wic_slot_id > len(adapter.wics) - 1:
+ raise DynamipsError("WIC slot {wic_slot_id} doesn't exist".format(name=self._name,
+ wic_slot_id=wic_slot_id))
+
+ if adapter.wic_slot_available(wic_slot_id):
+ raise DynamipsError("No WIC is installed in WIC slot {wic_slot_id}".format(name=self._name,
+ wic_slot_id=wic_slot_id))
+ # Dynamips WICs slot IDs start on a multiple of 16
+ # WIC1 = 16, WIC2 = 32 and WIC3 = 48
+ internal_wic_slot_id = 16 * (wic_slot_id + 1)
+ self._hypervisor.send("vm slot_remove_binding {name} {slot_id} {wic_slot_id}".format(name=self._name,
+ slot_id=slot_id,
+ wic_slot_id=internal_wic_slot_id))
+ adapter.uninstall_wic(wic_slot_id)
+
+ def get_slot_nio_bindings(self, slot_id):
+ """
+ Returns slot NIO bindings.
+
+ :param slot_id: slot ID
+
+ :returns: list of NIO bindings
+ """
+
+ return (self._hypervisor.send("vm slot_nio_bindings {name} {slot_id}".format(name=self._name,
+ slot_id=slot_id)))
+
+ def slot_add_nio_binding(self, slot_id, port_id, nio):
+ """
+ Adds a slot NIO binding.
+
+ :param slot_id: slot ID
+ :param port_id: port ID
+ :param nio: NIO to add to the slot/port (object)
+ """
+
+ try:
+ adapter = self._slots[slot_id]
+ except IndexError:
+ raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name,
+ slot_id=slot_id))
+ if not adapter.port_exists(port_id):
+ raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter,
+ port_id=port_id))
+
+ self._hypervisor.send("vm slot_add_nio_binding {name} {slot_id} {port_id} {nio}".format(name=self._name,
+ slot_id=slot_id,
+ port_id=port_id,
+ nio=nio))
+ self.slot_enable_nio(slot_id, port_id)
+ adapter.add_nio(port_id, nio)
+
+ def slot_remove_nio_binding(self, slot_id, port_id):
+ """
+ Removes a slot NIO binding.
+
+ :param slot_id: slot ID
+ :param port_id: port ID
+ """
+
+ try:
+ adapter = self._slots[slot_id]
+ except IndexError:
+ raise DynamipsError("Slot {slot_id} doesn't exist on router {name}".format(name=self._name,
+ slot_id=slot_id))
+ if not adapter.port_exists(port_id):
+ raise DynamipsError("Port {port_id} doesn't exist in adapter {adapter}".format(adapter=adapter,
+ port_id=port_id))
+
+ self.slot_disable_nio(slot_id, port_id)
+ self._hypervisor.send("vm slot_remove_binding {name} {slot_id} {port_id}".format(name=self._name,
+ slot_id=slot_id,
+ port_id=port_id))
+
+ adapter.remove_nio(port_id)
+
+ def slot_enable_nio(self, slot_id, port_id):
+ """
+ Enables a slot NIO binding.
+
+ :param slot_id: slot ID
+ :param port_id: port ID
+ """
+
+ if self.is_running(): # running router
+ self._hypervisor.send("vm slot_enable_nio {name} {slot_id} {port_id}".format(name=self._name,
+ slot_id=slot_id,
+ port_id=port_id))
+
+ def slot_disable_nio(self, slot_id, port_id):
+ """
+ Disables a slot NIO binding.
+
+ :param slot_id: slot ID
+ :param port_id: port ID
+ """
+
+ if self.is_running(): # running router
+ self._hypervisor.send("vm slot_disable_nio {name} {slot_id} {port_id}".format(name=self._name,
+ slot_id=slot_id,
+ port_id=port_id))
+
+ def _create_slots(self, numslots):
+ """
+ Creates the appropriate number of slots for this router.
+
+ :param numslots: number of slots to create
+ """
+
+ self._slots = numslots * [None]
+
+ @property
+ def slots(self):
+ """
+ Returns the slots for this router.
+
+ :return: slot list
+ """
+
+ return self._slots
diff --git a/gns3server/stomp/frame.py b/gns3server/stomp/frame.py
deleted file mode 100644
index 90d83e48..00000000
--- a/gns3server/stomp/frame.py
+++ /dev/null
@@ -1,161 +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 .
-
-"""
-STOMP frame representation, decoding and encoding
-http://stomp.github.io/stomp-specification-1.2.html
-Adapted from Jason R. Briggs's code
-https://github.com/jasonrbriggs/stomp.py
-"""
-
-import re
-from .utils import encode
-
-
-class Frame(object):
- """
- A STOMP frame. Comprises a command, the headers and the body content.
- """
-
- # Used to parse STOMP header lines in the format "key:value",
- HEADER_LINE_RE = re.compile('(?P[^:]+)[:](?P.*)')
- # As of STOMP 1.2, lines can end with either line feed, or carriage return plus line feed.
- PREAMBLE_END_RE = re.compile('\n\n|\r\n\r\n')
- # As of STOMP 1.2, lines can end with either line feed, or carriage return plus line feed.
- LINE_END_RE = re.compile('\n|\r\n')
- # NULL value
- NULL = b'\x00'
-
- def __init__(self, cmd=None, headers={}, body=None):
- self._cmd = cmd
- self._headers = headers
- self._body = body
-
- @property
- def cmd(self):
-
- return(self._cmd)
-
- @cmd.setter
- def cmd(self, cmd):
-
- self._cmd = cmd
-
- @property
- def headers(self):
-
- return(self._headers)
-
- @headers.setter
- def headers(self, headers):
-
- self._headers = headers
-
- @property
- def body(self):
-
- return(self._body)
-
- @body.setter
- def body(self, body):
-
- self._body = body
-
- def encode(self):
- """
- Encodes this frame to be send on the wire
- """
-
- lines = []
- if self._cmd:
- lines.append(self._cmd)
- lines.append("\n")
- for key, vals in sorted(self._headers.items()):
- if type(vals) != tuple:
- vals = (vals,)
- for val in vals:
- lines.append("%s:%s\n" % (key, val))
- lines.append("\n")
- if self._body:
- lines.append(self._body)
-
- if self._cmd:
- lines.append(self.NULL)
-
- encoded_lines = (encode(line) for line in lines)
- return b''.join(encoded_lines)
-
- @classmethod
- def parse_headers(cls, lines, offset=0):
- """
- Parses frame headers
-
- :param lines: Frame preamble lines
- :param offset: To start parsing at the given offset
-
- :returns: Headers in dict header:value
- """
-
- headers = {}
- for header_line in lines[offset:]:
- header_match = cls.HEADER_LINE_RE.match(header_line)
- if header_match:
- key = header_match.group('key')
- if key not in headers:
- headers[key] = header_match.group('value')
- return headers
-
- @classmethod
- def parse_frame(cls, frame):
- """
- Parses a frame
-
- :params frame: The frame data to be parsed
-
- :returns: STOMP Frame object
- """
-
- f = Frame()
- # End-of-line (EOL) indicates an heart beat frame
- if frame == '\x0a':
- f.cmd = 'heartbeat' # This will have the frame ignored
- return f
-
- mat = cls.PREAMBLE_END_RE.search(frame)
- preamble_end = -1
- if mat:
- preamble_end = mat.start()
- if preamble_end == -1:
- preamble_end = len(frame)
- preamble = frame[0:preamble_end]
- preamble_lines = cls.LINE_END_RE.split(preamble)
- f.body = frame[preamble_end + 2:]
- if f.body[-1] == '\x00':
- f.body = f.body[:-1]
-
- # Skip any leading newlines
- first_line = 0
- while first_line < len(preamble_lines) and len(preamble_lines[first_line]) == 0:
- first_line += 1
-
- # Extract frame type/command
- f.cmd = preamble_lines[first_line]
-
- # Put headers into a key/value map
- f.headers = cls.parse_headers(preamble_lines, first_line + 1)
-
- return f
diff --git a/gns3server/stomp/protocol.py b/gns3server/stomp/protocol.py
deleted file mode 100644
index 0491c1bf..00000000
--- a/gns3server/stomp/protocol.py
+++ /dev/null
@@ -1,234 +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 .
-
-"""
-Basic STOMP 1.2 protocol implementation
-http://stomp.github.io/stomp-specification-1.2.html
-"""
-
-import uuid
-from .frame import Frame
-from .utils import encode, hasbyte
-
-# Commands server-side
-CMD_CONNECTED = 'CONNECTED'
-CMD_ERROR = 'ERROR'
-CMD_MESSAGE = 'MESSAGE'
-CMD_RECEIPT = 'RECEIPT'
-
-# Commands client-side
-CMD_STOMP = 'STOMP'
-CMD_CONNECT = 'CONNECT'
-CMD_DISCONNECT = 'DISCONNECT'
-CMD_SEND = 'SEND'
-
-# Commands not supported
-CMD_SUBSCRIBE = 'SUBSCRIBE'
-CMD_UNSUBSCRIBE = 'UNSUBSCRIBE'
-CMD_ACK = 'ACK'
-CMD_NACK = 'NACK'
-CMD_BEGIN = 'BEGIN'
-CMD_ABORT = 'ABORT'
-
-# Headers
-HDR_VERSION = 'version'
-HDR_SESSION = 'session'
-HDR_SERVER = 'server'
-HDR_CONTENT_TYPE = 'content-type'
-HDR_CONTENT_LENGTH = 'content-length'
-HDR_RECEIPT_ID = 'receipt-id'
-HDR_MESSAGE = 'message'
-HDR_MESSAGE_ID = 'message-id'
-HDR_ACCEPT_VERSION = 'accept-version'
-HDR_HOST = 'host'
-HDR_DESTINATION = 'destination'
-HDR_RECEIPT = 'receipt'
-
-# Headers not supported
-HDR_HEARTBEAT = 'heart-beat'
-HDR_LOGIN = 'login'
-HDR_PASSCODE = 'passcode'
-HDR_ID = 'id'
-HDR_ACK = 'ack'
-HDR_SUBSCRIPTION = 'subscription'
-HDR_TRANSACTION = 'transaction'
-
-
-class serverProtocol(object):
- """
- STOMP 1.2 protocol support for servers.
- """
-
- def __init__(self):
-
- # STOMP protocol version
- self.version = 1.2
-
- def connected(self, session=None, server=None):
- """
- Replies to the CONNECT or STOMP command.
- Heart-beat header is not supported.
-
- :param session: A session identifier that uniquely identifies the session.
- :param server: A field that contains information about the STOMP server.
-
- :returns: STOMP Frame object
- """
-
- # Version header is required
- headers = {HDR_VERSION: self.version}
-
- if session:
- headers[HDR_SESSION] = session
-
- # The server-name field consists of a name token followed by an
- # optional version number token. Example: Apache/1.3.9
- if server:
- headers[HDR_SERVER] = server
-
- return Frame(CMD_CONNECTED, headers).encode()
-
- def message(self, destination, body, content_type=None, message_id=str(uuid.uuid4())):
- """
- Sends a message to a STOMP client.
-
- :param destination: Destination string
- :param body: Data to be added in the frame body
- :param content_type: MIME type which describes the format of the body
- :param message_id: Unique identifier for that message
-
- :returns: STOMP Frame object
- """
-
- # Destination and message id headers are required
- headers = {HDR_DESTINATION: destination,
- HDR_MESSAGE_ID: message_id}
-
- # Subscription is required but not implemented on this server
- headers[HDR_SUBSCRIPTION] = 0
-
- if content_type:
- headers[HDR_CONTENT_TYPE] = content_type
-
- body = encode(body)
- if HDR_CONTENT_LENGTH not in headers and hasbyte(0, body):
- headers[HDR_CONTENT_LENGTH] = len(body)
-
- return Frame(CMD_MESSAGE, headers, body).encode()
-
- def receipt(self, receipt_id):
- """
- Sends an acknowledgment for client frame that requests a receipt.
-
- :param receipt_id: Receipt ID to send back to the client
-
- :returns: STOMP Frame object
- """
-
- # Receipt ID header is required (the same sent in the client frame)
- headers = {HDR_RECEIPT_ID: receipt_id}
- return Frame(CMD_RECEIPT, headers).encode()
-
- def error(self, message='', body='', content_type=None):
- """
- Sends an error to the client if something goes wrong.
-
- :param message: Short description of the error
- :param body: Detailed information
- :param content_type: MIME type which describes the format of the body
-
- :returns: STOMP Frame object
- """
-
- headers = {}
- if message:
- headers[HDR_MESSAGE] = message
-
- if body:
- body = encode(body)
- if HDR_CONTENT_LENGTH not in headers and hasbyte(0, body):
- headers[HDR_CONTENT_LENGTH] = len(body)
- if content_type:
- headers[HDR_CONTENT_TYPE] = content_type
-
- return Frame(CMD_ERROR, headers, body).encode()
-
-
-class clientProtocol(object):
- """
- STOMP 1.2 protocol support for clients.
- """
-
- def connect(self, host, accept_version='1.2'):
- """
- Connects to a STOMP server.
- Heart-beat, login and passcode headers are not supported.
-
- :param host: Host name that the socket was established against.
- :param accept_version: The versions of the STOMP protocol the client supports.
-
- :returns: STOMP Frame object
- """
-
- # Currently only STOMP 1.2 is supported (required header)
- headers = {HDR_ACCEPT_VERSION: accept_version}
-
- if host:
- headers[HDR_HOST] = host
-
- # The STOMP command is not backward compatible with STOMP 1.0 servers.
- # Clients that use the STOMP frame instead of the CONNECT frame will
- # only be able to connect to STOMP 1.2 servers (as well as some STOMP 1.1 servers.
- return Frame(CMD_STOMP, headers).encode()
-
- def disconnect(self, receipt=str(uuid.uuid4())):
- """
- Disconnects to a STOMP server.
-
- :param receipt: unique identifier
-
- :returns: STOMP Frame object
- """
-
- # Receipt header is required
- headers = {HDR_RECEIPT: receipt}
- return Frame(CMD_DISCONNECT, headers).encode()
-
- def send(self, destination, body, content_type=None):
- """
- Sends a message to a destination in the messaging system.
- Transaction header is not supported.
- User defined headers are not supported too (against the protocol specification)
-
- :param destination: Destination string
- :param body: Data to be added in the frame body
- :param content_type: MIME type which describes the format of the body
-
- :returns: STOMP Frame object
- """
-
- # Destination header is required
- headers = {HDR_DESTINATION: destination}
-
- if content_type:
- headers[HDR_CONTENT_TYPE] = content_type
-
- body = encode(body)
- if HDR_CONTENT_LENGTH not in headers and hasbyte(0, body):
- headers[HDR_CONTENT_LENGTH] = len(body)
-
- return Frame(CMD_SEND, headers, body).encode()
diff --git a/gns3server/topology.py b/gns3server/topology.py
new file mode 100644
index 00000000..e14ce555
--- /dev/null
+++ b/gns3server/topology.py
@@ -0,0 +1,49 @@
+# -*- 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 .
+
+#import networkx as nx
+
+
+class Topology(object):
+
+ def __init__(self):
+
+ pass
+ #self._topology = nx.Graph()
+
+ def add_node(self, node):
+
+ self._topology.add_node(node)
+
+ def remove_node(self, node):
+
+ self._topology.remove_node(node)
+
+ def clear(self):
+
+ self._topology.clear()
+
+ def __str__(self):
+
+ return "GNS3 network topology"
+
+ @staticmethod
+ def instance():
+
+ if not hasattr(Topology, "_instance"):
+ Topology._instance = Topology()
+ return Topology._instance
diff --git a/tests/dynamips/.gitignore b/tests/dynamips/.gitignore
new file mode 100644
index 00000000..39ffa4b5
--- /dev/null
+++ b/tests/dynamips/.gitignore
@@ -0,0 +1 @@
+/c3725.image
diff --git a/tests/dynamips/conftest.py b/tests/dynamips/conftest.py
new file mode 100644
index 00000000..9d7f294a
--- /dev/null
+++ b/tests/dynamips/conftest.py
@@ -0,0 +1,30 @@
+from gns3server.modules.dynamips import HypervisorManager
+import pytest
+import os
+
+
+@pytest.fixture(scope="module")
+def hypervisor(request):
+
+ cwd = os.path.dirname(os.path.abspath(__file__))
+ dynamips_path = os.path.join(cwd, "dynamips.stable")
+ print("\nStarting Dynamips Hypervisor: {}".format(dynamips_path))
+ manager = HypervisorManager(dynamips_path, "/tmp", base_port=9000)
+ hypervisor = manager.start_new_hypervisor()
+
+ def stop():
+ print("\nStopping Dynamips Hypervisor")
+ manager.stop_all_hypervisors()
+
+ request.addfinalizer(stop)
+ return hypervisor
+
+
+@pytest.fixture(scope="session")
+def image(request):
+
+ cwd = os.path.dirname(os.path.abspath(__file__))
+ image_path = os.path.join(cwd, "c3725.image")
+ if not os.path.exists(image_path):
+ return None
+ return image_path
diff --git a/tests/dynamips/dynamips.stable b/tests/dynamips/dynamips.stable
new file mode 100755
index 00000000..df7950ca
Binary files /dev/null and b/tests/dynamips/dynamips.stable differ
diff --git a/tests/dynamips/test_atm_bridge.py b/tests/dynamips/test_atm_bridge.py
new file mode 100644
index 00000000..8b84fe61
--- /dev/null
+++ b/tests/dynamips/test_atm_bridge.py
@@ -0,0 +1,62 @@
+from gns3server.modules.dynamips import ATMBridge
+from gns3server.modules.dynamips import NIO_Null
+from gns3server.modules.dynamips import DynamipsError
+import pytest
+
+
+@pytest.fixture
+def atm_bridge(request, hypervisor):
+
+ atm_bridge = ATMBridge(hypervisor, "ATM bridge")
+ request.addfinalizer(atm_bridge.delete)
+ return atm_bridge
+
+
+def test_atm_bridge_exists(atm_bridge):
+
+ assert atm_bridge.list()
+
+
+def test_rename_atm_bridge(atm_bridge):
+
+ atm_bridge.rename("new ATM bridge")
+ assert atm_bridge.name == "new ATM bridge"
+
+
+def test_add_remove_nio(atm_bridge):
+
+ nio = NIO_Null(atm_bridge.hypervisor)
+ atm_bridge.add_nio(nio, 0) # add NIO on port 0
+ assert atm_bridge.nios
+ atm_bridge.remove_nio(0) # remove NIO from port 0
+ nio.delete()
+
+
+def test_add_nio_already_allocated_port(atm_bridge):
+
+ nio = NIO_Null(atm_bridge.hypervisor)
+ atm_bridge.add_nio(nio, 0) # add NIO on port 0
+ with pytest.raises(DynamipsError):
+ atm_bridge.add_nio(nio, 0)
+ nio.delete()
+
+
+def test_remove_nio_non_allocated_port(atm_bridge):
+
+ with pytest.raises(DynamipsError):
+ atm_bridge.remove_nio(0) # remove NIO from port 0
+
+
+def test_bridge(atm_bridge):
+
+ nio1 = NIO_Null(atm_bridge.hypervisor)
+ atm_bridge.add_nio(nio1, 0) # add NIO on port 0 (Ethernet NIO)
+ nio2 = NIO_Null(atm_bridge.hypervisor)
+ atm_bridge.add_nio(nio1, 1) # add NIO on port 1 (ATM NIO)
+ atm_bridge.configure(0, 1, 10, 10) # configure Ethernet port 0 -> ATM port 1 with VC 10:10
+ assert atm_bridge.mapping[0] == (1, 10, 10)
+ atm_bridge.unconfigure()
+ atm_bridge.remove_nio(0)
+ atm_bridge.remove_nio(1)
+ nio1.delete()
+ nio2.delete()
diff --git a/tests/dynamips/test_atm_switch.py b/tests/dynamips/test_atm_switch.py
new file mode 100644
index 00000000..8d2f92f6
--- /dev/null
+++ b/tests/dynamips/test_atm_switch.py
@@ -0,0 +1,83 @@
+from gns3server.modules.dynamips import ATMSwitch
+from gns3server.modules.dynamips import NIO_Null
+from gns3server.modules.dynamips import DynamipsError
+import pytest
+
+
+@pytest.fixture
+def atmsw(request, hypervisor):
+
+ atmsw = ATMSwitch(hypervisor, "ATM switch")
+ request.addfinalizer(atmsw.delete)
+ return atmsw
+
+
+def test_atmsw_exists(atmsw):
+
+ assert atmsw.list()
+
+
+def test_rename_atmsw(atmsw):
+
+ atmsw.rename("new ATM switch")
+ assert atmsw.name == "new ATM switch"
+
+
+def test_add_remove_nio(atmsw):
+
+ nio = NIO_Null(atmsw.hypervisor)
+ atmsw.add_nio(nio, 0) # add NIO on port 0
+ assert atmsw.nios
+ atmsw.remove_nio(0) # remove NIO from port 0
+ nio.delete()
+
+
+def test_add_nio_already_allocated_port(atmsw):
+
+ nio = NIO_Null(atmsw.hypervisor)
+ atmsw.add_nio(nio, 0) # add NIO on port 0
+ with pytest.raises(DynamipsError):
+ atmsw.add_nio(nio, 0)
+ nio.delete()
+
+
+def test_remove_nio_non_allocated_port(atmsw):
+
+ with pytest.raises(DynamipsError):
+ atmsw.remove_nio(0) # remove NIO from port 0
+
+
+def test_vp(atmsw):
+
+ nio1 = NIO_Null(atmsw.hypervisor)
+ atmsw.add_nio(nio1, 0) # add NIO on port 0
+ nio2 = NIO_Null(atmsw.hypervisor)
+ atmsw.add_nio(nio1, 1) # add NIO on port 1
+ atmsw.map_vp(0, 10, 1, 20) # port 0 VP 10 to port 1 VP 20 (unidirectional)
+ atmsw.map_vp(1, 20, 0, 10) # port 1 VP 20 to port 0 VP 10 (unidirectional)
+ assert atmsw.mapping[(0, 10)] == (1, 20)
+ assert atmsw.mapping[(1, 20)] == (0, 10)
+ atmsw.unmap_vp(0, 10, 1, 20) # port 0 VP 10 to port 1 VP 20 (unidirectional)
+ atmsw.unmap_vp(1, 20, 0, 10) # port 1 VP 20 to port 0 VP 10 (unidirectional)
+ atmsw.remove_nio(0)
+ atmsw.remove_nio(1)
+ nio1.delete()
+ nio2.delete()
+
+
+def test_pvc(atmsw):
+
+ nio1 = NIO_Null(atmsw.hypervisor)
+ atmsw.add_nio(nio1, 0) # add NIO on port 0
+ nio2 = NIO_Null(atmsw.hypervisor)
+ atmsw.add_nio(nio1, 1) # add NIO on port 1
+ atmsw.map_pvc(0, 10, 10, 1, 20, 20) # port 0 VC 10:10 to port 1 VP 20:20 (unidirectional)
+ atmsw.map_pvc(1, 20, 20, 0, 10, 10) # port 1 VC 20:20 to port 0 VC 10:10 (unidirectional)
+ assert atmsw.mapping[(0, 10, 10)] == (1, 20, 20)
+ assert atmsw.mapping[(1, 20, 20)] == (0, 10, 10)
+ atmsw.unmap_pvc(0, 10, 10, 1, 20, 20) # port 0 VC 10:10 to port 1 VP 20:20 (unidirectional)
+ atmsw.unmap_pvc(1, 20, 20, 0, 10, 10) # port 1 VC 20:20 to port 0 VC 10:10 (unidirectional)
+ atmsw.remove_nio(0)
+ atmsw.remove_nio(1)
+ nio1.delete()
+ nio2.delete()
diff --git a/tests/dynamips/test_bridge.py b/tests/dynamips/test_bridge.py
new file mode 100644
index 00000000..6ab07ee1
--- /dev/null
+++ b/tests/dynamips/test_bridge.py
@@ -0,0 +1,31 @@
+from gns3server.modules.dynamips import Bridge
+from gns3server.modules.dynamips import NIO_Null
+import pytest
+
+
+@pytest.fixture
+def bridge(request, hypervisor):
+
+ bridge = Bridge(hypervisor, "bridge")
+ request.addfinalizer(bridge.delete)
+ return bridge
+
+
+def test_bridge_exists(bridge):
+
+ assert bridge.list()
+
+
+def test_rename_bridge(bridge):
+
+ bridge.rename("new bridge")
+ assert bridge.name == "new bridge"
+
+
+def test_add_remove_nio(bridge):
+
+ nio = NIO_Null(bridge.hypervisor)
+ bridge.add_nio(nio)
+ assert bridge.nios
+ bridge.remove_nio(nio)
+ nio.delete()
diff --git a/tests/dynamips/test_c1700.py b/tests/dynamips/test_c1700.py
new file mode 100644
index 00000000..2202a50f
--- /dev/null
+++ b/tests/dynamips/test_c1700.py
@@ -0,0 +1,167 @@
+from gns3server.modules.dynamips import C1700
+from gns3server.modules.dynamips import DynamipsError
+from gns3server.modules.dynamips import WIC_2T
+from gns3server.modules.dynamips import WIC_1ENET
+from gns3server.modules.dynamips import NIO_Null
+import pytest
+
+
+@pytest.fixture
+def router_c1700(request, hypervisor):
+
+ router = C1700(hypervisor, "c1700 router")
+ request.addfinalizer(router.delete)
+ return router
+
+
+def test_router_exists(router_c1700):
+
+ assert router_c1700.platform == "c1700"
+ assert router_c1700.list()
+
+
+def test_chassis_1721(hypervisor):
+
+ router = C1700(hypervisor, "1721 chassis", chassis="1721")
+ assert router.chassis == "1721"
+ assert str(router.slots[0]) == "C1700-MB-1FE"
+ router.delete()
+
+
+def test_chassis_change_to_1721(router_c1700):
+
+ assert router_c1700.chassis == "1720" # default chassis
+ router_c1700.chassis = "1721"
+ assert router_c1700.chassis == "1721"
+
+
+def test_chassis_1750(hypervisor):
+
+ router = C1700(hypervisor, "1750 chassis", chassis="1750")
+ assert router.chassis == "1750"
+ assert str(router.slots[0]) == "C1700-MB-1FE"
+ router.delete()
+
+
+def test_chassis_change_to_1750(router_c1700):
+
+ assert router_c1700.chassis == "1720" # default chassis
+ router_c1700.chassis = "1750"
+ assert router_c1700.chassis == "1750"
+
+
+def test_chassis_1751(hypervisor):
+
+ router = C1700(hypervisor, "1751 chassis", chassis="1751")
+ assert router.chassis == "1751"
+ assert str(router.slots[0]) == "C1700-MB-1FE"
+ router.delete()
+
+
+def test_chassis_change_to_1751(router_c1700):
+
+ assert router_c1700.chassis == "1720" # default chassis
+ router_c1700.chassis = "1751"
+ assert router_c1700.chassis == "1751"
+
+
+def test_chassis_1760(hypervisor):
+
+ router = C1700(hypervisor, "1760 chassis", chassis="1760")
+ assert router.chassis == "1760"
+ assert str(router.slots[0]) == "C1700-MB-1FE"
+ router.delete()
+
+
+def test_chassis_change_to_1760(router_c1700):
+
+ assert router_c1700.chassis == "1720" # default chassis
+ router_c1700.chassis = "1760"
+ assert router_c1700.chassis == "1760"
+
+
+def test_iomem(router_c1700):
+
+ assert router_c1700.iomem == 15 # default value
+ router_c1700.iomem = 20
+ assert router_c1700.iomem == 20
+
+
+def test_mac_addr(router_c1700):
+
+ assert router_c1700.mac_addr == None # default value
+ router_c1700.mac_addr = "aa:aa:aa:aa:aa:aa"
+ assert router_c1700.mac_addr == "aa:aa:aa:aa:aa:aa"
+
+
+def test_bogus_mac_addr(router_c1700):
+
+ with pytest.raises(DynamipsError):
+ router_c1700.mac_addr = "zz:zz:zz:zz:zz:zz"
+
+
+def test_system_id(router_c1700):
+
+ assert router_c1700.system_id == None # default value
+ router_c1700.system_id = "FTX0945W0MO"
+ assert router_c1700.system_id == "FTX0945W0MO"
+
+
+def test_get_hardware_info(router_c1700):
+
+ router_c1700.get_hardware_info() # FIXME: Dynamips doesn't return anything
+
+
+def test_install_remove_wic(router_c1700):
+
+ wic = WIC_2T()
+ router_c1700.install_wic(0, wic) # install in WIC slot 0
+ assert router_c1700.slots[0].wics[0]
+ wic = WIC_1ENET()
+ router_c1700.install_wic(1, wic) # install in WIC slot 1
+ assert router_c1700.slots[0].wics[1]
+ router_c1700.uninstall_wic(0) # uninstall WIC from slot 0
+ assert not router_c1700.slots[0].wics[0]
+
+
+def test_install_wic_into_wrong_slot(router_c1700):
+
+ wic = WIC_2T()
+ with pytest.raises(DynamipsError):
+ router_c1700.install_wic(2, wic) # install in WIC slot 2
+
+
+def test_install_wic_into_already_occupied_slot(router_c1700):
+
+ wic = WIC_2T()
+ router_c1700.install_wic(0, wic) # install in WIC slot 0
+ wic = WIC_1ENET()
+ with pytest.raises(DynamipsError):
+ router_c1700.install_wic(0, wic) # install in WIC slot 0
+
+
+def test_wic_add_remove_nio_binding(router_c1700):
+
+ nio = NIO_Null(router_c1700.hypervisor)
+ wic = WIC_2T()
+ router_c1700.install_wic(0, wic) # install WIC in slot 0
+ router_c1700.slot_add_nio_binding(0, 17, nio) # slot 0/17 (slot 0, wic 0, port 1)
+ assert router_c1700.slots[0].ports[17] == nio
+ assert router_c1700.get_slot_nio_bindings(slot_id=0)
+ router_c1700.slot_remove_nio_binding(0, 17) # slot 0/17 (slot 0, wic 0, port 1)
+ assert not router_c1700.get_slot_nio_bindings(slot_id=0)
+ assert not router_c1700.slots[0].ports[17] == nio
+ nio.delete()
+
+
+def test_wic_add_remove_nio_binding_for_chassis_1760(hypervisor):
+
+ router = C1700(hypervisor, "1760 chassis", chassis="1760")
+ nio = NIO_Null(router.hypervisor)
+ wic = WIC_2T()
+ router.install_wic(1, wic) # install WIC in slot 1
+ router.slot_add_nio_binding(0, 32, nio) # slot 0/17 (slot 0, wic 1, port 0)
+ router.slot_remove_nio_binding(0, 32)
+ assert not router.get_slot_nio_bindings(slot_id=0)
+ nio.delete()
+ router.delete()
diff --git a/tests/dynamips/test_c2600.py b/tests/dynamips/test_c2600.py
new file mode 100644
index 00000000..d17ee345
--- /dev/null
+++ b/tests/dynamips/test_c2600.py
@@ -0,0 +1,216 @@
+from gns3server.modules.dynamips import C2600
+from gns3server.modules.dynamips import DynamipsError
+from gns3server.modules.dynamips import NM_1E
+from gns3server.modules.dynamips import NM_4E
+from gns3server.modules.dynamips import NM_1FE_TX
+from gns3server.modules.dynamips import NM_16ESW
+import pytest
+
+
+@pytest.fixture
+def router_c2600(request, hypervisor):
+
+ router = C2600(hypervisor, "c2600 router")
+ request.addfinalizer(router.delete)
+ return router
+
+
+def test_router_exists(router_c2600):
+
+ assert router_c2600.platform == "c2600"
+ assert router_c2600.list()
+
+
+def test_chassis_2611(hypervisor):
+
+ router = C2600(hypervisor, "2611 chassis", chassis="2611")
+ assert router.chassis == "2611"
+ assert isinstance(router.slots[0], router.integrated_adapters["2611"])
+ router.delete()
+
+
+def test_chassis_change_to_2611(router_c2600):
+
+ assert router_c2600.chassis == "2610" # default chassis
+ router_c2600.chassis = "2611"
+ assert router_c2600.chassis == "2611"
+
+
+def test_chassis_2620(hypervisor):
+
+ router = C2600(hypervisor, "2620 chassis", chassis="2620")
+ assert router.chassis == "2620"
+ assert isinstance(router.slots[0], router.integrated_adapters["2620"])
+ router.delete()
+
+
+def test_chassis_change_to_2620(router_c2600):
+
+ assert router_c2600.chassis == "2610" # default chassis
+ router_c2600.chassis = "2620"
+ assert router_c2600.chassis == "2620"
+
+
+def test_chassis_2621(hypervisor):
+
+ router = C2600(hypervisor, "2621 chassis", chassis="2621")
+ assert router.chassis == "2621"
+ assert isinstance(router.slots[0], router.integrated_adapters["2621"])
+ router.delete()
+
+
+def test_chassis_change_to_2621(router_c2600):
+
+ assert router_c2600.chassis == "2610" # default chassis
+ router_c2600.chassis = "2621"
+ assert router_c2600.chassis == "2621"
+
+
+def test_chassis_2610XM(hypervisor):
+
+ router = C2600(hypervisor, "2610XM chassis", chassis="2610XM")
+ assert router.chassis == "2610XM"
+ assert isinstance(router.slots[0], router.integrated_adapters["2610XM"])
+ router.delete()
+
+
+def test_chassis_change_to_2610XM(router_c2600):
+
+ assert router_c2600.chassis == "2610" # default chassis
+ router_c2600.chassis = "2610XM"
+ assert router_c2600.chassis == "2610XM"
+
+
+def test_chassis_2611XM(hypervisor):
+
+ router = C2600(hypervisor, "2611XM chassis", chassis="2611XM")
+ assert router.chassis == "2611XM"
+ assert isinstance(router.slots[0], router.integrated_adapters["2611XM"])
+ router.delete()
+
+
+def test_chassis_change_to_2611XM(router_c2600):
+
+ assert router_c2600.chassis == "2610" # default chassis
+ router_c2600.chassis = "2611XM"
+ assert router_c2600.chassis == "2611XM"
+
+
+def test_chassis_2620XM(hypervisor):
+
+ router = C2600(hypervisor, "2620XM chassis", chassis="2620XM")
+ assert router.chassis == "2620XM"
+ assert isinstance(router.slots[0], router.integrated_adapters["2620XM"])
+ router.delete()
+
+
+def test_chassis_change_to_2620XM(router_c2600):
+
+ assert router_c2600.chassis == "2610" # default chassis
+ router_c2600.chassis = "2620XM"
+ assert router_c2600.chassis == "2620XM"
+
+
+def test_chassis_2621XM(hypervisor):
+
+ router = C2600(hypervisor, "2621XM chassis", chassis="2621XM")
+ assert router.chassis == "2621XM"
+ assert isinstance(router.slots[0], router.integrated_adapters["2621XM"])
+ router.delete()
+
+
+def test_chassis_change_to_2621XM(router_c2600):
+
+ assert router_c2600.chassis == "2610" # default chassis
+ router_c2600.chassis = "2621XM"
+ assert router_c2600.chassis == "2621XM"
+
+
+def test_chassis_2650XM(hypervisor):
+
+ router = C2600(hypervisor, "2650XM chassis", chassis="2650XM")
+ assert router.chassis == "2650XM"
+ assert isinstance(router.slots[0], router.integrated_adapters["2650XM"])
+ router.delete()
+
+
+def test_chassis_change_to_2650XM(router_c2600):
+
+ assert router_c2600.chassis == "2610" # default chassis
+ router_c2600.chassis = "2650XM"
+ assert router_c2600.chassis == "2650XM"
+
+
+def test_chassis_2651XM(hypervisor):
+
+ router = C2600(hypervisor, "2651XM chassis", chassis="2651XM")
+ assert router.chassis == "2651XM"
+ assert isinstance(router.slots[0], router.integrated_adapters["2651XM"])
+ router.delete()
+
+
+def test_chassis_change_to_2651XM(router_c2600):
+
+ assert router_c2600.chassis == "2610" # default chassis
+ router_c2600.chassis = "2651XM"
+ assert router_c2600.chassis == "2651XM"
+
+
+def test_iomem(router_c2600):
+
+ assert router_c2600.iomem == 15 # default value
+ router_c2600.iomem = 20
+ assert router_c2600.iomem == 20
+
+
+def test_mac_addr(router_c2600):
+
+ assert router_c2600.mac_addr == None # default value
+ router_c2600.mac_addr = "aa:aa:aa:aa:aa:aa"
+ assert router_c2600.mac_addr == "aa:aa:aa:aa:aa:aa"
+
+
+def test_bogus_mac_addr(router_c2600):
+
+ with pytest.raises(DynamipsError):
+ router_c2600.mac_addr = "zz:zz:zz:zz:zz:zz"
+
+
+def test_system_id(router_c2600):
+
+ assert router_c2600.system_id == None # default value
+ router_c2600.system_id = "FTX0945W0MO"
+ assert router_c2600.system_id == "FTX0945W0MO"
+
+
+def test_get_hardware_info(router_c2600):
+
+ router_c2600.get_hardware_info() # FIXME: Dynamips doesn't return anything
+
+
+def test_slot_add_NM_1E(router_c2600):
+
+ adapter = NM_1E()
+ router_c2600.slot_add_binding(1, adapter)
+ assert router_c2600.slots[1] == adapter
+
+
+def test_slot_add_NM_4E(router_c2600):
+
+ adapter = NM_4E()
+ router_c2600.slot_add_binding(1, adapter)
+ assert router_c2600.slots[1] == adapter
+
+
+def test_slot_add_NM_1FE_TX(router_c2600):
+
+ adapter = NM_1FE_TX()
+ router_c2600.slot_add_binding(1, adapter)
+ assert router_c2600.slots[1] == adapter
+
+
+def test_slot_add_NM_16ESW(router_c2600):
+
+ adapter = NM_16ESW()
+ router_c2600.slot_add_binding(1, adapter)
+ assert router_c2600.slots[1] == adapter
diff --git a/tests/dynamips/test_c2691.py b/tests/dynamips/test_c2691.py
new file mode 100644
index 00000000..2af7e94a
--- /dev/null
+++ b/tests/dynamips/test_c2691.py
@@ -0,0 +1,75 @@
+from gns3server.modules.dynamips import C2691
+from gns3server.modules.dynamips import DynamipsError
+from gns3server.modules.dynamips import NM_1FE_TX
+from gns3server.modules.dynamips import NM_4T
+from gns3server.modules.dynamips import NM_16ESW
+import pytest
+
+
+@pytest.fixture
+def router_c2691(request, hypervisor):
+
+ router = C2691(hypervisor, "c2691 router")
+ request.addfinalizer(router.delete)
+ return router
+
+
+def test_router_exists(router_c2691):
+
+ assert router_c2691.platform == "c2691"
+ assert router_c2691.list()
+
+
+def test_iomem(router_c2691):
+
+ assert router_c2691.iomem == 5 # default value
+ router_c2691.iomem = 10
+ assert router_c2691.iomem == 10
+
+
+def test_mac_addr(router_c2691):
+
+ assert router_c2691.mac_addr == None # default value
+ router_c2691.mac_addr = "aa:aa:aa:aa:aa:aa"
+ assert router_c2691.mac_addr == "aa:aa:aa:aa:aa:aa"
+
+
+def test_bogus_mac_addr(router_c2691):
+
+ with pytest.raises(DynamipsError):
+ router_c2691.mac_addr = "zz:zz:zz:zz:zz:zz"
+
+
+# FIXME: no implemented within Dynamips
+# def test_system_id(hypervisor):
+# router = C2691(hypervisor, "test system id")
+# assert router.system_id == None # default value
+# router.system_id = "FTX0945W0MO"
+# assert router.system_id == "FTX0945W0MO"
+# router.delete()
+
+
+def test_get_hardware_info(router_c2691):
+
+ router_c2691.get_hardware_info() # FIXME: Dynamips doesn't return anything
+
+
+def test_slot_add_NM_1FE_TX(router_c2691):
+
+ adapter = NM_1FE_TX()
+ router_c2691.slot_add_binding(1, adapter)
+ assert router_c2691.slots[1] == adapter
+
+
+def test_slot_add_NM_4T(router_c2691):
+
+ adapter = NM_4T()
+ router_c2691.slot_add_binding(1, adapter)
+ assert router_c2691.slots[1] == adapter
+
+
+def test_slot_add_NM_16ESW(router_c2691):
+
+ adapter = NM_16ESW()
+ router_c2691.slot_add_binding(1, adapter)
+ assert router_c2691.slots[1] == adapter
diff --git a/tests/dynamips/test_c3600.py b/tests/dynamips/test_c3600.py
new file mode 100644
index 00000000..f3bd06cb
--- /dev/null
+++ b/tests/dynamips/test_c3600.py
@@ -0,0 +1,118 @@
+from gns3server.modules.dynamips import C3600
+from gns3server.modules.dynamips import DynamipsError
+from gns3server.modules.dynamips import NM_1E
+from gns3server.modules.dynamips import NM_4E
+from gns3server.modules.dynamips import NM_1FE_TX
+from gns3server.modules.dynamips import NM_16ESW
+from gns3server.modules.dynamips import NM_4T
+import pytest
+
+
+@pytest.fixture
+def router_c3600(request, hypervisor):
+
+ router = C3600(hypervisor, "c3600 router")
+ request.addfinalizer(router.delete)
+ return router
+
+
+def test_router_exist(router_c3600):
+
+ assert router_c3600.platform == "c3600"
+ assert router_c3600.list()
+
+
+def test_chassis_3620(hypervisor):
+
+ router = C3600(hypervisor, "3620 chassis", chassis="3620")
+ assert router.chassis == "3620"
+ router.delete()
+
+
+def test_chassis_change_to_3620(router_c3600):
+
+ assert router_c3600.chassis == "3640" # default chassis
+ router_c3600.chassis = "3620"
+ assert router_c3600.chassis == "3620"
+
+
+def test_chassis_3660(hypervisor):
+
+ router = C3600(hypervisor, "3660 chassis", chassis="3660")
+ assert router.chassis == "3660"
+ assert str(router.slots[0]) == "Leopard-2FE"
+ router.delete()
+
+
+def test_chassis_change_to_3660(router_c3600):
+
+ assert router_c3600.chassis == "3640" # default chassis
+ router_c3600.chassis = "3660"
+ assert router_c3600.chassis == "3660"
+
+
+def test_iomem(router_c3600):
+
+ assert router_c3600.iomem == 5 # default value
+ router_c3600.iomem = 10
+ assert router_c3600.iomem == 10
+
+
+def test_mac_addr(router_c3600):
+
+ assert router_c3600.mac_addr == None # default value
+ router_c3600.mac_addr = "aa:aa:aa:aa:aa:aa"
+ assert router_c3600.mac_addr == "aa:aa:aa:aa:aa:aa"
+
+
+def test_bogus_mac_addr(router_c3600):
+
+ with pytest.raises(DynamipsError):
+ router_c3600.mac_addr = "zz:zz:zz:zz:zz:zz"
+
+
+def test_system_id(router_c3600):
+
+ assert router_c3600.system_id == None # default value
+ router_c3600.system_id = "FTX0945W0MO"
+ assert router_c3600.system_id == "FTX0945W0MO"
+
+
+def test_get_hardware_info(router_c3600):
+
+ router_c3600.get_hardware_info() # FIXME: Dynamips doesn't return anything
+
+
+def test_slot_add_NM_1E(router_c3600):
+
+ adapter = NM_1E()
+ router_c3600.slot_add_binding(1, adapter)
+ assert router_c3600.slots[1] == adapter
+
+
+def test_slot_add_NM_4E(router_c3600):
+
+ adapter = NM_4E()
+ router_c3600.slot_add_binding(1, adapter)
+ assert router_c3600.slots[1] == adapter
+
+
+def test_slot_add_NM_1FE_TX(router_c3600):
+
+ adapter = NM_1FE_TX()
+ router_c3600.slot_add_binding(1, adapter)
+ assert router_c3600.slots[1] == adapter
+
+
+def test_slot_add_NM_16ESW(router_c3600):
+
+ adapter = NM_16ESW()
+ router_c3600.slot_add_binding(1, adapter)
+ assert router_c3600.slots[1] == adapter
+
+
+def test_slot_add_NM_4T(router_c3600):
+
+ adapter = NM_4T()
+ router_c3600.slot_add_binding(1, adapter)
+ assert router_c3600.slots[1] == adapter
diff --git a/tests/dynamips/test_c3725.py b/tests/dynamips/test_c3725.py
new file mode 100644
index 00000000..5bb6f6e9
--- /dev/null
+++ b/tests/dynamips/test_c3725.py
@@ -0,0 +1,73 @@
+from gns3server.modules.dynamips import C3725
+from gns3server.modules.dynamips import DynamipsError
+from gns3server.modules.dynamips import NM_1FE_TX
+from gns3server.modules.dynamips import NM_4T
+from gns3server.modules.dynamips import NM_16ESW
+import pytest
+
+
+@pytest.fixture
+def router_c3725(request, hypervisor):
+
+ router = C3725(hypervisor, "c3725 router")
+ request.addfinalizer(router.delete)
+ return router
+
+
+def test_router_exists(router_c3725):
+
+ assert router_c3725.platform == "c3725"
+ assert router_c3725.list()
+
+
+def test_iomem(router_c3725):
+
+ assert router_c3725.iomem == 5 # default value
+ router_c3725.iomem = 10
+ assert router_c3725.iomem == 10
+
+
+def test_mac_addr(router_c3725):
+
+ assert router_c3725.mac_addr == None # default value
+ router_c3725.mac_addr = "aa:aa:aa:aa:aa:aa"
+ assert router_c3725.mac_addr == "aa:aa:aa:aa:aa:aa"
+
+
+def test_bogus_mac_addr(router_c3725):
+
+ with pytest.raises(DynamipsError):
+ router_c3725.mac_addr = "zz:zz:zz:zz:zz:zz"
+
+
+def test_system_id(router_c3725):
+
+ assert router_c3725.system_id == None # default value
+ router_c3725.system_id = "FTX0945W0MO"
+ assert router_c3725.system_id == "FTX0945W0MO"
+
+
+def test_get_hardware_info(router_c3725):
+
+ router_c3725.get_hardware_info() # FIXME: Dynamips doesn't return anything
+
+
+def test_slot_add_NM_1FE_TX(router_c3725):
+
+ adapter = NM_1FE_TX()
+ router_c3725.slot_add_binding(1, adapter)
+ assert router_c3725.slots[1] == adapter
+
+
+def test_slot_add_NM_4T(router_c3725):
+
+ adapter = NM_4T()
+ router_c3725.slot_add_binding(1, adapter)
+ assert router_c3725.slots[1] == adapter
+
+
+def test_slot_add_NM_16ESW(router_c3725):
+
+ adapter = NM_16ESW()
+ router_c3725.slot_add_binding(1, adapter)
+ assert router_c3725.slots[1] == adapter
diff --git a/tests/dynamips/test_c3745.py b/tests/dynamips/test_c3745.py
new file mode 100644
index 00000000..78cc53e3
--- /dev/null
+++ b/tests/dynamips/test_c3745.py
@@ -0,0 +1,73 @@
+from gns3server.modules.dynamips import C3745
+from gns3server.modules.dynamips import DynamipsError
+from gns3server.modules.dynamips import NM_1FE_TX
+from gns3server.modules.dynamips import NM_4T
+from gns3server.modules.dynamips import NM_16ESW
+import pytest
+
+
+@pytest.fixture
+def router_c3745(request, hypervisor):
+
+ router = C3745(hypervisor, "c3745 router")
+ request.addfinalizer(router.delete)
+ return router
+
+
+def test_router_exists(router_c3745):
+
+ assert router_c3745.platform == "c3745"
+ assert router_c3745.list()
+
+
+def test_iomem(router_c3745):
+
+ assert router_c3745.iomem == 5 # default value
+ router_c3745.iomem = 10
+ assert router_c3745.iomem == 10
+
+
+def test_mac_addr(router_c3745):
+
+ assert router_c3745.mac_addr == None # default value
+ router_c3745.mac_addr = "aa:aa:aa:aa:aa:aa"
+ assert router_c3745.mac_addr == "aa:aa:aa:aa:aa:aa"
+
+
+def test_bogus_mac_addr(router_c3745):
+
+ with pytest.raises(DynamipsError):
+ router_c3745.mac_addr = "zz:zz:zz:zz:zz:zz"
+
+
+def test_system_id(router_c3745):
+
+ assert router_c3745.system_id == None # default value
+ router_c3745.system_id = "FTX0945W0MO"
+ assert router_c3745.system_id == "FTX0945W0MO"
+
+
+def test_get_hardware_info(router_c3745):
+
+ router_c3745.get_hardware_info() # FIXME: Dynamips doesn't return anything
+
+
+def test_slot_add_NM_1FE_TX(router_c3745):
+
+ adapter = NM_1FE_TX()
+ router_c3745.slot_add_binding(1, adapter)
+ assert router_c3745.slots[1] == adapter
+
+
+def test_slot_add_NM_4T(router_c3745):
+
+ adapter = NM_4T()
+ router_c3745.slot_add_binding(1, adapter)
+ assert router_c3745.slots[1] == adapter
+
+
+def test_slot_add_NM_16ESW(router_c3745):
+
+ adapter = NM_16ESW()
+ router_c3745.slot_add_binding(1, adapter)
+ assert router_c3745.slots[1] == adapter
diff --git a/tests/dynamips/test_c7200.py b/tests/dynamips/test_c7200.py
new file mode 100644
index 00000000..d3929188
--- /dev/null
+++ b/tests/dynamips/test_c7200.py
@@ -0,0 +1,188 @@
+from gns3server.modules.dynamips import C7200
+from gns3server.modules.dynamips import DynamipsError
+from gns3server.modules.dynamips import PA_2FE_TX
+from gns3server.modules.dynamips import PA_4E
+from gns3server.modules.dynamips import PA_4T
+from gns3server.modules.dynamips import PA_8E
+from gns3server.modules.dynamips import PA_8T
+from gns3server.modules.dynamips import PA_A1
+from gns3server.modules.dynamips import PA_FE_TX
+from gns3server.modules.dynamips import PA_GE
+from gns3server.modules.dynamips import PA_POS_OC3
+from gns3server.modules.dynamips import NIO_Null
+import pytest
+
+
+@pytest.fixture
+def router_c7200(request, hypervisor):
+
+ router = C7200(hypervisor, "c7200 router")
+ request.addfinalizer(router.delete)
+ return router
+
+
+def test_router_exists(router_c7200):
+
+ assert router_c7200.platform == "c7200"
+ assert router_c7200.list()
+
+
+def test_npe(router_c7200):
+
+ assert router_c7200.npe == "npe-400" # default value
+ router_c7200.npe = "npe-200"
+ assert router_c7200.npe == "npe-200"
+
+
+def test_midplane(router_c7200):
+
+ assert router_c7200.midplane == "vxr" # default value
+ router_c7200.midplane = "std"
+ assert router_c7200.midplane == "std"
+
+
+def test_sensors(router_c7200):
+
+ assert router_c7200.sensors == [22, 22, 22, 22] # default values (everything at 22C)
+ router_c7200.sensors = [25, 25, 25, 25]
+ assert router_c7200.sensors == [25, 25, 25, 25]
+
+
+def test_power_supplies(router_c7200):
+
+ assert router_c7200.power_supplies == [1, 1] # default values (1 = powered on)
+ router_c7200.power_supplies = [0, 0]
+ assert router_c7200.power_supplies == [0, 0]
+
+
+def test_mac_addr(router_c7200):
+
+ assert router_c7200.mac_addr == None # default value
+ router_c7200.mac_addr = "aa:aa:aa:aa:aa:aa"
+ assert router_c7200.mac_addr == "aa:aa:aa:aa:aa:aa"
+
+
+def test_bogus_mac_addr(router_c7200):
+
+ with pytest.raises(DynamipsError):
+ router_c7200.mac_addr = "zz:zz:zz:zz:zz:zz"
+
+
+def test_system_id(router_c7200):
+
+ assert router_c7200.system_id == None # default value
+ router_c7200.system_id = "FTX0945W0MO"
+ assert router_c7200.system_id == "FTX0945W0MO"
+
+
+def test_get_hardware_info(router_c7200):
+
+ router_c7200.get_hardware_info() # FIXME: Dynamips doesn't return anything
+
+
+def test_slot_add_PA_2FE_TX(router_c7200):
+
+ adapter = PA_2FE_TX()
+ router_c7200.slot_add_binding(1, adapter)
+ assert router_c7200.slots[1] == adapter
+
+
+def test_slot_add_PA_4E(router_c7200):
+
+ adapter = PA_4E()
+ router_c7200.slot_add_binding(2, adapter)
+ assert router_c7200.slots[2] == adapter
+
+
+def test_slot_add_PA_4T(router_c7200):
+
+ adapter = PA_4T()
+ router_c7200.slot_add_binding(3, adapter)
+ assert router_c7200.slots[3] == adapter
+
+
+def test_slot_add_PA_8E(router_c7200):
+
+ adapter = PA_8E()
+ router_c7200.slot_add_binding(4, adapter)
+ assert router_c7200.slots[4] == adapter
+
+
+def test_slot_add_PA_8T(router_c7200):
+
+ adapter = PA_8T()
+ router_c7200.slot_add_binding(5, adapter)
+ assert router_c7200.slots[5] == adapter
+
+
+def test_slot_add_PA_A1(router_c7200):
+
+ adapter = PA_A1()
+ router_c7200.slot_add_binding(1, adapter)
+ assert router_c7200.slots[1] == adapter
+
+
+def test_slot_add_PA_FE_TX(router_c7200):
+
+ adapter = PA_FE_TX()
+ router_c7200.slot_add_binding(2, adapter)
+ assert router_c7200.slots[2] == adapter
+
+
+def test_slot_add_PA_GE(router_c7200):
+
+ adapter = PA_GE()
+ router_c7200.slot_add_binding(3, adapter)
+ assert router_c7200.slots[3] == adapter
+
+
+def test_slot_add_PA_POS_OC3(router_c7200):
+
+ adapter = PA_POS_OC3()
+ router_c7200.slot_add_binding(4, adapter)
+ assert router_c7200.slots[4] == adapter
+
+
+def test_slot_add_into_already_occupied_slot(router_c7200):
+
+ adapter = PA_FE_TX()
+ with pytest.raises(DynamipsError):
+ router_c7200.slot_add_binding(0, adapter)
+
+
+def test_slot_add_into_wrong_slot(router_c7200):
+
+ adapter = PA_FE_TX()
+ with pytest.raises(DynamipsError):
+ router_c7200.slot_add_binding(10, adapter)
+
+
+def test_slot_remove_adapter(router_c7200):
+
+ adapter = PA_FE_TX()
+ router_c7200.slot_add_binding(1, adapter)
+ router_c7200.slot_remove_binding(1)
+ assert router_c7200.slots[1] == None
+
+
+def test_slot_add_remove_nio_binding(router_c7200):
+
+ adapter = PA_FE_TX()
+ router_c7200.slot_add_binding(1, adapter)
+ nio = NIO_Null(router_c7200.hypervisor)
+ router_c7200.slot_add_nio_binding(1, 0, nio) # slot 1/0
+ assert router_c7200.get_slot_nio_bindings(slot_id=1)
+ assert router_c7200.slots[1].ports[0] == nio
+ router_c7200.slot_remove_nio_binding(1, 0) # slot 1/0
+ assert not router_c7200.get_slot_nio_bindings(slot_id=0)
+ nio.delete()
+
+
+def test_slot_add_nio_to_wrong_port(router_c7200):
+
+ adapter = PA_FE_TX()
+ router_c7200.slot_add_binding(1, adapter)
+ nio = NIO_Null(router_c7200.hypervisor)
+ with pytest.raises(DynamipsError):
+ router_c7200.slot_add_nio_binding(1, 1, nio) # slot 1/1
+ nio.delete()
diff --git a/tests/dynamips/test_ethernet_switch.py b/tests/dynamips/test_ethernet_switch.py
new file mode 100644
index 00000000..52574ec5
--- /dev/null
+++ b/tests/dynamips/test_ethernet_switch.py
@@ -0,0 +1,87 @@
+from gns3server.modules.dynamips import EthernetSwitch
+from gns3server.modules.dynamips import NIO_Null
+from gns3server.modules.dynamips import DynamipsError
+import pytest
+
+
+@pytest.fixture
+def ethsw(request, hypervisor):
+
+ ethsw = EthernetSwitch(hypervisor, "Ethernet switch")
+ request.addfinalizer(ethsw.delete)
+ return ethsw
+
+
+def test_ethsw_exists(ethsw):
+
+ assert ethsw.list()
+
+
+def test_rename_ethsw(ethsw):
+
+ ethsw.rename("new Ethernet switch")
+ assert ethsw.name == "new Ethernet switch"
+
+
+def test_add_remove_nio(ethsw):
+
+ nio = NIO_Null(ethsw.hypervisor)
+ ethsw.add_nio(nio, 0) # add NIO on port 0
+ assert ethsw.nios
+ ethsw.remove_nio(0) # remove NIO from port 0
+ nio.delete()
+
+
+def test_add_nio_already_allocated_port(ethsw):
+
+ nio = NIO_Null(ethsw.hypervisor)
+ ethsw.add_nio(nio, 0) # add NIO on port 0
+ with pytest.raises(DynamipsError):
+ ethsw.add_nio(nio, 0)
+ nio.delete()
+
+
+def test_remove_nio_non_allocated_port(ethsw):
+
+ with pytest.raises(DynamipsError):
+ ethsw.remove_nio(0) # remove NIO from port 0
+
+
+def test_set_access_port(ethsw):
+
+ nio = NIO_Null(ethsw.hypervisor)
+ ethsw.add_nio(nio, 0) # add NIO on port 0
+ ethsw.set_access_port(0, 10) # set port 0 as access in VLAN 10
+ assert ethsw.mapping[0] == ("access", 10)
+ ethsw.remove_nio(0) # remove NIO from port 0
+ nio.delete()
+
+
+def test_set_dot1q_port(ethsw):
+
+ nio = NIO_Null(ethsw.hypervisor)
+ ethsw.add_nio(nio, 0) # add NIO on port 0
+ ethsw.set_dot1q_port(0, 1) # set port 0 as 802.1Q trunk with native VLAN 1
+ assert ethsw.mapping[0] == ("dot1q", 1)
+ ethsw.remove_nio(0) # remove NIO from port 0
+ nio.delete()
+
+
+def test_set_qinq_port(ethsw):
+
+ nio = NIO_Null(ethsw.hypervisor)
+ ethsw.add_nio(nio, 0) # add NIO on port 0
+ ethsw.set_qinq_port(0, 100) # set port 0 as QinQ trunk with outer VLAN 100
+ assert ethsw.mapping[0] == ("qinq", 100)
+ ethsw.remove_nio(0) # remove NIO from port 0
+ nio.delete()
+
+
+def test_get_mac_addr_table(ethsw):
+
+ assert not ethsw.get_mac_addr_table() # MAC address table should be empty
+
+
+def test_clear_mac_addr_table(ethsw):
+
+ ethsw.clear_mac_addr_table()
diff --git a/tests/dynamips/test_frame_relay_switch.py b/tests/dynamips/test_frame_relay_switch.py
new file mode 100644
index 00000000..79be3d7a
--- /dev/null
+++ b/tests/dynamips/test_frame_relay_switch.py
@@ -0,0 +1,65 @@
+from gns3server.modules.dynamips import FrameRelaySwitch
+from gns3server.modules.dynamips import NIO_Null
+from gns3server.modules.dynamips import DynamipsError
+import pytest
+
+
+@pytest.fixture
+def frsw(request, hypervisor):
+
+ frsw = FrameRelaySwitch(hypervisor, "Frane Relay switch")
+ request.addfinalizer(frsw.delete)
+ return frsw
+
+
+def test_frsw_exists(frsw):
+
+ assert frsw.list()
+
+
+def test_rename_frsw(frsw):
+
+ frsw.rename("new Frame Relay switch")
+ assert frsw.name == "new Frame Relay switch"
+
+
+def test_add_remove_nio(frsw):
+
+ nio = NIO_Null(frsw.hypervisor)
+ frsw.add_nio(nio, 0) # add NIO on port 0
+ assert frsw.nios
+ frsw.remove_nio(0) # remove NIO from port 0
+ nio.delete()
+
+
+def test_add_nio_already_allocated_port(frsw):
+
+ nio = NIO_Null(frsw.hypervisor)
+ frsw.add_nio(nio, 0) # add NIO on port 0
+ with pytest.raises(DynamipsError):
+ frsw.add_nio(nio, 0)
+ nio.delete()
+
+
+def test_remove_nio_non_allocated_port(frsw):
+
+ with pytest.raises(DynamipsError):
+ frsw.remove_nio(0) # remove NIO from port 0
+
+
+def test_vc(frsw):
+
+ nio1 = NIO_Null(frsw.hypervisor)
+ frsw.add_nio(nio1, 0) # add NIO on port 0
+ nio2 = NIO_Null(frsw.hypervisor)
+ frsw.add_nio(nio1, 1) # add NIO on port 1
+ frsw.map_vc(0, 10, 1, 20) # port 0 DLCI 10 to port 1 DLCI 20 (unidirectional)
+ frsw.map_vc(1, 20, 0, 10) # port 1 DLCI 20 to port 0 DLCI 10 (unidirectional)
+ assert frsw.mapping[(0, 10)] == (1, 20)
+ assert frsw.mapping[(1, 20)] == (0, 10)
+ frsw.unmap_vc(0, 10, 1, 20) # port 0 DLCI 10 to port 1 DLCI 20 (unidirectional)
+ frsw.unmap_vc(1, 20, 0, 10) # port 1 DLCI 20 to port 0 DLCI 10 (unidirectional)
+ frsw.remove_nio(0)
+ frsw.remove_nio(1)
+ nio1.delete()
+ nio2.delete()
diff --git a/tests/dynamips/test_hub.py b/tests/dynamips/test_hub.py
new file mode 100644
index 00000000..d490cb11
--- /dev/null
+++ b/tests/dynamips/test_hub.py
@@ -0,0 +1,25 @@
+from gns3server.modules.dynamips import Hub
+from gns3server.modules.dynamips import NIO_Null
+import pytest
+
+
+@pytest.fixture
+def hub(request, hypervisor):
+
+ hub = Hub(hypervisor, "hub")
+ request.addfinalizer(hub.delete)
+ return hub
+
+
+def test_hub_exists(hub):
+
+ assert hub.list()
+
+
+def test_add_remove_nio(hub):
+
+ nio = NIO_Null(hub.hypervisor)
+ hub.add_nio(nio, 0) # add NIO to port 0
+ assert hub.mapping[0] == nio
+ hub.remove_nio(0) # remove NIO from port 0
+ nio.delete()
diff --git a/tests/dynamips/test_hypervisor.py b/tests/dynamips/test_hypervisor.py
new file mode 100644
index 00000000..d89da84e
--- /dev/null
+++ b/tests/dynamips/test_hypervisor.py
@@ -0,0 +1,44 @@
+from gns3server.modules.dynamips import Hypervisor
+import time
+import os
+
+
+def test_is_started(hypervisor):
+
+ assert hypervisor.is_running()
+
+
+def test_port(hypervisor):
+
+ assert hypervisor.port == 9000
+
+
+def test_host(hypervisor):
+
+ assert hypervisor.host == "127.0.0.1"
+
+
+def test_workingdir(hypervisor):
+
+ assert hypervisor.workingdir == "/tmp"
+
+
+def test_path(hypervisor):
+
+ cwd = os.path.dirname(os.path.abspath(__file__))
+ dynamips_path = os.path.join(cwd, "dynamips.stable")
+ assert hypervisor.path == dynamips_path
+
+
+def test_stdout():
+
+ # try to launch Dynamips on the same port
+ # this will fail so that we can read its stdout/stderr
+ cwd = os.path.dirname(os.path.abspath(__file__))
+ dynamips_path = os.path.join(cwd, "dynamips.stable")
+ hypervisor = Hypervisor(dynamips_path, "/tmp", "172.0.0.1", 7200)
+ hypervisor.start()
+ # give some time for Dynamips to start
+ time.sleep(0.01)
+ output = hypervisor.read_stdout()
+ assert output
diff --git a/tests/dynamips/test_hypervisor_manager.py b/tests/dynamips/test_hypervisor_manager.py
new file mode 100644
index 00000000..658cb9b9
--- /dev/null
+++ b/tests/dynamips/test_hypervisor_manager.py
@@ -0,0 +1,51 @@
+from gns3server.modules.dynamips import Router
+from gns3server.modules.dynamips import HypervisorManager
+import pytest
+import os
+
+
+@pytest.fixture(scope="module")
+def hypervisor_manager(request):
+
+ cwd = os.path.dirname(os.path.abspath(__file__))
+ dynamips_path = os.path.join(cwd, "dynamips.stable")
+ print("\nStarting Dynamips Hypervisor: {}".format(dynamips_path))
+ manager = HypervisorManager(dynamips_path, "/tmp", "127.0.0.1", 9000)
+ #manager.start_new_hypervisor()
+
+ def stop():
+ print("\nStopping Dynamips Hypervisor")
+ manager.stop_all_hypervisors()
+
+ request.addfinalizer(stop)
+ return manager
+
+
+def test_allocate_hypervisor_for_router(hypervisor_manager):
+
+ # default of 1GB of RAM per hypervisor instance
+ assert hypervisor_manager.memory_usage_limit_per_hypervisor == 1024
+ hypervisor = hypervisor_manager.allocate_hypervisor_for_router("c3725.image", 512)
+ assert hypervisor.is_running()
+ hypervisor = hypervisor_manager.allocate_hypervisor_for_router("c3725.image", 256)
+ assert hypervisor.memory_load == 768
+ hypervisor = hypervisor_manager.allocate_hypervisor_for_router("c3725.image", 512)
+ assert hypervisor.memory_load == 512
+ assert len(hypervisor_manager.hypervisors) == 2
+
+
+def test_unallocate_hypervisor_for_router(hypervisor_manager):
+
+ assert len(hypervisor_manager.hypervisors) == 2
+ hypervisor = hypervisor_manager.hypervisors[0]
+ assert hypervisor.memory_load == 768
+ router = Router(hypervisor, "router", "c3725") # default is 128MB of RAM
+ hypervisor_manager.unallocate_hypervisor_for_router(router)
+ assert hypervisor.memory_load == 640
+ hypervisor.decrease_memory_load(512) # forces memory load down to 128
+ assert hypervisor.memory_load == 128
+ router.delete()
+ hypervisor_manager.unallocate_hypervisor_for_router(router)
+ # router is deleted and memory load to 0 now, one hypervisor must
+ # have been shutdown
+ assert len(hypervisor_manager.hypervisors) == 1
diff --git a/tests/dynamips/test_nios.py b/tests/dynamips/test_nios.py
new file mode 100644
index 00000000..0538c298
--- /dev/null
+++ b/tests/dynamips/test_nios.py
@@ -0,0 +1,139 @@
+from gns3server.modules.dynamips import NIO_UDP
+from gns3server.modules.dynamips import NIO_UDP_auto
+from gns3server.modules.dynamips import NIO_FIFO
+from gns3server.modules.dynamips import NIO_Mcast
+from gns3server.modules.dynamips import NIO_Null
+from gns3server.modules.dynamips import DynamipsError
+import pytest
+
+# TODO: test UNIX, TAP, VDE, generic Ethernet and Linux Ethernet NIOs
+
+
+def test_nio_udp(hypervisor):
+
+ nio1 = NIO_UDP(hypervisor, 10001, "127.0.0.1", 10002)
+ assert nio1.lport == 10001
+ nio2 = NIO_UDP(hypervisor, 10002, "127.0.0.1", 10001)
+ assert nio2.lport == 10002
+ nio1.delete()
+ nio2.delete()
+
+
+def test_nio_udp_auto(hypervisor):
+
+ nio1 = NIO_UDP_auto(hypervisor, "127.0.0.1", 10001, 10010)
+ assert nio1.lport == 10001
+ nio2 = NIO_UDP_auto(hypervisor, "127.0.0.1", 10001, 10010)
+ assert nio2.lport == 10002
+ nio1.connect("127.0.0.1", nio2.lport)
+ nio2.connect("127.0.0.1", nio1.lport)
+ nio1.delete()
+ nio2.delete()
+
+
+def test_nio_fifo(hypervisor):
+
+ nio1 = NIO_FIFO(hypervisor)
+ nio2 = NIO_FIFO(hypervisor)
+ nio1.crossconnect(nio2)
+ assert nio1.list()
+ nio1.delete()
+ nio2.delete()
+
+
+def test_nio_mcast(hypervisor):
+
+ nio1 = NIO_Mcast(hypervisor, "232.0.0.1", 10001)
+ assert nio1.group == "232.0.0.1"
+ assert nio1.port == 10001
+ nio1.ttl = 254
+ assert nio1.ttl == 254
+ nio2 = NIO_UDP(hypervisor, 10002, "232.0.0.1", 10001)
+ nio1.delete()
+ nio2.delete()
+
+
+def test_nio_null(hypervisor):
+
+ nio = NIO_Null(hypervisor)
+ assert nio.list()
+ nio.delete()
+
+
+def test_rename_nio(hypervisor):
+
+ nio = NIO_Null(hypervisor)
+ assert nio.name.startswith("nio_null")
+ nio.rename("test")
+ assert nio.name == "test"
+ nio.delete()
+
+
+def test_debug_nio(hypervisor):
+
+ nio = NIO_Null(hypervisor)
+ nio.debug(1)
+ nio.debug(0)
+ nio.delete()
+
+
+def test_bind_unbind_filter(hypervisor):
+
+ nio = NIO_Null(hypervisor)
+ nio.bind_filter("both", "freq_drop")
+ assert nio.input_filter == ("freq_drop", None)
+ assert nio.output_filter == ("freq_drop", None)
+ nio.unbind_filter("both")
+ nio.bind_filter("in", "capture")
+ assert nio.input_filter == ("capture", None)
+ nio.unbind_filter("in")
+ nio.delete()
+
+
+def test_bind_unknown_filter(hypervisor):
+
+ nio = NIO_Null(hypervisor)
+ with pytest.raises(DynamipsError):
+ nio.bind_filter("both", "my_filter")
+ nio.delete()
+
+
+def test_unbind_with_no_filter_applied(hypervisor):
+
+ nio = NIO_Null(hypervisor)
+ with pytest.raises(DynamipsError):
+ nio.unbind_filter("out")
+ nio.delete()
+
+
+def test_setup_filter(hypervisor):
+
+ nio = NIO_Null(hypervisor)
+ nio.bind_filter("in", "freq_drop")
+ nio.setup_filter("in", "5") # drop every 5th packet
+ assert nio.input_filter == ("freq_drop", "5")
+ nio.unbind_filter("in")
+ nio.delete()
+
+
+def test_get_stats(hypervisor):
+
+ nio = NIO_Null(hypervisor)
+ assert nio.get_stats() == "0 0 0 0" # nothing has been transmitted or received
+ nio.delete()
+
+
+def test_reset_stats(hypervisor):
+
+ nio = NIO_Null(hypervisor)
+ nio.reset_stats()
+ nio.delete()
+
+
+def test_set_bandwidth(hypervisor):
+
+ nio = NIO_Null(hypervisor)
+ assert nio.bandwidth == None # no constraint by default
+ nio.set_bandwidth(1000) # bandwidth = 1000 Kb/s
+ assert nio.bandwidth == 1000
+ nio.delete()
diff --git a/tests/dynamips/test_router.py b/tests/dynamips/test_router.py
new file mode 100644
index 00000000..7540caac
--- /dev/null
+++ b/tests/dynamips/test_router.py
@@ -0,0 +1,229 @@
+from gns3server.modules.dynamips import Router
+from gns3server.modules.dynamips import DynamipsError
+import pytest
+import tempfile
+import base64
+
+
+@pytest.fixture
+def router(request, hypervisor):
+
+ router = Router(hypervisor, "router", "c3725")
+ request.addfinalizer(router.delete)
+ return router
+
+
+def test_hypervisor_is_started(hypervisor):
+
+ assert hypervisor.is_running()
+
+
+def test_create_and_delete_router(hypervisor):
+
+ router = Router(hypervisor, "test my router")
+ assert router.id >= 0
+ assert router.name == "test my router"
+ assert router.platform == "c7200" # default platform
+ assert not router.is_running()
+ router.delete()
+ with pytest.raises(DynamipsError):
+ router.get_status()
+
+
+# def test_rename_router(router):
+#
+# assert router.name == "router"
+# router.rename("my_router")
+# assert router.name == "my_router"
+# router.rename("router")
+# assert router.name == "router"
+ #router.delete() # FIXME: fails with current Dynamips version
+
+
+def test_image(router):
+
+ # let's pretend this file is an IOS image
+ with tempfile.NamedTemporaryFile() as ios_image:
+ router.image = ios_image.name
+ assert router.image == ios_image.name
+
+
+def test_set_config(router):
+
+ with tempfile.NamedTemporaryFile() as startup_config:
+ startup_config.write(b"hostname test_config\n")
+ router.set_config(startup_config.name)
+
+
+def test_push_config(router):
+
+ startup_config = base64.b64encode(b"hostname test_config\n").decode("utf-8")
+ private_config = base64.b64encode(b"private config\n").decode("utf-8")
+ router.push_config(startup_config, private_config)
+ router_startup_config, router_private_config = router.extract_config()
+ assert startup_config == router_startup_config
+ assert private_config == router_private_config
+
+
+def test_status(router, image):
+ # don't test if we have no IOS image
+ if not image:
+ return
+
+ assert router.get_status() == "inactive"
+ router.ram = 256
+ router.image = image
+ router.start()
+ assert router.is_running()
+ router.suspend()
+ assert router.get_status() == "suspended"
+ router.resume()
+ assert router.is_running()
+ router.stop()
+ assert router.get_status() == "inactive"
+
+
+def test_ram(router):
+
+ assert router.ram == 128 # default ram
+ router.ram = 256
+ assert router.ram == 256
+
+
+def test_nvram(router):
+
+ assert router.nvram == 128 # default nvram
+ router.nvram = 256
+ assert router.nvram == 256
+
+
+def test_mmap(router):
+
+ assert router.mmap == True # default value
+ router.mmap = False
+ assert router.mmap == False
+
+
+def test_sparsemem(router):
+
+ assert router.sparsemem == True # default value
+ router.sparsemem = False
+ assert router.sparsemem == False
+
+
+def test_clock_divisor(router):
+
+ assert router.clock_divisor == 8 # default value
+ router.clock_divisor = 4
+ assert router.clock_divisor == 4
+
+
+def test_idlepc(router):
+
+ assert router.idlepc == "" # no default value
+ router.idlepc = "0x60c086a8"
+ assert router.idlepc == "0x60c086a8"
+
+
+def test_idlemax(router):
+
+ assert router.idlemax == 1500 # default value
+ router.idlemax = 500
+ assert router.idlemax == 500
+
+
+def test_idlesleep(router):
+
+ assert router.idlesleep == 30 # default value
+ router.idlesleep = 15
+ assert router.idlesleep == 15
+
+
+def test_exec_area(router):
+
+ assert router.exec_area == None # default value
+ router.exec_area = 64
+ assert router.exec_area == 64
+
+
+def test_disk0(router):
+
+ assert router.disk0 == 0 # default value
+ router.disk0 = 16
+ assert router.disk0 == 16
+
+
+def test_disk1(router):
+
+ assert router.disk1 == 0 # default value
+ router.disk1 = 16
+ assert router.disk1 == 16
+
+
+def test_confreg(router):
+
+ assert router.confreg == "0x2102" # default value
+ router.confreg = "0x2142"
+ assert router.confreg == "0x2142"
+
+
+def test_console(router):
+
+ assert router.console == router.hypervisor.baseconsole + router.id
+ new_console_port = router.console + 100
+ router.console = new_console_port
+ assert router.console == new_console_port
+
+
+def test_aux(router):
+
+ assert router.aux == router.hypervisor.baseaux + router.id
+ new_aux_port = router.aux + 100
+ router.aux = new_aux_port
+ assert router.aux == new_aux_port
+
+
+def test_cpu_info(router):
+
+ router.get_cpu_info() # nothing is returned by the hypervisor, cannot test?
+
+
+def test_cpu_usage(router):
+
+ usage = router.get_cpu_usage()
+ assert usage == 0 # router isn't running, so usage must be 0
+
+
+def test_get_slot_bindings(router):
+
+ assert router.get_slot_bindings()[0] == "0/0: GT96100-FE"
+
+
+def test_get_slot_nio_bindings(router):
+
+ router.get_slot_nio_bindings(slot_id=0)
+
+
+def test_mac_addr(router):
+
+ assert router.mac_addr == None # default value
+ router.mac_addr = "aa:aa:aa:aa:aa:aa"
+ assert router.mac_addr == "aa:aa:aa:aa:aa:aa"
+
+
+def test_bogus_mac_addr(router):
+
+ with pytest.raises(DynamipsError):
+ router.mac_addr = "zz:zz:zz:zz:zz:zz"
+
+
+def test_system_id(router):
+
+ assert router.system_id == None # default value
+ router.system_id = "FTX0945W0MO"
+ assert router.system_id == "FTX0945W0MO"
+
+
+def test_get_hardware_info(router):
+
+ router.get_hardware_info()
diff --git a/tests/dynamips/test_vmhandler.py b/tests/dynamips/test_vmhandler.py
new file mode 100644
index 00000000..cdc4998c
--- /dev/null
+++ b/tests/dynamips/test_vmhandler.py
@@ -0,0 +1,65 @@
+from tornado.testing import AsyncHTTPTestCase
+#from gns3server.plugins.dynamips import Dynamips
+#from gns3server._compat import urlencode
+from functools import partial
+import tornado.web
+import json
+import tempfile
+
+
+# class TestVMHandler(AsyncHTTPTestCase):
+#
+# def setUp(self):
+#
+# AsyncHTTPTestCase.setUp(self)
+# self.post_request = partial(self.http_client.fetch,
+# self.get_url("/api/vms/dynamips"),
+# self.stop,
+# method="POST")
+#
+# def get_app(self):
+# return tornado.web.Application(Dynamips().handlers())
+#
+# def test_endpoint(self):
+# self.http_client.fetch(self.get_url("/api/vms/dynamips"), self.stop)
+# response = self.wait()
+# assert response.code == 200
+#
+# def test_upload(self):
+#
+# try:
+# from poster.encode import multipart_encode
+# except ImportError:
+# # poster isn't available for Python 3, let's just ignore the test
+# return
+#
+# file_to_upload = tempfile.NamedTemporaryFile()
+# data, headers = multipart_encode({"file1": file_to_upload})
+# body = ""
+# for d in data:
+# body += d
+#
+# response = self.fetch('/api/vms/dynamips/storage/upload',
+# headers=headers,
+# body=body,
+# method='POST')
+#
+# assert response.code == 200
+#
+# def get_new_ioloop(self):
+# return tornado.ioloop.IOLoop.instance()
+#
+# def test_create_vm(self):
+#
+# post_data = {"name": "R1",
+# "platform": "c3725",
+# "console": 2000,
+# "aux": 3000,
+# "image": "c3725.bin",
+# "ram": 128}
+#
+# self.post_request(body=json.dumps(post_data))
+# response = self.wait()
+# assert(response.headers['Content-Type'].startswith('application/json'))
+# expected = {"success": True}
+# assert response.body.decode("utf-8") == json.dumps(expected)