Progress with LinuxTAP and UDP connections
[nepi.git] / src / nepi / resources / linux / tap.py
index ee977ef..f2e42a6 100644 (file)
@@ -76,6 +76,10 @@ class LinuxTap(LinuxApplication):
                 "Public IP of remote endpoint for GRE tunnel", 
                 flags = Flags.Design)
 
+        pi = Attribute("pi", "Add PI (protocol information) header", 
+                default = False,
+                type = Types.Bool)
         tear_down = Attribute("tearDown", 
                 "Bash script to be executed before releasing the resource",
                 flags = Flags.Design)
@@ -90,12 +94,14 @@ class LinuxTap(LinuxApplication):
         cls._register_attribute(txqueuelen)
         cls._register_attribute(gre_key)
         cls._register_attribute(gre_remote)
+        cls._register_attribute(pi)
         cls._register_attribute(tear_down)
 
     def __init__(self, ec, guid):
         super(LinuxTap, self).__init__(ec, guid)
         self._home = "tap-%s" % self.guid
         self._gre_enabled = False
+        self._tunnel_mode = False
 
     @property
     def node(self):
@@ -112,7 +118,37 @@ class LinuxTap(LinuxApplication):
 
         return self._gre_enabled
 
+    @property
+    def tunnel_mode(self):
+        if not self._tunnel_mode:
+            from nepi.resources.linux.tunnel import LinuxTunnel
+            tunnel = self.get_connected(LinuxTunnel.get_rtype())
+            if tunnel: self._tunnel_mode = True
+
+        return self._tunnel_mode
+
     def upload_sources(self):
+        scripts = []
+
+        # udp-connect python script
+        udp_connect = os.path.join(os.path.dirname(__file__), "scripts",
+                "linux-udp-connect.py")
+        
+        scripts.append(udp_connect)
+
+        # tunnel creation python script
+        tunchannel = os.path.join(os.path.dirname(__file__), "scripts", 
+                "tunchannel.py")
+
+        scripts.append(tunchannel)
+
+        # Upload scripts
+        scripts = ";".join(scripts)
+
+        self.node.upload(scripts,
+                os.path.join(self.node.src_dir),
+                overwrite = False)
+
         # upload stop.sh script
         stop_command = self.replace_paths(self._stop_command)
 
@@ -127,7 +163,7 @@ class LinuxTap(LinuxApplication):
     def upload_start_command(self):
         # If GRE mode is enabled, TAP creation is delayed until the
         # tunnel is established
-        if not self.gre_enabled:
+        if not self.tunnel_mode:
             # We want to make sure the device is up and running
             # before the deploy is over, so we execute the 
             # start script now and wait until it finishes. 
@@ -225,7 +261,7 @@ class LinuxTap(LinuxApplication):
 
         # invoke connect script
         cmd = "bash %s" % shfile
-        (out, err), proc = self.node.run(cmd, connection_run_home) 
+        (out, err), proc = self.node.run(cmd, connection_run_home)
              
         # check if execution errors occurred
         msg = " Failed to connect endpoints "
@@ -249,6 +285,105 @@ class LinuxTap(LinuxApplication):
         
         return True
 
