mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-13 20:08:55 +00:00
Dynamips devices.
This commit is contained in:
parent
094339304c
commit
4f38d96522
45
gns3server/modules/dynamips/dynamips_device.py
Normal file
45
gns3server/modules/dynamips/dynamips_device.py
Normal file
@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2015 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 .dynamips_error import DynamipsError
|
||||
from .nodes.atm_switch import ATMSwitch
|
||||
from .nodes.ethernet_switch import EthernetSwitch
|
||||
from .nodes.ethernet_hub import EthernetHub
|
||||
from .nodes.frame_relay_switch import FrameRelaySwitch
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DEVICES = {'atmsw': ATMSwitch,
|
||||
'frsw': FrameRelaySwitch,
|
||||
'ethsw': EthernetSwitch,
|
||||
'ethhub': EthernetHub}
|
||||
|
||||
|
||||
class DynamipsDevice:
|
||||
|
||||
"""
|
||||
Factory to create an Device object based on the type
|
||||
"""
|
||||
|
||||
def __new__(cls, name, vm_id, project, manager, device_type, **kwargs):
|
||||
|
||||
if type not in DEVICES:
|
||||
raise DynamipsError("Unknown device type: {}".format(device_type))
|
||||
|
||||
return DEVICES[device_type](name, vm_id, project, manager, **kwargs)
|
348
gns3server/modules/dynamips/nodes/atm_switch.py
Normal file
348
gns3server/modules/dynamips/nodes/atm_switch.py
Normal file
@ -0,0 +1,348 @@
|
||||
# -*- 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
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from .device import Device
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ATMSwitch(Device):
|
||||
"""
|
||||
Dynamips ATM switch.
|
||||
|
||||
:param name: name for this switch
|
||||
:param node_id: Node instance identifier
|
||||
:param project: Project instance
|
||||
:param manager: Parent VM Manager
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
"""
|
||||
|
||||
def __init__(self, name, node_id, project, manager, hypervisor=None):
|
||||
|
||||
super().__init__(name, node_id, project, manager)
|
||||
self._nios = {}
|
||||
self._mapping = {}
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
if self._hypervisor is None:
|
||||
self._hypervisor = yield from self.manager.start_new_hypervisor()
|
||||
|
||||
yield from self._hypervisor.send('atmsw create "{}"'.format(self._name))
|
||||
log.info('ATM switch "{name}" [{id}] has been created'.format(name=self._name, id=self._id))
|
||||
self._hypervisor.devices.append(self)
|
||||
|
||||
@asyncio.coroutine
|
||||
def set_name(self, new_name):
|
||||
"""
|
||||
Renames this ATM switch.
|
||||
|
||||
:param new_name: New name for this switch
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('atm rename "{name}" "{new_name}"'.format(name=self._name, new_name=new_name))
|
||||
log.info('ATM switch "{name}" [{id}]: renamed to "{new_name}"'.format(name=self._name,
|
||||
id=self._id,
|
||||
new_name=new_name))
|
||||
self._name = new_name
|
||||
|
||||
|
||||
@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
|
||||
|
||||
@asyncio.coroutine
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this ATM switch.
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('atmsw delete "{}"'.format(self._name))
|
||||
log.info('ATM switch "{name}" [{id}] has been deleted'.format(name=self._name, id=self._id))
|
||||
self._hypervisor.devices.remove(self)
|
||||
self._instances.remove(self._id)
|
||||
|
||||
def has_port(self, port):
|
||||
"""
|
||||
Checks if a port exists on this ATM switch.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
if port in self._nios:
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_nio(self, nio, port_number):
|
||||
"""
|
||||
Adds a NIO as new port on ATM switch.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
:param port_number: port to allocate for the NIO
|
||||
"""
|
||||
|
||||
if port_number in self._nios:
|
||||
raise DynamipsError("Port {} isn't free".format(port_number))
|
||||
|
||||
log.info('ATM switch "{name}" [id={id}]: NIO {nio} bound to port {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port_number))
|
||||
|
||||
self._nios[port_number] = nio
|
||||
|
||||
def remove_nio(self, port_number):
|
||||
"""
|
||||
Removes the specified NIO as member of this ATM switch.
|
||||
|
||||
:param port_number: allocated port number
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
log.info('ATM switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port_number))
|
||||
|
||||
del self._nios[port_number]
|
||||
return nio
|
||||
|
||||
@asyncio.coroutine
|
||||
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]
|
||||
|
||||
yield from 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))
|
||||
|
||||
log.info('ATM switch "{name}" [{id}]: VPC from port {port1} VPI {vpi1} to port {port2} VPI {vpi2} created'.format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
port2=port2,
|
||||
vpi2=vpi2))
|
||||
|
||||
self._mapping[(port1, vpi1)] = (port2, vpi2)
|
||||
|
||||
@asyncio.coroutine
|
||||
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]
|
||||
|
||||
yield from 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))
|
||||
|
||||
log.info('ATM switch "{name}" [{id}]: VPC from port {port1} VPI {vpi1} to port {port2} VPI {vpi2} deleted'.format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
port2=port2,
|
||||
vpi2=vpi2))
|
||||
|
||||
del self._mapping[(port1, vpi1)]
|
||||
|
||||
@asyncio.coroutine
|
||||
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]
|
||||
|
||||
yield from 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))
|
||||
|
||||
log.info('ATM switch "{name}" [{id}]: VCC from port {port1} VPI {vpi1} VCI {vci1} to port {port2} VPI {vpi2} VCI {vci2} created'.format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
vci1=vci1,
|
||||
port2=port2,
|
||||
vpi2=vpi2,
|
||||
vci2=vci2))
|
||||
|
||||
self._mapping[(port1, vpi1, vci1)] = (port2, vpi2, vci2)
|
||||
|
||||
@asyncio.coroutine
|
||||
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]
|
||||
|
||||
yield from 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))
|
||||
|
||||
log.info('ATM switch "{name}" [{id}]: VCC from port {port1} VPI {vpi1} VCI {vci1} to port {port2} VPI {vpi2} VCI {vci2} deleted'.format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
vpi1=vpi1,
|
||||
vci1=vci1,
|
||||
port2=port2,
|
||||
vpi2=vpi2,
|
||||
vci2=vci2))
|
||||
del self._mapping[(port1, vpi1, vci1)]
|
||||
|
||||
@asyncio.coroutine
|
||||
def start_capture(self, port_number, output_file, data_link_type="DLT_ATM_RFC1483"):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
:param port_number: allocated port number
|
||||
:param output_file: PCAP destination file for the capture
|
||||
:param data_link_type: PCAP data link type (DLT_*), default is DLT_ATM_RFC1483
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
|
||||
data_link_type = data_link_type.lower()
|
||||
if data_link_type.startswith("dlt_"):
|
||||
data_link_type = data_link_type[4:]
|
||||
|
||||
if nio.input_filter[0] is not None and nio.output_filter[0] is not None:
|
||||
raise DynamipsError("Port {} has already a filter applied".format(port_number))
|
||||
|
||||
yield from nio.bind_filter("both", "capture")
|
||||
yield from nio.setup_filter("both", "{} {}".format(data_link_type, output_file))
|
||||
|
||||
log.info('ATM switch "{name}" [{id}]: starting packet capture on {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number))
|
||||
|
||||
@asyncio.coroutine
|
||||
def stop_capture(self, port_number):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
:param port_number: allocated port number
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
yield from nio.unbind_filter("both")
|
||||
log.info('ATM switch "{name}" [{id}]: stopping packet capture on {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number))
|
104
gns3server/modules/dynamips/nodes/bridge.py
Normal file
104
gns3server/modules/dynamips/nodes/bridge.py
Normal file
@ -0,0 +1,104 @@
|
||||
# -*- 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
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from .device import Device
|
||||
|
||||
|
||||
class Bridge(Device):
|
||||
"""
|
||||
Dynamips bridge.
|
||||
|
||||
:param name: name for this bridge
|
||||
:param node_id: Node instance identifier
|
||||
:param project: Project instance
|
||||
:param manager: Parent VM Manager
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
"""
|
||||
|
||||
def __init__(self, name, node_id, project, manager, hypervisor=None):
|
||||
|
||||
super().__init__(name, node_id, project, manager, hypervisor)
|
||||
self._nios = []
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
if self._hypervisor is None:
|
||||
self._hypervisor = yield from self.manager.start_new_hypervisor()
|
||||
|
||||
yield from self._hypervisor.send('nio_bridge create "{}"'.format(self._name))
|
||||
self._hypervisor.devices.append(self)
|
||||
|
||||
@asyncio.coroutine
|
||||
def set_name(self, new_name):
|
||||
"""
|
||||
Renames this bridge.
|
||||
|
||||
:param new_name: New name for this bridge
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('nio_bridge rename "{name}" "{new_name}"'.format(name=self._name,
|
||||
new_name=new_name))
|
||||
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def nios(self):
|
||||
"""
|
||||
Returns all the NIOs member of this bridge.
|
||||
|
||||
:returns: nio list
|
||||
"""
|
||||
|
||||
return self._nios
|
||||
|
||||
@asyncio.coroutine
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this bridge.
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('nio_bridge delete "{}"'.format(self._name))
|
||||
self._hypervisor.devices.remove(self)
|
||||
|
||||
@asyncio.coroutine
|
||||
def add_nio(self, nio):
|
||||
"""
|
||||
Adds a NIO as new port on this bridge.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('nio_bridge add_nio "{name}" {nio}'.format(name=self._name, nio=nio))
|
||||
self._nios.append(nio)
|
||||
|
||||
@asyncio.coroutine
|
||||
def remove_nio(self, nio):
|
||||
"""
|
||||
Removes the specified NIO as member of this bridge.
|
||||
|
||||
:param nio: NIO instance to remove
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('nio_bridge remove_nio "{name}" {nio}'.format(name=self._name, nio=nio))
|
||||
self._nios.remove(nio)
|
54
gns3server/modules/dynamips/nodes/device.py
Normal file
54
gns3server/modules/dynamips/nodes/device.py
Normal file
@ -0,0 +1,54 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2015 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 ...base_vm import BaseVM
|
||||
|
||||
|
||||
class Device(BaseVM):
|
||||
"""
|
||||
Base device for switches and hubs
|
||||
|
||||
:param name: name for this bridge
|
||||
:param vm_id: Node instance identifier
|
||||
:param project: Project instance
|
||||
:param manager: Parent VM Manager
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
"""
|
||||
|
||||
def __init__(self, name, node_id, project, manager, hypervisor=None):
|
||||
|
||||
super().__init__(name, node_id, project, manager)
|
||||
self._hypervisor = hypervisor
|
||||
|
||||
@property
|
||||
def hypervisor(self):
|
||||
"""
|
||||
Returns the current hypervisor.
|
||||
|
||||
:returns: hypervisor instance
|
||||
"""
|
||||
|
||||
return self._hypervisor
|
||||
|
||||
def start(self):
|
||||
|
||||
pass # Dynamips switches and hubs are always on
|
||||
|
||||
def stop(self):
|
||||
|
||||
pass # Dynamips switches and hubs are always on
|
161
gns3server/modules/dynamips/nodes/ethernet_hub.py
Normal file
161
gns3server/modules/dynamips/nodes/ethernet_hub.py
Normal file
@ -0,0 +1,161 @@
|
||||
# -*- 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.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from .bridge import Bridge
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EthernetHub(Bridge):
|
||||
"""
|
||||
Dynamips Ethernet hub (based on Bridge)
|
||||
|
||||
:param name: name for this hub
|
||||
:param node_id: Node instance identifier
|
||||
:param project: Project instance
|
||||
:param manager: Parent VM Manager
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
"""
|
||||
|
||||
def __init__(self, name, node_id, project, manager, hypervisor=None):
|
||||
|
||||
Bridge.__init__(self, name, node_id, project, manager, hypervisor)
|
||||
self._mapping = {}
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
yield from Bridge.create()
|
||||
log.info('Ethernet hub "{name}" [{id}] has been created'.format(name=self._name, id=self._id))
|
||||
|
||||
@property
|
||||
def mapping(self):
|
||||
"""
|
||||
Returns port mapping
|
||||
|
||||
:returns: mapping list
|
||||
"""
|
||||
|
||||
return self._mapping
|
||||
|
||||
@asyncio.coroutine
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this hub.
|
||||
"""
|
||||
|
||||
yield from Bridge.delete(self)
|
||||
log.info('Ethernet hub "{name}" [{id}] has been deleted'.format(name=self._name, id=self._id))
|
||||
self._instances.remove(self._id)
|
||||
|
||||
@asyncio.coroutine
|
||||
def add_nio(self, nio, port_number):
|
||||
"""
|
||||
Adds a NIO as new port on this hub.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
:param port_number: port to allocate for the NIO
|
||||
"""
|
||||
|
||||
if port_number in self._mapping:
|
||||
raise DynamipsError("Port {} isn't free".format(port_number))
|
||||
|
||||
yield from Bridge.add_nio(self, nio)
|
||||
|
||||
log.info('Ethernet hub "{name}" [{id}]: NIO {nio} bound to port {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port_number))
|
||||
self._mapping[port_number] = nio
|
||||
|
||||
@asyncio.coroutine
|
||||
def remove_nio(self, port_number):
|
||||
"""
|
||||
Removes the specified NIO as member of this hub.
|
||||
|
||||
:param port_number: allocated port number
|
||||
|
||||
:returns: the NIO that was bound to the allocated port
|
||||
"""
|
||||
|
||||
if port_number not in self._mapping:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._mapping[port_number]
|
||||
yield from Bridge.remove_nio(self, nio)
|
||||
|
||||
log.info('Ethernet switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port_number))
|
||||
|
||||
del self._mapping[port_number]
|
||||
return nio
|
||||
|
||||
@asyncio.coroutine
|
||||
def start_capture(self, port_number, output_file, data_link_type="DLT_EN10MB"):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
:param port_number: allocated port number
|
||||
:param output_file: PCAP destination file for the capture
|
||||
:param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB
|
||||
"""
|
||||
|
||||
if port_number not in self._mapping:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._mapping[port_number]
|
||||
|
||||
data_link_type = data_link_type.lower()
|
||||
if data_link_type.startswith("dlt_"):
|
||||
data_link_type = data_link_type[4:]
|
||||
|
||||
if nio.input_filter[0] is not None and nio.output_filter[0] is not None:
|
||||
raise DynamipsError("Port {} has already a filter applied".format(port_number))
|
||||
|
||||
yield from nio.bind_filter("both", "capture")
|
||||
yield from nio.setup_filter("both", "{} {}".format(data_link_type, output_file))
|
||||
|
||||
log.info('Ethernet hub "{name}" [{id}]: starting packet capture on {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number))
|
||||
|
||||
@asyncio.coroutine
|
||||
def stop_capture(self, port_number):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
:param port_number: allocated port number
|
||||
"""
|
||||
|
||||
if port_number not in self._mapping:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._mapping[port_number]
|
||||
yield from nio.unbind_filter("both")
|
||||
log.info('Ethernet hub "{name}" [{id}]: stopping packet capture on {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number))
|
285
gns3server/modules/dynamips/nodes/ethernet_switch.py
Normal file
285
gns3server/modules/dynamips/nodes/ethernet_switch.py
Normal file
@ -0,0 +1,285 @@
|
||||
# -*- 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
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from .device import Device
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EthernetSwitch(Device):
|
||||
"""
|
||||
Dynamips Ethernet switch.
|
||||
|
||||
:param name: name for this switch
|
||||
:param node_id: Node instance identifier
|
||||
:param project: Project instance
|
||||
:param manager: Parent VM Manager
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
"""
|
||||
|
||||
def __init__(self, name, node_id, project, manager, hypervisor=None):
|
||||
|
||||
super().__init__(name, node_id, project, manager, hypervisor)
|
||||
self._nios = {}
|
||||
self._mapping = {}
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
if self._hypervisor is None:
|
||||
self._hypervisor = yield from self.manager.start_new_hypervisor()
|
||||
|
||||
yield from self._hypervisor.send('ethsw create "{}"'.format(self._name))
|
||||
log.info('Ethernet switch "{name}" [{id}] has been created'.format(name=self._name, id=self._id))
|
||||
self._hypervisor.devices.append(self)
|
||||
|
||||
@asyncio.coroutine
|
||||
def set_name(self, new_name):
|
||||
"""
|
||||
Renames this Ethernet switch.
|
||||
|
||||
:param new_name: New name for this switch
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('ethsw rename "{name}" "{new_name}"'.format(name=self._name, new_name=new_name))
|
||||
log.info('Ethernet switch "{name}" [{id}]: renamed to "{new_name}"'.format(name=self._name,
|
||||
id=self._id,
|
||||
new_name=new_name))
|
||||
self._name = new_name
|
||||
|
||||
@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
|
||||
|
||||
@asyncio.coroutine
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this Ethernet switch.
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('ethsw delete "{}"'.format(self._name))
|
||||
log.info('Ethernet switch "{name}" [{id}] has been deleted'.format(name=self._name, id=self._id))
|
||||
self._hypervisor.devices.remove(self)
|
||||
self._instances.remove(self._id)
|
||||
|
||||
@asyncio.coroutine
|
||||
def add_nio(self, nio, port_number):
|
||||
"""
|
||||
Adds a NIO as new port on Ethernet switch.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
:param port_number: port to allocate for the NIO
|
||||
"""
|
||||
|
||||
if port_number in self._nios:
|
||||
raise DynamipsError("Port {} isn't free".format(port_number))
|
||||
|
||||
yield from self._hypervisor.send('ethsw add_nio "{name}" {nio}'.format(name=self._name, nio=nio))
|
||||
|
||||
log.info('Ethernet switch "{name}" [{id}]: NIO {nio} bound to port {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port_number))
|
||||
self._nios[port_number] = nio
|
||||
|
||||
@asyncio.coroutine
|
||||
def remove_nio(self, port_number):
|
||||
"""
|
||||
Removes the specified NIO as member of this Ethernet switch.
|
||||
|
||||
:param port_number: allocated port number
|
||||
|
||||
:returns: the NIO that was bound to the port
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
yield from self._hypervisor.send('ethsw remove_nio "{name}" {nio}'.format(name=self._name, nio=nio))
|
||||
|
||||
log.info('Ethernet switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port_number))
|
||||
|
||||
del self._nios[port_number]
|
||||
if port_number in self._mapping:
|
||||
del self._mapping[port_number]
|
||||
|
||||
return nio
|
||||
|
||||
@asyncio.coroutine
|
||||
def set_access_port(self, port_number, vlan_id):
|
||||
"""
|
||||
Sets the specified port as an ACCESS port.
|
||||
|
||||
:param port_number: allocated port number
|
||||
:param vlan_id: VLAN number membership
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
yield from self._hypervisor.send('ethsw set_access_port "{name}" {nio} {vlan_id}'.format(name=self._name,
|
||||
nio=nio,
|
||||
vlan_id=vlan_id))
|
||||
|
||||
log.info('Ethernet switch "{name}" [{id}]: port {port} set as an access port in VLAN {vlan_id}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number,
|
||||
vlan_id=vlan_id))
|
||||
self._mapping[port_number] = ("access", vlan_id)
|
||||
|
||||
@asyncio.coroutine
|
||||
def set_dot1q_port(self, port_number, native_vlan):
|
||||
"""
|
||||
Sets the specified port as a 802.1Q trunk port.
|
||||
|
||||
:param port_number: allocated port number
|
||||
:param native_vlan: native VLAN for this trunk port
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
yield from self._hypervisor.send('ethsw set_dot1q_port "{name}" {nio} {native_vlan}'.format(name=self._name,
|
||||
nio=nio,
|
||||
native_vlan=native_vlan))
|
||||
|
||||
log.info('Ethernet switch "{name}" [{id}]: port {port} set as a 802.1Q port with native VLAN {vlan_id}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number,
|
||||
vlan_id=native_vlan))
|
||||
|
||||
self._mapping[port_number] = ("dot1q", native_vlan)
|
||||
|
||||
@asyncio.coroutine
|
||||
def set_qinq_port(self, port_number, outer_vlan):
|
||||
"""
|
||||
Sets the specified port as a trunk (QinQ) port.
|
||||
|
||||
:param port_number: allocated port number
|
||||
:param outer_vlan: outer VLAN (transport VLAN) for this QinQ port
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
yield from self._hypervisor.send('ethsw set_qinq_port "{name}" {nio} {outer_vlan}'.format(name=self._name,
|
||||
nio=nio,
|
||||
outer_vlan=outer_vlan))
|
||||
|
||||
log.info('Ethernet switch "{name}" [{id}]: port {port} set as a QinQ port with outer VLAN {vlan_id}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number,
|
||||
vlan_id=outer_vlan))
|
||||
self._mapping[port_number] = ("qinq", outer_vlan)
|
||||
|
||||
@asyncio.coroutine
|
||||
def get_mac_addr_table(self):
|
||||
"""
|
||||
Returns the MAC address table for this Ethernet switch.
|
||||
|
||||
:returns: list of entries (Ethernet address, VLAN, NIO)
|
||||
"""
|
||||
|
||||
mac_addr_table = yield from self._hypervisor.send('ethsw show_mac_addr_table "{}"'.format(self._name))
|
||||
return mac_addr_table
|
||||
|
||||
@asyncio.coroutine
|
||||
def clear_mac_addr_table(self):
|
||||
"""
|
||||
Clears the MAC address table for this Ethernet switch.
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('ethsw clear_mac_addr_table "{}"'.format(self._name))
|
||||
|
||||
@asyncio.coroutine
|
||||
def start_capture(self, port_number, output_file, data_link_type="DLT_EN10MB"):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
:param port_number: allocated port number
|
||||
:param output_file: PCAP destination file for the capture
|
||||
:param data_link_type: PCAP data link type (DLT_*), default is DLT_EN10MB
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
|
||||
data_link_type = data_link_type.lower()
|
||||
if data_link_type.startswith("dlt_"):
|
||||
data_link_type = data_link_type[4:]
|
||||
|
||||
if nio.input_filter[0] is not None and nio.output_filter[0] is not None:
|
||||
raise DynamipsError("Port {} has already a filter applied".format(port_number))
|
||||
|
||||
yield from nio.bind_filter("both", "capture")
|
||||
yield from nio.setup_filter("both", "{} {}".format(data_link_type, output_file))
|
||||
|
||||
log.info('Ethernet switch "{name}" [{id}]: starting packet capture on {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number))
|
||||
|
||||
@asyncio.coroutine
|
||||
def stop_capture(self, port_number):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
:param port_number: allocated port number
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
yield from nio.unbind_filter("both")
|
||||
log.info('Ethernet switch "{name}" [{id}]: stopping packet capture on {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number))
|
267
gns3server/modules/dynamips/nodes/frame_relay_switch.py
Normal file
267
gns3server/modules/dynamips/nodes/frame_relay_switch.py
Normal file
@ -0,0 +1,267 @@
|
||||
# -*- 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
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
|
||||
from .device import Device
|
||||
from ..dynamips_error import DynamipsError
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FrameRelaySwitch(Device):
|
||||
"""
|
||||
Dynamips Frame Relay switch.
|
||||
|
||||
:param name: name for this switch
|
||||
:param node_id: Node instance identifier
|
||||
:param project: Project instance
|
||||
:param manager: Parent VM Manager
|
||||
:param hypervisor: Dynamips hypervisor instance
|
||||
"""
|
||||
|
||||
def __init__(self, name, node_id, project, manager, hypervisor=None):
|
||||
|
||||
super().__init__(name, node_id, project, manager, hypervisor)
|
||||
self._nios = {}
|
||||
self._mapping = {}
|
||||
|
||||
@asyncio.coroutine
|
||||
def create(self):
|
||||
|
||||
if self._hypervisor is None:
|
||||
self._hypervisor = yield from self.manager.start_new_hypervisor()
|
||||
|
||||
yield from self._hypervisor.send('frsw create "{}"'.format(self._name))
|
||||
log.info('Frame Relay switch "{name}" [{id}] has been created'.format(name=self._name, id=self._id))
|
||||
self._hypervisor.devices.append(self)
|
||||
|
||||
@asyncio.coroutine
|
||||
def set_name(self, new_name):
|
||||
"""
|
||||
Renames this Frame Relay switch.
|
||||
|
||||
:param new_name: New name for this switch
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('frsw rename "{name}" "{new_name}"'.format(name=self._name, new_name=new_name))
|
||||
log.info('Frame Relay switch "{name}" [{id}]: renamed to "{new_name}"'.format(name=self._name,
|
||||
id=self._id,
|
||||
new_name=new_name))
|
||||
self._name = new_name
|
||||
|
||||
@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
|
||||
|
||||
@asyncio.coroutine
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this Frame Relay switch.
|
||||
"""
|
||||
|
||||
yield from self._hypervisor.send('frsw delete "{}"'.format(self._name))
|
||||
log.info('Frame Relay switch "{name}" [{id}] has been deleted'.format(name=self._name, id=self._id))
|
||||
self._hypervisor.devices.remove(self)
|
||||
self._instances.remove(self._id)
|
||||
|
||||
def has_port(self, port):
|
||||
"""
|
||||
Checks if a port exists on this Frame Relay switch.
|
||||
|
||||
:returns: boolean
|
||||
"""
|
||||
|
||||
if port in self._nios:
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_nio(self, nio, port_number):
|
||||
"""
|
||||
Adds a NIO as new port on Frame Relay switch.
|
||||
|
||||
:param nio: NIO instance to add
|
||||
:param port_number: port to allocate for the NIO
|
||||
"""
|
||||
|
||||
if port_number in self._nios:
|
||||
raise DynamipsError("Port {} isn't free".format(port_number))
|
||||
|
||||
log.info('Frame Relay switch "{name}" [{id}]: NIO {nio} bound to port {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port_number))
|
||||
|
||||
self._nios[port_number] = nio
|
||||
|
||||
def remove_nio(self, port_number):
|
||||
"""
|
||||
Removes the specified NIO as member of this Frame Relay switch.
|
||||
|
||||
:param port_number: allocated port number
|
||||
|
||||
:returns: the NIO that was bound to the allocated port
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
log.info('Frame Relay switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
nio=nio,
|
||||
port=port_number))
|
||||
|
||||
del self._nios[port_number]
|
||||
return nio
|
||||
|
||||
@asyncio.coroutine
|
||||
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]
|
||||
|
||||
yield from 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))
|
||||
|
||||
log.info('Frame Relay switch "{name}" [{id}]: VC from port {port1} DLCI {dlci1} to port {port2} DLCI {dlci2} created'.format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
dlci1=dlci1,
|
||||
port2=port2,
|
||||
dlci2=dlci2))
|
||||
|
||||
self._mapping[(port1, dlci1)] = (port2, dlci2)
|
||||
|
||||
@asyncio.coroutine
|
||||
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]
|
||||
|
||||
yield from 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))
|
||||
|
||||
log.info('Frame Relay switch "{name}" [{id}]: VC from port {port1} DLCI {dlci1} to port {port2} DLCI {dlci2} deleted'.format(name=self._name,
|
||||
id=self._id,
|
||||
port1=port1,
|
||||
dlci1=dlci1,
|
||||
port2=port2,
|
||||
dlci2=dlci2))
|
||||
del self._mapping[(port1, dlci1)]
|
||||
|
||||
@asyncio.coroutine
|
||||
def start_capture(self, port_number, output_file, data_link_type="DLT_FRELAY"):
|
||||
"""
|
||||
Starts a packet capture.
|
||||
|
||||
:param port_number: allocated port number
|
||||
:param output_file: PCAP destination file for the capture
|
||||
:param data_link_type: PCAP data link type (DLT_*), default is DLT_FRELAY
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
|
||||
data_link_type = data_link_type.lower()
|
||||
if data_link_type.startswith("dlt_"):
|
||||
data_link_type = data_link_type[4:]
|
||||
|
||||
if nio.input_filter[0] is not None and nio.output_filter[0] is not None:
|
||||
raise DynamipsError("Port {} has already a filter applied".format(port_number))
|
||||
|
||||
yield from nio.bind_filter("both", "capture")
|
||||
yield from nio.setup_filter("both", "{} {}".format(data_link_type, output_file))
|
||||
|
||||
log.info('Frame relay switch "{name}" [{id}]: starting packet capture on {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number))
|
||||
|
||||
@asyncio.coroutine
|
||||
def stop_capture(self, port_number):
|
||||
"""
|
||||
Stops a packet capture.
|
||||
|
||||
:param port_number: allocated port number
|
||||
"""
|
||||
|
||||
if port_number not in self._nios:
|
||||
raise DynamipsError("Port {} is not allocated".format(port_number))
|
||||
|
||||
nio = self._nios[port_number]
|
||||
yield from nio.unbind_filter("both")
|
||||
log.info('Frame relay switch "{name}" [{id}]: stopping packet capture on {port}'.format(name=self._name,
|
||||
id=self._id,
|
||||
port=port_number))
|
@ -1310,12 +1310,6 @@ class Router(BaseVM):
|
||||
raise DynamipsError("Port {port_number} has already a filter applied on {adapter}".format(adapter=adapter,
|
||||
port_number=port_number))
|
||||
|
||||
# FIXME: capture
|
||||
# try:
|
||||
# os.makedirs(os.path.dirname(output_file), exist_ok=True)
|
||||
# except OSError as e:
|
||||
# raise DynamipsError("Could not create captures directory {}".format(e))
|
||||
|
||||
yield from nio.bind_filter("both", "capture")
|
||||
yield from nio.setup_filter("both", '{} "{}"'.format(data_link_type, output_file))
|
||||
|
||||
@ -1411,6 +1405,7 @@ class Router(BaseVM):
|
||||
|
||||
self._private_config = private_config
|
||||
|
||||
# TODO: rename
|
||||
# def rename(self, new_name):
|
||||
# """
|
||||
# Renames this router.
|
||||
|
@ -880,3 +880,281 @@ VM_OBJECT_SCHEMA = {
|
||||
"additionalProperties": False,
|
||||
"required": ["name", "vm_id", "project_id", "dynamips_id"]
|
||||
}
|
||||
|
||||
DEVICE_CREATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to create a new Dynamips device instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Dynamips device name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"vm_id": {
|
||||
"description": "Dynamips device instance identifier",
|
||||
"type": "string",
|
||||
"minLength": 36,
|
||||
"maxLength": 36,
|
||||
"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$"
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["name"]
|
||||
}
|
||||
|
||||
ETHHUB_UPDATE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to update an Ethernet hub instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"description": "Ethernet hub name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id"]
|
||||
}
|
||||
|
||||
ETHHUB_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to add a NIO for an Ethernet hub instance",
|
||||
"type": "object",
|
||||
|
||||
"definitions": {
|
||||
"UDP": {
|
||||
"description": "UDP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_udp"]
|
||||
},
|
||||
"lport": {
|
||||
"description": "Local port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"rhost": {
|
||||
"description": "Remote host",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"rport": {
|
||||
"description": "Remote port",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
}
|
||||
},
|
||||
"required": ["type", "lport", "rhost", "rport"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"Ethernet": {
|
||||
"description": "Generic Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_generic_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"LinuxEthernet": {
|
||||
"description": "Linux Ethernet Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_linux_ethernet"]
|
||||
},
|
||||
"ethernet_device": {
|
||||
"description": "Ethernet device name e.g. eth0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "ethernet_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"TAP": {
|
||||
"description": "TAP Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_tap"]
|
||||
},
|
||||
"tap_device": {
|
||||
"description": "TAP device name e.g. tap0",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "tap_device"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"UNIX": {
|
||||
"description": "UNIX Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_unix"]
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the UNIX socket file (local)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"remote_file": {
|
||||
"description": "path to the UNIX socket file (remote)",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "local_file", "remote_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"VDE": {
|
||||
"description": "VDE Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_vde"]
|
||||
},
|
||||
"control_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"local_file": {
|
||||
"description": "path to the VDE control file",
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
},
|
||||
"required": ["type", "control_file", "local_file"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"NULL": {
|
||||
"description": "NULL Network Input/Output",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["nio_null"]
|
||||
},
|
||||
},
|
||||
"required": ["type"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
},
|
||||
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet hub instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"nio": {
|
||||
"type": "object",
|
||||
"description": "Network Input/Output",
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/UDP"},
|
||||
{"$ref": "#/definitions/Ethernet"},
|
||||
{"$ref": "#/definitions/LinuxEthernet"},
|
||||
{"$ref": "#/definitions/TAP"},
|
||||
{"$ref": "#/definitions/UNIX"},
|
||||
{"$ref": "#/definitions/VDE"},
|
||||
{"$ref": "#/definitions/NULL"},
|
||||
]
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port", "nio"]
|
||||
}
|
||||
|
||||
ETHHUB_DELETE_NIO_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to delete a NIO for an Ethernet hub instance",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port"]
|
||||
}
|
||||
|
||||
ETHHUB_START_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to start a packet capture on an Ethernet hub instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet hub instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"capture_file_name": {
|
||||
"description": "Capture file name",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"data_link_type": {
|
||||
"description": "PCAP data link type",
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port", "capture_file_name"]
|
||||
}
|
||||
|
||||
ETHHUB_STOP_CAPTURE_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Request validation to stop a packet capture on an Ethernet hub instance port",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "Ethernet hub instance ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"port_id": {
|
||||
"description": "Unique port identifier for the Ethernet hub instance",
|
||||
"type": "integer"
|
||||
},
|
||||
"port": {
|
||||
"description": "Port number",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"required": ["id", "port_id", "port"]
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ def test_vbox_nio_create_udp(server, vm):
|
||||
assert args[0] == 0
|
||||
|
||||
assert response.status == 201
|
||||
assert response.route == "/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_id:\d+}/ports/{port_id:\d+}/nio"
|
||||
assert response.route == "/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
|
||||
assert response.json["type"] == "nio_udp"
|
||||
|
||||
|
||||
@ -119,7 +119,7 @@ def test_vbox_delete_nio(server, vm):
|
||||
assert args[0] == 0
|
||||
|
||||
assert response.status == 204
|
||||
assert response.route == "/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_id:\d+}/ports/{port_id:\d+}/nio"
|
||||
assert response.route == "/projects/{project_id}/virtualbox/vms/{vm_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
|
||||
|
||||
|
||||
def test_vbox_update(server, vm, free_console_port):
|
||||
|
Loading…
Reference in New Issue
Block a user