Dynamips backend (API implementation)

pull/11/head
grossmj 11 years ago
parent 0cb98318b5
commit 2516bf80a8

@ -16,10 +16,61 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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))

@ -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 <http://www.gnu.org/licenses/>.
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

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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"

@ -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 <http://www.gnu.org/licenses/>.
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

@ -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 <http://www.gnu.org/licenses/>.
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

@ -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 <http://www.gnu.org/licenses/>.
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

@ -16,28 +16,18 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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()

@ -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 <http://www.gnu.org/licenses/>.
"""
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 "<frequency>". It will drop
everything with a -1 frequency, drop every Nth packet with a
positive frequency, or drop nothing.
Filter "capture" has 2 arguments "<link_type_name> <output_file>".
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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))

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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))

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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)]

@ -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 <http://www.gnu.org/licenses/>.
"""
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)

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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

@ -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 <http://www.gnu.org/licenses/>.
"""
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))

@ -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 <http://www.gnu.org/licenses/>.
"""
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)]

@ -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 <http://www.gnu.org/licenses/>.
"""
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]

File diff suppressed because it is too large Load Diff

@ -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 <http://www.gnu.org/licenses/>.
"""
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<key>[^:]+)[:](?P<value>.*)')
# 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

@ -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 <http://www.gnu.org/licenses/>.
"""
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()

@ -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 <http://www.gnu.org/licenses/>.
#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

@ -0,0 +1 @@
/c3725.image

@ -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

Binary file not shown.

@ -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()

@ -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()

@ -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()

@ -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()

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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()

@ -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()

@ -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()

@ -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()

@ -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

@ -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

@ -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()

@ -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()

@ -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)
Loading…
Cancel
Save