update the openflow part and the ping experiment to work
authorJulien Tribino <julien.tribino@inria.fr>
Mon, 10 Feb 2014 10:26:01 +0000 (11:26 +0100)
committerJulien Tribino <julien.tribino@inria.fr>
Mon, 10 Feb 2014 10:26:01 +0000 (11:26 +0100)
examples/linux/ping.py
examples/openvswitch/ovs_ping_exp.py
src/nepi/resources/planetlab/openvswitch/tunnel.py
src/nepi/resources/planetlab/scripts/pl-vroute.py [new file with mode: 0644]
src/nepi/resources/planetlab/tap.py
src/nepi/resources/planetlab/vroute.py [new file with mode: 0644]

index eaee0de..aa80364 100644 (file)
@@ -23,8 +23,8 @@ from nepi.execution.ec import ExperimentController
 ec = ExperimentController(exp_id = "ping-exp")
         
 node = ec.register_resource("LinuxNode")
-ec.set(node, "hostname", host)
-ec.set(node, "username", username)
+ec.set(node, "hostname", "planetlab2.cs.aueb.gr")
+ec.set(node, "username", "inria_pres")
 ec.set(node, "cleanHome", True)
 ec.set(node, "cleanProcesses", True)
 
index b07b383..18c2f15 100644 (file)
@@ -67,8 +67,9 @@ def add_tap(ec, ip4, prefix4, pointopoint, node):
     ec.register_connection(tap, node)
     return tap
 
-def add_tunnel(ec, port0, tap):
+def add_tunnel(ec, network, port0, tap):
     tunnel = ec.register_resource("OVSTunnel")
+    ec.set(tunnel, "network", network)
     ec.register_connection(port0, tunnel)
     ec.register_connection(tunnel, tap)
     return tunnel
@@ -87,6 +88,8 @@ switch2 = "planetlab2.upc.es"
 host1 = "planetlab2.ionio.gr"
 host2 = "iraplab2.iralab.uni-karlsruhe.de"
 
+network = "192.168.3.0"
+
 slicename = "inria_nepi"
 
 pl_user = os.environ.get("PL_USER")
@@ -113,26 +116,61 @@ tap1 = add_tap(ec, "192.168.3.3", 24, "192.168.3.1", h1_node)
 tap2 = add_tap(ec, "192.168.3.4", 24, "192.168.3.2", h2_node)
 
 # Connect the nodes
-tunnel1 = add_tunnel(ec, port1, tap1)
-tunnel2 = add_tunnel(ec, port2, tap2)
-tunnel3 = add_tunnel(ec, port3, port4)
+tunnel1 = add_tunnel(ec, network, port1, tap1)
+tunnel2 = add_tunnel(ec, network, port2, tap2)
+tunnel3 = add_tunnel(ec, network, port3, port4)
 
 # Add ping commands
-app1 = add_app(ec, "ping -c3 192.168.3.3", s1_node)
-app2 = add_app(ec, "ping -c3 192.168.3.4", s2_node)
+app1 = add_app(ec, "ping -c5 192.168.3.2", s1_node)
+app2 = add_app(ec, "ping -c5 192.168.3.3", s1_node)
+app3 = add_app(ec, "ping -c5 192.168.3.4", s1_node)
+app4 = add_app(ec, "ping -c5 192.168.3.1", s2_node)
+app5 = add_app(ec, "ping -c5 192.168.3.3", s2_node)
+app6 = add_app(ec, "ping -c5 192.168.3.4", s2_node)
+app7 = add_app(ec, "ping -c5 192.168.3.1", h1_node)
+app8 = add_app(ec, "ping -c5 192.168.3.2", h1_node)
+app9 = add_app(ec, "ping -c5 192.168.3.4", h1_node)
+app10 = add_app(ec, "ping -c5 192.168.3.1", h2_node)
+app11 = add_app(ec, "ping -c5 192.168.3.2", h2_node)
+app12 = add_app(ec, "ping -c5 192.168.3.3", h2_node)
 
 ec.deploy()
 
