From: Julien Tribino Date: Mon, 10 Feb 2014 10:26:01 +0000 (+0100) Subject: update the openflow part and the ping experiment to work X-Git-Tag: nepi-3.1.0~126 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=f73ff8dcf111fe0bcfcd688a6571c49620935688;p=nepi.git update the openflow part and the ping experiment to work --- diff --git a/examples/linux/ping.py b/examples/linux/ping.py index eaee0dee..aa803642 100644 --- a/examples/linux/ping.py +++ b/examples/linux/ping.py @@ -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) diff --git a/examples/openvswitch/ovs_ping_exp.py b/examples/openvswitch/ovs_ping_exp.py index b07b3836..18c2f158 100644 --- a/examples/openvswitch/ovs_ping_exp.py +++ b/examples/openvswitch/ovs_ping_exp.py @@ -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 diff --git a/src/nepi/resources/planetlab/openvswitch/tunnel.py b/src/nepi/resources/planetlab/openvswitch/tunnel.py index a494212e..0b28327e 100644 --- a/src/nepi/resources/planetlab/openvswitch/tunnel.py +++ b/src/nepi/resources/planetlab/openvswitch/tunnel.py @@ -18,13 +18,16 @@ # Author: Alina Quereilhac # Alexandros Kouvakas + 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 index 00000000..04b42fab --- /dev/null +++ b/src/nepi/resources/planetlab/scripts/pl-vroute.py @@ -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 . +# +# Author: Alina Quereilhac + +import vsys +from optparse import OptionParser, SUPPRESS_HELP + +def get_options(): + usage = ("usage: %prog -a -n -p " + "-g -f ") + + 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) + + diff --git a/src/nepi/resources/planetlab/tap.py b/src/nepi/resources/planetlab/tap.py index 5ca85905..b6b1744c 100644 --- a/src/nepi/resources/planetlab/tap.py +++ b/src/nepi/resources/planetlab/tap.py @@ -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 index 00000000..681e7559 --- /dev/null +++ b/src/nepi/resources/planetlab/vroute.py @@ -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 . +# +# Author: Alina Quereilhac + +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 +