From: Claudio-Daniel Freire Date: Tue, 17 May 2011 13:13:20 +0000 (+0200) Subject: General cross TUN fixes X-Git-Tag: nepi_v2~24 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=4012656f3b75b0945c502935a7d5d2aa9a42470d;p=nepi.git General cross TUN fixes --- diff --git a/src/nepi/testbeds/ns3/metadata_v3_9_RC3.py b/src/nepi/testbeds/ns3/metadata_v3_9_RC3.py index 96f30e62..0b280dd8 100644 --- a/src/nepi/testbeds/ns3/metadata_v3_9_RC3.py +++ b/src/nepi/testbeds/ns3/metadata_v3_9_RC3.py @@ -141,6 +141,11 @@ def connect_tunchannel_fd(testbed_instance, tun_guid, fdnd_guid): # Send the other endpoint to the TUN channel tun.tun_socket = sock2 + + # With this kind of tun_socket, NS3 will expect a PI header + # (sockets don't support the TUNGETIFF ioctl, so it will assume + # the default presence of PI headers) + tun.with_pi = True ### Connector information ### diff --git a/src/nepi/testbeds/planetlab/application.py b/src/nepi/testbeds/planetlab/application.py index db623e7b..72f83a84 100644 --- a/src/nepi/testbeds/planetlab/application.py +++ b/src/nepi/testbeds/planetlab/application.py @@ -498,21 +498,25 @@ class NS3Dependency(Dependency): pybindgen_source_url = "http://pybindgen.googlecode.com/files/pybindgen-0.15.0.zip" pygccxml_source_url = "http://leaseweb.dl.sourceforge.net/project/pygccxml/pygccxml/pygccxml-1.0/pygccxml-1.0.0.zip" ns3_source_url = "http://yans.pl.sophia.inria.fr/code/hgwebdir.cgi/ns-3-dev/archive/tip.tar.gz" + passfd_source_url = "http://yans.pl.sophia.inria.fr/code/hgwebdir.cgi/python-passfd/archive/tip.tar.gz" self.build =( " ( " " cd .. && " - " python -c 'import pygccxml, pybindgen' && " + " python -c 'import pygccxml, pybindgen, passfd' && " " test -f lib/_ns3.so && " " test -f lib/libns3.so " " ) || ( " # Not working, rebuild "wget -q -c -O pybindgen-src.zip %(pybindgen_source_url)s && " # continue, to exploit the case when it has already been dl'ed "wget -q -c -O pygccxml-1.0.0.zip %(pygccxml_source_url)s && " + "wget -q -c -O passfd-src.tar.gz %(passfd_source_url)s && " "wget -q -c -O ns3-src.tar.gz %(ns3_source_url)s && " "unzip -n pybindgen-src.zip && " # Do not overwrite files, to exploit the case when it has already been built "unzip -n pygccxml-1.0.0.zip && " "mkdir -p ns3-src && " + "mkdir -p passfd-src && " "tar xzf ns3-src.tar.gz --strip-components=1 -C ns3-src && " + "tar xzf passfd-src.tar.gz --strip-components=1 -C passfd-src && " "rm -rf target && " # mv doesn't like unclean targets "mkdir -p target && " "cd pygccxml-1.0.0 && " @@ -528,6 +532,10 @@ class NS3Dependency(Dependency): "./waf clean && " "mv -f ${BUILD}/target/lib/python*/site-packages/pybindgen ${BUILD}/target/. && " "rm -rf ${BUILD}/target/lib && " + "cd ../passfd-src && " + "python setup.py build && " + "python setup.py install --install-lib ${BUILD}/target && " + "python setup.py clean && " "cd ../ns3-src && " "./waf configure --prefix=${BUILD}/target -d release --disable-examples --high-precision-as-double && " "./waf &&" @@ -538,13 +546,14 @@ class NS3Dependency(Dependency): pybindgen_source_url = server.shell_escape(pybindgen_source_url), pygccxml_source_url = server.shell_escape(pygccxml_source_url), ns3_source_url = server.shell_escape(ns3_source_url), + passfd_source_url = server.shell_escape(passfd_source_url), )) # Just move ${BUILD}/target self.install = ( " ( " " cd .. && " - " python -c 'import pygccxml, pybindgen' && " + " python -c 'import pygccxml, pybindgen, passfd' && " " test -f lib/_ns3.so && " " test -f lib/libns3.so " " ) || ( " diff --git a/src/nepi/testbeds/planetlab/interfaces.py b/src/nepi/testbeds/planetlab/interfaces.py index 19997207..671b6ade 100644 --- a/src/nepi/testbeds/planetlab/interfaces.py +++ b/src/nepi/testbeds/planetlab/interfaces.py @@ -92,6 +92,14 @@ class _CrossIface(object): # Cannot access cross peers self.peer_proto_impl = None + + def __str__(self): + return "%s%r" % ( + self.__class__.__name__, + ( self.tun_proto, + self.tun_addr, + self.tun_port ) + ) class TunIface(object): _PROTO_MAP = tunproto.TUN_PROTO_MAP diff --git a/src/nepi/testbeds/planetlab/metadata_v01.py b/src/nepi/testbeds/planetlab/metadata_v01.py index 09b741a8..7913a265 100644 --- a/src/nepi/testbeds/planetlab/metadata_v01.py +++ b/src/nepi/testbeds/planetlab/metadata_v01.py @@ -951,7 +951,7 @@ factories_info = dict({ "box_attributes": [ "up", "device_name", "mtu", "snat", "txqueuelen", - "tun_proto", "tun_addr", "tun_port" + "tun_proto", "tun_addr", "tun_port", "tun_key" ], "traces": ["packets"], "connector_types": ["node","udp","tcp","fd->"] diff --git a/src/nepi/testbeds/planetlab/tunproto.py b/src/nepi/testbeds/planetlab/tunproto.py index 34bd636e..aeceaf0a 100644 --- a/src/nepi/testbeds/planetlab/tunproto.py +++ b/src/nepi/testbeds/planetlab/tunproto.py @@ -135,10 +135,10 @@ class TunProtoBase(object): if check_proto != peer_proto: raise RuntimeError, "Peering protocol mismatch: %s != %s" % (check_proto, peer_proto) - if not listen and (not peer_port or not peer_addr): + if not listen and ((peer_proto != 'fd' and not peer_port) or not peer_addr): raise RuntimeError, "Misconfigured peer: %s" % (peer,) - if listen and (not local_port or not local_addr or not local_mask): + if listen and ((peer_proto != 'fd' and not local_port) or not local_addr or not local_mask): raise RuntimeError, "Misconfigured TUN: %s" % (local,) args = ["python", "tun_connect.py", diff --git a/src/nepi/util/tunchannel_impl.py b/src/nepi/util/tunchannel_impl.py index 30b21394..0baabff0 100644 --- a/src/nepi/util/tunchannel_impl.py +++ b/src/nepi/util/tunchannel_impl.py @@ -4,6 +4,9 @@ import random import threading import socket import select +import weakref + +from tunchannel import tun_fwd class TunChannel(object): """ @@ -37,6 +40,8 @@ class TunChannel(object): ethernet_mode: set if the incoming packet stream is composed of ethernet frames (as opposed of IP packets). + udp: set to use UDP datagrams instead of TCP connections. + tun_socket: a socket or file object that can be read from and written to. Packets will be read when available, remote packets will be forwarded as writes. @@ -74,6 +79,7 @@ class TunChannel(object): # some state self.prepared = False self._terminate = [] # terminate signaller + self._exc = [] # exception store, to relay exceptions from the forwarder thread self._connected = threading.Event() self._forwarder_thread = None @@ -91,21 +97,25 @@ class TunChannel(object): def __str__(self): - return "%s" % ( + return "%s<%s %s:%s %s %s:%s>" % ( self.__class__.__name__, - self.address, self.netprefix, - " up" if self.up else " down", - " snat" if self.snat else "", + self.tun_proto, + self.tun_addr, self.tun_port, + self.peer_proto, + self.peer_addr, self.peer_port, ) def Prepare(self): - if not self.udp and self.listen and not self._forwarder_thread: - if self.listen or (self.peer_addr and self.peer_port and self.peer_proto): - self._launch() + if self.tun_proto: + udp = self.tun_proto == "udp" + if not udp and self.listen and not self._forwarder_thread: + if self.listen or (self.peer_addr and self.peer_port and self.peer_proto): + self._launch() def Setup(self): - if not self._forwarder_thread: - self._launch() + if self.tun_proto: + if not self._forwarder_thread: + self._launch() def Cleanup(self): if self._forwarder_thread: @@ -114,6 +124,10 @@ class TunChannel(object): def Wait(self): if self._forwarder_thread: self._connected.wait() + for exc in self._exc: + # Relay exception + eTyp, eVal, eLoc = exc + raise eTyp, eVal, eLoc def Kill(self): if self._forwarder_thread: @@ -126,12 +140,23 @@ class TunChannel(object): # to self, so that we don't create any strong cycles # and automatic refcounting works as expected self._forwarder_thread = threading.Thread( - self._forwarder, + target = self._forwarder, args = (weakref.ref(self),) ) self._forwarder_thread.start() - + @staticmethod def _forwarder(weak_self): + try: + weak_self().__forwarder(weak_self) + except: + self = weak_self() + + # store exception and wake up anyone waiting + self._exc.append(sys.exc_info()) + self._connected.set() + + @staticmethod + def __forwarder(weak_self): # grab strong reference self = weak_self() if not self: @@ -170,10 +195,9 @@ class TunChannel(object): if udp: # listen on udp port - if remaining_args and not remaining_args[0].startswith('-'): - rsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) - rsock.bind((local_addr,local_port)) - rsock.connect((peer_addr,peer_port)) + rsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) + rsock.bind((local_addr,local_port)) + rsock.connect((peer_addr,peer_port)) remote = os.fdopen(rsock.fileno(), 'r+b', 0) elif listen: # accept tcp connections