-ec.wait_finished([app2])
+ec.wait_finished([app1, app2, app3, app4, app5, app6, app7, app8, app9, app10, app11, app12])
 
 # Retreive ping results and save
 # them in a file
 ping1 = ec.trace(app1, 'stdout')
 ping2 = ec.trace(app2, 'stdout')
-f = open("examples/openvswitch/ping_res.txt", 'w').close()
-f = open("examples/openvswitch/ping_res.txt", 'a')
+ping3 = ec.trace(app3, 'stdout')
+ping4 = ec.trace(app4, 'stdout')
+ping5 = ec.trace(app5, 'stdout')
+ping6 = ec.trace(app6, 'stdout')
+ping7 = ec.trace(app7, 'stdout')
+ping8 = ec.trace(app8, 'stdout')
+ping9 = ec.trace(app9, 'stdout')
+ping10 = ec.trace(app10, 'stdout')
+ping11 = ec.trace(app11, 'stdout')
+ping12 = ec.trace(app12, 'stdout')
+
+
+f = open("examples/openvswitch/ping_res.txt", 'w')
+
+if not ping12:
+  ec.shutdown()
+
 f.write(ping1)
 f.write(ping2)
+f.write(ping3)
+f.write(ping4)
+f.write(ping5)
+f.write(ping6)
+f.write(ping7)
+f.write(ping8)
+f.write(ping9)
+f.write(ping10)
+f.write(ping11)
+f.write(ping12)
 f.close()
 
 # Delete the overlay network
index a494212..0b28327 100644 (file)
 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
 #            Alexandros Kouvakas <alexandros.kouvakas@gmail.com>
 
+
 from nepi.execution.attribute import Attribute, Flags, Types
-from nepi.execution.resource import ResourceManager, clsinit_copy, \
+from nepi.execution.resource import ResourceManager, ResourceFactory, clsinit_copy, \
         ResourceState
 from nepi.resources.linux.application import LinuxApplication
 from nepi.resources.planetlab.node import PlanetlabNode            
 from nepi.resources.planetlab.openvswitch.ovs import OVSWitch   
-from nepi.util.timefuncs import tnow, tdiffsec     
+from nepi.util.timefuncs import tnow, tdiffsec    
+from nepi.resources.planetlab.vroute import PlanetlabVroute
+from nepi.resources.planetlab.tap import PlanetlabTap
 
 import os
 import time
@@ -54,6 +57,9 @@ class OVSTunnel(LinuxApplication):
         """ Register the attributes of Connection RM 
 
         """
+        network = Attribute("network", "IPv4 Network Address",
+               flags = Flags.ExecReadOnly)
+
         cipher = Attribute("cipher",
                "Cipher to encript communication. "
                 "One of PLAIN, AES, Blowfish, DES, DES3. ",
@@ -80,6 +86,7 @@ class OVSTunnel(LinuxApplication):
                 type = Types.Integer, 
                 flags = Flags.ExecReadOnly)
 
+        cls._register_attribute(network)
         cls._register_attribute(cipher)
         cls._register_attribute(cipher_key)
         cls._register_attribute(txqueuelen)
@@ -99,6 +106,7 @@ class OVSTunnel(LinuxApplication):
         self._nodes = []
         self._pid = None
         self._ppid = None
+        self._vroute = None
 
 
     def log_message(self, msg):
@@ -110,7 +118,7 @@ class OVSTunnel(LinuxApplication):
             return self._nodes[0]
 
     def app_home(self, node):
-        return os.path.join(node.exp_home, self._home)
+        return os.path.join(self.node.exp_home, self._home)
 
     def run_home(self, node):
         return os.path.join(self.app_home(node), self.ec.run_id)
@@ -124,6 +132,7 @@ class OVSTunnel(LinuxApplication):
                 connected.append(rm)
         return connected
 
+    
     def mixed_endpoints(self):
         # Switch-Host connection
         connected = [1, 2]
@@ -151,7 +160,7 @@ class OVSTunnel(LinuxApplication):
 
     @property
     def endpoint1(self):
-        if self.check_endpoints():
+        if self.check_endpoints:
             port_endpoints = self.port_endpoints()
             if port_endpoints: return port_endpoints[0]
         else:
