General cross TUN fixes
authorClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Tue, 17 May 2011 13:13:20 +0000 (15:13 +0200)
committerClaudio-Daniel Freire <claudio-daniel.freire@inria.fr>
Tue, 17 May 2011 13:13:20 +0000 (15:13 +0200)
src/nepi/testbeds/ns3/metadata_v3_9_RC3.py
src/nepi/testbeds/planetlab/application.py
src/nepi/testbeds/planetlab/interfaces.py
src/nepi/testbeds/planetlab/metadata_v01.py
src/nepi/testbeds/planetlab/tunproto.py
src/nepi/util/tunchannel_impl.py

index 96f30e6..0b280dd 100644 (file)
@@ -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 ###
index db623e7..72f83a8 100644 (file)
@@ -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 "
             " ) || ( "
index 1999720..671b6ad 100644 (file)
@@ -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
index 09b741a..7913a26 100644 (file)
@@ -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->"]
index 34bd636..aeceaf0 100644 (file)
@@ -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", 
index 30b2139..0baabff 100644 (file)
@@ -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<ip:%s/%s %s%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