diff --git a/gns3server/modules/dynamips/backends/ethsw.py b/gns3server/modules/dynamips/backends/ethsw.py
index 891a8a1e..5c288369 100644
--- a/gns3server/modules/dynamips/backends/ethsw.py
+++ b/gns3server/modules/dynamips/backends/ethsw.py
@@ -99,10 +99,10 @@ class ETHSW(object):
Mandatory request parameters:
- id (switch identifier)
- - ports (ports settings)
Optional request parameters:
- name (new switch name)
+ - ports (ports settings)
Response parameters:
- same as original request
@@ -118,22 +118,24 @@ class ETHSW(object):
log.debug("received request {}".format(request))
ethsw_id = request["id"]
ethsw = self._ethernet_switches[ethsw_id]
- ports = request["ports"]
- # update the port settings
- for port, info in ports.items():
- vlan = info["vlan"]
- port_type = info["type"]
- try:
- if port_type == "access":
- ethsw.set_access_port(int(port), vlan)
- elif port_type == "dot1q":
- ethsw.set_dot1q_port(int(port), vlan)
- elif port_type == "qinq":
- ethsw.set_qinq_port(int(port), vlan)
- except DynamipsError as e:
- self.send_custom_error(str(e))
- return
+ if "ports" in request:
+ ports = request["ports"]
+
+ # update the port settings
+ for port, info in ports.items():
+ vlan = info["vlan"]
+ port_type = info["type"]
+ try:
+ if port_type == "access":
+ ethsw.set_access_port(int(port), vlan)
+ elif port_type == "dot1q":
+ ethsw.set_dot1q_port(int(port), vlan)
+ elif port_type == "qinq":
+ ethsw.set_qinq_port(int(port), vlan)
+ except DynamipsError as e:
+ self.send_custom_error(str(e))
+ return
# rename the switch if requested
if "name" in request and ethsw.name != request["name"]:
diff --git a/gns3server/modules/dynamips/dynamips_hypervisor.py b/gns3server/modules/dynamips/dynamips_hypervisor.py
index c4d554bd..0b746cc6 100644
--- a/gns3server/modules/dynamips/dynamips_hypervisor.py
+++ b/gns3server/modules/dynamips/dynamips_hypervisor.py
@@ -356,11 +356,11 @@ class DynamipsHypervisor(object):
try:
if ":" in host:
# IPv6 address support
- s = socket.socket(socket.AF_INET6, socket_type)
+ with socket.socket(socket.AF_INET6, socket_type) as s:
+ s.bind((host, port)) # the port is available if bind is a success
else:
- s = socket.socket(socket.AF_INET, socket_type)
- # the port is available if bind is a success
- s.bind((host, port))
+ with socket.socket(socket.AF_INET, socket_type) as s:
+ s.bind((host, port)) # the port is available if bind is a success
return port
except socket.error as e:
if e.errno == errno.EADDRINUSE: # socket already in use
diff --git a/gns3server/modules/iou/__init__.py b/gns3server/modules/iou/__init__.py
index a51f5df1..06ff909c 100644
--- a/gns3server/modules/iou/__init__.py
+++ b/gns3server/modules/iou/__init__.py
@@ -23,11 +23,16 @@ import os
import sys
import base64
import tempfile
+import fcntl
+import struct
+import socket
from gns3server.modules import IModule
from gns3server.config import Config
from .iou_device import IOUDevice
from .iou_error import IOUError
from .nios.nio_udp import NIO_UDP
+from .nios.nio_tap import NIO_TAP
+from .nios.nio_generic_ethernet import NIO_GenericEthernet
import gns3server.jsonrpc as jsonrpc
import logging
@@ -469,6 +474,10 @@ class IOU(IModule):
- lport (local port)
- rhost (remote host)
- rport (remote port)
+ - "NIO_GenericEthernet"
+ - ethernet_device (Ethernet device name e.g. eth0)
+ - "NIO_TAP"
+ - tap_device (TAP device name e.g. tap0)
Response parameters:
- same as original request
@@ -490,12 +499,40 @@ class IOU(IModule):
try:
nio = None
- #TODO: support for TAP and Ethernet NIOs
if request["nio"] == "NIO_UDP":
lport = request["lport"]
rhost = request["rhost"]
rport = request["rport"]
nio = NIO_UDP(lport, rhost, rport)
+ elif request["nio"] == "NIO_TAP":
+ tap_device = request["tap_device"]
+
+ # check that we have access to the tap device
+ TUNSETIFF = 0x400454ca
+ IFF_TAP = 0x0002
+ IFF_NO_PI = 0x1000
+ try:
+ tun = os.open("/dev/net/tun", os.O_RDWR)
+ except EnvironmentError as e:
+ raise IOUError("Could not open /dev/net/tun: {}".format(e))
+ ifr = struct.pack("16sH", tap_device.encode("utf-8"), IFF_TAP | IFF_NO_PI)
+ try:
+ fcntl.ioctl(tun, TUNSETIFF, ifr)
+ os.close(tun)
+ except IOError as e:
+ raise IOUError("TAP NIO {}: {}".format(tap_device, e))
+
+ nio = NIO_TAP(tap_device)
+ elif request["nio"] == "NIO_GenericEthernet":
+ ethernet_device = request["ethernet_device"]
+
+ # check that we have access to the Ethernet device
+ try:
+ with socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW):
+ pass
+ except socket.error as e:
+ raise IOUError("Generic Ethernet NIO {}: {}".format(ethernet_device, e))
+ nio = NIO_GenericEthernet(ethernet_device)
if not nio:
raise IOUError("Requested NIO doesn't exist or is not supported: {}".format(request["nio"]))
except IOUError as e:
diff --git a/gns3server/modules/iou/iou_device.py b/gns3server/modules/iou/iou_device.py
index 912ee471..9b6ae08c 100644
--- a/gns3server/modules/iou/iou_device.py
+++ b/gns3server/modules/iou/iou_device.py
@@ -32,7 +32,9 @@ from .ioucon import start_ioucon
from .iou_error import IOUError
from .adapters.ethernet_adapter import EthernetAdapter
from .adapters.serial_adapter import SerialAdapter
-
+from .nios.nio_udp import NIO_UDP
+from .nios.nio_tap import NIO_TAP
+from .nios.nio_generic_ethernet import NIO_GenericEthernet
import logging
log = logging.getLogger(__name__)
@@ -323,12 +325,20 @@ class IOUDevice(object):
for unit in adapter.ports.keys():
nio = adapter.get_nio(unit)
if nio:
- #TODO: handle TAP and Ethernet NIOs
- tunnel = {"tunnel_udp": "{lport}:{rhost}:{rport}".format(lport=nio.lport,
- rhost=nio.rhost,
- rport=nio.rport)}
-
- config["{iouyap_id}:{bay}/{unit}".format(iouyap_id=str(self._id + 512), bay=bay_id, unit=unit_id)] = tunnel
+ if isinstance(nio, NIO_UDP):
+ # UDP tunnel
+ connection = {"tunnel_udp": "{lport}:{rhost}:{rport}".format(lport=nio.lport,
+ rhost=nio.rhost,
+ rport=nio.rport)}
+ elif isinstance(nio, NIO_TAP):
+ # TAP interface
+ connection = {"tap_dev": "{tap_device}".format(tap_device=nio.tap_device)}
+
+ elif isinstance(nio, NIO_GenericEthernet):
+ # Ethernet interface
+ connection = {"eth_dev": "{ethernet_device}".format(ethernet_device=nio.ethernet_device)}
+
+ config["{iouyap_id}:{bay}/{unit}".format(iouyap_id=str(self._id + 512), bay=bay_id, unit=unit_id)] = connection
unit_id += 1
bay_id += 1
@@ -766,11 +776,11 @@ class IOUDevice(object):
try:
if ":" in host:
# IPv6 address support
- s = socket.socket(socket.AF_INET6, socket_type)
+ with socket.socket(socket.AF_INET6, socket_type) as s:
+ s.bind((host, port)) # the port is available if bind is a success
else:
- s = socket.socket(socket.AF_INET, socket_type)
- # the port is available if bind is a success
- s.bind((host, port))
+ with socket.socket(socket.AF_INET, socket_type) as s:
+ s.bind((host, port)) # the port is available if bind is a success
return port
except socket.error as e:
if e.errno == errno.EADDRINUSE: # socket already in use
diff --git a/gns3server/modules/iou/nios/nio_generic_ethernet.py b/gns3server/modules/iou/nios/nio_generic_ethernet.py
new file mode 100644
index 00000000..130fb2ff
--- /dev/null
+++ b/gns3server/modules/iou/nios/nio_generic_ethernet.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013 GNS3 Technologies Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""
+Interface for generic Ethernet NIOs (PCAP library).
+"""
+
+
+class NIO_GenericEthernet(object):
+ """
+ NIO generic Ethernet NIO.
+
+ :param ethernet_device: Ethernet device name (e.g. eth0)
+ """
+
+ def __init__(self, ethernet_device):
+
+ self._ethernet_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
+
+ def __str__(self):
+
+ return "NIO Ethernet"
diff --git a/gns3server/modules/iou/nios/nio_tap.py b/gns3server/modules/iou/nios/nio_tap.py
new file mode 100644
index 00000000..ee550e7b
--- /dev/null
+++ b/gns3server/modules/iou/nios/nio_tap.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013 GNS3 Technologies Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""
+Interface for TAP NIOs (UNIX based OSes only).
+"""
+
+
+class NIO_TAP(object):
+ """
+ IOU TAP NIO.
+
+ :param tap_device: TAP device name (e.g. tap0)
+ """
+
+ def __init__(self, tap_device):
+
+ self._tap_device = tap_device
+
+ @property
+ def tap_device(self):
+ """
+ Returns the TAP device used by this NIO.
+
+ :returns: the TAP device name
+ """
+
+ return self._tap_device
+
+ def __str__(self):
+
+ return "NIO TAP"
diff --git a/gns3server/modules/iou/nios/nio_udp.py b/gns3server/modules/iou/nios/nio_udp.py
index bf4353ee..3142d70e 100644
--- a/gns3server/modules/iou/nios/nio_udp.py
+++ b/gns3server/modules/iou/nios/nio_udp.py
@@ -19,9 +19,6 @@
Interface for UDP NIOs.
"""
-import logging
-log = logging.getLogger(__name__)
-
class NIO_UDP(object):
"""