@@ -160,13 +169,14 @@ class OVSTunnel(LinuxApplication):
 
     @property
     def endpoint2(self):
-        if self.check_endpoints():
+        if self.check_endpoints:
             port_endpoints = self.port_endpoints()
             if port_endpoints: return port_endpoints[1]
         else:
             mixed_endpoints = self.mixed_endpoints()
             if mixed_endpoints: return mixed_endpoints[1]
-                
+
+    @property          
     def check_endpoints(self):
         """ Check if the links are between switches
             or switch-host. Return False for latter.
@@ -184,7 +194,7 @@ class OVSTunnel(LinuxApplication):
             :type port_info_tunl: list
         """
         self.port_info_tunl = []
-        if self.check_endpoints():
+        if self.check_endpoints:
             # Use for the link switch-->switch
             self.port_info_tunl.append(endpoint.port_info)
             host0, ip0, pname0, virt_ip0, pnumber0 = self.port_info_tunl[0]
@@ -300,16 +310,38 @@ class OVSTunnel(LinuxApplication):
         msg = "Connection on port %s configured" % local_port_name
         self.info(msg)
 
+    def wait_local_port(self):
+        """ Waits until the if_name file for the command is generated, 
+            and returns the if_name for the device """
+        local_port = None
+        delay = 1.0
+
+        for i in xrange(10):
+            (out, err), proc = self.node.check_output(self.run_home(self.node), 'local_port')
+
+            if out:
+                local_port = int(out)
+                break
+            else:
+                time.sleep(delay)
+                delay = delay * 1.5
+        else:
+            msg = "Couldn't retrieve local_port"
+            self.error(msg, out, err)
+            raise RuntimeError, msg
+
+        return local_port
+
     def sw_host_connect(self, endpoint, rem_endpoint):
         """Link switch--> host
         """
         # Retrieve remote port number from rem_endpoint
         local_port_name = endpoint.get('port_name')
         self._nodes = self.get_node(rem_endpoint)
-        time.sleep(2) # Without this, sometimes I get nothing in remote_port_num
-        remote_port_num = ''
-        (out, err), proc = self.node.check_output(self.run_home(self.node), 'local_port')
-        remote_port_num = int(out)
+
+     #   time.sleep(4) # Without this, sometimes I get nothing in remote_port_num
+        out = err= ''
+        remote_port_num = self.wait_local_port()
         remote_ip = socket.gethostbyname(self.node.get("hostname"))
         switch_connect_command = endpoint.switch_connect_command(
                 local_port_name, remote_ip, remote_port_num)
@@ -349,7 +381,7 @@ class OVSTunnel(LinuxApplication):
         self._nodes = self.get_node(self.endpoint2)
         self.node.mkdir(self.run_home(self.node))
 
-        if self.check_endpoints():
+        if self.check_endpoints:
             #Invoke connect script between switches
             self.switch_connect(self.endpoint1, self.endpoint2)
             self.switch_connect(self.endpoint2, self.endpoint1)
@@ -361,6 +393,34 @@ class OVSTunnel(LinuxApplication):
 
         super(OVSTunnel, self).do_provision()
 
+    @property
+    def tap(self):
+        rclass = ResourceFactory.get_resource_type(PlanetlabTap.get_rtype())
+        for guid in self.connections:
+            rm = self.ec.get_resource(guid)
+            if isinstance(rm, rclass):
+                return rm
+
+    @property
+    def ovswitch(self):
+        for guid in self.connections:
+            rm_port = self.ec.get_resource(guid)
+            if hasattr(rm_port, "create_port"):
+                rm_list = rm_port.get_connected(OVSWitch.get_rtype())
+                if rm_list:
+                    return rm_list[0]
+
+    def configure(self):
+        if not self.check_endpoints:
+            self._vroute = self.ec.register_resource("PlanetlabVroute")
+            self.ec.set(self._vroute, "action", "add")
+            self.ec.set(self._vroute, "network", self.get("network"))
+
+            self.ec.register_connection(self._vroute, self.tap.guid)
+            # schedule deploy
+            self.ec.deploy(guids=[self._vroute], group = self.deployment_group)
+
+
     def do_deploy(self):
         if (not self.endpoint1 or self.endpoint1.state < ResourceState.READY) or \
             (not self.endpoint2 or self.endpoint2.state < ResourceState.READY):