+    ## XXX: NOT REALLY WORKING YET!
+    def udp_connect(self, remote_endpoint, connection_app_home, 
+            connection_run_home, cipher, cipher_key, bwlimit, txqueuelen):
+        udp_connect_command = self._udp_connect_command(
+                remote_endpoint, connection_run_home,
+                cipher, cipher_key, bwlimit, txqueuelen)
+
+        # upload command to connect.sh script
+        shfile = os.path.join(connection_app_home, "udp-connect.sh")
+        self.node.upload(udp_connect_command,
+                shfile,
+                text = True, 
+                overwrite = False)
+
+        # invoke connect script
+        cmd = "bash %s" % shfile
+        (out, err), proc = self.node.run(cmd, connection_run_home) 
+             
+        # check if execution errors occurred
+        msg = "Failed to connect endpoints "
+        
+        if proc.poll():
+            self.error(msg, out, err)
+            raise RuntimeError, msg
+    
+        # Wait for pid file to be generated
+        pid, ppid = self.node.wait_pid(connection_run_home)
+        
+        # If the process is not running, check for error information
+        # on the remote machine
+        if not pid or not ppid:
+            (out, err), proc = self.node.check_errors(connection_run_home)
+            # Out is what was written in the stderr file
+            if err:
+                msg = " Failed to start command '%s' " % command
+                self.error(msg, out, err)
+                raise RuntimeError, msg
+
+        return pid, ppid
+
+    def _udp_connect_command(self, remote_endpoint, connection_run_home, 
+            cipher, cipher_key, bwlimit, txqueuelen):
+
+        # Set the remote endpoint
+        self.set("pointopoint", remote_endpoint.get("ip4"))
+        
+        # Planetlab TAPs always use PI headers
+        from nepi.resources.planetlab.tap import PlanetlabTap
+        if self.is_rm_instance(PlanetlabTap.get_rtype()):
+            self.set("pi", True)
+
+        remote_ip = socket.gethostbyname(
+                remote_endpoint.node.get("hostname"))
+
+        local_port_file = os.path.join(connection_run_home, 
+                "local_port")
+
+        remote_port_file = os.path.join(connection_run_home, 
+                "remote_port")
+
+        ret_file = os.path.join(connection_run_home, 
+                "ret_file")
+
+        # Generate UDP connect command
+        # Use the start command to configure TAP with peer info
+        start_command = self._start_command
+        
+        command = ["( "]
+        command.append(start_command)
+
+        # Use pl-vid-udp-connect.py to stablish the tunnel between endpoints
+        command.append(") & (")
+        command.append("sudo -S")
+        command.append("PYTHONPATH=$PYTHONPATH:${SRC}")
+        command.append("python ${SRC}/linux-udp-connect.py")
+        command.append("-N %s" % self.get("deviceName"))
+        command.append("-t %s" % self.vif_type)
+        if self.get("pi"):
+            command.append("-p")
+        command.append("-l %s " % local_port_file)
+        command.append("-r %s " % remote_port_file)
+        command.append("-H %s " % remote_ip)
+        command.append("-R %s " % ret_file)
+        if cipher:
+            command.append("-c %s " % cipher)
+        if cipher_key:
+            command.append("-k %s " % cipher_key)
+        if txqueuelen:
+            command.append("-q %s " % txqueuelen)
+        if bwlimit:
+            command.append("-b %s " % bwlimit)
+
+        command.append(")")
+
+        command = " ".join(command)
+        command = self.replace_paths(command)
+
+        return command
+
     def _gre_connect_command(self, remote_endpoint, connection_run_home): 
         # Set the remote endpoint
         self.set("pointopoint", remote_endpoint.get("ip4"))
@@ -270,14 +405,31 @@ class LinuxTap(LinuxApplication):
     @property
     def _start_command(self):
         command = []
-        command.append("sudo -S ip tuntap add %s mode tap" % self.get("deviceName"))
-        command.append("sudo -S ip link set %s up" % self.get("deviceName"))
-        command.append("sudo -S ip addr add %s/%d dev %s" % (
-            self.get("ip4"),
-            self.get("prefix4"),
-            self.get("deviceName"),
-            ))
-        return ";".join(command)
+        if not self.gre_enabled:
+            # Make sure to clean TAP if it existed
+            stop_command = self._stop_command
+            
+            start_command = []
+            start_command.append("sudo -S ip tuntap add %s mode %s %s" % (
+                self.get("deviceName"),
+                self.vif_prefix,
+                "pi" if self.get("pi") else ""))
+            start_command.append("sudo -S ip link set %s up" % self.get("deviceName"))
+            start_command.append("sudo -S ip addr add %s/%d dev %s" % (
+                self.get("ip4"),
+                self.get("prefix4"),
+                self.get("deviceName"),
+                ))
+
+            start_command = ";".join(start_command)
+
+            command.append("(")
+            command.append(stop_command)
+            command.append(") ; (")
+            command.append(start_command)
+            command.append(")")
+
+        return " ".join(command)
 
     @property
     def _stop_command(self):