@@ -369,6 +429,7 @@ class OVSTunnel(LinuxApplication):
 
         self.do_discover()
         self.do_provision()
+        self.configure()
 
         super(OVSTunnel, self).do_deploy()
  
@@ -376,7 +437,7 @@ class OVSTunnel(LinuxApplication):
         """ Release the udp_tunnel on endpoint2.
             On endpoint1 means nothing special.        
         """
-        if not self.check_endpoints():
+        if not self.check_endpoints:
             # Kill the TAP devices
             # TODO: Make more generic Release method of PLTAP
             if self._pid and self._ppid:
diff --git a/src/nepi/resources/planetlab/scripts/pl-vroute.py b/src/nepi/resources/planetlab/scripts/pl-vroute.py
new file mode 100644 (file)
index 0000000..04b42fa
--- /dev/null
@@ -0,0 +1,56 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    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/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+import vsys
+from optparse import OptionParser, SUPPRESS_HELP
+
+def get_options():
+    usage = ("usage: %prog -a <action> -n <ip4-network> -p <ip4-prefix> "
+        "-g <gateway> -f <if-name-file>")
+    
+    parser = OptionParser(usage = usage)
+
+    parser.add_option("-a", "--action", dest="action",
+        help = "Either add or del ", type="str")
+
+    parser.add_option("-n", "--ip4-network-address", dest="ip4_network",
+        help = "IPv4 address of the network ", type="str")
+
+    parser.add_option("-p", "--ip4-prefix", dest="ip4_prefix",
+        help = "IPv4 network prefix for the interface. It must be the one "
+            "given by the slice's vsys_vnet tag. ",
+        type="int")
+
+    parser.add_option("-g", "--ip4-gateway", dest="ip4_gateway",
+        help="IPv4 address of the gateway")
+
+    parser.add_option("-f", "--if-name", dest="if_name",
+        help = "Interface name assigned by the OS", type="str")
+
+    (options, args) = parser.parse_args()
+
+    return (options.action, options.ip4_network, options.ip4_prefix,
+            options.ip4_gateway, options.if_name)
+
+if __name__ == '__main__':
+
+    (action, ip4_network, ip4_prefix, ip4_gateway, if_name) = get_options()
+    vsys.vroute(action, ip4_network, ip4_prefix, ip4_gateway, if_name)
+    
+  
index 5ca8590..b6b1744 100644 (file)
@@ -231,7 +231,7 @@ class PlanetlabTap(LinuxApplication):
         if_name = None
         delay = 1.0
 
-        for i in xrange(4):
+        for i in xrange(10):
             (out, err), proc = self.node.check_output(self.run_home, "if_name")
 
             if out:
diff --git a/src/nepi/resources/planetlab/vroute.py b/src/nepi/resources/planetlab/vroute.py
new file mode 100644 (file)
index 0000000..681e755
--- /dev/null
@@ -0,0 +1,169 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    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/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+
+from nepi.execution.attribute import Attribute, Flags, Types
+from nepi.execution.resource import clsinit_copy, ResourceState, \
+        reschedule_delay
+from nepi.resources.linux.application import LinuxApplication
+from nepi.resources.planetlab.node import PlanetlabNode
+from nepi.resources.planetlab.tap import PlanetlabTap
+from nepi.util.timefuncs import tnow, tdiffsec
+
+import os
+import time
+
+PYTHON_VSYS_VERSION = "1.0"
+
+@clsinit_copy
+class PlanetlabVroute(LinuxApplication):
+    _rtype = "PlanetlabVroute"
+    _help = "Creates a Vroute on a PlanetLab host"
+    _backend = "planetlab"
+
+    @classmethod
+    def _register_attributes(cls):
+        action = Attribute("action", "Either add or del",
+              allowed = ["add", "del"],
+              flags = Flags.ExecReadOnly)
+
+        network = Attribute("network", "IPv4 Network Address",
+              flags = Flags.ExecReadOnly)
+
+        cls._register_attribute(action)
+        cls._register_attribute(network)
+
+    def __init__(self, ec, guid):
+        super(PlanetlabVroute, self).__init__(ec, guid)
+        self._home = "vroute-%s" % self.guid
+
+    @property
+    def tap(self):
+        tap = self.get_connected(PlanetlabTap.get_rtype())
+        if tap: return tap[0]
+        return None
+
+    @property
+    def node(self):
+        node = self.tap.get_connected(PlanetlabNode.get_rtype())
+        if node: return node[0]
+        return None
+
+    def upload_sources(self):
+        # upload vif-creation python script
+        pl_vroute = os.path.join(os.path.dirname(__file__), "scripts",
+                "pl-vroute.py")
+
+        self.node.upload(pl_vroute,
+                os.path.join(self.node.src_dir, "pl-vroute.py"),
+                overwrite = False)
+
+        # upload stop.sh script
+        stop_command = self.replace_paths(self._stop_command)
+        self.node.upload(stop_command,
+                os.path.join(self.app_home, "stop.sh"),
+                text = True,
+                # Overwrite file every time. 
+                # The stop.sh has the path to the socket, wich should change
+                # on every experiment run.
+                overwrite = True)
+
+    def upload_start_command(self):
+        # Overwrite file every time. 
+        # The stop.sh has the path to the socket, wich should change
+        # on every experiment run.
+        super(PlanetlabVroute, self).upload_start_command(overwrite = True)
+
+        (out, err), proc = self.execute_command(self.get("command"), blocking = True)
+    def do_deploy(self):
+        if not self.tap or self.tap.state < ResourceState.PROVISIONED:
+            self.ec.schedule(reschedule_delay, self.deploy)
+        else:
+            if not self.get("command"):
+                self.set("command", self._start_command)
+
+            self.do_discover()
+            self.do_provision()
+
+            self.debug("----- READY ---- ")
+            self.set_ready()
+
+    def do_start(self):
+        if self.state == ResourceState.READY:
+            command = self.get("command")
+            self.info("Starting command '%s'" % command)
+
+            # Vroute started during deployment
+            self.set_started()
+        else:
+            msg = " Failed to execute command '%s'" % command
+            self.error(msg, out, err)
+            raise RuntimeError, msg
+
+    def do_stop(self):
+
+        command = self.get('command') or ''
+
+        if self.state == ResourceState.STARTED:
+            self.info("Stopping command '%s'" % self._stop_command)
+
+            command = "bash %s" % os.path.join(self.app_home, "stop.sh")
+            (out, err), proc = self.execute_command(command,
+                    blocking = True)
+
+            self.set_stopped()
+
+    def do_release(self):
+        # Node needs to wait until all associated RMs are released
+        # to be released
+        if not self.get("tearDown"):
+            self.set("tearDown", self._tear_down_command())
+
+        super(PlanetlabVroute, self).do_release()
+
+    def _tear_down_command(self):
+        if self.get("action") == "del":
+            return
+
+        return self._stop_command
+
+    @property
+    def _start_command(self):
+        command = ["sudo -S python ${SRC}/pl-vroute.py"]
+        command.append("-a %s" % self.get("action"))
+        command.append("-n %s" % self.get("network"))
+        command.append("-p %d" % self.tap.get("prefix4"))
+        command.append("-g %s" % self.tap.get("pointopoint"))
+        command.append("-f %s" % self.tap.get("deviceName"))
+        return " ".join(command)
+
+    @property
+    def _stop_command(self):
+        command = ["sudo -S python ${SRC}/pl-vroute.py"]
+        command.append("-a %s" % "del")
+        command.append("-n %s" % self.get("network"))
+        command.append("-p %d" % self.tap.get("prefix4"))
+        command.append("-g %s" % self.tap.get("pointopoint"))
+        command.append("-f %s" % self.tap.get("deviceName"))
+        return " ".join(command)
+
+    def valid_connection(self, guid):
+        # TODO: Validate!
+        return True
+